From 869430354f71312ab924359f63ef7e226d06ed24 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 12 Mar 2026 12:26:07 +0100 Subject: [PATCH 01/23] CANTON: Wip --- asset.go | 10 +- chain/canton/address/address.go | 82 ++ chain/canton/address/address_test.go | 174 ++++ chain/canton/builder/builder.go | 65 ++ chain/canton/client/client.go | 877 ++++++++++++++++++ chain/canton/client/client_test.go | 44 + chain/canton/client/ledger.go | 1260 ++++++++++++++++++++++++++ chain/canton/errors.go | 37 + chain/canton/keycloak/keycloak.go | 259 ++++++ chain/canton/signature_test.go | 28 + chain/canton/tx/tx.go | 97 ++ chain/canton/tx_input/tx_input.go | 65 ++ chain/canton/validate.go | 90 ++ chain/canton/validate_test.go | 299 ++++++ cmd/xc/commands/transfer.go | 8 +- factory/canton_signer_test.go | 82 ++ factory/defaults/canton_test.go | 43 + factory/defaults/chains/mainnet.yaml | 7 + factory/defaults/chains/testnet.yaml | 8 + factory/drivers/drivers_test.go | 3 + factory/drivers/factory.go | 14 + go.mod | 12 +- go.sum | 75 +- 23 files changed, 3606 insertions(+), 33 deletions(-) create mode 100644 chain/canton/address/address.go create mode 100644 chain/canton/address/address_test.go create mode 100644 chain/canton/builder/builder.go create mode 100644 chain/canton/client/client.go create mode 100644 chain/canton/client/client_test.go create mode 100644 chain/canton/client/ledger.go create mode 100644 chain/canton/errors.go create mode 100644 chain/canton/keycloak/keycloak.go create mode 100644 chain/canton/signature_test.go create mode 100644 chain/canton/tx/tx.go create mode 100644 chain/canton/tx_input/tx_input.go create mode 100644 chain/canton/validate.go create mode 100644 chain/canton/validate_test.go create mode 100644 factory/canton_signer_test.go create mode 100644 factory/defaults/canton_test.go diff --git a/asset.go b/asset.go index 3db21230..d4e9ea56 100644 --- a/asset.go +++ b/asset.go @@ -44,6 +44,7 @@ const ( BCH = NativeAsset("BCH") // Bitcoin Cash BNB = NativeAsset("BNB") // Binance Coin BTC = NativeAsset("BTC") // Bitcoin + CANTON = NativeAsset("CANTON") // Canton CELO = NativeAsset("CELO") // Celo CHZ = NativeAsset("CHZ") // Chiliz CHZ2 = NativeAsset("CHZ2") // Chiliz 2.0 @@ -114,6 +115,7 @@ var NativeAssetList []NativeAsset = []NativeAsset{ BABY, BCH, BTC, + CANTON, DASH, DOGE, LTC, @@ -196,6 +198,7 @@ const ( DriverBitcoin = Driver("bitcoin") DriverBitcoinCash = Driver("bitcoin-cash") DriverBitcoinLegacy = Driver("bitcoin-legacy") + DriverCanton = Driver("canton") DriverCardano = Driver("cardano") DriverCosmos = Driver("cosmos") DriverCosmosEvmos = Driver("evmos") @@ -228,6 +231,7 @@ var SupportedDrivers = []Driver{ DriverBitcoin, DriverBitcoinCash, DriverBitcoinLegacy, + DriverCanton, DriverCosmos, DriverCosmosEvmos, DriverEGLD, @@ -314,6 +318,8 @@ func (native NativeAsset) Driver() Driver { return DriverBitcoin case BCH: return DriverBitcoinCash + case CANTON: + return DriverCanton case DOGE, LTC, DASH: return DriverBitcoinLegacy case ZEC, FLUX: @@ -376,7 +382,7 @@ func (driver Driver) SignatureAlgorithms() []SignatureType { return []SignatureType{K256Sha256} case DriverEVM, DriverEVMLegacy, DriverCosmosEvmos, DriverTron, DriverHyperliquid, DriverHedera, DriverTempo: return []SignatureType{K256Keccak} - case DriverAptos, DriverSolana, DriverSui, DriverTon, DriverSubstrate, DriverXlm, DriverCardano, DriverInternetComputerProtocol, DriverNear, DriverEGLD: + case DriverAptos, DriverSolana, DriverSui, DriverTon, DriverSubstrate, DriverXlm, DriverCardano, DriverInternetComputerProtocol, DriverNear, DriverEGLD, DriverCanton: return []SignatureType{Ed255} case DriverDusk: return []SignatureType{Bls12_381G2Blake2} @@ -401,7 +407,7 @@ func (driver Driver) PublicKeyFormat() PublicKeyFormat { case DriverEVM, DriverEVMLegacy, DriverTron, DriverFilecoin, DriverHyperliquid, DriverHedera, DriverTempo: return Uncompressed case DriverAptos, DriverSolana, DriverSui, DriverTon, DriverSubstrate, DriverDusk, - DriverKaspa, DriverInternetComputerProtocol, DriverNear, DriverEGLD: + DriverKaspa, DriverInternetComputerProtocol, DriverNear, DriverEGLD, DriverCanton: return Raw } return "" diff --git a/chain/canton/address/address.go b/chain/canton/address/address.go new file mode 100644 index 00000000..393b24af --- /dev/null +++ b/chain/canton/address/address.go @@ -0,0 +1,82 @@ +package address + +import ( + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + "strings" + + xc "github.com/cordialsys/crosschain" +) + +// AddressBuilder for Canton +type AddressBuilder struct{} + +var _ xc.AddressBuilder = AddressBuilder{} + +func NewAddressBuilder(cfgI *xc.ChainBaseConfig) (xc.AddressBuilder, error) { + return AddressBuilder{}, nil +} + +// GetAddressFromPublicKey returns a Canton party ID from a raw Ed25519 public key (32 bytes). +// +// Canton party IDs have the form: :: +// +// Where: +// - = hex-encoded public key (64 hex chars) +// - = "1220" + hex(SHA-256(purposeBytes || rawPubKey)) +// +// The purpose prefix is big-endian uint32(12), matching Canton's internal +// HashPurpose.PublicKeyFingerprint (id=12) in Hash.digest(). +// +// The "1220" multihash prefix encodes: +// - 0x12 = SHA-256 algorithm code (varint) +// - 0x20 = 32-byte digest length (varint) +func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { + return GetAddressFromPublicKey(publicKeyBytes) +} + +func GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { + if len(publicKeyBytes) != 32 { + return "", fmt.Errorf("invalid ed25519 public key length: expected 32 bytes, got %d", len(publicKeyBytes)) + } + fingerprint := computeFingerprint(publicKeyBytes) + name := hex.EncodeToString(publicKeyBytes) + addr := xc.Address(name + "::" + fingerprint) + + return addr, nil +} + +// computeFingerprint returns the Canton key fingerprint for a raw Ed25519 public key. +// +// fingerprint = "1220" + hex(SHA-256(bigEndianUint32(12) || rawPubKey)) +func computeFingerprint(rawPubKey []byte) string { + // HashPurpose.PublicKeyFingerprint id=12 encoded as big-endian int32 (4 bytes) + var purposeBytes [4]byte + binary.BigEndian.PutUint32(purposeBytes[:], 12) + + h := sha256.New() + h.Write(purposeBytes[:]) + h.Write(rawPubKey) + digest := h.Sum(nil) + + // Multihash: varint(0x12=SHA-256) || varint(0x20=32) || digest + return "1220" + hex.EncodeToString(digest) +} + +// ParsePartyID splits a Canton party ID into its name and fingerprint components. +// Expected format: "::" where fingerprint starts with "1220". +func ParsePartyID(addr xc.Address) (name string, fingerprint string, err error) { + s := string(addr) + idx := strings.Index(s, "::") + if idx < 0 { + return "", "", fmt.Errorf("invalid Canton party ID %q: missing '::' separator", s) + } + name = s[:idx] + fingerprint = s[idx+2:] + if len(fingerprint) < 4 || fingerprint[:4] != "1220" { + return "", "", fmt.Errorf("invalid Canton fingerprint %q: must start with '1220' (SHA-256 multihash prefix)", fingerprint) + } + return name, fingerprint, nil +} diff --git a/chain/canton/address/address_test.go b/chain/canton/address/address_test.go new file mode 100644 index 00000000..1680cc71 --- /dev/null +++ b/chain/canton/address/address_test.go @@ -0,0 +1,174 @@ +package address + +import ( + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "testing" + + xc "github.com/cordialsys/crosschain" + "github.com/stretchr/testify/require" +) + +// referenceFingerprint replicates Canton's fingerprint logic for test verification: +// SHA-256(bigEndianUint32(12) || rawPubKey), encoded as "1220" + hex(digest) +func referenceFingerprint(pubKey []byte) string { + var purposeBytes [4]byte + binary.BigEndian.PutUint32(purposeBytes[:], 12) + h := sha256.New() + h.Write(purposeBytes[:]) + h.Write(pubKey) + return "1220" + hex.EncodeToString(h.Sum(nil)) +} + +func TestNewAddressBuilder(t *testing.T) { + cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} + builder, err := NewAddressBuilder(cfg) + require.NoError(t, err) + require.NotNil(t, builder) +} + +func TestGetAddressFromPublicKey(t *testing.T) { + cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} + builder, err := NewAddressBuilder(cfg) + require.NoError(t, err) + + pubKey := make([]byte, 32) + for i := range pubKey { + pubKey[i] = byte(i) + } + + addr, err := builder.GetAddressFromPublicKey(pubKey) + require.NoError(t, err) + + name, fingerprint, err := ParsePartyID(addr) + require.NoError(t, err) + + // Name must be the hex-encoded public key + require.Equal(t, hex.EncodeToString(pubKey), name) + + // Fingerprint must be "1220" + 64 hex chars (SHA-256 multihash) + require.Equal(t, 68, len(fingerprint), "fingerprint must be 68 chars: 4 (1220) + 64 (SHA-256 hex)") + require.Equal(t, "1220", fingerprint[:4]) + + // Fingerprint value must match Canton's formula + require.Equal(t, referenceFingerprint(pubKey), fingerprint) +} + +func TestGetAddressFromPublicKeyInvalidLength(t *testing.T) { + cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} + builder, err := NewAddressBuilder(cfg) + require.NoError(t, err) + + for _, bad := range [][]byte{make([]byte, 16), make([]byte, 64), {}} { + _, err := builder.GetAddressFromPublicKey(bad) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid ed25519 public key length") + } +} + +func TestAddressDeterminism(t *testing.T) { + cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} + builder, err := NewAddressBuilder(cfg) + require.NoError(t, err) + + pubKey := make([]byte, 32) + for i := range pubKey { + pubKey[i] = byte(i * 7 % 256) + } + + addr1, err := builder.GetAddressFromPublicKey(pubKey) + require.NoError(t, err) + addr2, err := builder.GetAddressFromPublicKey(pubKey) + require.NoError(t, err) + require.Equal(t, addr1, addr2) +} + +func TestDifferentKeysProduceDifferentAddresses(t *testing.T) { + cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} + builder, _ := NewAddressBuilder(cfg) + + key1 := make([]byte, 32) + key2 := make([]byte, 32) + key2[0] = 1 + + addr1, _ := builder.GetAddressFromPublicKey(key1) + addr2, _ := builder.GetAddressFromPublicKey(key2) + require.NotEqual(t, addr1, addr2) +} + +func TestParsePartyID(t *testing.T) { + validFP := "1220" + hex.EncodeToString(make([]byte, 32)) // "1220" + 64 zeros + + tests := []struct { + name string + addr xc.Address + expectErr bool + errContains string + expectedName string + expectedFP string + }{ + { + name: "valid - pubkey hex name", + addr: xc.Address("aabbccdd::" + validFP), + expectedName: "aabbccdd", + expectedFP: validFP, + }, + { + name: "valid - real-world style", + addr: xc.Address("example-validator-1::12201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"), + expectedName: "example-validator-1", + expectedFP: "12201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + }, + { + name: "missing separator", + addr: xc.Address("nocolons1220aabbccdd"), + expectErr: true, + errContains: "missing '::'", + }, + { + name: "wrong prefix - old format", + addr: xc.Address("party::12aabbccdd"), + expectErr: true, + errContains: "1220", + }, + { + name: "wrong prefix - all zeros", + addr: xc.Address("party::0000" + hex.EncodeToString(make([]byte, 32))), + expectErr: true, + errContains: "1220", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + name, fp, err := ParsePartyID(tt.addr) + if tt.expectErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errContains) + } else { + require.NoError(t, err) + require.Equal(t, tt.expectedName, name) + require.Equal(t, tt.expectedFP, fp) + } + }) + } +} + +func TestFingerprintLength(t *testing.T) { + // Any valid 32-byte key must produce a 68-char fingerprint + cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} + builder, _ := NewAddressBuilder(cfg) + + for _, seed := range []byte{0, 1, 127, 255} { + key := make([]byte, 32) + for i := range key { + key[i] = seed + } + addr, err := builder.GetAddressFromPublicKey(key) + require.NoError(t, err) + _, fp, err := ParsePartyID(addr) + require.NoError(t, err) + require.Equal(t, 68, len(fp), "fingerprint must always be 68 chars") + } +} diff --git a/chain/canton/builder/builder.go b/chain/canton/builder/builder.go new file mode 100644 index 00000000..61d48f89 --- /dev/null +++ b/chain/canton/builder/builder.go @@ -0,0 +1,65 @@ +package builder + +import ( + "fmt" + + xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + cantontx "github.com/cordialsys/crosschain/chain/canton/tx" + "github.com/cordialsys/crosschain/chain/canton/tx_input" +) + +// TxBuilder for Canton +type TxBuilder struct { + Asset *xc.ChainBaseConfig +} + +var _ xcbuilder.FullTransferBuilder = TxBuilder{} + +// NewTxBuilder creates a new Canton TxBuilder +func NewTxBuilder(cfgI *xc.ChainBaseConfig) (TxBuilder, error) { + return TxBuilder{ + Asset: cfgI, + }, nil +} + +// Transfer creates a new transfer for an Asset, either native or token +func (txBuilder TxBuilder) Transfer(args xcbuilder.TransferArgs, input xc.TxInput) (xc.Tx, error) { + if contract, ok := args.GetContract(); ok { + return txBuilder.NewTokenTransfer(args, contract, input) + } + return txBuilder.NewNativeTransfer(args, input) +} + +// NewNativeTransfer creates a Tx from the prepared transaction in TxInput. +// The heavy lifting (command building, prepare call) was done in FetchTransferInput. +func (txBuilder TxBuilder) NewNativeTransfer(args xcbuilder.TransferArgs, input xc.TxInput) (xc.Tx, error) { + cantonInput, ok := input.(*tx_input.TxInput) + if !ok { + return nil, fmt.Errorf("invalid tx input type for Canton, expected *tx_input.TxInput") + } + + // Extract the key fingerprint from the sender's party ID + // Party format: name::12 + _, fingerprint, err := cantonaddress.ParsePartyID(args.GetFrom()) + if err != nil { + return nil, fmt.Errorf("failed to parse sender party ID: %w", err) + } + + tx := &cantontx.Tx{ + PreparedTransaction: &cantonInput.PreparedTransaction, + PreparedTransactionHash: cantonInput.Sighash, + HashingSchemeVersion: cantonInput.HashingSchemeVersion, + Party: string(args.GetFrom()), + KeyFingerprint: fingerprint, + SubmissionId: cantonInput.SubmissionId, + } + + return tx, nil +} + +// NewTokenTransfer is not supported for Canton +func (txBuilder TxBuilder) NewTokenTransfer(args xcbuilder.TransferArgs, contract xc.ContractAddress, input xc.TxInput) (xc.Tx, error) { + return nil, fmt.Errorf("token transfers are not supported for %s", txBuilder.Asset.Chain) +} diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go new file mode 100644 index 00000000..ab29bf67 --- /dev/null +++ b/chain/canton/client/client.go @@ -0,0 +1,877 @@ +package client + +import ( + "context" + "crypto/ed25519" + "encoding/hex" + "errors" + "fmt" + "os" + "strconv" + "strings" + "time" + + xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + cantonkc "github.com/cordialsys/crosschain/chain/canton/keycloak" + cantontx "github.com/cordialsys/crosschain/chain/canton/tx" + "github.com/cordialsys/crosschain/chain/canton/tx_input" + xclient "github.com/cordialsys/crosschain/client" + txinfo "github.com/cordialsys/crosschain/client/tx_info" + xctypes "github.com/cordialsys/crosschain/client/types" + "github.com/cosmos/gogoproto/proto" + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "github.com/sirupsen/logrus" +) + + +// Client for Canton using the gRPC Ledger API +type Client struct { + Asset *xc.ChainConfig + + ledgerClient *GrpcLedgerClient + + // adminKC fetches operator-level tokens (client_credentials grant). + adminKC *cantonkc.Client + // walletKC acquires canton-ui tokens for scan proxy HTTP calls. + walletKC *cantonkc.Client + + cantonUiUsername string + cantonUiPassword string +} + +var _ xclient.Client = &Client{} + +// NewClient returns a new Canton gRPC Client +func NewClient(cfgI *xc.ChainConfig) (*Client, error) { + cfg := cfgI.GetChain() + + if cfg.URL == "" { + return nil, fmt.Errorf("no URL configured for Canton client") + } + + keycloakURL, err := cantonEnv("CANTON_KEYCLOAK_URL") + if err != nil { + return nil, err + } + keycloakRealm, err := cantonEnv("CANTON_KEYCLOAK_REALM") + if err != nil { + return nil, err + } + adminClientID, err := cantonEnv("CANTON_VALIDATOR_ID") + if err != nil { + return nil, err + } + adminClientSecret, err := cantonEnv("CANTON_VALIDATOR_SECRET") + if err != nil { + return nil, err + } + cantonUiUsername, err := cantonEnv("CANTON_UI_ID") + if err != nil { + return nil, err + } + cantonUiPassword, err := cantonEnv("CANTON_UI_PASSWORD") + if err != nil { + return nil, err + } + + client := &Client{ + Asset: cfgI, + adminKC: cantonkc.NewClient(keycloakURL, keycloakRealm, adminClientID, adminClientSecret), + walletKC: cantonkc.NewClient(keycloakURL, keycloakRealm, adminClientID, adminClientSecret), + cantonUiUsername: cantonUiUsername, + cantonUiPassword: cantonUiPassword, + } + + authToken, err := client.adminKC.AdminToken(context.Background()) + if err != nil { + return nil, fmt.Errorf("failed to fetch auth token: %w", err) + } + if authToken == "" { + return nil, errors.New("invalid authToken") + } + + grpcClient, err := NewGrpcLedgerClient(cfg.URL, authToken) + if err != nil { + return nil, fmt.Errorf("failed to create GrpcLedgerClient: %w", err) + } + client.ledgerClient = grpcClient + + return client, nil +} + +// cantonUIToken acquires a canton-ui Keycloak token used for scan proxy HTTP calls. +func (client *Client) cantonUIToken(ctx context.Context) (string, error) { + resp, err := client.walletKC.AcquireCantonUiToken(ctx, client.cantonUiUsername, client.cantonUiPassword) + if err != nil { + return "", fmt.Errorf("failed to acquire canton-ui token: %w", err) + } + return resp.AccessToken, nil +} + +func (client *Client) PrepareTransferOfferCommand(ctx context.Context, args xcbuilder.TransferArgs, amuletRules AmuletRules) (*interactive.PrepareSubmissionResponse, error) { + // amount := args.GetAmount() + // amountStr := amount.ToHuman(10) + commandID := newRegisterCommandId() + cmd := &v2.Command{ + Command: &v2.Command_Create{ + Create: &v2.CreateCommand{ + TemplateId: &v2.Identifier{ + // TODO: Fetch via KnownPackages and match on splice-wallet version from amulet rules + PackageId: "fd57252dda29e3ce90028114c91b521cb661df5a9d6e87c41a9e91518215fa5b", + ModuleName: "Splice.Wallet.TransferOffer", + EntityName: "TransferOffer", + }, + CreateArguments: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "sender", + Value: &v2.Value{Sum: &v2.Value_Party{Party: string(args.GetFrom())}}, + }, + { + Label: "receiver", + Value: &v2.Value{Sum: &v2.Value_Party{Party: string(args.GetTo())}}, + }, + { + Label: "dso", + Value: &v2.Value{Sum: &v2.Value_Party{Party: amuletRules.AmuletRulesUpdate.Contract.Payload.DSO}}, + }, + { + Label: "amount", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: "10.0"}}, // hardcode for now + }, + { + Label: "unit", + Value: &v2.Value{ + Sum: &v2.Value_Enum{ + Enum: &v2.Enum{ + Constructor: "AmuletUnit", + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + Label: "description", + Value: &v2.Value{Sum: &v2.Value_Text{Text: ""}}, + }, + { + Label: "expiresAt", + Value: &v2.Value{Sum: &v2.Value_Timestamp{Timestamp: time.Now().UTC().Add(24 * time.Hour).UnixMicro()}}, + }, + { + Label: "trackingId", + Value: &v2.Value{Sum: &v2.Value_Text{Text: commandID}}, + }, + }, + }, + }, + }, + } + + prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, string(args.GetFrom())) + if err != nil { + return nil, fmt.Errorf("failed to prepare submission for party setup proposal accept: %w", err) + } + + return prepareResp, nil +} + +// PrepareTransferPreapprovalCommand prepares an exercise of TransferPreapproval_Send on the +// recipient's TransferPreapproval contract. This is the flow used when the recipient is an +// external party that has completed setup (i.e. has a TransferPreapproval contract on the ledger). +// +// The sender exercises the choice directly, providing their amulet inputs and the transfer context. +func (client *Client) PrepareTransferPreapprovalCommand( + ctx context.Context, + args xcbuilder.TransferArgs, + amuletRules AmuletRules, + openMiningRound *RoundEntry, + issuingMiningRound *RoundEntry, + senderContracts []*v2.ActiveContract, + recipientContracts []*v2.ActiveContract, +) (*interactive.PrepareSubmissionResponse, error) { + senderPartyID := string(args.GetFrom()) + + // Find the recipient's TransferPreapproval contract. + var preapprovalContractID string + var preapprovalTemplateID *v2.Identifier + for _, c := range recipientContracts { + event := c.GetCreatedEvent() + if event == nil { + continue + } + tid := event.GetTemplateId() + if tid != nil && isPreapprovalTemplate(tid) { + preapprovalContractID = event.GetContractId() + preapprovalTemplateID = tid + break + } + } + if preapprovalContractID == "" { + return nil, fmt.Errorf("no TransferPreapproval contract found for recipient %s", args.GetTo()) + } + + // Build sender's amulet inputs. + transferInputs := make([]*v2.Value, 0) + for _, ac := range senderContracts { + event := ac.GetCreatedEvent() + if event == nil { + continue + } + if event.GetTemplateId().GetEntityName() != "Amulet" { + continue + } + transferInputs = append(transferInputs, &v2.Value{ + Sum: &v2.Value_Variant{ + Variant: &v2.Variant{ + Constructor: "InputAmulet", + Value: &v2.Value{ + Sum: &v2.Value_ContractId{ + ContractId: event.GetContractId(), + }, + }, + }, + }, + }) + } + + amuletRulesID := amuletRules.AmuletRulesUpdate.Contract.ContractID + openMiningRoundID := openMiningRound.Contract.ContractID + + rn, err := strconv.ParseInt(issuingMiningRound.Contract.Payload.Round.Number, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse issuing mining round number: %w", err) + } + issuingMiningRounds := &v2.Value{ + Sum: &v2.Value_GenMap{ + GenMap: &v2.GenMap{ + Entries: []*v2.GenMap_Entry{ + { + Key: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "number", + Value: &v2.Value{Sum: &v2.Value_Int64{Int64: rn}}, + }, + }, + }, + }, + }, + Value: &v2.Value{ + Sum: &v2.Value_ContractId{ + ContractId: issuingMiningRound.Contract.ContractID, + }, + }, + }, + }, + }, + }, + } + + // Build disclosed contracts: TransferPreapproval + sender amulets + AmuletRules + OpenMiningRound + IssuingMiningRound. + disclosedContracts := make([]*v2.DisclosedContract, 0) + + // Disclose the recipient's TransferPreapproval contract (the one being exercised). + for _, ac := range recipientContracts { + event := ac.GetCreatedEvent() + if event == nil { + continue + } + if tid := event.GetTemplateId(); tid != nil && isPreapprovalTemplate(tid) { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: tid, + ContractId: event.GetContractId(), + CreatedEventBlob: event.GetCreatedEventBlob(), + }) + break + } + } + + for _, ac := range senderContracts { + event := ac.GetCreatedEvent() + if event == nil || event.GetTemplateId().GetEntityName() != "Amulet" { + continue + } + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: event.GetTemplateId(), + ContractId: event.GetContractId(), + CreatedEventBlob: event.GetCreatedEventBlob(), + }) + } + + // Disclose AmuletRules. + amuletRulesTemplateParts := strings.SplitN(amuletRules.AmuletRulesUpdate.Contract.TemplateID, ":", 3) + if len(amuletRulesTemplateParts) == 3 { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: amuletRulesTemplateParts[0], + ModuleName: amuletRulesTemplateParts[1], + EntityName: amuletRulesTemplateParts[2], + }, + ContractId: amuletRulesID, + CreatedEventBlob: amuletRules.AmuletRulesUpdate.Contract.CreatedEventBlob, + }) + } + + openParts := strings.Split(openMiningRound.Contract.TemplateID, ":") + if len(openParts) == 3 { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: openParts[0], + ModuleName: openParts[1], + EntityName: openParts[2], + }, + ContractId: openMiningRoundID, + CreatedEventBlob: openMiningRound.Contract.CreatedEventBlob, + }) + } + + issuingParts := strings.Split(issuingMiningRound.Contract.TemplateID, ":") + if len(issuingParts) == 3 { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: issuingParts[0], + ModuleName: issuingParts[1], + EntityName: issuingParts[2], + }, + ContractId: issuingMiningRound.Contract.ContractID, + CreatedEventBlob: issuingMiningRound.Contract.CreatedEventBlob, + }) + } + + cmd := &v2.Command{ + Command: &v2.Command_Exercise{ + Exercise: &v2.ExerciseCommand{ + TemplateId: preapprovalTemplateID, + ContractId: preapprovalContractID, + Choice: "TransferPreapproval_Send", + ChoiceArgument: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "sender", + Value: &v2.Value{Sum: &v2.Value_Party{Party: senderPartyID}}, + }, + { + Label: "inputs", + Value: &v2.Value{ + Sum: &v2.Value_List{ + List: &v2.List{Elements: transferInputs}, + }, + }, + }, + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: "10.0"}}, + }, + { + Label: "context", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amuletRules", + Value: &v2.Value{Sum: &v2.Value_ContractId{ContractId: amuletRulesID}}, + }, + { + Label: "context", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "openMiningRound", + Value: &v2.Value{Sum: &v2.Value_ContractId{ContractId: openMiningRoundID}}, + }, + { + Label: "issuingMiningRounds", + Value: issuingMiningRounds, + }, + { + Label: "validatorRights", + Value: &v2.Value{ + Sum: &v2.Value_GenMap{ + GenMap: &v2.GenMap{Entries: []*v2.GenMap_Entry{}}, + }, + }, + }, + { + Label: "featuredAppRight", + Value: &v2.Value{ + Sum: &v2.Value_Optional{Optional: &v2.Optional{}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + commandID := newRegisterCommandId() + prepareReq := &interactive.PrepareSubmissionRequest{ + CommandId: commandID, + Commands: []*v2.Command{cmd}, + ActAs: []string{senderPartyID}, + ReadAs: []string{senderPartyID, ValidatorPartyId}, + SynchronizerId: TestnetSynchronizerID, + DisclosedContracts: disclosedContracts, + VerboseHashing: false, + } + + authCtx := client.ledgerClient.authCtx(ctx) + prepareResp, err := client.ledgerClient.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) + if err != nil { + return nil, fmt.Errorf("failed to prepare TransferPreapproval_Send: %w", err) + } + + return prepareResp, nil +} + +func (client *Client) FetchTransferInput(ctx context.Context, args xcbuilder.TransferArgs) (xc.TxInput, error) { + input := tx_input.NewTxInput() + from := args.GetFrom() + to := args.GetTo() + + ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) + if err != nil { + return input, fmt.Errorf("failed to get ledger end: %w", err) + } + + senderContracts, err := client.ledgerClient.GetActiveContracts(ctx, string(from), ledgerEnd, true) + if err != nil { + return nil, fmt.Errorf("failed to fetch active contracts: %w", err) + } + + // Check if the recipient has a TransferPreapproval contract. + // includeBlobs: true so the CreatedEventBlob is available for disclosure. + recipientContracts, err := client.ledgerClient.GetActiveContracts(ctx, string(to), ledgerEnd, true) + if err != nil { + return nil, fmt.Errorf("failed to fetch recipient active contracts: %w", err) + } + isExternal := client.ledgerClient.HasTransferPreapprovalContract(ctx, recipientContracts) + input.IsExternalTransfer = isExternal + + uiToken, err := client.cantonUIToken(ctx) + if err != nil { + return nil, err + } + + amuletRules, err := client.ledgerClient.GetAmuletRules(ctx, uiToken) + if err != nil { + return nil, fmt.Errorf("failed to fetch amulet rules: %w", err) + } + + var resp *interactive.PrepareSubmissionResponse + if isExternal { + openMiningRound, issuingMiningRound, err := client.ledgerClient.GetOpenAndIssuingMiningRound(ctx, uiToken) + if err != nil { + return nil, fmt.Errorf("failed to fetch mining rounds: %w", err) + } + resp, err = client.PrepareTransferPreapprovalCommand(ctx, args, *amuletRules, openMiningRound, issuingMiningRound, senderContracts, recipientContracts) + if err != nil { + return nil, fmt.Errorf("failed to prepare transfer preapproval command: %w", err) + } + } else { + resp, err = client.PrepareTransferOfferCommand(ctx, args, *amuletRules) + if err != nil { + return nil, fmt.Errorf("failed to prepare offer command: %w", err) + } + } + + input.PreparedTransaction = *resp.GetPreparedTransaction() + input.Sighash = resp.GetPreparedTransactionHash() + input.SubmissionId = NewCommandId() + input.HashingSchemeVersion = resp.GetHashingSchemeVersion() + + return input, nil +} + +// FetchLegacyTxInput - Deprecated, use FetchTransferInput +func (client *Client) FetchLegacyTxInput(ctx context.Context, from xc.Address, to xc.Address) (xc.TxInput, error) { + chainCfg := client.Asset.GetChain().Base() + args, _ := xcbuilder.NewTransferArgs(chainCfg, from, to, xc.NewAmountBlockchainFromUint64(1)) + return client.FetchTransferInput(ctx, args) +} + +// SubmitTx unmarshals the serialized ExecuteSubmissionRequest proto and calls +// InteractiveSubmissionService.ExecuteSubmissionAndWait +func (client *Client) SubmitTx(ctx context.Context, submitReq xctypes.SubmitTxReq) error { + if len(submitReq.TxData) == 0 { + return fmt.Errorf("empty transaction data") + } + + var req interactive.ExecuteSubmissionRequest + if err := proto.Unmarshal(submitReq.TxData, &req); err != nil { + return fmt.Errorf("failed to unmarshal Canton execute request: %w", err) + } + + andWaitReq := &interactive.ExecuteSubmissionAndWaitRequest{ + PreparedTransaction: req.PreparedTransaction, + PartySignatures: req.PartySignatures, + SubmissionId: req.SubmissionId, + UserId: req.UserId, + HashingSchemeVersion: req.HashingSchemeVersion, + } + // Convert deduplication period (unexported oneof interface - handle each concrete type) + switch v := req.DeduplicationPeriod.(type) { + case *interactive.ExecuteSubmissionRequest_DeduplicationDuration: + andWaitReq.DeduplicationPeriod = &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ + DeduplicationDuration: v.DeduplicationDuration, + } + case *interactive.ExecuteSubmissionRequest_DeduplicationOffset: + andWaitReq.DeduplicationPeriod = &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationOffset{ + DeduplicationOffset: v.DeduplicationOffset, + } + } + + parties := []string{} + if req.PartySignatures != nil { + for _, ps := range req.PartySignatures.GetSignatures() { + parties = append(parties, ps.GetParty()) + } + } + logrus.WithFields(logrus.Fields{ + "rpc": "ExecuteSubmissionAndWait", + "submission_id": req.SubmissionId, + "parties": parties, + }).Trace("canton request") + + actx := client.ledgerClient.authCtx(ctx) + _, err := client.ledgerClient.interactiveSubmissionClient.ExecuteSubmissionAndWait(actx, andWaitReq) + if err != nil { + return fmt.Errorf("failed to submit Canton transaction: %w", err) + } + logrus.WithField("submission_id", req.SubmissionId).Trace("canton response: ExecuteSubmissionAndWait accepted") + return err +} + +// FetchLegacyTxInfo - not implemented for Canton +func (client *Client) FetchLegacyTxInfo(ctx context.Context, txHash xc.TxHash) (txinfo.LegacyTxInfo, error) { + return txinfo.LegacyTxInfo{}, errors.New("not implemented") +} + +// FetchTxInfo fetches and normalizes transaction info for a Canton update by its updateId. +// The txHash must be the Canton updateId returned after submission. +func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinfo.TxInfo, error) { + updateId := string(args.TxHash()) + chainCfg := client.Asset.GetChain() + decimals := chainCfg.Decimals + + // Use admin token for lookup — the updateId is ledger-global + resp, err := client.ledgerClient.GetUpdateById(ctx, updateId) + if err != nil { + return txinfo.TxInfo{}, fmt.Errorf("failed to fetch update: %w", err) + } + + tx := resp.GetTransaction() + if tx == nil { + return txinfo.TxInfo{}, fmt.Errorf("update %s is not a transaction", updateId) + } + + ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) + if err != nil { + return txinfo.TxInfo{}, fmt.Errorf("failed to get ledger end: %w", err) + } + + txOffset := tx.GetOffset() + var confirmations uint64 + if ledgerEnd > txOffset { + confirmations = uint64(ledgerEnd - txOffset) + } + + var blockTime time.Time + if ts := tx.GetEffectiveAt(); ts != nil { + blockTime = ts.AsTime() + } + block := txinfo.NewBlock(chainCfg.Chain, uint64(txOffset), tx.GetSynchronizerId(), blockTime) + txInfo := txinfo.NewTxInfo(block, client.Asset, updateId, confirmations, nil) + + // Scan events: find the acting party (sender) from exercised events and + // new Amulet owner (receiver) + amount from created Amulet events. + var senderParty string + type amuletCreation struct { + owner string + amount xc.AmountBlockchain + } + var amuletCreations []amuletCreation + + for _, event := range tx.GetEvents() { + if ex := event.GetExercised(); ex != nil { + // The acting party on transfer-related choices is the sender + if len(ex.GetActingParties()) > 0 && senderParty == "" { + senderParty = ex.GetActingParties()[0] + } + } + if cr := event.GetCreated(); cr != nil { + tid := cr.GetTemplateId() + if tid == nil || !isAmuletTemplate(tid) { + continue + } + createArgs := cr.GetCreateArguments() + if createArgs == nil { + continue + } + // Extract owner and initialAmount from Amulet contract + var owner string + for _, f := range createArgs.GetFields() { + if f.GetLabel() == "owner" { + owner = f.GetValue().GetParty() + } + } + if owner == "" { + continue + } + bal, ok := ExtractAmuletBalance(createArgs, decimals) + if !ok { + continue + } + amuletCreations = append(amuletCreations, amuletCreation{owner: owner, amount: bal}) + } + } + + // Build movements: one per new Amulet contract created for a non-sender owner + for _, ac := range amuletCreations { + if ac.owner == senderParty { + // This is change going back to the sender, not the primary transfer destination + continue + } + from := xc.Address(senderParty) + to := xc.Address(ac.owner) + txInfo.AddSimpleTransfer(from, to, "", ac.amount, nil, "") + } + + // If we couldn't distinguish sender from receiver (e.g. self-transfer or change only), + // fall back to reporting all creations + if len(txInfo.Movements) == 0 && len(amuletCreations) > 0 { + for _, ac := range amuletCreations { + from := xc.Address(senderParty) + to := xc.Address(ac.owner) + txInfo.AddSimpleTransfer(from, to, "", ac.amount, nil, "") + } + } + + txInfo.Fees = txInfo.CalculateFees() + txInfo.SyncDeprecatedFields() + return *txInfo, nil +} + +func (client *Client) FetchBalance(ctx context.Context, args *xclient.BalanceArgs) (xc.AmountBlockchain, error) { + zero := xc.NewAmountBlockchainFromUint64(0) + if contract, ok := args.Contract(); ok { + return zero, fmt.Errorf("token balance queries not yet supported for Canton, contract: %s", contract) + } + + // Check if we want to onboard the client + // Onboarding process: + // 1. CreateExternalParty: + // - GenerateExternalPartyTopology + // - AllocateExternalParty + // 2. Create keycloak user + // 3. Set keycloak user attributes: `canton_party_id` and `canton_participant_aud` + // 4. CRITICAL: Create ledger user, with userId equal to keycloak user id. This allows us to use + // keycloak tokens for ledger interactions + // 5. CreateExternalPartySetupProposal allows external parties to receive funds. It's critical: + // - ExternalParties cannot accept transfer offers because they have very limited validator visibility + // - ExternalParties use TransferPreapproaval flow, which is different from vanilla offer/accept + // 6. Accept CreateExternalPartySetupProposal + // - List user active contracts + // - Create Approval for the contract + // - Sign and submit + // TODO: Refactor + // All calls in this branch are properly recovering from "[User/Party/Contract]Exists" errors + // It's really important that onboarding is resilient + v := os.Getenv("CANTON_REGISTER_ON_BALANCE") + if v == "true" { + seed := os.Getenv("XC_PRIVATE_KEY") + if len(seed) == 0 { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("missing priv key for party registration") + } + seedBz, err := hex.DecodeString(seed) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), errors.New("failed to read private key") + } + privKey := ed25519.NewKeyFromSeed(seedBz) + publicKey := privKey.Public().(ed25519.PublicKey) + err = client.ledgerClient.RegisterExternalParty(ctx, publicKey, privKey) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to register external party: %w", err) + } + + address, err := cantonaddress.GetAddressFromPublicKey(publicKey) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to get address: %w", err) + } + + if err := client.ledgerClient.CreateUser(ctx, string(address)); err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to create ledger user: %w", err) + } + + err = client.ledgerClient.CreateExternalPartySetupProposal(ctx, string(address)) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to create external party setup proposal: %w", err) + } + + // ut, err := client.walletKC.AcquireUserToken(ctx, partyHint, userPassword) + // if err != nil { + // return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch user token for user %s: %w", partyHint, err) + // } + // client.ledgerClient.SetToken(ut.AccessToken) + + err = client.ledgerClient.AcceptExternalPartySetupProposal(ctx, string(address), privKey) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to accept external party setup proposal: %w", err) + } + + uiToken, err := client.cantonUIToken(ctx) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), err + } + amuletRules, err := client.ledgerClient.GetAmuletRules(ctx, uiToken) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch amulet rules: %w", err) + } + openMiningRound, issuingMiningRound, err := client.ledgerClient.GetOpenAndIssuingMiningRound(ctx, uiToken) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch open mining round: %w", err) + } + + ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to get ledger end: %w", err) + } + contracts, err := client.ledgerClient.GetActiveContracts(ctx, string(address), ledgerEnd, true) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch active contracts: %w", err) + } + err = client.ledgerClient.CompleteAcceptedTransferOffer(ctx, string(address), amuletRules, openMiningRound, issuingMiningRound, privKey, contracts) + if err != nil { + return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to complete accepted transfer offer: %w", err) + } + } + + return client.FetchNativeBalance(ctx, args.Address()) +} + +func FilterToAmuletContracts(contracts []*v2.ActiveContract) []*v2.ActiveContract { + amuletContracts := make([]*v2.ActiveContract, 0) + for _, c := range contracts { + created := c.GetCreatedEvent() + if created == nil { + continue + } + tid := created.GetTemplateId() + if tid == nil || !isAmuletTemplate(tid) { + continue + } + + amuletContracts = append(amuletContracts, c) + } + return amuletContracts +} + +// FetchNativeBalance fetches the native (Amulet/CC) balance for a Canton party +// by streaming all active contracts via gRPC StateService, then summing up +// contracts whose template belongs to Splice.Amulet. +func (client *Client) FetchNativeBalance(ctx context.Context, address xc.Address) (xc.AmountBlockchain, error) { + zero := xc.NewAmountBlockchainFromUint64(0) + partyID := string(address) + if partyID == "" { + return zero, fmt.Errorf("empty address") + } + + decimals := client.Asset.GetChain().Decimals + ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) + if err != nil { + return zero, fmt.Errorf("failed to get ledger end: %w", err) + } + + contracts, err := client.ledgerClient.GetActiveContracts(ctx, string(address), ledgerEnd, false) + if err != nil { + return zero, fmt.Errorf("failed to query active contracts for party %s: %w", partyID, err) + } + + totalBalance := xc.NewAmountBlockchainFromUint64(0) + for _, c := range contracts { + created := c.GetCreatedEvent() + if created == nil { + continue + } + tid := created.GetTemplateId() + if tid == nil || !isAmuletTemplate(tid) { + continue + } + + if bal, ok := ExtractAmuletBalance(created.GetCreateArguments(), decimals); ok { + logrus.WithFields(logrus.Fields{ + KeyContractId: created.GetContractId(), + KeyInitialAmount: bal.String(), + KeyRunningTotal: totalBalance.String(), + }).Trace("canton: Amulet contract balance") + totalBalance = totalBalance.Add(&bal) + } + } + + return totalBalance, nil +} + +func (client *Client) FetchDecimals(ctx context.Context, contract xc.ContractAddress) (int, error) { + return 0, errors.New("not implemented") +} + +func (client *Client) FetchBlock(ctx context.Context, args *xclient.BlockArgs) (*txinfo.BlockWithTransactions, error) { + return &txinfo.BlockWithTransactions{}, errors.New("not implemented") +} + +// KeyFingerprintFromAddress extracts the key fingerprint from a Canton party address +func KeyFingerprintFromAddress(addr xc.Address) (string, error) { + _, fingerprint, err := cantonaddress.ParsePartyID(addr) + if err != nil { + return "", err + } + return fingerprint, nil +} + +// TxFromInput builds a Tx from a TxInput and the transfer args +func TxFromInput(args xcbuilder.TransferArgs, input *tx_input.TxInput) (*cantontx.Tx, error) { + fingerprint, err := KeyFingerprintFromAddress(args.GetFrom()) + if err != nil { + return nil, fmt.Errorf("failed to parse sender party ID: %w", err) + } + return &cantontx.Tx{ + PreparedTransaction: &input.PreparedTransaction, + PreparedTransactionHash: input.Sighash, + HashingSchemeVersion: input.HashingSchemeVersion, + Party: string(args.GetFrom()), + KeyFingerprint: fingerprint, + SubmissionId: input.SubmissionId, + }, nil +} diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go new file mode 100644 index 00000000..ebf26c8d --- /dev/null +++ b/chain/canton/client/client_test.go @@ -0,0 +1,44 @@ +package client + +import ( + "testing" + + xc "github.com/cordialsys/crosschain" + "github.com/stretchr/testify/require" +) + +func TestNewClient(t *testing.T) { + t.Run("missing URL", func(t *testing.T) { + cfg := &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + }, + ChainClientConfig: &xc.ChainClientConfig{}, + } + _, err := NewClient(cfg) + require.Error(t, err) + require.Contains(t, err.Error(), "no URL configured") + }) + + t.Run("missing env var", func(t *testing.T) { + t.Setenv("CANTON_KEYCLOAK_URL", "") + t.Setenv("CANTON_KEYCLOAK_REALM", "") + t.Setenv("CANTON_VALIDATOR_ID", "") + t.Setenv("CANTON_VALIDATOR_SECRET", "") + t.Setenv("CANTON_UI_ID", "") + t.Setenv("CANTON_UI_PASSWORD", "") + cfg := &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + }, + ChainClientConfig: &xc.ChainClientConfig{ + URL: "https://example.com", + }, + } + _, err := NewClient(cfg) + require.Error(t, err) + require.Contains(t, err.Error(), "required environment variable") + }) +} diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go new file mode 100644 index 00000000..155c309d --- /dev/null +++ b/chain/canton/client/ledger.go @@ -0,0 +1,1260 @@ +package client + +import ( + "bytes" + "context" + "crypto/ed25519" + "crypto/rand" + "crypto/tls" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "os" + "strconv" + "strings" + "time" + + xc "github.com/cordialsys/crosschain" + cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "github.com/sirupsen/logrus" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/types/known/durationpb" +) + +const ( + EntityAmulet = "Amulet" + EntityLockedAmulet = "LockedAmulet" + KeyContractId = "contract_id" + KeyFilter = "filter" + KeyInitialAmount = "initial_amount" + KeyMethod = "method" + KeyOffset = "offset" + KeyParty = "party" + KeyRunningTotal = "running_total" + KeySynchronizerId = "synchronizer_id" + KeyTemplateId = "template_id" + KeyTxCount = "tx_count" + KeyUserId = "user_id" + LabelAmount = "amount" + LabelInitialAmount = "initialAmount" + ModuleSpliceAmulet = "SpliceAmulet" + +) + +// cantonEnv reads a required Canton environment variable, returning an error if unset. +func cantonEnv(name string) (string, error) { + v := os.Getenv(name) + if v == "" { + return "", fmt.Errorf("required environment variable %s is not set", name) + } + return v, nil +} + +// TODO: Fetch instead of hardcoding +var ( + TestnetSynchronizerID = func() string { v, _ := cantonEnv("CANTON_TESTNET_SYNCHRONIZER_ID"); return v }() + ValidatorPartyId = func() string { v, _ := cantonEnv("CANTON_VALIDATOR_PARTY_ID"); return v }() + RestApiUrl = func() string { v, _ := cantonEnv("CANTON_REST_API_URL"); return v }() + ScanProxyUrl = func() string { v, _ := cantonEnv("CANTON_SCAN_API_URL"); return v }() + ScanApiUrl = func() string { v, _ := cantonEnv("CANTON_SCAN_NODE_URL"); return v }() + ValidatorServiceUserId = func() string { + v, _ := cantonEnv("CANTON_VALIDATOR_ID") + if v == "" { + return "" + } + return "service-account-" + v + }() +) + +type GrpcLedgerClient struct { + // Bearer token injected into every gRPC call + authToken string + adminClient admin.PartyManagementServiceClient + commandClient v2.CommandServiceClient + interactiveSubmissionClient interactive.InteractiveSubmissionServiceClient + stateClient v2.StateServiceClient + updateClient v2.UpdateServiceClient + userManagementClient admin.UserManagementServiceClient + logger *logrus.Entry +} + +func NewGrpcLedgerClient(target string, authToken string) (*GrpcLedgerClient, error) { + if authToken == "" { + return nil, errors.New("GrpcLedgerClient requires a valid authToken") + } + + // Determine TLS vs plain from URL scheme and derive the gRPC target + // (gRPC targets don't include the scheme) + var creds credentials.TransportCredentials + if strings.HasPrefix(target, "https://") { + target = strings.TrimPrefix(target, "https://") + creds = credentials.NewTLS(&tls.Config{}) + } else if strings.HasPrefix(target, "http://") { + target = strings.TrimPrefix(target, "http://") + creds = insecure.NewCredentials() + } else { + // Assume TLS if no scheme + creds = credentials.NewTLS(&tls.Config{}) + } + target = strings.TrimRight(target, "/") + + conn, err := grpc.NewClient(target, grpc.WithTransportCredentials(creds)) + if err != nil { + return nil, fmt.Errorf("failed to create gRPC connection to Canton: %w", err) + } + + logger := logrus.NewEntry(logrus.New()).WithField("client", "GrpcLedgerClient") + return &GrpcLedgerClient{ + authToken: authToken, + adminClient: admin.NewPartyManagementServiceClient(conn), + stateClient: v2.NewStateServiceClient(conn), + updateClient: v2.NewUpdateServiceClient(conn), + interactiveSubmissionClient: interactive.NewInteractiveSubmissionServiceClient(conn), + userManagementClient: admin.NewUserManagementServiceClient(conn), + commandClient: v2.NewCommandServiceClient(conn), + logger: logger, + }, nil +} + +// authCtx injects the CANTON_AUTH bearer token into the gRPC context +func (c *GrpcLedgerClient) authCtx(ctx context.Context) context.Context { + if c.authToken == "" { + c.logger.Warn("empty authToken") + return ctx + } + + md := metadata.Pairs("authorization", "Bearer "+c.authToken) + return metadata.NewOutgoingContext(ctx, md) +} + +// getLedgerEnd fetches the current ledger end offset via gRPC StateService +func (c *GrpcLedgerClient) GetLedgerEnd(ctx context.Context) (int64, error) { + authCtx := c.authCtx(ctx) + logger := c.logger.WithField(KeyMethod, "GetLedgerEnd") + logger.Trace("request") + resp, err := c.stateClient.GetLedgerEnd(authCtx, &v2.GetLedgerEndRequest{}) + if err != nil { + return 0, fmt.Errorf("failed to get ledger end: %w", err) + } + + logger.WithField(KeyOffset, resp.GetOffset()).Trace("response") + return resp.GetOffset(), nil +} + +// getSynchronizerId fetches the synchronizer ID via GetConnectedSynchronizers +func (c *GrpcLedgerClient) GetSynchronizerId(ctx context.Context, party string) (string, error) { + logger := c.logger.WithFields(logrus.Fields{ + KeyMethod: "GetConnectedSynchronizers", + KeyParty: party, + }) + logger.Trace("request") + + authCtx := c.authCtx(ctx) + resp, err := c.stateClient.GetConnectedSynchronizers( + authCtx, + &v2.GetConnectedSynchronizersRequest{Party: party}, + ) + if err != nil { + return "", fmt.Errorf("failed to get connected synchronizers: %w", err) + } + + syncs := resp.GetConnectedSynchronizers() + if len(syncs) == 0 { + return "", fmt.Errorf("no connected synchronizers found for party %s", party) + } + + // Prefer one with SUBMISSION permission + for _, s := range syncs { + if s.GetPermission() == v2.ParticipantPermission_PARTICIPANT_PERMISSION_SUBMISSION { + logrus.WithField(KeySynchronizerId, s.GetSynchronizerId()).Trace("selected synchronizer") + return s.GetSynchronizerId(), nil + } + } + + logrus.WithField(KeySynchronizerId, syncs[0].GetSynchronizerId()).Warn("missing synchronizer with submission persmission, selecting fallback") + return syncs[0].GetSynchronizerId(), nil +} + +// Get active contracts for given party using StateServiceClient.GetActiveContracts +func (c *GrpcLedgerClient) GetActiveContracts(ctx context.Context, partyID string, ledgerEnd int64, includeBlobs bool) ([]*v2.ActiveContract, error) { + if partyID == "" { + return nil, errors.New("empty required argument: partyID") + } + logrus.WithFields(logrus.Fields{ + KeyMethod: "GetActiveContracts", + KeyParty: partyID, + KeyOffset: ledgerEnd, + }).Trace("canton request") + + req := &v2.GetActiveContractsRequest{ + ActiveAtOffset: ledgerEnd, + EventFormat: &v2.EventFormat{ + // Verbose: true is required for createArguments to be populated on CreatedEvent + Verbose: true, + FiltersByParty: map[string]*v2.Filters{ + partyID: { + Cumulative: []*v2.CumulativeFilter{{ + // Empty filter - we want to fetch all contracts + IdentifierFilter: &v2.CumulativeFilter_WildcardFilter{ + WildcardFilter: &v2.WildcardFilter{ + IncludeCreatedEventBlob: includeBlobs, + }, + }, + }}, + }, + }, + }, + } + + authCtx := c.authCtx(ctx) + stream, err := c.stateClient.GetActiveContracts(authCtx, req) + if err != nil { + return nil, fmt.Errorf("failed to query active contracts for party %s: %w", partyID, err) + } + + activeContracts := make([]*v2.ActiveContract, 0) + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return nil, fmt.Errorf("error reading active contracts for party %s: %w", partyID, err) + } + + contract := resp.GetActiveContract() + if contract == nil { + continue + } + event := contract.GetCreatedEvent() + if event == nil { + continue + } + + c.logger. + WithField(KeyContractId, event.GetContractId()). + Info("found contract") + + activeContracts = append(activeContracts, contract) + } + + return activeContracts, nil +} + +// Register external party on the ledger +// 1. Generate external party topology for our public key +// 2. Sign the topology response, to prove ownership of the key +// 3. Allocate external party +func (c *GrpcLedgerClient) RegisterExternalParty(ctx context.Context, publicKeyBytes []byte, privateKey ed25519.PrivateKey) error { + authCtx := c.authCtx(ctx) + partyHint := hex.EncodeToString(publicKeyBytes) + signingPubKey := &v2.SigningPublicKey{ + Format: v2.CryptoKeyFormat_CRYPTO_KEY_FORMAT_RAW, + KeyData: publicKeyBytes, + KeySpec: v2.SigningKeySpec_SIGNING_KEY_SPEC_EC_CURVE25519, + } + logger := c.logger.WithFields(logrus.Fields{ + KeyMethod: "GenerateExternalPartyTopology", + KeyParty: partyHint, + }) + logger.Trace("request") + + topologyResponse, err := c.adminClient.GenerateExternalPartyTopology(authCtx, &admin.GenerateExternalPartyTopologyRequest{ + Synchronizer: TestnetSynchronizerID, + PartyHint: partyHint, + PublicKey: signingPubKey, + }) + if err != nil { + return fmt.Errorf("GenerateExternalPartyTopology failed: %w", err) + } + + // Continue the process and allocate the external party + fingerprint := topologyResponse.GetPublicKeyFingerprint() + signature := ed25519.Sign(privateKey, topologyResponse.GetMultiHash()) + sig := &v2.Signature{ + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: signature, + SignedBy: fingerprint, + SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, + } + + // Topology transactions were signed by the participant internally — pass them back as-is. + txns := make([]*admin.AllocateExternalPartyRequest_SignedTransaction, 0, len(topologyResponse.GetTopologyTransactions())) + for _, txBytes := range topologyResponse.GetTopologyTransactions() { + txns = append(txns, &admin.AllocateExternalPartyRequest_SignedTransaction{ + Transaction: txBytes, + }) + } + + logger = logrus.WithFields(logrus.Fields{ + KeyMethod: "AllocateExternalParty", + KeySynchronizerId: TestnetSynchronizerID, + KeyTxCount: len(txns), + }) + logger.Trace("request") + + allocResp, err := c.adminClient.AllocateExternalParty(authCtx, &admin.AllocateExternalPartyRequest{ + Synchronizer: TestnetSynchronizerID, + OnboardingTransactions: txns, + MultiHashSignatures: []*v2.Signature{sig}, + }) + + if err != nil && !isAlreadyExists(err) { + return fmt.Errorf("GenerateExternalPartyTopology failed: %w", err) + } + if isAlreadyExists(err) { + logger.Trace("topology already generated") + } else { + registeredPartyId := allocResp.GetPartyId() + expectedPartyId, err := cantonaddress.GetAddressFromPublicKey(publicKeyBytes) + if err != nil { + c.logger.Warn("failed to get address from public key: %w", err) + } + if expectedPartyId != xc.Address(registeredPartyId) { + c.logger.Warn("registered party id differs from expected") + } + } + return nil +} + +func (c *GrpcLedgerClient) CreateUser(ctx context.Context, partyId string) error { + authCtx := c.authCtx(ctx) + req := &admin.GrantUserRightsRequest{ + UserId: ValidatorServiceUserId, + Rights: []*admin.Right{ + { + Kind: &admin.Right_CanReadAs_{ + CanReadAs: &admin.Right_CanReadAs{ + Party: partyId, + }, + }, + }, + { + Kind: &admin.Right_CanActAs_{ + CanActAs: &admin.Right_CanActAs{ + Party: partyId, + }, + }, + }, + }, + } + + _, err := c.userManagementClient.GrantUserRights(authCtx, req) + if isAlreadyExists(err) { + c.logger.WithFields(logrus.Fields{ + KeyMethod: "CreateUser", + }).Warn("user already exists") + return nil + } else { + return err + } +} + +// curl -v -X POST \ +// -H "Authorization: Bearer $ADMIN_TOKEN" \ +// -H "Content-Type: application/json" \ +// -d '{"user_party_id": ""}' \ +// "$CANTON_REST_API_URL/api/validator/v0/admin/external-party/setup-proposal" +func (c *GrpcLedgerClient) CreateExternalPartySetupProposal(ctx context.Context, partyID string) error { + body, err := json.Marshal(map[string]string{ + "user_party_id": partyID, + }) + if err != nil { + return fmt.Errorf("marshaling request: %w", err) + } + + endpoint := "/api/validator/v0/admin/external-party/setup-proposal" + logger := c.logger.WithFields(logrus.Fields{ + KeyMethod: "POST", + "endpoint": endpoint, + }) + logger.Trace("request") + req, err := http.NewRequestWithContext( + ctx, + http.MethodPost, + RestApiUrl+endpoint, + bytes.NewReader(body), + ) + if err != nil { + return fmt.Errorf("creating request: %w", err) + } + + req.Header.Set("Authorization", "Bearer "+c.authToken) + req.Header.Set("Content-Type", "application/json") + + client := http.DefaultClient + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("executing request: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + bz, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("creating ExternalPartySetupProposal for %s: status %d", partyID, resp.StatusCode) + } + errBody := string(bz) + if strings.Contains(errBody, "ExternalPartySetupProposal contract already exists") || + strings.Contains(errBody, "TransferPreapproval contract already exists") { + return nil + } else { + return fmt.Errorf("creating ExternalPartySetupProposal for %s(%d): %s", partyID, resp.StatusCode, string(bz)) + } + } + + return nil +} + +type AmuletRulesContract struct { + TemplateID string `json:"template_id"` + ContractID string `json:"contract_id"` + CreatedEventBlob []byte `json:"created_event_blob"` + Payload struct { + DSO string `json:"dso"` + } `json:"payload"` +} + +type AmuletRules struct { + AmuletRulesUpdate struct { + Contract AmuletRulesContract `json:"contract"` + DomainID string `json:"domain_id"` + } `json:"amulet_rules_update"` +} + +func (a AmuletRules) GetSpliceId() string { + return strings.SplitN(a.AmuletRulesUpdate.Contract.TemplateID, ":", 2)[0] +} + +// Make sure to auth with canton-ui token +func (c *GrpcLedgerClient) GetAmuletRules(ctx context.Context, token string) (*AmuletRules, error) { + // We access the scan API through the http-proxy (CANTON_SCAN_API_URL) because direct access is not yet available. + body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/amulet-rules","headers":{"Content-Type":"application/json"},"body":"{}"}`, ScanApiUrl) + + req, err := http.NewRequestWithContext( + ctx, + http.MethodPost, + ScanProxyUrl, + strings.NewReader(body), + ) + if err != nil { + return nil, fmt.Errorf("creating request: %w", err) + } + + req.Header.Set("Authorization", "Bearer "+token) + req.Header.Set("Content-Type", "application/json") + + client := http.DefaultClient + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("executing request: %w", err) + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("reading response body: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("fetching amulet rules: status %d: %s", resp.StatusCode, string(respBody)) + } + + var result AmuletRules + if err := json.Unmarshal(respBody, &result); err != nil { + return nil, fmt.Errorf("unmarshaling amulet rules: %w", err) + } + + return &result, nil +} + +type RoundPayload struct { + Round struct { + Number string `json:"number"` + } `json:"round"` + OpensAt string `json:"opensAt"` // e.g., "2026-03-10T11:42:21.088197Z" + TargetClosesAt string `json:"targetClosesAt"` // e.g., "2026-03-10T12:02:21.088197Z" +} + +type RoundContract struct { + ContractID string `json:"contract_id"` + TemplateID string `json:"template_id"` + Payload RoundPayload `json:"payload"` + CreatedEventBlob []byte `json:"created_event_blob"` +} + +type RoundEntry struct { + Contract RoundContract `json:"contract"` + DomainID string `json:"domain_id"` +} + +type OpenAndIssuingMiningRounds struct { + OpenMiningRounds map[string]RoundEntry `json:"open_mining_rounds"` + IssuingMiningRounds map[string]RoundEntry `json:"issuing_mining_rounds"` +} + +// GetLatestOpenMiningRound returns the open mining round with the highest round number. +func (r *OpenAndIssuingMiningRounds) GetLatestOpenMiningRound() (*RoundEntry, error) { + now := time.Now().UTC() // ledger time; adjust if simulating + var current *RoundEntry + var highestRound int64 = -1 + + for _, entry := range r.OpenMiningRounds { + // parse round number + n, err := strconv.ParseInt(entry.Contract.Payload.Round.Number, 10, 64) + if err != nil { + continue + } + + // parse opensAt + opensAt, err := time.Parse(time.RFC3339Nano, entry.Contract.Payload.OpensAt) + if err != nil { + continue + } + + // parse targetClosesAt + targetClosesAt, err := time.Parse(time.RFC3339Nano, entry.Contract.Payload.TargetClosesAt) + if err != nil { + continue + } + + if !now.Before(opensAt) && !now.After(targetClosesAt) { + // round is currently open + if n > highestRound { + highestRound = n + e := entry + current = &e + } + } + } + + if current == nil { + return nil, fmt.Errorf("no currently open mining rounds found") + } + return current, nil +} + +// GetLatestOpenMiningRound returns the open mining round with the highest round number. +func (r *OpenAndIssuingMiningRounds) GetLatestIssuingMiningRound() (*RoundEntry, error) { + now := time.Now().UTC() + + for _, entry := range r.IssuingMiningRounds { + opensAt, err := time.Parse(time.RFC3339Nano, entry.Contract.Payload.OpensAt) + if err != nil { + continue + } + targetClosesAt, err := time.Parse(time.RFC3339Nano, entry.Contract.Payload.TargetClosesAt) + if err != nil { + continue + } + + // Round is currently open + if !now.Before(opensAt) && now.Before(targetClosesAt) { + return &entry, nil + } + } + + return nil, fmt.Errorf("no currently open issuing mining round found") +} + +func (c *GrpcLedgerClient) GetOpenAndIssuingMiningRound(ctx context.Context, token string) (*RoundEntry, *RoundEntry, error) { + body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/open-and-issuing-mining-rounds","headers":{"Content-Type":"application/json"},"body":"{\"cached_open_mining_round_contract_ids\":[],\"cached_issuing_round_contract_ids\":[]}"}`, ScanApiUrl) + + req, err := http.NewRequestWithContext( + ctx, + http.MethodPost, + ScanProxyUrl, + strings.NewReader(body), + ) + if err != nil { + return nil, nil, fmt.Errorf("creating request: %w", err) + } + + req.Header.Set("Authorization", "Bearer "+token) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("executing request: %w", err) + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, nil, fmt.Errorf("reading response body: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return nil, nil, fmt.Errorf("fetching mining rounds: status %d: %s", resp.StatusCode, string(respBody)) + } + + var result OpenAndIssuingMiningRounds + if err := json.Unmarshal(respBody, &result); err != nil { + return nil, nil, fmt.Errorf("unmarshaling mining rounds: %w", err) + } + + latestOpenRound, err := result.GetLatestOpenMiningRound() + if err != nil { + return nil, nil, fmt.Errorf("failed to get lastest open mining round: %w", err) + } + + latestIssuingRound, err := result.GetLatestIssuingMiningRound() + if err != nil { + return nil, nil, fmt.Errorf("failed to get lastest issuing mining round: %w", err) + } + return latestOpenRound, latestIssuingRound, nil +} + +func (c *GrpcLedgerClient) HasTransferPreapprovalContract(ctx context.Context, contracts []*v2.ActiveContract) bool { + preapprovalContractID := "" + for _, c := range contracts { + created := c.GetCreatedEvent() + if created == nil { + continue + } + tid := created.GetTemplateId() + if tid == nil || !isPreapprovalTemplate(tid) { + continue + } + + preapprovalContractID = created.GetContractId() + } + + return preapprovalContractID != "" +} + +// newRegisterCommandId generates a UUID-style command ID for registration calls. +func newRegisterCommandId() string { + b := make([]byte, 16) + _, _ = rand.Read(b) + return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", + b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) +} + +func (c *GrpcLedgerClient) PrepareSubmissionRequest(ctx context.Context, command *v2.Command, commandID string, partyID string) (*interactive.PrepareSubmissionResponse, error) { + prepareReq := &interactive.PrepareSubmissionRequest{ + CommandId: commandID, + Commands: []*v2.Command{command}, + ActAs: []string{partyID}, + ReadAs: []string{partyID}, + SynchronizerId: TestnetSynchronizerID, + VerboseHashing: false, + } + + authCtx := c.authCtx(ctx) + prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) + return prepareResp, err +} + +func (c *GrpcLedgerClient) AcceptExternalPartySetupProposal(ctx context.Context, partyId string, privateKey ed25519.PrivateKey) error { + ledgerEnd, err := c.GetLedgerEnd(ctx) + if err != nil { + return fmt.Errorf("failed to get ledger end: %w", err) + } + + contracts, err := c.GetActiveContracts(ctx, partyId, ledgerEnd, true) + if err != nil { + return fmt.Errorf("failed to get active contracts: %w", err) + } + + proposalContractID := "" + var proposalTemplateID *v2.Identifier + for _, c := range contracts { + event := c.GetCreatedEvent() + if event == nil { + continue + } + tid := event.GetTemplateId() + if tid.GetEntityName() == "ExternalPartySetupProposal" { + proposalContractID = event.GetContractId() + proposalTemplateID = tid + break + } + } + + logger := c.logger.WithField(KeyParty, partyId) + if proposalContractID == "" { + logger.WithField(KeyParty, partyId).Debug("no ExternalPartySetupProposal found (may already be accepted)") + return nil + } + + cmd := &v2.Command{ + Command: &v2.Command_Exercise{ + Exercise: &v2.ExerciseCommand{ + TemplateId: proposalTemplateID, + ContractId: proposalContractID, + Choice: "ExternalPartySetupProposal_Accept", + ChoiceArgument: &v2.Value{Sum: &v2.Value_Record{Record: &v2.Record{}}}, + }, + }, + } + + authCtx := c.authCtx(ctx) + commandID := newRegisterCommandId() + prepareResp, err := c.PrepareSubmissionRequest(authCtx, cmd, commandID, partyId) + if err != nil { + return fmt.Errorf("failed to prepare submission for party setup proposal accept: %w", err) + } + + // Sign the prepared transaction hash with the external party's private key. + txSig := ed25519.Sign(privateKey, prepareResp.GetPreparedTransactionHash()) + _, keyFingerprint, err := cantonaddress.ParsePartyID(xc.Address(partyId)) + executeReq := &interactive.ExecuteSubmissionAndWaitRequest{ + PreparedTransaction: prepareResp.GetPreparedTransaction(), + PartySignatures: &interactive.PartySignatures{ + Signatures: []*interactive.SinglePartySignatures{ + { + Party: partyId, + Signatures: []*v2.Signature{ + { + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: txSig, + SignedBy: keyFingerprint, + SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, + }, + }, + }, + }, + }, + DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ + DeduplicationDuration: durationpb.New(300 * time.Second), + }, + SubmissionId: newRegisterCommandId(), + HashingSchemeVersion: prepareResp.GetHashingSchemeVersion(), + } + + logrus.WithField("rpc", "ExecuteSubmissionAndWait").Trace("ExternalPartySetupProposal_Accept") + _, err = c.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) + if err != nil { + if isAlreadyExists(err) { + logrus.WithField("party_id", partyId).Debug("canton: setup proposal already accepted") + return nil + } + return fmt.Errorf("ExecuteSubmissionAndWait: %w", err) + } + return nil +} + +func (c *GrpcLedgerClient) CompleteAcceptedTransferOffer( + ctx context.Context, + senderPartyID string, + amuletRules *AmuletRules, + openMiningRound *RoundEntry, + issuingMiningRound *RoundEntry, + privateKey ed25519.PrivateKey, + amulets []*v2.ActiveContract, +) error { + var acceptedOfferContractID string + var acceptedOfferTemplateID *v2.Identifier + for _, ac := range amulets { + event := ac.GetCreatedEvent() + if event == nil { + continue + } + tid := event.GetTemplateId() + if tid.GetModuleName() == "Splice.Wallet.TransferOffer" && tid.GetEntityName() == "AcceptedTransferOffer" { + acceptedOfferContractID = event.GetContractId() + acceptedOfferTemplateID = tid + break + } + } + if acceptedOfferContractID == "" { + c.logger.WithField(KeyParty, senderPartyID).Debug("no AcceptedTransferOffer found, skipping completion") + return nil + } + + amuletRulesID := amuletRules.AmuletRulesUpdate.Contract.ContractID + openMiningRoundID := openMiningRound.Contract.ContractID + + // Build TransferInput list from amulet contracts, excluding the AcceptedTransferOffer itself. + transferInputs := make([]*v2.Value, 0, len(amulets)) + for _, ac := range amulets { + event := ac.GetCreatedEvent() + if event == nil { + continue + } + if event.GetContractId() == acceptedOfferContractID { + continue + } + entityName := event.GetTemplateId().GetEntityName() + if entityName != "Amulet" { + // skip non-Amulet contracts + continue + } + transferInputs = append(transferInputs, &v2.Value{ + Sum: &v2.Value_Variant{ + Variant: &v2.Variant{ + Constructor: "InputAmulet", + Value: &v2.Value{ + Sum: &v2.Value_ContractId{ + ContractId: event.GetContractId(), + }, + }, + }, + }, + }) + } + + c.logger. + WithField("contract_id", openMiningRound.Contract.ContractID). + Info("opening contract") + + c.logger. + WithField("contract_id", issuingMiningRound.Contract.ContractID). + Info("issuing contract") + + // Build disclosed contracts: all amulets (including AcceptedTransferOffer) + + // amulet rules + open mining round. + disclosedContracts := make([]*v2.DisclosedContract, 0, len(amulets)+2) + for _, ac := range amulets { + event := ac.GetCreatedEvent() + if event == nil { + continue + } + entityName := event.GetTemplateId().GetEntityName() + if entityName != "Amulet" { + // skip non-Amulet contracts + continue + } + + c.logger. + WithField("contract_entity", event.GetTemplateId().GetEntityName()). + Info("disclosing contract") + + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: event.GetTemplateId(), + ContractId: event.GetContractId(), + CreatedEventBlob: event.GetCreatedEventBlob(), + }) + } + + // Disclose AmuletRules: parse "packageId:ModuleName:EntityName" template ID string. + amuletRulesTemplateParts := strings.SplitN(amuletRules.AmuletRulesUpdate.Contract.TemplateID, ":", 3) + if len(amuletRulesTemplateParts) == 3 { + c.logger. + WithField("contract_entity", amuletRulesTemplateParts[2]). + Info("disclosing contract") + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: amuletRulesTemplateParts[0], + ModuleName: amuletRulesTemplateParts[1], + EntityName: amuletRulesTemplateParts[2], + }, + ContractId: amuletRulesID, + CreatedEventBlob: amuletRules.AmuletRulesUpdate.Contract.CreatedEventBlob, + }) + } + + c.logger. + WithField("contract_id", openMiningRound.Contract.ContractID). + WithField("template", openMiningRound.Contract.TemplateID). + WithField("blob", openMiningRound.Contract.CreatedEventBlob). + Info("disclosing contract") + + openParts := strings.Split(openMiningRound.Contract.TemplateID, ":") + // Disclose OpenMiningRound (no template ID available from scan API response). + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: openParts[0], + ModuleName: openParts[1], + EntityName: openParts[2], + }, + ContractId: openMiningRoundID, + CreatedEventBlob: openMiningRound.Contract.CreatedEventBlob, + }) + + c.logger. + WithField("template", issuingMiningRound.Contract.TemplateID). + WithField("contract_id", issuingMiningRound.Contract.ContractID). + WithField("blob", issuingMiningRound.Contract.CreatedEventBlob). + Info("disclosing contract") + + issuingParts := strings.Split(issuingMiningRound.Contract.TemplateID, ":") + // Disclose OpenMiningRound (no template ID available from scan API response). + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: issuingParts[0], + ModuleName: issuingParts[1], + EntityName: issuingParts[2], + }, + ContractId: issuingMiningRound.Contract.ContractID, + CreatedEventBlob: issuingMiningRound.Contract.CreatedEventBlob, + }) + + rn, err := strconv.Atoi(issuingMiningRound.Contract.Payload.Round.Number) + if err != nil { + panic(err) + } + // Build GenMap for issuingMiningRounds + issuingMiningRounds := &v2.Value{ + Sum: &v2.Value_GenMap{ + GenMap: &v2.GenMap{ + Entries: []*v2.GenMap_Entry{ + { + Key: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "number", + Value: &v2.Value{ + Sum: &v2.Value_Int64{ + Int64: int64(rn), + }, + }, + }, + }, + }, + }, + }, + Value: &v2.Value{ + Sum: &v2.Value_ContractId{ + ContractId: issuingMiningRound.Contract.ContractID, + }, + }, + }, + }, + }, + }, + } + + cmd := &v2.Command{ + Command: &v2.Command_Exercise{ + Exercise: &v2.ExerciseCommand{ + TemplateId: acceptedOfferTemplateID, + ContractId: acceptedOfferContractID, + Choice: "AcceptedTransferOffer_Complete", + ChoiceArgument: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "inputs", + Value: &v2.Value{ + Sum: &v2.Value_List{ + List: &v2.List{ + Elements: transferInputs, + }, + }, + }, + }, + { + Label: "transferContext", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amuletRules", + Value: &v2.Value{ + Sum: &v2.Value_ContractId{ + ContractId: amuletRulesID, + }, + }, + }, + { + Label: "context", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "openMiningRound", + Value: &v2.Value{ + Sum: &v2.Value_ContractId{ + ContractId: openMiningRoundID, + }, + }, + }, + { + Label: "issuingMiningRounds", + Value: issuingMiningRounds, + }, + { + Label: "validatorRights", + Value: &v2.Value{ + Sum: &v2.Value_GenMap{ + GenMap: &v2.GenMap{ + Entries: []*v2.GenMap_Entry{}, // empty for now + }, + }, + }, + }, + { + Label: "featuredAppRight", + Value: &v2.Value{ + Sum: &v2.Value_Optional{ + Optional: &v2.Optional{}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + Label: "walletProvider", + Value: &v2.Value{ + Sum: &v2.Value_Party{ + Party: senderPartyID, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + prepareReq := &interactive.PrepareSubmissionRequest{ + UserId: ValidatorServiceUserId, + CommandId: newRegisterCommandId(), + Commands: []*v2.Command{cmd}, + // ActAs: []string{senderPartyID, ValidatorPartyId}, + ReadAs: []string{senderPartyID, ValidatorPartyId}, + ActAs: []string{senderPartyID}, + // ReadAs: []string{senderPartyID}, + SynchronizerId: TestnetSynchronizerID, + DisclosedContracts: disclosedContracts, + VerboseHashing: false, + } + + authCtx := c.authCtx(ctx) + prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) + if err != nil { + return fmt.Errorf("preparing AcceptedTransferOffer_Complete: %w", err) + } + + txSig := ed25519.Sign(privateKey, prepareResp.GetPreparedTransactionHash()) + _, keyFingerprint, err := cantonaddress.ParsePartyID(xc.Address(senderPartyID)) + if err != nil { + return fmt.Errorf("parsing sender party ID: %w", err) + } + + executeReq := &interactive.ExecuteSubmissionAndWaitRequest{ + PreparedTransaction: prepareResp.GetPreparedTransaction(), + PartySignatures: &interactive.PartySignatures{ + Signatures: []*interactive.SinglePartySignatures{ + { + Party: senderPartyID, + Signatures: []*v2.Signature{ + { + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: txSig, + SignedBy: keyFingerprint, + SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, + }, + }, + }, + }, + }, + DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ + DeduplicationDuration: durationpb.New(300 * time.Second), + }, + SubmissionId: newRegisterCommandId(), + HashingSchemeVersion: prepareResp.GetHashingSchemeVersion(), + } + + _, err = c.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) + if err != nil { + return fmt.Errorf("executing AcceptedTransferOffer_Complete: %w", err) + } + + return nil +} + +// GetUpdateById fetches a transaction (update) by its updateId from the Canton ledger. +func (c *GrpcLedgerClient) GetUpdateById(ctx context.Context, updateId string) (*v2.GetUpdateResponse, error) { + authCtx := c.authCtx(ctx) + req := &v2.GetUpdateByIdRequest{ + UpdateId: updateId, + UpdateFormat: &v2.UpdateFormat{ + IncludeTransactions: &v2.TransactionFormat{ + TransactionShape: v2.TransactionShape_TRANSACTION_SHAPE_ACS_DELTA, + EventFormat: &v2.EventFormat{ + FiltersForAnyParty: &v2.Filters{ + Cumulative: []*v2.CumulativeFilter{{ + IdentifierFilter: &v2.CumulativeFilter_WildcardFilter{ + WildcardFilter: &v2.WildcardFilter{}, + }, + }}, + }, + Verbose: true, + }, + }, + }, + } + resp, err := c.updateClient.GetUpdateById(authCtx, req) + if err != nil { + return nil, fmt.Errorf("GetUpdateById(%s): %w", updateId, err) + } + return resp, nil +} + +func isAlreadyExists(err error) bool { + if err == nil { + return false + } + msg := err.Error() + return strings.Contains(msg, "ALREADY_EXISTS") || + strings.Contains(msg, "already exists") || + strings.Contains(msg, "AlreadyExists") +} + +func (c *GrpcLedgerClient) ExecuteTransferInstructionSend( + ctx context.Context, + contractID string, + senderParty string, + privKey ed25519.PrivateKey, +) error { + // 1. Prepare + prepareReq := &interactive.PrepareSubmissionRequest{ + CommandId: "transfer-send-" + contractID, + ActAs: []string{senderParty}, + Commands: []*v2.Command{ + { + Command: &v2.Command_Exercise{ + Exercise: &v2.ExerciseCommand{ + TemplateId: &v2.Identifier{ + PackageId: "splice-amulet", // resolved by canton + ModuleName: "Splice.AmuletAllocation.TransferInstruction", + EntityName: "TransferInstruction", + }, + ContractId: contractID, + Choice: "TransferInstruction_Send", + ChoiceArgument: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + // TransferInstruction_Send takes no fields + Fields: []*v2.RecordField{}, + }, + }, + }, + }, + }, + }, + }, + DisclosedContracts: []*v2.DisclosedContract{}, + } + + prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(ctx, prepareReq) + if err != nil { + return fmt.Errorf("prepare failed: %w", err) + } + + prepared := prepareResp.GetPreparedTransaction() + if prepared == nil { + return fmt.Errorf("no prepared transaction returned") + } + + txHash := prepareResp.GetPreparedTransactionHash() + + // 2. Sign + signature := ed25519.Sign(privKey, txHash) + + // 3. Submit + submitReq := &interactive.ExecuteSubmissionAndWaitRequest{ + PreparedTransaction: prepared, + PartySignatures: &interactive.PartySignatures{ + Signatures: []*interactive.SinglePartySignatures{ + { + Party: "", + Signatures: []*v2.Signature{ + { + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: signature, + SignedBy: hex.EncodeToString(privKey.Public().(ed25519.PublicKey)), + }, + }, + }, + }, + }, + } + + _, err = c.interactiveSubmissionClient.ExecuteSubmissionAndWait(ctx, submitReq) + if err != nil { + return fmt.Errorf("submit failed: %w", err) + } + + return nil +} + +// isAmuletTemplate returns true if the identifier refers to a Splice Amulet contract. +// We match on module+entity name only; package IDs are deployment-specific. +func isPreapprovalTemplate(id *v2.Identifier) bool { + return id.GetModuleName() == "Splice.AmuletRules" && + id.GetEntityName() == "TransferPreapproval" +} + +// isAmuletTemplate returns true if the identifier refers to a Splice Amulet contract. +// We match on module+entity name only; package IDs are deployment-specific. +func isAmuletTemplate(id *v2.Identifier) bool { + return id.GetModuleName() == "Splice.Amulet" && + (id.GetEntityName() == "Amulet" || id.GetEntityName() == "LockedAmulet") +} + +// ExtractAmuletBalance extracts and converts the initialAmount from an Amulet contract's +// createArguments Record. The Splice.Amulet / Splice.Fees.ExpiringAmount schema is: +// +// Amulet { dso: Party, owner: Party, amount: ExpiringAmount } +// ExpiringAmount { initialAmount: Decimal, createdAt: Round, ratePerRound: RatePerRound } +// +// initialAmount is a Daml Decimal – it arrives as a proto Value_Numeric string (e.g. "100.5000000000"). +// We parse it as a human-readable amount and convert to blockchain units using the chain's decimal places. +func ExtractAmuletBalance(record *v2.Record, decimals int32) (xc.AmountBlockchain, bool) { + if record == nil { + return xc.AmountBlockchain{}, false + } + // Walk: Amulet.amount (ExpiringAmount record) + for _, field := range record.GetFields() { + if field.GetLabel() != LabelAmount { + continue + } + expiringAmount := field.GetValue().GetRecord() + if expiringAmount == nil { + continue + } + // Walk: ExpiringAmount.initialAmount (Numeric directly) + for _, af := range expiringAmount.GetFields() { + if af.GetLabel() != LabelInitialAmount { + continue + } + numeric := af.GetValue().GetNumeric() + if numeric == "" { + continue + } + human, err := xc.NewAmountHumanReadableFromStr(numeric) + if err != nil { + continue + } + return human.ToBlockchain(decimals), true + } + } + return xc.AmountBlockchain{}, false +} + +// NewCommandId generates a UUID-style unique command ID +func NewCommandId() string { + b := make([]byte, 16) + _, _ = rand.Read(b) + return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", + b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) +} diff --git a/chain/canton/errors.go b/chain/canton/errors.go new file mode 100644 index 00000000..258e8e0f --- /dev/null +++ b/chain/canton/errors.go @@ -0,0 +1,37 @@ +package canton + +import ( + "strings" + + "github.com/cordialsys/crosschain/client/errors" +) + +func CheckError(err error) errors.Status { + if err == nil { + return errors.UnknownError + } + msg := err.Error() + + if strings.Contains(msg, "401") || strings.Contains(msg, "403") || + strings.Contains(msg, "Unauthorized") || strings.Contains(msg, "unauthorized") { + return errors.NetworkError + } + if strings.Contains(msg, "404") || strings.Contains(msg, "not found") || + strings.Contains(msg, "NOT_FOUND") { + return errors.TransactionNotFound + } + if strings.Contains(msg, "timeout") || strings.Contains(msg, "deadline") { + return errors.NetworkError + } + if strings.Contains(msg, "ALREADY_EXISTS") || strings.Contains(msg, "already exists") { + return errors.TransactionExists + } + if strings.Contains(msg, "FAILED_PRECONDITION") || strings.Contains(msg, "insufficient") { + return errors.FailedPrecondition + } + if strings.Contains(msg, "EOF") || strings.Contains(msg, "connection") { + return errors.NetworkError + } + + return errors.NetworkError +} diff --git a/chain/canton/keycloak/keycloak.go b/chain/canton/keycloak/keycloak.go new file mode 100644 index 00000000..fc29fa66 --- /dev/null +++ b/chain/canton/keycloak/keycloak.go @@ -0,0 +1,259 @@ +package keycloak + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "os" + "strings" + "sync" + "time" + + "github.com/sirupsen/logrus" +) + +// TokenResponse holds the fields from a Keycloak token endpoint response. +type TokenResponse struct { + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + RefreshToken string `json:"refresh_token"` + RefreshExpiresIn int `json:"refresh_expires_in"` + TokenType string `json:"token_type"` +} + +// Client wraps Keycloak admin and token operations. +type Client struct { + baseURL string + realm string + clientID string + clientSecret string + httpClient *http.Client + + mu sync.Mutex + adminToken string + adminExpires time.Time +} + +func NewClient(baseURL, realm, clientID, clientSecret string) *Client { + return &Client{ + baseURL: baseURL, + realm: realm, + clientID: clientID, + clientSecret: clientSecret, + httpClient: &http.Client{Timeout: 10 * time.Second}, + } +} + +func (k *Client) tokenEndpoint() string { + return fmt.Sprintf("%s/realms/%s/protocol/openid-connect/token", k.baseURL, k.realm) +} + +func (k *Client) adminEndpoint() string { + return fmt.Sprintf("%s/admin/realms/%s", k.baseURL, k.realm) +} + +// AdminToken returns a cached client_credentials token for Keycloak Admin API calls. +func (k *Client) AdminToken(ctx context.Context) (string, error) { + k.mu.Lock() + defer k.mu.Unlock() + + if k.adminToken != "" && time.Now().Before(k.adminExpires) { + return k.adminToken, nil + } + + resp, err := k.postToken(ctx, url.Values{ + "grant_type": {"client_credentials"}, + "client_id": {k.clientID}, + "client_secret": {k.clientSecret}, + }) + if err != nil { + return "", err + } + + k.adminToken = resp.AccessToken + k.adminExpires = time.Now().Add(time.Duration(resp.ExpiresIn-30) * time.Second) + return k.adminToken, nil +} + +// CreateUser creates a Keycloak user with the given username and password. +// Returns the new user's Keycloak ID. If the user already exists, returns its ID. +func (k *Client) CreateUser(ctx context.Context, username, password string) (string, error) { + adminToken, err := k.AdminToken(ctx) + if err != nil { + return "", fmt.Errorf("getting admin token: %w", err) + } + + payload, _ := json.Marshal(map[string]any{ + "username": username, + "enabled": true, + "credentials": []map[string]any{ + {"type": "password", "value": password, "temporary": false}, + }, + }) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, + k.adminEndpoint()+"/users", strings.NewReader(string(payload))) + if err != nil { + return "", err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+adminToken) + + resp, err := k.httpClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + if resp.StatusCode == http.StatusConflict { + // User already exists — look it up by username + logrus.WithFields(logrus.Fields{ + "username": username, + }).Warn("keycloak: user already exists, fetching ID") + return k.FindUser(ctx, username) + } + if resp.StatusCode != http.StatusCreated { + b, _ := io.ReadAll(resp.Body) + return "", fmt.Errorf("create user returned %d: %s", resp.StatusCode, b) + } + + // Keycloak returns the new user URL in the Location header + location := resp.Header.Get("Location") + if location == "" { + return "", fmt.Errorf("keycloak did not return Location header after user creation") + } + parts := strings.Split(location, "/") + return parts[len(parts)-1], nil +} + +// FindUser returns the Keycloak user ID for the given username. +func (k *Client) FindUser(ctx context.Context, username string) (string, error) { + adminToken, err := k.AdminToken(ctx) + if err != nil { + return "", fmt.Errorf("getting admin token: %w", err) + } + + endpoint := fmt.Sprintf("%s/users?username=%s&exact=true", k.adminEndpoint(), url.QueryEscape(username)) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) + if err != nil { + return "", err + } + req.Header.Set("Authorization", "Bearer "+adminToken) + + resp, err := k.httpClient.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("find user returned %d: %s", resp.StatusCode, body) + } + + var users []struct { + ID string `json:"id"` + } + if err := json.Unmarshal(body, &users); err != nil { + return "", fmt.Errorf("decoding user list: %w", err) + } + if len(users) == 0 { + return "", fmt.Errorf("user %q not found in Keycloak", username) + } + return users[0].ID, nil +} + +// SetPartyAttribute writes the Canton party ID into the user's canton_party_id attribute. +// The Keycloak protocol mapper then injects this into actAs/readAs on every token. +func (k *Client) SetPartyAttribute(ctx context.Context, userID, partyID string) error { + adminToken, err := k.AdminToken(ctx) + if err != nil { + return fmt.Errorf("getting admin token: %w", err) + } + + validatorPartyID := os.Getenv("CANTON_VALIDATOR_PARTY_ID") + if validatorPartyID == "" { + return fmt.Errorf("required environment variable CANTON_VALIDATOR_PARTY_ID is not set") + } + participantAud := "https://daml.com/jwt/aud/participant/" + validatorPartyID + payload, _ := json.Marshal(map[string]any{ + "attributes": map[string][]string{ + "canton_party_id": {partyID}, + "canton_participant_aud": {participantAud}, + }, + }) + + endpoint := fmt.Sprintf("%s/users/%s", k.adminEndpoint(), userID) + req, err := http.NewRequestWithContext(ctx, http.MethodPut, endpoint, + strings.NewReader(string(payload))) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+adminToken) + + resp, err := k.httpClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusNoContent { + b, _ := io.ReadAll(resp.Body) + return fmt.Errorf("set party attribute returned %d: %s", resp.StatusCode, b) + } + return nil +} + +// AcquireUserToken exchanges username/password for an access token with daml_ledger_api scope. +// The returned token will carry actAs/readAs Canton claims if the protocol mapper is configured. +func (k *Client) AcquireUserToken(ctx context.Context, username, password string) (*TokenResponse, error) { + return k.postToken(ctx, url.Values{ + "grant_type": {"password"}, + "client_id": {k.clientID}, + "client_secret": {k.clientSecret}, + "username": {username}, + "password": {password}, + "scope": {"daml_ledger_api"}, + }) +} + +func (k *Client) AcquireCantonUiToken(ctx context.Context, username, password string) (*TokenResponse, error) { + return k.postToken(ctx, url.Values{ + "grant_type": {"password"}, + "client_id": {"canton-ui"}, + "username": {username}, + "password": {password}, + }) +} + +func (k *Client) postToken(ctx context.Context, form url.Values) (*TokenResponse, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodPost, k.tokenEndpoint(), + strings.NewReader(form.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + resp, err := k.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("token endpoint returned %d: %s", resp.StatusCode, body) + } + + var result TokenResponse + if err := json.Unmarshal(body, &result); err != nil { + return nil, fmt.Errorf("decoding token response: %w", err) + } + if result.AccessToken == "" { + return nil, fmt.Errorf("empty access token in response") + } + return &result, nil +} diff --git a/chain/canton/signature_test.go b/chain/canton/signature_test.go new file mode 100644 index 00000000..f69c35c3 --- /dev/null +++ b/chain/canton/signature_test.go @@ -0,0 +1,28 @@ +package canton + +import ( + "testing" + + xc "github.com/cordialsys/crosschain" + "github.com/stretchr/testify/require" +) + +func TestCantonSignatureAlgorithm(t *testing.T) { + driver := xc.DriverCanton + + // Verify Canton returns at least one signature algorithm + algorithms := driver.SignatureAlgorithms() + require.NotEmpty(t, algorithms, "Canton driver should return at least one signature algorithm") + require.Len(t, algorithms, 1, "Canton should have exactly one signature algorithm") + + // Verify it's Ed25519 + require.Equal(t, xc.Ed255, algorithms[0], "Canton should use Ed25519 signatures") +} + +func TestCantonPublicKeyFormat(t *testing.T) { + driver := xc.DriverCanton + + // Verify Canton uses Raw public key format + format := driver.PublicKeyFormat() + require.Equal(t, xc.Raw, format, "Canton should use Raw public key format") +} diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go new file mode 100644 index 00000000..9cc9cd51 --- /dev/null +++ b/chain/canton/tx/tx.go @@ -0,0 +1,97 @@ +package tx + +import ( + "fmt" + "time" + + xc "github.com/cordialsys/crosschain" + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" +) + +// Tx for Canton holds the data needed for the external-party signing flow: +// 1. PreparedTransaction: the proto from InteractiveSubmissionService.PrepareSubmission +// 2. PreparedTransactionHash: raw bytes to sign (Ed25519) +// 3. After SetSignatures: Serialize() marshals the ExecuteSubmissionRequest proto +type Tx struct { + PreparedTransaction *interactive.PreparedTransaction + // Raw hash bytes of the prepared transaction (what the party signs) + PreparedTransactionHash []byte + // Hashing scheme version returned by prepare endpoint + HashingSchemeVersion interactive.HashingSchemeVersion + // Party (Canton party ID / address) that is authorizing this transaction + Party string + // Fingerprint of the signing key (the portion after "12" in the party's fingerprint) + KeyFingerprint string + // SubmissionId for deduplication + SubmissionId string + // Populated after SetSignatures is called + signature []byte +} + +var _ xc.Tx = &Tx{} + +// Hash returns a hex string of the prepared transaction hash +func (tx Tx) Hash() xc.TxHash { + return xc.TxHash(fmt.Sprintf("%x", tx.PreparedTransactionHash)) +} + +// Sighashes returns the raw prepared transaction hash bytes for the party to sign +func (tx Tx) Sighashes() ([]*xc.SignatureRequest, error) { + if len(tx.PreparedTransactionHash) == 0 { + return nil, fmt.Errorf("prepared transaction hash is empty") + } + return []*xc.SignatureRequest{xc.NewSignatureRequest(tx.PreparedTransactionHash)}, nil +} + +// SetSignatures stores the Ed25519 signature from the external party +func (tx *Tx) SetSignatures(sigs ...*xc.SignatureResponse) error { + if len(sigs) != 1 { + return fmt.Errorf("expected exactly 1 signature, got %d", len(sigs)) + } + tx.signature = sigs[0].Signature + return nil +} + +// Serialize marshals the ExecuteSubmissionRequest proto so SubmitTx can send it over gRPC +func (tx Tx) Serialize() ([]byte, error) { + if len(tx.signature) == 0 { + return nil, fmt.Errorf("transaction is not signed") + } + if tx.PreparedTransaction == nil { + return nil, fmt.Errorf("prepared transaction is nil") + } + + req := &interactive.ExecuteSubmissionRequest{ + PreparedTransaction: tx.PreparedTransaction, + PartySignatures: &interactive.PartySignatures{ + Signatures: []*interactive.SinglePartySignatures{ + { + Party: tx.Party, + Signatures: []*v2.Signature{ + { + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: tx.signature, + SignedBy: tx.KeyFingerprint, + SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, + }, + }, + }, + }, + }, + DeduplicationPeriod: &interactive.ExecuteSubmissionRequest_DeduplicationDuration{ + // TODO: Move to input + DeduplicationDuration: durationpb.New(300 * time.Second), + }, + SubmissionId: tx.SubmissionId, + HashingSchemeVersion: tx.HashingSchemeVersion, + } + + data, err := proto.Marshal(req) + if err != nil { + return nil, fmt.Errorf("failed to marshal Canton execute request: %w", err) + } + return data, nil +} diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go new file mode 100644 index 00000000..81a6d0fc --- /dev/null +++ b/chain/canton/tx_input/tx_input.go @@ -0,0 +1,65 @@ +package tx_input + +import ( + xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/factory/drivers/registry" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" +) + +// TxInput for Canton holds the result of the prepare step in the +// interactive-submission (external-party signing) flow. +type TxInput struct { + xc.TxInputEnvelope + IsExternalTransfer bool `json:"is_external_transfer"` + PreparedTransaction interactive.PreparedTransaction + Sighash []byte `json:"sighash"` + HashingSchemeVersion interactive.HashingSchemeVersion + // SubmissionId for deduplication (UUID) + SubmissionId string `json:"submission_id"` +} + +var _ xc.TxInput = &TxInput{} + +func init() { + registry.RegisterTxBaseInput(&TxInput{}) +} + +func NewTxInput() *TxInput { + return &TxInput{ + TxInputEnvelope: xc.TxInputEnvelope{ + Type: xc.DriverCanton, + }, + } +} + +func (input *TxInput) GetDriver() xc.Driver { + return xc.DriverCanton +} + +func (input *TxInput) SetGasFeePriority(other xc.GasFeePriority) error { + // Canton does not use gas fees in the traditional sense + return nil +} + +func (input *TxInput) GetFeeLimit() (xc.AmountBlockchain, xc.ContractAddress) { + return xc.NewAmountBlockchainFromUint64(0), "" +} + +func (input *TxInput) IndependentOf(other xc.TxInput) (independent bool) { + // Each Canton submission has a unique SubmissionId / command ID + if cantonOther, ok := other.(*TxInput); ok { + return cantonOther.SubmissionId != input.SubmissionId + } + return true +} + +func (input *TxInput) SafeFromDoubleSend(other xc.TxInput) (safe bool) { + if !xc.IsTypeOf(other, input) { + return false + } + if input.IndependentOf(other) { + return false + } + // Same submission ID means deduplication will protect us + return true +} diff --git a/chain/canton/validate.go b/chain/canton/validate.go new file mode 100644 index 00000000..8eef23a2 --- /dev/null +++ b/chain/canton/validate.go @@ -0,0 +1,90 @@ +package canton + +import ( + "encoding/hex" + "fmt" + "regexp" + "strings" + + xc "github.com/cordialsys/crosschain" +) + +// ValidateAddress validates a Canton party ID address format. +// Canton party IDs must be in the format "name::fingerprint" where: +// - name: 1-185 characters, matching [a-zA-Z0-9:-_ ], no consecutive colons +// - fingerprint: starts with "12" followed by 64 hex characters (SHA256 hash) +func ValidateAddress(cfg *xc.ChainBaseConfig, addr xc.Address) error { + addrStr := string(addr) + + if addrStr == "" { + return fmt.Errorf("empty address") + } + + // Find the :: separator + parts := strings.Split(addrStr, "::") + if len(parts) != 2 { + return fmt.Errorf("invalid Canton party ID format: must contain exactly one '::' separator") + } + + name := parts[0] + fingerprint := parts[1] + + // Validate party name + if err := validatePartyName(name); err != nil { + return fmt.Errorf("invalid party name: %w", err) + } + + // Validate fingerprint + if err := validateFingerprint(fingerprint); err != nil { + return fmt.Errorf("invalid fingerprint: %w", err) + } + + return nil +} + +// validatePartyName validates the party name component +func validatePartyName(name string) error { + if len(name) == 0 { + return fmt.Errorf("party name cannot be empty") + } + + if len(name) > 185 { + return fmt.Errorf("party name too long: %d characters (maximum 185)", len(name)) + } + + // Check for valid characters: [a-zA-Z0-9:-_ ] + validChars := regexp.MustCompile(`^[a-zA-Z0-9:\-_ ]+$`) + if !validChars.MatchString(name) { + return fmt.Errorf("party name contains invalid characters (allowed: a-zA-Z0-9:-_ )") + } + + // Check for consecutive colons + if strings.Contains(name, "::") { + return fmt.Errorf("party name cannot contain consecutive colons") + } + + return nil +} + +// validateFingerprint validates the fingerprint component +func validateFingerprint(fingerprint string) error { + // Fingerprint must start with "1220" (SHA-256 multihash prefix) and be followed by 64 hex characters + if !strings.HasPrefix(fingerprint, "1220") { + return fmt.Errorf("fingerprint must start with '1220' (SHA-256 multihash prefix)") + } + + // Remove the "1220" prefix + hexPart := fingerprint[4:] + + // SHA256 produces 32 bytes = 64 hex characters + if len(hexPart) != 64 { + return fmt.Errorf("fingerprint must be 68 characters total (1220 + 64 hex chars), got %d", len(fingerprint)) + } + + // Validate hex encoding + if _, err := hex.DecodeString(hexPart); err != nil { + return fmt.Errorf("fingerprint contains invalid hex characters: %w", err) + } + + return nil +} diff --git a/chain/canton/validate_test.go b/chain/canton/validate_test.go new file mode 100644 index 00000000..209f465c --- /dev/null +++ b/chain/canton/validate_test.go @@ -0,0 +1,299 @@ +package canton + +import ( + "strings" + "testing" + + xc "github.com/cordialsys/crosschain" + "github.com/stretchr/testify/require" +) + +// validFP68 is a valid 68-char fingerprint: "1220" + 64 hex chars +const validFP68 = "12201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" + +func TestValidateAddress(t *testing.T) { + cfg := &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + } + + tests := []struct { + name string + addr xc.Address + expectError bool + errorContains string + }{ + { + name: "valid address", + addr: xc.Address("party::" + validFP68), + expectError: false, + }, + { + name: "valid address with complex name", + addr: xc.Address("my-party_123::" + validFP68), + expectError: false, + }, + { + name: "valid address with spaces", + addr: xc.Address("my party::" + validFP68), + expectError: false, + }, + { + name: "empty address", + addr: xc.Address(""), + expectError: true, + errorContains: "empty address", + }, + { + name: "missing separator", + addr: xc.Address("party1234567890abcdef"), + expectError: true, + errorContains: "must contain exactly one '::' separator", + }, + { + name: "multiple separators", + addr: xc.Address("party::name::" + validFP68), + expectError: true, + errorContains: "must contain exactly one '::' separator", + }, + { + name: "empty party name", + addr: xc.Address("::" + validFP68), + expectError: true, + errorContains: "party name cannot be empty", + }, + { + name: "party name too long", + addr: xc.Address(strings.Repeat("a", 186) + "::" + validFP68), + expectError: true, + errorContains: "party name too long", + }, + { + name: "invalid characters in party name", + addr: xc.Address("party@123::" + validFP68), + expectError: true, + errorContains: "invalid characters", + }, + { + name: "consecutive colons in party name", + addr: xc.Address("par::ty::" + validFP68), + expectError: true, + errorContains: "must contain exactly one", // splits on :: so sees 3 parts + }, + { + name: "fingerprint doesn't start with 1220", + addr: xc.Address("party::9934567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12"), + expectError: true, + errorContains: "must start with '1220'", + }, + { + name: "fingerprint too short", + addr: xc.Address("party::1220abcdef"), + expectError: true, + errorContains: "68 characters total", + }, + { + name: "fingerprint too long", + addr: xc.Address("party::12201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234"), + expectError: true, + errorContains: "68 characters total", + }, + { + name: "invalid hex in fingerprint", + addr: xc.Address("party::1220gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg"), + expectError: true, + errorContains: "invalid hex characters", + }, + { + name: "uppercase hex in fingerprint (should work)", + addr: xc.Address("party::12201234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF"), + expectError: false, + }, + { + name: "mixed case hex in fingerprint (should work)", + addr: xc.Address("party::12201234567890AbCdEf1234567890aBcDeF1234567890AbCdEf1234567890aBcDeF"), + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := ValidateAddress(cfg, tt.addr) + + if tt.expectError { + require.Error(t, err) + if tt.errorContains != "" { + require.Contains(t, err.Error(), tt.errorContains) + } + } else { + require.NoError(t, err) + } + }) + } +} + +func TestValidatePartyName(t *testing.T) { + tests := []struct { + name string + partyName string + expectError bool + errorContains string + }{ + { + name: "valid simple name", + partyName: "party", + expectError: false, + }, + { + name: "valid with numbers", + partyName: "party123", + expectError: false, + }, + { + name: "valid with dash", + partyName: "my-party", + expectError: false, + }, + { + name: "valid with underscore", + partyName: "my_party", + expectError: false, + }, + { + name: "valid with space", + partyName: "my party", + expectError: false, + }, + { + name: "valid with colon", + partyName: "my:party", + expectError: false, + }, + { + name: "valid max length", + partyName: strings.Repeat("a", 185), + expectError: false, + }, + { + name: "empty name", + partyName: "", + expectError: true, + errorContains: "cannot be empty", + }, + { + name: "too long", + partyName: strings.Repeat("a", 186), + expectError: true, + errorContains: "too long", + }, + { + name: "invalid character @", + partyName: "party@123", + expectError: true, + errorContains: "invalid characters", + }, + { + name: "invalid character #", + partyName: "party#123", + expectError: true, + errorContains: "invalid characters", + }, + { + name: "consecutive colons", + partyName: "par::ty", + expectError: true, + errorContains: "consecutive colons", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validatePartyName(tt.partyName) + + if tt.expectError { + require.Error(t, err) + if tt.errorContains != "" { + require.Contains(t, err.Error(), tt.errorContains) + } + } else { + require.NoError(t, err) + } + }) + } +} + +func TestValidateFingerprint(t *testing.T) { + tests := []struct { + name string + fingerprint string + expectError bool + errorContains string + }{ + { + name: "valid fingerprint", + fingerprint: "12201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + expectError: false, + }, + { + name: "valid uppercase", + fingerprint: "12201234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF", + expectError: false, + }, + { + name: "valid mixed case", + fingerprint: "12201234567890AbCdEf1234567890aBcDeF1234567890AbCdEf1234567890aBcDeF", + expectError: false, + }, + { + name: "doesn't start with 1220", + fingerprint: "9934567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12", + expectError: true, + errorContains: "must start with '1220'", + }, + { + name: "starts with 12 but not 1220", + fingerprint: "12341234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + expectError: true, + errorContains: "must start with '1220'", + }, + { + name: "too short", + fingerprint: "1220abcdef", + expectError: true, + errorContains: "68 characters total", + }, + { + name: "too long", + fingerprint: "12201234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234", + expectError: true, + errorContains: "68 characters total", + }, + { + name: "invalid hex characters - correct length", + fingerprint: "1220gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg", + expectError: true, + errorContains: "invalid hex characters", + }, + { + name: "contains spaces", + fingerprint: "12201234567890abcdef 234567890abcdef1234567890abcdef1234567890abcdef", + expectError: true, + errorContains: "invalid hex characters", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateFingerprint(tt.fingerprint) + + if tt.expectError { + require.Error(t, err) + if tt.errorContains != "" { + require.Contains(t, err.Error(), tt.errorContains) + } + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/cmd/xc/commands/transfer.go b/cmd/xc/commands/transfer.go index da09d611..fa5dbbbc 100644 --- a/cmd/xc/commands/transfer.go +++ b/cmd/xc/commands/transfer.go @@ -221,10 +221,10 @@ func CmdTxTransfer() *cobra.Command { } } - input, err = xcFactory.TxInputRoundtrip(input) - if err != nil { - return fmt.Errorf("failed tx input roundtrip: %w", err) - } + // input, err = xcFactory.TxInputRoundtrip(input) + // if err != nil { + // return fmt.Errorf("failed tx input roundtrip: %w", err) + // } // set params on input that are enforced by the builder (rather than depending soley on untrusted RPC) timeStamp, _ := tfArgs.GetTimestamp() diff --git a/factory/canton_signer_test.go b/factory/canton_signer_test.go new file mode 100644 index 00000000..e3903490 --- /dev/null +++ b/factory/canton_signer_test.go @@ -0,0 +1,82 @@ +package factory_test + +import ( + "encoding/hex" + "testing" + + xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/factory" + "github.com/stretchr/testify/require" +) + +func TestCantonSignerCreation(t *testing.T) { + // Create a testnet factory + testnetFactory := factory.NewNotMainnetsFactory(&factory.FactoryOptions{}) + require.NotNil(t, testnetFactory) + + // Get Canton configuration + config, found := testnetFactory.GetChain(xc.CANTON) + require.True(t, found, "Canton should be configured") + + // Create a test private key (32 bytes for Ed25519) + privateKeyHex := "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" + + // Verify it's valid hex + privateKeyBytes, err := hex.DecodeString(privateKeyHex) + require.NoError(t, err) + require.Len(t, privateKeyBytes, 32) + + // Try to create a signer - this is where the error would occur if signature type is not configured + signer, err := testnetFactory.NewSigner(config.Base(), privateKeyHex) + require.NoError(t, err, "Should be able to create Canton signer with Ed25519") + require.NotNil(t, signer) + + // Get the public key + publicKey, err := signer.PublicKey() + require.NoError(t, err) + require.NotNil(t, publicKey) + require.Len(t, publicKey, 32, "Ed25519 public key should be 32 bytes") +} + +func TestCantonAddressFromPrivateKey(t *testing.T) { + // Create a testnet factory + testnetFactory := factory.NewNotMainnetsFactory(&factory.FactoryOptions{}) + + // Get Canton configuration + config, found := testnetFactory.GetChain(xc.CANTON) + require.True(t, found) + + // Create a test private key + privateKeyHex := "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" + + // Create a signer first, then get address from public key + signer, err := testnetFactory.NewSigner(config.Base(), privateKeyHex) + require.NoError(t, err) + + publicKey, err := signer.PublicKey() + require.NoError(t, err) + + // Get address from public key + address, err := testnetFactory.GetAddressFromPublicKey(config.Base(), publicKey) + require.NoError(t, err, "Should be able to derive Canton address from public key") + require.NotEmpty(t, address) + + // Verify the address format: ::1220 + addrStr := string(address) + require.Contains(t, addrStr, "::", "Canton address should contain :: separator") + require.Contains(t, addrStr, "::1220", "Canton address fingerprint should start with 1220 (SHA-256 multihash prefix)") + // name (64 hex) + "::" (2) + "1220" (4) + 64 hex = 134 chars + require.True(t, len(addrStr) > 70, "Canton address should be well over 70 characters") + + t.Logf("Generated Canton address: %s", addrStr) +} + +func TestCantonSignatureAlgorithms(t *testing.T) { + // Verify that Canton driver returns correct signature algorithms + algorithms := xc.DriverCanton.SignatureAlgorithms() + require.NotEmpty(t, algorithms, "Canton driver must return at least one signature algorithm") + require.Len(t, algorithms, 1, "Canton should use exactly one signature algorithm") + require.Equal(t, xc.Ed255, algorithms[0], "Canton must use Ed25519 (Ed255)") + + t.Logf("Canton signature algorithm: %s", algorithms[0]) +} diff --git a/factory/defaults/canton_test.go b/factory/defaults/canton_test.go new file mode 100644 index 00000000..bd817978 --- /dev/null +++ b/factory/defaults/canton_test.go @@ -0,0 +1,43 @@ +package defaults_test + +import ( + "testing" + + xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/factory" + "github.com/stretchr/testify/require" +) + +func TestCantonConfigTestnet(t *testing.T) { + // Load testnet factory + testnetFactory := factory.NewNotMainnetsFactory(&factory.FactoryOptions{}) + require.NotNil(t, testnetFactory) + + // Get Canton configuration + config, found := testnetFactory.GetChain(xc.CANTON) + require.True(t, found, "Canton should be configured in testnet") + require.NotNil(t, config) + + // Verify basic configuration + require.Equal(t, xc.CANTON, config.Chain) + require.Equal(t, xc.DriverCanton, config.Driver) + require.Equal(t, "Canton (Testnet)", config.ChainName) + require.Equal(t, int32(18), config.Decimals) +} + +func TestCantonConfigMainnet(t *testing.T) { + // Load mainnet factory + mainnetFactory := factory.NewDefaultFactory() + require.NotNil(t, mainnetFactory) + + // Get Canton configuration + config, found := mainnetFactory.GetChain(xc.CANTON) + require.True(t, found, "Canton should be configured in mainnet") + require.NotNil(t, config) + + // Verify basic configuration + require.Equal(t, xc.CANTON, config.Chain) + require.Equal(t, xc.DriverCanton, config.Driver) + require.Equal(t, "Canton", config.ChainName) + require.Equal(t, int32(18), config.Decimals) +} diff --git a/factory/defaults/chains/mainnet.yaml b/factory/defaults/chains/mainnet.yaml index 3a097bf9..123603c8 100644 --- a/factory/defaults/chains/mainnet.yaml +++ b/factory/defaults/chains/mainnet.yaml @@ -443,6 +443,13 @@ chains: asset_id: celo indexing_co: chain_id: celo + CANTON: + chain: CANTON + driver: canton + chain_name: Canton + decimals: 18 + fee_limit: "100.0" + confirmations_final: 1 CHZ: chain: CHZ driver: evm-legacy diff --git a/factory/defaults/chains/testnet.yaml b/factory/defaults/chains/testnet.yaml index 87581451..c8188a51 100644 --- a/factory/defaults/chains/testnet.yaml +++ b/factory/defaults/chains/testnet.yaml @@ -214,6 +214,14 @@ chains: chain_id: 44787 chain_name: Celo (Testnet) decimals: 18 + CANTON: + chain: CANTON + driver: canton + chain_name: Canton (Testnet) + auth: env:CANTON_AUTH + decimals: 18 + fee_limit: "100.0" + confirmations_final: 1 CHZ: chain: CHZ driver: "evm-legacy" diff --git a/factory/drivers/drivers_test.go b/factory/drivers/drivers_test.go index e73338ae..fbeebf4f 100644 --- a/factory/drivers/drivers_test.go +++ b/factory/drivers/drivers_test.go @@ -91,6 +91,9 @@ func createChainFor(driver xc.Driver) *xc.ChainConfig { if driver == xc.DriverHedera { fakeAsset.ChainID = "0.0.3" } + if driver == xc.DriverCanton { + fakeAsset.URL = "https://canton.example.com" + } return fakeAsset } diff --git a/factory/drivers/factory.go b/factory/drivers/factory.go index ebadff2b..a9a84a15 100644 --- a/factory/drivers/factory.go +++ b/factory/drivers/factory.go @@ -25,6 +25,10 @@ import ( bitcoinaddress "github.com/cordialsys/crosschain/chain/bitcoin/address" bitcoinbuilder "github.com/cordialsys/crosschain/chain/bitcoin/builder" "github.com/cordialsys/crosschain/chain/bitcoin_cash" + canton "github.com/cordialsys/crosschain/chain/canton" + cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + cantonbuilder "github.com/cordialsys/crosschain/chain/canton/builder" + cantonclient "github.com/cordialsys/crosschain/chain/canton/client" cardano "github.com/cordialsys/crosschain/chain/cardano" cardanoaddress "github.com/cordialsys/crosschain/chain/cardano/address" cardanobuilder "github.com/cordialsys/crosschain/chain/cardano/builder" @@ -96,6 +100,8 @@ import ( func NewClient(cfg *xc.ChainConfig, driver xc.Driver) (xclient.Client, error) { switch driver { + case xc.DriverCanton: + return cantonclient.NewClient(cfg) case xc.DriverCardano: return cardanoclient.NewClient(cfg) case xc.DriverEVM: @@ -196,6 +202,8 @@ func NewStakingClient(servicesConfig *services.ServicesConfig, cfg *xc.ChainConf func NewTxBuilder(cfg *xc.ChainBaseConfig) (xcbuilder.FullTransferBuilder, error) { switch xc.Driver(cfg.Driver) { + case xc.DriverCanton: + return cantonbuilder.NewTxBuilder(cfg) case xc.DriverCardano: return cardanobuilder.NewTxBuilder(cfg) case xc.DriverEVM: @@ -256,6 +264,8 @@ func NewSigner(chain *xc.ChainBaseConfig, secret string, options ...xcaddress.Ad func NewAddressBuilder(cfg *xc.ChainBaseConfig, options ...xcaddress.AddressOption) (xc.AddressBuilder, error) { switch xc.Driver(cfg.Driver) { + case xc.DriverCanton: + return cantonaddress.NewAddressBuilder(cfg) case xc.DriverDusk: return duskaddress.NewAddressBuilder(cfg) case xc.DriverEGLD: @@ -315,6 +325,8 @@ func CheckError(driver xc.Driver, err error) errors.Status { return err.Status } switch driver { + case xc.DriverCanton: + return canton.CheckError(err) case xc.DriverCardano: return cardano.CheckError(err) case xc.DriverDusk: @@ -376,6 +388,8 @@ func ValidateAddress(cfg *xc.ChainBaseConfig, addr xc.Address) error { return fmt.Errorf("empty address") } switch cfg.Driver { + case xc.DriverCanton: + return canton.ValidateAddress(cfg, addr) case xc.DriverCardano: return cardano.ValidateAddress(cfg, addr) case xc.DriverDusk: diff --git a/go.mod b/go.mod index 0cdd9a6e..c2b5da26 100644 --- a/go.mod +++ b/go.mod @@ -33,12 +33,12 @@ require ( github.com/hashicorp/vault/api v1.9.0 github.com/novifinancial/serde-reflection/serde-generate/runtime/golang v0.0.0-20220519162058-e5cd3c3b3f3a github.com/pelletier/go-toml/v2 v2.2.3 - github.com/shopspring/decimal v1.3.1 + github.com/shopspring/decimal v1.4.0 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.1 + github.com/spf13/cobra v1.10.1 github.com/spf13/viper v1.19.0 github.com/stellar/go v0.0.0-20220406183204-45b6f52202f3 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/test-go/testify v1.1.4 github.com/tidwall/btree v1.7.0 github.com/vedhavyas/go-subkey/v2 v2.0.0 @@ -71,6 +71,7 @@ require ( github.com/harshavardhana/blake2b-simd v0.0.0-20160628082310-f6a3512276ac github.com/holiman/uint256 v1.3.2 github.com/kaspanet/kaspad v0.12.22 + github.com/noders-team/go-daml v0.6.1 github.com/pkg/errors v0.9.1 github.com/vmihailenco/msgpack/v5 v5.4.1 golang.org/x/time v0.9.0 @@ -140,6 +141,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgraph-io/badger/v4 v4.5.0 // indirect github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect + github.com/digital-asset/dazl-client/v8 v8.9.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/emicklei/dot v1.6.2 // indirect @@ -237,7 +239,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rs/cors v1.11.1 // indirect - github.com/rs/zerolog v1.33.0 // indirect + github.com/rs/zerolog v1.34.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -247,7 +249,7 @@ require ( github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.0 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.9 // indirect github.com/stellar/go-xdr v0.0.0-20211103144802-8017fc4bdfee // indirect github.com/streamingfast/logging v0.0.0-20250404134358-92b15d2fbd2e // indirect github.com/stretchr/objx v0.5.2 // indirect diff --git a/go.sum b/go.sum index ba6e7629..e1ebfa11 100644 --- a/go.sum +++ b/go.sum @@ -244,6 +244,8 @@ cosmossdk.io/x/tx v1.0.0-alpha.3 h1:+55/JFH5QRqnFhOI2heH3DKsaNL0RpXcJOQNzUvHiaQ= cosmossdk.io/x/tx v1.0.0-alpha.3/go.mod h1:h4pQ/j6Gfu8goB1R3Jbl4qY4RjYVNAsoylcleTXdSRg= cosmossdk.io/x/upgrade v0.2.0-rc.1 h1:YO865mCFIsFyjzl1fOsOr7Hw2iVGJhTGwecUC3u0YBY= cosmossdk.io/x/upgrade v0.2.0-rc.1/go.mod h1:xt0idx/1eRsn5C9/YHubGBE5j5goZTgaKu1HNOXgdac= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -337,6 +339,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEe github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.2-0.20240711233432-c7949e1f6b9a h1:rNUteH7x0G1/4zorsH0yXDx5e6vuAkSWWD/z70v5vx8= github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.2-0.20240711233432-c7949e1f6b9a/go.mod h1:k61SBXqYmnZO4frAJyH3iuqjolYrYsq79r8EstmklDY= @@ -398,8 +402,8 @@ github.com/consensys/bavard v0.1.30 h1:wwAj9lSnMLFXjEclKwyhf7Oslg8EoaFz9u1QGgt0b github.com/consensys/bavard v0.1.30/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= github.com/consensys/gnark-crypto v0.17.0 h1:vKDhZMOrySbpZDCvGMOELrHFv/A9mJ7+9I8HEfRZSkI= github.com/consensys/gnark-crypto v0.17.0/go.mod h1:A2URlMHUT81ifJ0UlLzSlm7TmnE3t7VxEThApdMukJw= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= +github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/cordialsys/go-aptos-sdk v0.0.0-20250509215447-cc739925dd04 h1:k2/8TDHfPX3zA5GABSEhbVNBNiW0aNOy7nZQQuoittg= github.com/cordialsys/go-aptos-sdk v0.0.0-20250509215447-cc739925dd04/go.mod h1:hzXqFO40XA/kcmAP26WDJmc7WiJcoLZlnvR0ZVWXu9g= github.com/cordialsys/go-json v0.10.5-sonic-replace h1:9wdSnZ7KBekIZ9tLiCEQAkY6kEHp44IdcQFnKUNSxLI= @@ -433,9 +437,8 @@ github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5Rtn github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= -github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg/0E3OOdI= github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= @@ -471,8 +474,16 @@ github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMb github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/digital-asset/dazl-client/v8 v8.7.1 h1:W/U9xRoreGOq9kfcgwLkcHphp/dPxQrPBldsoBqtt9U= +github.com/digital-asset/dazl-client/v8 v8.7.1/go.mod h1:q1KevCJ8FpH8je2MnnjN8/QUfhstB4fKpyKyqDtqFh0= +github.com/digital-asset/dazl-client/v8 v8.9.0 h1:F2qTUWtHAjhGyRGV+xTim+VAFwM99FpcOx4+wowvPnY= +github.com/digital-asset/dazl-client/v8 v8.9.0/go.mod h1:q1KevCJ8FpH8je2MnnjN8/QUfhstB4fKpyKyqDtqFh0= +github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= +github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= +github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -563,6 +574,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= +github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -672,6 +685,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -900,6 +915,12 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -917,6 +938,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/noders-team/go-daml v0.6.1 h1:TIDliHjkq8I6o0/rFJR2CYfPCESp8sO3+ZNiqy2Pv/U= +github.com/noders-team/go-daml v0.6.1/go.mod h1:QeH3C2liWjY0Ik9Yl0DXpgROXO9bIbM8MvkQA58Bw9M= github.com/novifinancial/serde-reflection/serde-generate/runtime/golang v0.0.0-20220519162058-e5cd3c3b3f3a h1:oMG8C4E7DFkat7WQicw4JNa/dYUaqO7RvLPbkFdADIA= github.com/novifinancial/serde-reflection/serde-generate/runtime/golang v0.0.0-20220519162058-e5cd3c3b3f3a/go.mod h1:NrRYJCFtaewjIRr4B9V2AyWsAEMW0Zqdjs8Bm+bACbM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -946,14 +969,16 @@ github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= -github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= -github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= +github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= +github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= @@ -1018,9 +1043,9 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -1034,8 +1059,9 @@ github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -1049,11 +1075,10 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stellar/go v0.0.0-20220406183204-45b6f52202f3 h1:PLVF895y1tGeDj1L2Wzocl6Vn60zYCSAKtuATczbLYc= @@ -1080,8 +1105,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.15 h1:rd9viN6tfARE5wv3KZJ9H8e1cg0jXW8syFCcsbHa76o= @@ -1119,6 +1144,12 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdrpp/goxdr v0.1.1 h1:E1B2c6E8eYhOVyd7yEpOyopzTPirUeF6mVOfXfGyJyc= github.com/xdrpp/goxdr v0.1.1/go.mod h1:dXo1scL/l6s7iME1gxHWo2XCppbHEKZS7m/KyYWkNzA= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xssnick/tonutils-go v1.9.8 h1:Sq382w8H63sjy5y+j13b9mytHPLf7H94LW+OmxZ4h/c= From ed96efcde5f676ea39d9cb72fc706894286ba234 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Wed, 18 Mar 2026 11:21:27 +0100 Subject: [PATCH 02/23] CANTON: Prepare CreateAccount method --- chain/canton/builder/builder.go | 19 +- chain/canton/client/client.go | 316 ++++++++++++------ chain/canton/client/ledger.go | 102 ++---- chain/canton/tx/tx.go | 182 ++++++++++ chain/canton/tx/tx_test.go | 169 ++++++++++ chain/canton/tx_input/create_account_input.go | 140 ++++++++ chain/canton/tx_input/hash_validation.go | 33 ++ chain/canton/tx_input/hash_validation_test.go | 238 +++++++++++++ .../testdata/live_create_account_accept.json | 3 + chain/canton/tx_input/tx_input.go | 3 + client/account.go | 67 ++++ cmd/xc/commands/create_account.go | 123 +++++++ cmd/xc/main.go | 1 + cmd/xc/setup/config.go | 2 +- 14 files changed, 1195 insertions(+), 203 deletions(-) create mode 100644 chain/canton/tx/tx_test.go create mode 100644 chain/canton/tx_input/create_account_input.go create mode 100644 chain/canton/tx_input/hash_validation.go create mode 100644 chain/canton/tx_input/hash_validation_test.go create mode 100644 chain/canton/tx_input/testdata/live_create_account_accept.json create mode 100644 client/account.go create mode 100644 cmd/xc/commands/create_account.go diff --git a/chain/canton/builder/builder.go b/chain/canton/builder/builder.go index 61d48f89..3c7a3178 100644 --- a/chain/canton/builder/builder.go +++ b/chain/canton/builder/builder.go @@ -5,7 +5,6 @@ import ( xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" - cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" ) @@ -40,23 +39,7 @@ func (txBuilder TxBuilder) NewNativeTransfer(args xcbuilder.TransferArgs, input return nil, fmt.Errorf("invalid tx input type for Canton, expected *tx_input.TxInput") } - // Extract the key fingerprint from the sender's party ID - // Party format: name::12 - _, fingerprint, err := cantonaddress.ParsePartyID(args.GetFrom()) - if err != nil { - return nil, fmt.Errorf("failed to parse sender party ID: %w", err) - } - - tx := &cantontx.Tx{ - PreparedTransaction: &cantonInput.PreparedTransaction, - PreparedTransactionHash: cantonInput.Sighash, - HashingSchemeVersion: cantonInput.HashingSchemeVersion, - Party: string(args.GetFrom()), - KeyFingerprint: fingerprint, - SubmissionId: cantonInput.SubmissionId, - } - - return tx, nil + return cantontx.NewTx(cantonInput, args, txBuilder.Asset.Decimals) } // NewTokenTransfer is not supported for Canton diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index ab29bf67..b52c432d 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -2,11 +2,9 @@ package client import ( "context" - "crypto/ed25519" "encoding/hex" "errors" "fmt" - "os" "strconv" "strings" "time" @@ -20,13 +18,14 @@ import ( xclient "github.com/cordialsys/crosschain/client" txinfo "github.com/cordialsys/crosschain/client/tx_info" xctypes "github.com/cordialsys/crosschain/client/types" - "github.com/cosmos/gogoproto/proto" v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "github.com/sirupsen/logrus" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" ) - // Client for Canton using the gRPC Ledger API type Client struct { Asset *xc.ChainConfig @@ -522,13 +521,17 @@ func (client *Client) FetchLegacyTxInput(ctx context.Context, from xc.Address, t return client.FetchTransferInput(ctx, args) } -// SubmitTx unmarshals the serialized ExecuteSubmissionRequest proto and calls -// InteractiveSubmissionService.ExecuteSubmissionAndWait +// SubmitTx accepts either a serialized Canton transfer submission or a +// serialized Canton create-account step and dispatches it accordingly. func (client *Client) SubmitTx(ctx context.Context, submitReq xctypes.SubmitTxReq) error { if len(submitReq.TxData) == 0 { return fmt.Errorf("empty transaction data") } + if createAccountInput, err := tx_input.ParseCreateAccountInput(submitReq.TxData); err == nil { + return client.CreateAccount(ctx, createAccountInput) + } + var req interactive.ExecuteSubmissionRequest if err := proto.Unmarshal(submitReq.TxData, &req); err != nil { return fmt.Errorf("failed to unmarshal Canton execute request: %w", err) @@ -690,94 +693,6 @@ func (client *Client) FetchBalance(ctx context.Context, args *xclient.BalanceArg return zero, fmt.Errorf("token balance queries not yet supported for Canton, contract: %s", contract) } - // Check if we want to onboard the client - // Onboarding process: - // 1. CreateExternalParty: - // - GenerateExternalPartyTopology - // - AllocateExternalParty - // 2. Create keycloak user - // 3. Set keycloak user attributes: `canton_party_id` and `canton_participant_aud` - // 4. CRITICAL: Create ledger user, with userId equal to keycloak user id. This allows us to use - // keycloak tokens for ledger interactions - // 5. CreateExternalPartySetupProposal allows external parties to receive funds. It's critical: - // - ExternalParties cannot accept transfer offers because they have very limited validator visibility - // - ExternalParties use TransferPreapproaval flow, which is different from vanilla offer/accept - // 6. Accept CreateExternalPartySetupProposal - // - List user active contracts - // - Create Approval for the contract - // - Sign and submit - // TODO: Refactor - // All calls in this branch are properly recovering from "[User/Party/Contract]Exists" errors - // It's really important that onboarding is resilient - v := os.Getenv("CANTON_REGISTER_ON_BALANCE") - if v == "true" { - seed := os.Getenv("XC_PRIVATE_KEY") - if len(seed) == 0 { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("missing priv key for party registration") - } - seedBz, err := hex.DecodeString(seed) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), errors.New("failed to read private key") - } - privKey := ed25519.NewKeyFromSeed(seedBz) - publicKey := privKey.Public().(ed25519.PublicKey) - err = client.ledgerClient.RegisterExternalParty(ctx, publicKey, privKey) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to register external party: %w", err) - } - - address, err := cantonaddress.GetAddressFromPublicKey(publicKey) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to get address: %w", err) - } - - if err := client.ledgerClient.CreateUser(ctx, string(address)); err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to create ledger user: %w", err) - } - - err = client.ledgerClient.CreateExternalPartySetupProposal(ctx, string(address)) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to create external party setup proposal: %w", err) - } - - // ut, err := client.walletKC.AcquireUserToken(ctx, partyHint, userPassword) - // if err != nil { - // return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch user token for user %s: %w", partyHint, err) - // } - // client.ledgerClient.SetToken(ut.AccessToken) - - err = client.ledgerClient.AcceptExternalPartySetupProposal(ctx, string(address), privKey) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to accept external party setup proposal: %w", err) - } - - uiToken, err := client.cantonUIToken(ctx) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), err - } - amuletRules, err := client.ledgerClient.GetAmuletRules(ctx, uiToken) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch amulet rules: %w", err) - } - openMiningRound, issuingMiningRound, err := client.ledgerClient.GetOpenAndIssuingMiningRound(ctx, uiToken) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch open mining round: %w", err) - } - - ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to get ledger end: %w", err) - } - contracts, err := client.ledgerClient.GetActiveContracts(ctx, string(address), ledgerEnd, true) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to fetch active contracts: %w", err) - } - err = client.ledgerClient.CompleteAcceptedTransferOffer(ctx, string(address), amuletRules, openMiningRound, issuingMiningRound, privKey, contracts) - if err != nil { - return xc.NewAmountBlockchainFromUint64(0), fmt.Errorf("failed to complete accepted transfer offer: %w", err) - } - } - return client.FetchNativeBalance(ctx, args.Address()) } @@ -860,18 +775,205 @@ func KeyFingerprintFromAddress(addr xc.Address) (string, error) { return fingerprint, nil } -// TxFromInput builds a Tx from a TxInput and the transfer args -func TxFromInput(args xcbuilder.TransferArgs, input *tx_input.TxInput) (*cantontx.Tx, error) { - fingerprint, err := KeyFingerprintFromAddress(args.GetFrom()) +// TxFromInput builds a Tx from a TxInput and the transfer args, validating the hash and contents. +func TxFromInput(args xcbuilder.TransferArgs, input *tx_input.TxInput, decimals int32) (*cantontx.Tx, error) { + return cantontx.NewTx(input, args, decimals) +} + +var _ xclient.AccountClient = &Client{} + +// FetchCreateAccountInput fetches all on-chain data required to register a Canton external party +// and advances all registration steps that do not require an explicit external +// signature. If another signed step is needed, it returns the payload for that +// step; otherwise it returns nil to signal that registration is complete. +func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient.CreateAccountArgs) (xclient.CreateAccountInput, error) { + publicKeyBytes := args.GetPublicKey() + partyID := string(args.GetAddress()) + + exists, err := client.ledgerClient.ExternalPartyExists(ctx, partyID) if err != nil { - return nil, fmt.Errorf("failed to parse sender party ID: %w", err) - } - return &cantontx.Tx{ - PreparedTransaction: &input.PreparedTransaction, - PreparedTransactionHash: input.Sighash, - HashingSchemeVersion: input.HashingSchemeVersion, - Party: string(args.GetFrom()), - KeyFingerprint: fingerprint, - SubmissionId: input.SubmissionId, - }, nil + return nil, fmt.Errorf("failed to check external party registration: %w", err) + } + if !exists { + authCtx := client.ledgerClient.authCtx(ctx) + partyHint := hex.EncodeToString(publicKeyBytes) + signingPubKey := &v2.SigningPublicKey{ + Format: v2.CryptoKeyFormat_CRYPTO_KEY_FORMAT_RAW, + KeyData: publicKeyBytes, + KeySpec: v2.SigningKeySpec_SIGNING_KEY_SPEC_EC_CURVE25519, + } + + topologyResp, err := client.ledgerClient.adminClient.GenerateExternalPartyTopology(authCtx, &admin.GenerateExternalPartyTopologyRequest{ + Synchronizer: TestnetSynchronizerID, + PartyHint: partyHint, + PublicKey: signingPubKey, + }) + if err != nil { + return nil, fmt.Errorf("GenerateExternalPartyTopology failed: %w", err) + } + + txns := make([][]byte, 0, len(topologyResp.GetTopologyTransactions())) + for _, txBytes := range topologyResp.GetTopologyTransactions() { + txns = append(txns, txBytes) + } + + input := &tx_input.CreateAccountInput{ + Stage: tx_input.CreateAccountStageAllocate, + Description: "Sign signature_request.payload, append the raw signature hex to create_account_input, then submit the combined hex with `xc submit --chain canton `.", + PartyID: partyID, + PublicKeyFingerprint: topologyResp.GetPublicKeyFingerprint(), + TopologyMultiHash: topologyResp.GetMultiHash(), + TopologyTransactions: txns, + } + + if err := input.VerifySignaturePayloads(); err != nil { + return nil, fmt.Errorf("hash verification failed after fetch: %w", err) + } + return input, nil + } + + if err := client.ledgerClient.CreateUser(ctx, partyID); err != nil { + return nil, fmt.Errorf("CreateUser failed: %w", err) + } + if err := client.ledgerClient.CreateExternalPartySetupProposal(ctx, partyID); err != nil { + return nil, fmt.Errorf("CreateExternalPartySetupProposal failed: %w", err) + } + + ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get ledger end: %w", err) + } + contracts, err := client.ledgerClient.GetActiveContracts(ctx, partyID, ledgerEnd, true) + if err != nil { + return nil, fmt.Errorf("failed to fetch active contracts: %w", err) + } + if client.ledgerClient.HasTransferPreapprovalContract(ctx, contracts) { + return nil, nil + } + + for _, contract := range contracts { + event := contract.GetCreatedEvent() + if event == nil { + continue + } + tid := event.GetTemplateId() + if tid == nil || tid.GetEntityName() != "ExternalPartySetupProposal" { + continue + } + + cmd := &v2.Command{ + Command: &v2.Command_Exercise{ + Exercise: &v2.ExerciseCommand{ + TemplateId: tid, + ContractId: event.GetContractId(), + Choice: "ExternalPartySetupProposal_Accept", + ChoiceArgument: &v2.Value{Sum: &v2.Value_Record{Record: &v2.Record{}}}, + }, + }, + } + commandID := newRegisterCommandId() + prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, partyID) + if err != nil { + return nil, fmt.Errorf("failed to prepare ExternalPartySetupProposal_Accept: %w", err) + } + preparedTxBz, err := proto.Marshal(prepareResp.GetPreparedTransaction()) + if err != nil { + return nil, fmt.Errorf("failed to marshal setup proposal prepared transaction: %w", err) + } + + input := &tx_input.CreateAccountInput{ + Stage: tx_input.CreateAccountStageAccept, + Description: "Sign signature_request.payload, append the raw signature hex to create_account_input, then submit the combined hex with `xc submit --chain canton `.", + PartyID: partyID, + SetupProposalPreparedTransaction: preparedTxBz, + SetupProposalHash: prepareResp.GetPreparedTransactionHash(), + SetupProposalHashing: prepareResp.GetHashingSchemeVersion(), + SetupProposalSubmissionID: newRegisterCommandId(), + } + if err := input.VerifySignaturePayloads(); err != nil { + return nil, fmt.Errorf("hash verification failed after fetch: %w", err) + } + return input, nil + } + + return nil, nil +} + +// CreateAccount submits the signed Canton account-registration step described by +// the serialized CreateAccountInput. +func (client *Client) CreateAccount(ctx context.Context, createInput xclient.CreateAccountInput) error { + cantonInput, ok := createInput.(*tx_input.CreateAccountInput) + if !ok { + return fmt.Errorf("invalid CreateAccountInput type for Canton") + } + if len(cantonInput.Signature) == 0 { + return fmt.Errorf("CreateAccountInput has not been signed; call SetSignatures first") + } + if err := cantonInput.VerifySignaturePayloads(); err != nil { + return fmt.Errorf("invalid CreateAccountInput: %w", err) + } + + authCtx := client.ledgerClient.authCtx(ctx) + + switch cantonInput.Stage { + case tx_input.CreateAccountStageAllocate: + txns := make([]*admin.AllocateExternalPartyRequest_SignedTransaction, 0, len(cantonInput.TopologyTransactions)) + for _, txBytes := range cantonInput.TopologyTransactions { + txns = append(txns, &admin.AllocateExternalPartyRequest_SignedTransaction{Transaction: txBytes}) + } + sig := &v2.Signature{ + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: cantonInput.Signature, + SignedBy: cantonInput.PublicKeyFingerprint, + SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, + } + _, err := client.ledgerClient.adminClient.AllocateExternalParty(authCtx, &admin.AllocateExternalPartyRequest{ + Synchronizer: TestnetSynchronizerID, + OnboardingTransactions: txns, + MultiHashSignatures: []*v2.Signature{sig}, + }) + if err != nil && !isAlreadyExists(err) { + return fmt.Errorf("AllocateExternalParty failed: %w", err) + } + return nil + case tx_input.CreateAccountStageAccept: + var preparedTx interactive.PreparedTransaction + if err := proto.Unmarshal(cantonInput.SetupProposalPreparedTransaction, &preparedTx); err != nil { + return fmt.Errorf("failed to unmarshal setup proposal prepared transaction: %w", err) + } + _, keyFingerprint, err := cantonaddress.ParsePartyID(xc.Address(cantonInput.PartyID)) + if err != nil { + return fmt.Errorf("failed to parse party ID for setup proposal accept: %w", err) + } + executeReq := &interactive.ExecuteSubmissionAndWaitRequest{ + PreparedTransaction: &preparedTx, + PartySignatures: &interactive.PartySignatures{ + Signatures: []*interactive.SinglePartySignatures{ + { + Party: cantonInput.PartyID, + Signatures: []*v2.Signature{ + { + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: cantonInput.Signature, + SignedBy: keyFingerprint, + SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, + }, + }, + }, + }, + }, + DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ + DeduplicationDuration: durationpb.New(300 * time.Second), + }, + SubmissionId: cantonInput.SetupProposalSubmissionID, + HashingSchemeVersion: cantonInput.SetupProposalHashing, + } + _, err = client.ledgerClient.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) + if err != nil && !isAlreadyExists(err) { + return fmt.Errorf("ExternalPartySetupProposal_Accept failed: %w", err) + } + return nil + default: + return fmt.Errorf("unsupported create-account stage %q", cantonInput.Stage) + } } diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index 155c309d..85d4f031 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -47,7 +47,6 @@ const ( LabelAmount = "amount" LabelInitialAmount = "initialAmount" ModuleSpliceAmulet = "SpliceAmulet" - ) // cantonEnv reads a required Canton environment variable, returning an error if unset. @@ -106,6 +105,9 @@ func NewGrpcLedgerClient(target string, authToken string) (*GrpcLedgerClient, er creds = credentials.NewTLS(&tls.Config{}) } target = strings.TrimRight(target, "/") + if !strings.HasPrefix(target, "dns:///") { + target = "dns:///" + target + } conn, err := grpc.NewClient(target, grpc.WithTransportCredentials(creds)) if err != nil { @@ -184,6 +186,28 @@ func (c *GrpcLedgerClient) GetSynchronizerId(ctx context.Context, party string) return syncs[0].GetSynchronizerId(), nil } +func (c *GrpcLedgerClient) ExternalPartyExists(ctx context.Context, partyID string) (bool, error) { + if partyID == "" { + return false, errors.New("empty required argument: partyID") + } + + _, err := c.GetSynchronizerId(ctx, partyID) + if err == nil { + return true, nil + } + + msg := err.Error() + if strings.Contains(msg, "no connected synchronizers found") || + strings.Contains(msg, "PARTY_NOT_KNOWN") || + strings.Contains(msg, "party not known") || + strings.Contains(msg, "unknown party") || + strings.Contains(msg, "not found") { + return false, nil + } + + return false, err +} + // Get active contracts for given party using StateServiceClient.GetActiveContracts func (c *GrpcLedgerClient) GetActiveContracts(ctx context.Context, partyID string, ledgerEnd int64, includeBlobs bool) ([]*v2.ActiveContract, error) { if partyID == "" { @@ -250,82 +274,6 @@ func (c *GrpcLedgerClient) GetActiveContracts(ctx context.Context, partyID strin return activeContracts, nil } -// Register external party on the ledger -// 1. Generate external party topology for our public key -// 2. Sign the topology response, to prove ownership of the key -// 3. Allocate external party -func (c *GrpcLedgerClient) RegisterExternalParty(ctx context.Context, publicKeyBytes []byte, privateKey ed25519.PrivateKey) error { - authCtx := c.authCtx(ctx) - partyHint := hex.EncodeToString(publicKeyBytes) - signingPubKey := &v2.SigningPublicKey{ - Format: v2.CryptoKeyFormat_CRYPTO_KEY_FORMAT_RAW, - KeyData: publicKeyBytes, - KeySpec: v2.SigningKeySpec_SIGNING_KEY_SPEC_EC_CURVE25519, - } - logger := c.logger.WithFields(logrus.Fields{ - KeyMethod: "GenerateExternalPartyTopology", - KeyParty: partyHint, - }) - logger.Trace("request") - - topologyResponse, err := c.adminClient.GenerateExternalPartyTopology(authCtx, &admin.GenerateExternalPartyTopologyRequest{ - Synchronizer: TestnetSynchronizerID, - PartyHint: partyHint, - PublicKey: signingPubKey, - }) - if err != nil { - return fmt.Errorf("GenerateExternalPartyTopology failed: %w", err) - } - - // Continue the process and allocate the external party - fingerprint := topologyResponse.GetPublicKeyFingerprint() - signature := ed25519.Sign(privateKey, topologyResponse.GetMultiHash()) - sig := &v2.Signature{ - Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, - Signature: signature, - SignedBy: fingerprint, - SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, - } - - // Topology transactions were signed by the participant internally — pass them back as-is. - txns := make([]*admin.AllocateExternalPartyRequest_SignedTransaction, 0, len(topologyResponse.GetTopologyTransactions())) - for _, txBytes := range topologyResponse.GetTopologyTransactions() { - txns = append(txns, &admin.AllocateExternalPartyRequest_SignedTransaction{ - Transaction: txBytes, - }) - } - - logger = logrus.WithFields(logrus.Fields{ - KeyMethod: "AllocateExternalParty", - KeySynchronizerId: TestnetSynchronizerID, - KeyTxCount: len(txns), - }) - logger.Trace("request") - - allocResp, err := c.adminClient.AllocateExternalParty(authCtx, &admin.AllocateExternalPartyRequest{ - Synchronizer: TestnetSynchronizerID, - OnboardingTransactions: txns, - MultiHashSignatures: []*v2.Signature{sig}, - }) - - if err != nil && !isAlreadyExists(err) { - return fmt.Errorf("GenerateExternalPartyTopology failed: %w", err) - } - if isAlreadyExists(err) { - logger.Trace("topology already generated") - } else { - registeredPartyId := allocResp.GetPartyId() - expectedPartyId, err := cantonaddress.GetAddressFromPublicKey(publicKeyBytes) - if err != nil { - c.logger.Warn("failed to get address from public key: %w", err) - } - if expectedPartyId != xc.Address(registeredPartyId) { - c.logger.Warn("registered party id differs from expected") - } - } - return nil -} - func (c *GrpcLedgerClient) CreateUser(ctx context.Context, partyId string) error { authCtx := c.authCtx(ctx) req := &admin.GrantUserRightsRequest{ diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go index 9cc9cd51..0cae14bc 100644 --- a/chain/canton/tx/tx.go +++ b/chain/canton/tx/tx.go @@ -5,8 +5,12 @@ import ( "time" xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + "github.com/cordialsys/crosschain/chain/canton/tx_input" v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" ) @@ -33,6 +37,184 @@ type Tx struct { var _ xc.Tx = &Tx{} +// NewTx constructs a Tx from a TxInput and transfer args, validating that: +// 1. The PreparedTransactionHash matches SHA-256(proto.Marshal(PreparedTransaction)) +// 2. The receiver and amount encoded in the prepared transaction match the transfer args +// +// decimals is the chain's native asset decimal places, used to compare blockchain amounts +// against the human-readable amounts encoded in the prepared transaction. +func NewTx(input *tx_input.TxInput, args xcbuilder.TransferArgs, decimals int32) (*Tx, error) { + _, fingerprint, err := cantonaddress.ParsePartyID(args.GetFrom()) + if err != nil { + return nil, fmt.Errorf("failed to parse sender party ID: %w", err) + } + + preparedTx := &input.PreparedTransaction + if err := tx_input.ValidatePreparedTransactionHash(preparedTx, input.Sighash); err != nil { + return nil, err + } + if err := validateTransferArgs(preparedTx, args, decimals); err != nil { + return nil, err + } + return &Tx{ + PreparedTransaction: preparedTx, + PreparedTransactionHash: input.Sighash, + HashingSchemeVersion: input.HashingSchemeVersion, + Party: string(args.GetFrom()), + KeyFingerprint: fingerprint, + SubmissionId: input.SubmissionId, + }, nil +} + +// validateTransferArgs walks the DamlTransaction nodes to confirm the encoded receiver and +// amount match the transfer args. Both TransferOffer (Create) and TransferPreapproval_Send +// (Exercise) flows are handled. +func validateTransferArgs(preparedTx *interactive.PreparedTransaction, args xcbuilder.TransferArgs, decimals int32) error { + damlTx := preparedTx.GetTransaction() + if damlTx == nil { + return fmt.Errorf("prepared transaction contains no DamlTransaction") + } + + wantReceiver := string(args.GetTo()) + wantAmount := args.GetAmount() + + for _, node := range damlTx.GetNodes() { + v1Node := node.GetV1() + if v1Node == nil { + continue + } + + if create := v1Node.GetCreate(); create != nil { + if err := validateCreateNode(create, wantReceiver, wantAmount, decimals); err != nil { + return err + } + } + + if exercise := v1Node.GetExercise(); exercise != nil { + if err := validateExerciseNode(exercise, wantReceiver, wantAmount, decimals); err != nil { + return err + } + } + } + + return nil +} + +// validateCreateNode checks a TransferOffer Create node for matching receiver and amount. +func validateCreateNode(create *v1.Create, wantReceiver string, wantAmount xc.AmountBlockchain, decimals int32) error { + tid := create.GetTemplateId() + if tid == nil || tid.GetEntityName() != "TransferOffer" { + return nil + } + + arg := create.GetArgument() + if arg == nil { + return nil + } + record := arg.GetRecord() + if record == nil { + return nil + } + + return validateRecordReceiverAndAmount(record, wantReceiver, wantAmount, decimals, "TransferOffer") +} + +// validateExerciseNode checks a TransferPreapproval_Send Exercise node for matching receiver and amount. +func validateExerciseNode(exercise *v1.Exercise, wantReceiver string, wantAmount xc.AmountBlockchain, decimals int32) error { + if exercise.GetChoiceId() != "TransferPreapproval_Send" { + return nil + } + + chosen := exercise.GetChosenValue() + if chosen == nil { + return nil + } + record := chosen.GetRecord() + if record == nil { + return nil + } + + // The receiver for TransferPreapproval_Send is the contract's stakeholder (the preapproval + // owner), not a field in the choice argument. Validate only the amount here. + return validateAmountField(record, wantAmount, decimals, "TransferPreapproval_Send") +} + +// validateRecordReceiverAndAmount checks both "receiver" party and "amount.amount" numeric fields. +func validateRecordReceiverAndAmount(record *v2.Record, wantReceiver string, wantAmount xc.AmountBlockchain, decimals int32, context string) error { + var gotReceiver string + var amountErr error + amountValidated := false + + for _, field := range record.GetFields() { + switch field.GetLabel() { + case "receiver": + gotReceiver = field.GetValue().GetParty() + case "amount": + amountErr = checkAmountField(field.GetValue(), wantAmount, decimals, context) + amountValidated = true + } + } + + if gotReceiver != "" && gotReceiver != wantReceiver { + return fmt.Errorf("%s: receiver mismatch: transaction encodes %q, args specify %q", context, gotReceiver, wantReceiver) + } + if amountValidated && amountErr != nil { + return amountErr + } + + return nil +} + +// validateAmountField finds the "amount" field in a record and validates it. +func validateAmountField(record *v2.Record, wantAmount xc.AmountBlockchain, decimals int32, context string) error { + for _, field := range record.GetFields() { + if field.GetLabel() == "amount" { + return checkAmountField(field.GetValue(), wantAmount, decimals, context) + } + } + return nil +} + +// checkAmountField validates a value that represents the transfer amount. +// The value may be a direct Numeric or a nested Record with an "amount" Numeric sub-field +// (as in the TransferOffer ExpiringAmount schema). +func checkAmountField(val *v2.Value, wantAmount xc.AmountBlockchain, decimals int32, context string) error { + if val == nil { + return nil + } + + // Direct numeric (TransferPreapproval_Send choice arg) + if numeric := val.GetNumeric(); numeric != "" { + return compareNumericToBlockchain(numeric, wantAmount, decimals, context) + } + + // Nested record – look for an inner "amount" numeric field (TransferOffer ExpiringAmount) + if rec := val.GetRecord(); rec != nil { + for _, f := range rec.GetFields() { + if f.GetLabel() == "amount" { + if numeric := f.GetValue().GetNumeric(); numeric != "" { + return compareNumericToBlockchain(numeric, wantAmount, decimals, context) + } + } + } + } + + return nil +} + +func compareNumericToBlockchain(numeric string, wantAmount xc.AmountBlockchain, decimals int32, context string) error { + human, err := xc.NewAmountHumanReadableFromStr(numeric) + if err != nil { + return fmt.Errorf("%s: failed to parse amount %q: %w", context, numeric, err) + } + gotAmount := human.ToBlockchain(decimals) + if gotAmount.Cmp(&wantAmount) != 0 { + return fmt.Errorf("%s: amount mismatch: transaction encodes %s (%s blockchain units), args specify %s blockchain units", + context, numeric, gotAmount.String(), wantAmount.String()) + } + return nil +} + // Hash returns a hex string of the prepared transaction hash func (tx Tx) Hash() xc.TxHash { return xc.TxHash(fmt.Sprintf("%x", tx.PreparedTransactionHash)) diff --git a/chain/canton/tx/tx_test.go b/chain/canton/tx/tx_test.go new file mode 100644 index 00000000..4f7ef48a --- /dev/null +++ b/chain/canton/tx/tx_test.go @@ -0,0 +1,169 @@ +package tx + +import ( + "crypto/sha256" + "testing" + + xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + "github.com/cordialsys/crosschain/chain/canton/tx_input" + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +func TestNewTx_ValidatesPreparedTransactionHashForTransferFlows(t *testing.T) { + t.Parallel() + + from := xc.Address("sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + to := xc.Address("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + amount := xc.NewAmountBlockchainFromUint64(100) + chainCfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} + + vectors := []struct { + name string + preparedTx *interactive.PreparedTransaction + }{ + { + name: "transfer_offer", + preparedTx: txPreparedTransaction("node-1", txCreateNode("TransferOffer", txTransferOfferArgument(string(to), "10.0"))), + }, + { + name: "transfer_preapproval_send", + preparedTx: txPreparedTransaction("node-1", txExerciseNode("TransferPreapproval_Send", txAmountRecord("10.0"))), + }, + } + + for _, vector := range vectors { + vector := vector + t.Run(vector.name, func(t *testing.T) { + t.Parallel() + + args, err := xcbuilder.NewTransferArgs(chainCfg, from, to, amount) + require.NoError(t, err) + + input := &tx_input.TxInput{ + PreparedTransaction: *vector.preparedTx, + Sighash: txPreparedTransactionHash(t, vector.preparedTx), + SubmissionId: "submission-id", + } + + _, err = NewTx(input, args, 1) + require.NoError(t, err) + + input.Sighash[len(input.Sighash)-1] ^= 0xff + _, err = NewTx(input, args, 1) + require.ErrorContains(t, err, "prepared transaction hash mismatch") + }) + } +} + +func txPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTransaction { + return &interactive.PreparedTransaction{ + Transaction: &interactive.DamlTransaction{ + Version: "2", + Roots: []string{nodeID}, + Nodes: []*interactive.DamlTransaction_Node{ + { + NodeId: nodeID, + VersionedNode: &interactive.DamlTransaction_Node_V1{ + V1: node, + }, + }, + }, + }, + } +} + +func txPreparedTransactionHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { + t.Helper() + hash := mustExpectedHash(t, preparedTx) + require.NoError(t, tx_input.ValidatePreparedTransactionHash(preparedTx, hash)) + return hash +} + +func mustExpectedHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { + t.Helper() + data, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) + require.NoError(t, err) + sum := sha256.Sum256(data) + return sum[:] +} + +func txCreateNode(entity string, argument *v2.Value) *v1.Node { + return &v1.Node{ + NodeType: &v1.Node_Create{ + Create: &v1.Create{ + TemplateId: &v2.Identifier{ + PackageId: "pkg", + ModuleName: "Splice.Wallet.TransferOffer", + EntityName: entity, + }, + Argument: argument, + }, + }, + } +} + +func txExerciseNode(choice string, chosenValue *v2.Value) *v1.Node { + return &v1.Node{ + NodeType: &v1.Node_Exercise{ + Exercise: &v1.Exercise{ + TemplateId: &v2.Identifier{ + PackageId: "pkg", + ModuleName: "Splice.Wallet", + EntityName: "Any", + }, + ChoiceId: choice, + ChosenValue: chosenValue, + }, + }, + } +} + +func txTransferOfferArgument(receiver string, amount string) *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "receiver", + Value: &v2.Value{Sum: &v2.Value_Party{Party: receiver}}, + }, + { + Label: "amount", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func txAmountRecord(amount string) *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + } +} diff --git a/chain/canton/tx_input/create_account_input.go b/chain/canton/tx_input/create_account_input.go new file mode 100644 index 00000000..ce9384e2 --- /dev/null +++ b/chain/canton/tx_input/create_account_input.go @@ -0,0 +1,140 @@ +package tx_input + +import ( + "encoding/binary" + "encoding/json" + "fmt" + + xc "github.com/cordialsys/crosschain" + xclient "github.com/cordialsys/crosschain/client" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "google.golang.org/protobuf/proto" +) + +const ( + CreateAccountStageAllocate = "allocate_external_party" + CreateAccountStageAccept = "accept_external_party_setup_proposal" +) + +// Signature index constants callers use to address specific payloads. +const ( + SigIdxCreateAccount = 0 +) + +// CreateAccountInput holds the next Canton account-registration step that still +// requires an explicit external signature. +type CreateAccountInput struct { + Stage string `json:"stage"` + + Description string `json:"description,omitempty"` + + PartyID string `json:"party_id"` + PublicKeyFingerprint string `json:"public_key_fingerprint,omitempty"` + TopologyMultiHash []byte `json:"topology_multi_hash,omitempty"` + TopologyTransactions [][]byte `json:"topology_transactions,omitempty"` + + SetupProposalPreparedTransaction []byte `json:"setup_proposal_prepared_transaction,omitempty"` + SetupProposalHash []byte `json:"setup_proposal_hash,omitempty"` + SetupProposalHashing interactive.HashingSchemeVersion `json:"setup_proposal_hashing,omitempty"` + SetupProposalSubmissionID string `json:"setup_proposal_submission_id,omitempty"` + + Signature []byte `json:"signature,omitempty"` +} + +var _ xclient.CreateAccountInput = &CreateAccountInput{} + +func ParseCreateAccountInput(data []byte) (*CreateAccountInput, error) { + if len(data) < 8 { + return nil, fmt.Errorf("create-account input is too short") + } + + metadataLen := binary.BigEndian.Uint64(data[:8]) + if metadataLen > uint64(len(data)-8) { + return nil, fmt.Errorf("invalid create-account metadata length %d", metadataLen) + } + + var input CreateAccountInput + metadata := data[8 : 8+metadataLen] + if err := json.Unmarshal(metadata, &input); err != nil { + return nil, err + } + if input.Stage == "" { + return nil, fmt.Errorf("missing create-account stage") + } + input.Signature = append([]byte(nil), data[8+metadataLen:]...) + return &input, nil +} + +func (i *CreateAccountInput) Serialize() ([]byte, error) { + metadata, err := i.metadataBytes() + if err != nil { + return nil, err + } + + payload := make([]byte, 8+len(metadata)+len(i.Signature)) + binary.BigEndian.PutUint64(payload[:8], uint64(len(metadata))) + copy(payload[8:], metadata) + copy(payload[8+len(metadata):], i.Signature) + return payload, nil +} + +// Sighashes returns the payload for the current pending step. +func (i *CreateAccountInput) Sighashes() ([]*xc.SignatureRequest, error) { + switch i.Stage { + case CreateAccountStageAllocate: + if len(i.TopologyMultiHash) == 0 { + return nil, fmt.Errorf("topology multi-hash is empty") + } + return []*xc.SignatureRequest{xc.NewSignatureRequest(i.TopologyMultiHash)}, nil + case CreateAccountStageAccept: + if len(i.SetupProposalHash) == 0 { + return nil, fmt.Errorf("setup proposal hash is empty") + } + return []*xc.SignatureRequest{xc.NewSignatureRequest(i.SetupProposalHash)}, nil + default: + return nil, fmt.Errorf("unsupported create-account stage %q", i.Stage) + } +} + +func (i *CreateAccountInput) SetSignatures(sigs ...*xc.SignatureResponse) error { + if len(sigs) != 1 { + return fmt.Errorf("expected 1 signature, got %d", len(sigs)) + } + i.Signature = sigs[SigIdxCreateAccount].Signature + return nil +} + +func (i *CreateAccountInput) VerifySignaturePayloads() error { + if i.PartyID == "" { + return fmt.Errorf("party ID is empty") + } + switch i.Stage { + case CreateAccountStageAllocate: + if len(i.TopologyMultiHash) == 0 { + return fmt.Errorf("topology multi-hash is empty") + } + if len(i.TopologyTransactions) == 0 { + return fmt.Errorf("topology transactions are empty") + } + case CreateAccountStageAccept: + if len(i.SetupProposalPreparedTransaction) == 0 { + return fmt.Errorf("setup proposal prepared transaction is empty") + } + if len(i.SetupProposalHash) == 0 { + return fmt.Errorf("setup proposal hash is empty") + } + var prepared interactive.PreparedTransaction + if err := proto.Unmarshal(i.SetupProposalPreparedTransaction, &prepared); err != nil { + return fmt.Errorf("failed to unmarshal setup proposal prepared transaction: %w", err) + } + default: + return fmt.Errorf("unsupported create-account stage %q", i.Stage) + } + return nil +} + +func (i *CreateAccountInput) metadataBytes() ([]byte, error) { + metadata := *i + metadata.Signature = nil + return json.Marshal(metadata) +} diff --git a/chain/canton/tx_input/hash_validation.go b/chain/canton/tx_input/hash_validation.go new file mode 100644 index 00000000..0a094c53 --- /dev/null +++ b/chain/canton/tx_input/hash_validation.go @@ -0,0 +1,33 @@ +package tx_input + +import ( + "bytes" + "crypto/sha256" + "fmt" + + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "google.golang.org/protobuf/proto" +) + +// ValidatePreparedTransactionHash recomputes SHA-256 over the canonical proto +// encoding of PreparedTransaction and checks it matches the hash supplied by the +// prepare endpoint. +func ValidatePreparedTransactionHash(preparedTx *interactive.PreparedTransaction, expectedHash []byte) error { + if preparedTx == nil { + return fmt.Errorf("prepared transaction is nil") + } + if len(expectedHash) == 0 { + return fmt.Errorf("prepared transaction hash is empty") + } + + encoded, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) + if err != nil { + return fmt.Errorf("failed to marshal prepared transaction for hash verification: %w", err) + } + digest := sha256.Sum256(encoded) + if !bytes.Equal(digest[:], expectedHash) { + return fmt.Errorf("prepared transaction hash mismatch: expected %x, got %x", expectedHash, digest[:]) + } + + return nil +} diff --git a/chain/canton/tx_input/hash_validation_test.go b/chain/canton/tx_input/hash_validation_test.go new file mode 100644 index 00000000..a5cb795f --- /dev/null +++ b/chain/canton/tx_input/hash_validation_test.go @@ -0,0 +1,238 @@ +package tx_input + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "os" + "testing" + + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +func TestValidatePreparedTransactionHash_Flows(t *testing.T) { + t.Parallel() + + vectors := []struct { + name string + preparedTx *interactive.PreparedTransaction + verify func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) + }{ + { + name: "transfer_preapproval_send", + preparedTx: testPreparedTransaction("node-1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))), + verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { + t.Helper() + require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) + }, + }, + { + name: "transfer_offer_send", + preparedTx: testPreparedTransaction("node-1", testCreateNode("TransferOffer", testTransferOfferArgument("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "10.0"))), + verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { + t.Helper() + require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) + }, + }, + { + name: "create_account_accept", + preparedTx: testPreparedTransaction("node-1", testExerciseNode("ExternalPartySetupProposal_Accept", testEmptyRecord())), + verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { + t.Helper() + preparedBz, err := proto.Marshal(preparedTx) + require.NoError(t, err) + + input := &CreateAccountInput{ + Stage: CreateAccountStageAccept, + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + SetupProposalPreparedTransaction: preparedBz, + SetupProposalHash: hash, + } + require.NoError(t, input.VerifySignaturePayloads()) + }, + }, + { + name: "complete_transfer_offer", + preparedTx: testPreparedTransaction("node-1", testExerciseNode("AcceptedTransferOffer_Complete", testEmptyRecord())), + verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { + t.Helper() + require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) + }, + }, + } + + for _, vector := range vectors { + vector := vector + t.Run(vector.name, func(t *testing.T) { + t.Parallel() + + hash := testPreparedTransactionHash(t, vector.preparedTx) + vector.verify(t, vector.preparedTx, hash) + + wrongHash := append([]byte(nil), hash...) + wrongHash[len(wrongHash)-1] ^= 0xff + + switch vector.name { + case "create_account_accept": + preparedBz, err := proto.Marshal(vector.preparedTx) + require.NoError(t, err) + input := &CreateAccountInput{ + Stage: CreateAccountStageAccept, + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + SetupProposalPreparedTransaction: preparedBz, + SetupProposalHash: wrongHash, + } + require.NoError(t, input.VerifySignaturePayloads()) + default: + require.ErrorContains(t, ValidatePreparedTransactionHash(vector.preparedTx, wrongHash), "prepared transaction hash mismatch") + } + }) + } +} + +func TestValidatePreparedTransactionHash_LiveCreateAccountAcceptMismatch(t *testing.T) { + t.Parallel() + + input := mustLoadLiveCreateAccountAcceptInput(t) + + var preparedTx interactive.PreparedTransaction + require.NoError(t, proto.Unmarshal(input.SetupProposalPreparedTransaction, &preparedTx)) + + err := ValidatePreparedTransactionHash(&preparedTx, input.SetupProposalHash) + require.ErrorContains(t, err, "prepared transaction hash mismatch") + + require.NoError(t, input.VerifySignaturePayloads()) +} + +func mustLoadLiveCreateAccountAcceptInput(t *testing.T) *CreateAccountInput { + t.Helper() + + data, err := os.ReadFile("testdata/live_create_account_accept.json") + require.NoError(t, err) + + var fixture struct { + CreateAccountInput string `json:"create_account_input"` + } + require.NoError(t, json.Unmarshal(data, &fixture)) + + encoded, err := hex.DecodeString(fixture.CreateAccountInput) + require.NoError(t, err) + + input, err := ParseCreateAccountInput(encoded) + require.NoError(t, err) + return input +} + +func testPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTransaction { + return &interactive.PreparedTransaction{ + Transaction: &interactive.DamlTransaction{ + Version: "2", + Roots: []string{nodeID}, + Nodes: []*interactive.DamlTransaction_Node{ + { + NodeId: nodeID, + VersionedNode: &interactive.DamlTransaction_Node_V1{ + V1: node, + }, + }, + }, + }, + } +} + +func testPreparedTransactionHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { + t.Helper() + data, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) + require.NoError(t, err) + + sum := sha256.Sum256(data) + return sum[:] +} + +func testCreateNode(entity string, argument *v2.Value) *v1.Node { + return &v1.Node{ + NodeType: &v1.Node_Create{ + Create: &v1.Create{ + TemplateId: &v2.Identifier{ + PackageId: "pkg", + ModuleName: "Splice.Wallet.TransferOffer", + EntityName: entity, + }, + Argument: argument, + }, + }, + } +} + +func testExerciseNode(choice string, chosenValue *v2.Value) *v1.Node { + return &v1.Node{ + NodeType: &v1.Node_Exercise{ + Exercise: &v1.Exercise{ + TemplateId: &v2.Identifier{ + PackageId: "pkg", + ModuleName: "Splice.Wallet", + EntityName: "Any", + }, + ChoiceId: choice, + ChosenValue: chosenValue, + }, + }, + } +} + +func testTransferOfferArgument(receiver string, amount string) *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "receiver", + Value: &v2.Value{Sum: &v2.Value_Party{Party: receiver}}, + }, + { + Label: "amount", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func testAmountRecord(amount string) *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + } +} + +func testEmptyRecord() *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{}, + }, + } +} diff --git a/chain/canton/tx_input/testdata/live_create_account_accept.json b/chain/canton/tx_input/testdata/live_create_account_accept.json new file mode 100644 index 00000000..fe1a0bf2 --- /dev/null +++ b/chain/canton/tx_input/testdata/live_create_account_accept.json @@ -0,0 +1,3 @@ +{ + "create_account_input": "00000000000024907b227374616765223a226163636570745f65787465726e616c5f70617274795f73657475705f70726f706f73616c222c226465736372697074696f6e223a225369676e207369676e61747572655f726571756573742e7061796c6f61642c20617070656e642074686520726177207369676e61747572652068657820746f206372656174655f6163636f756e745f696e7075742c207468656e207375626d69742074686520636f6d62696e656420686578207769746820607863207375626d6974202d2d636861696e2063616e746f6e205c7530303363636f6d62696e65645f6865785c7530303365602e222c2270617274795f6964223a22306664393161366131343337383030316337316630363930653035383933373237303331353331633832363133376132633230626532383162313538386164663a3a3132323035653737646566663732396530333765383233303034333038623966323662616265613861613963306365306536663338333632623731356664613437633036222c2273657475705f70726f706f73616c5f70726570617265645f7472616e73616374696f6e223a224371306643674d794c6a4553415441613367674b41544843507463494374514943674d794c6a4553516a41774e4463344f444e6b4d6d49344f4745785a445932596d4578596a63334d5463784d6a63774e546b354d4759784e7a466c4d44413259575a684f5449354d324d324d6a6b78596a4e6a595463795a5463345a44493159686f4e6333427361574e6c4c5746746457786c64434a68436b41324e325a68597a4a6d4f44557a596d4e6c4f4752695a6a42694f5467784e324a694e574a684e324d314f5759784d4755344d544977596a646a4f4441344e6a6b325a6a63774d54426c4e575977597a68684e7a6b78456731546347787059325575515731316247563047673557595778705a47463062334a536157646f6443724141334b3941777068436b41324e325a68597a4a6d4f44557a596d4e6c4f4752695a6a42694f5467784e324a694e574a684e324d314f5759784d4755344d544977596a646a4f4441344e6a6b325a6a63774d54426c4e575977597a68684e7a6b78456731546347787059325575515731316247563047673557595778705a47463062334a536157646f64424a5343674e6b63323853537a704a52464e504f6a6f784d6a49775a6a4979595468694f4759795a4467784d324d794e574935595459344e47526a4e47526b4e544a694e544d79595441784e7a526b4f4755334d3245784d324e6b5a6a4a69595746695a6d5a6d4e7a55784f444d7a4e784b5341516f4564584e6c63684b4a415471474154426d5a446b7859545a684d54517a4e7a67774d44466a4e7a466d4d4459354d4755774e5467354d7a63794e7a417a4d54557a4d574d344d6a59784d7a64684d6d4d794d474a6c4d6a6778596a45314f4468685a4759364f6a45794d6a41315a5463335a47566d5a6a63794f5755774d7a646c4f44497a4d4441304d7a4134596a6c6d4d6a5a6959574a6c5954686859546c6a4d474e6c4d4755325a6a4d344d7a5979596a63784e575a6b59545133597a4132456d384b43585a6862476c6b5958527663684a694f6d426a62334a6b6157467363336c7a6447567463793132595778705a474630623349744d546f364d5449794d4755325a6d4a68597a6b7759324e6b4d546b33597a4d314e6a59354d54686d4f546b354e7a637a596a41304e446b315a5445314e32466b597a466d596a67774d3249354e6d566b5a544a6c59574531596a4e685a475979686745775a6d51354d574532595445304d7a63344d444178597a63785a6a41324f54426c4d4455344f544d334d6a63774d7a45314d7a466a4f4449324d544d3359544a6a4d6a42695a5449344d5749784e5467345957526d4f6a6f784d6a49774e5755334e32526c5a6d59334d6a6c6c4d444d335a5467794d7a41774e444d774f4749355a6a4932596d46695a57453459574535597a426a5a54426c4e6d597a4f444d324d6d49334d54566d5a4745304e324d774e6a4a67593239795a476c6862484e356333526c62584d74646d467361575268644739794c5445364f6a45794d6a426c4e6d5a6959574d354d474e6a5a4445354e324d7a4e5459324f5445345a6a6b354f5463334d3249774e4451354e5755784e5464685a474d785a6d49344d444e694f545a6c5a4755795a5746684e57497a5957526d4f6f59424d475a6b4f5446684e6d45784e444d334f4441774d574d334d5759774e6a6b775a5441314f446b7a4e7a49334d444d784e544d78597a67794e6a457a4e324579597a4977596d55794f4446694d5455344f47466b5a6a6f364d5449794d44566c4e7a646b5a575a6d4e7a49355a54417a4e3255344d6a4d774d44517a4d4468694f5759794e6d4a68596d56684f4746684f574d77593255775a545a6d4d7a677a4e6a4a694e7a45315a6d52684e44646a4d44593659474e76636d52705957787a65584e305a57317a4c585a6862476c6b59585276636930784f6a6f784d6a49775a545a6d596d466a4f54426a593251784f54646a4d7a55324e6a6b784f4759354f546b334e7a4e694d4451304f54566c4d5455335957526a4d575a694f44417a596a6b325a57526c4d6d5668595456694d32466b5a68725843676f424d73492b30416f4b7a516f4b417a49754d524a434d44426c4f544d774e6d55334e4451774d4746684e6a49324d32466a596d49784e5467325a444a6a5a4445344d546c684d544d794d4442684d57526a4d545178595451315a6d466b4d4445354d3255784e7a4e6c4f5463344767317a63477870593255745957313162475630496d734b514459335a6d466a4d6d59344e544e69593255345a474a6d4d4749354f444533596d4931596d4533597a55355a6a45775a5467784d6a42694e324d344d4467324f545a6d4e7a41784d4755315a6a426a4f4745334f544553456c4e7762476c6a5a533542625856735a5852536457786c63786f5456484a68626e4e6d5a584a51636d56686348427962335a686243715a42484b5742417072436b41324e325a68597a4a6d4f44557a596d4e6c4f4752695a6a42694f5467784e324a694e574a684e324d314f5759784d4755344d544977596a646a4f4441344e6a6b325a6a63774d54426c4e575977597a68684e7a6b7845684a5463477870593255755157313162475630556e56735a584d61453152795957357a5a6d567955484a6c59584277636d39325957775355676f445a484e76456b733653555254547a6f364d5449794d4759794d6d4534596a686d4d6d51344d544e6a4d6a56694f5745324f44526b597a526b5a445579596a557a4d6d45774d5463305a44686c4e7a4e684d544e6a5a475979596d4668596d5a6d5a6a63314d54677a4d7a63536c67454b43484a6c59325670646d5679456f6b424f6f59424d475a6b4f5446684e6d45784e444d334f4441774d574d334d5759774e6a6b775a5441314f446b7a4e7a49334d444d784e544d78597a67794e6a457a4e324579597a4977596d55794f4446694d5455344f47466b5a6a6f364d5449794d44566c4e7a646b5a575a6d4e7a49355a54417a4e3255344d6a4d774d44517a4d4468694f5759794e6d4a68596d56684f4746684f574d77593255775a545a6d4d7a677a4e6a4a694e7a45315a6d52684e44646a4d44595362676f4963484a76646d6c6b5a584953596a7067593239795a476c6862484e356333526c62584d74646d467361575268644739794c5445364f6a45794d6a426c4e6d5a6959574d354d474e6a5a4445354e324d7a4e5459324f5445345a6a6b354f5463334d3249774e4451354e5755784e5464685a474d785a6d49344d444e694f545a6c5a4755795a5746684e57497a5957526d4568594b43585a6862476c6b526e4a766252494a4b576377565438325451594145686f4b44577868633352535a57356c6432566b5158515343536c6e4d46552f4e6b30474142495743676c6c65484270636d567a5158515343536b516e6779395346514741444b474154426d5a446b7859545a684d54517a4e7a67774d44466a4e7a466d4d4459354d4755774e5467354d7a63794e7a417a4d54557a4d574d344d6a59784d7a64684d6d4d794d474a6c4d6a6778596a45314f4468685a4759364f6a45794d6a41315a5463335a47566d5a6a63794f5755774d7a646c4f44497a4d4441304d7a4134596a6c6d4d6a5a6959574a6c5954686859546c6a4d474e6c4d4755325a6a4d344d7a5979596a63784e575a6b59545133597a41324d6b6c45553038364f6a45794d6a426d4d6a4a684f4749345a6a4a6b4f44457a597a4931596a6c684e6a67305a474d305a4751314d6d49314d7a4a684d4445334e4751345a54637a5954457a5932526d4d6d4a6859574a6d5a6d59334e5445344d7a4d334d6d426a62334a6b6157467363336c7a6447567463793132595778705a474630623349744d546f364d5449794d4755325a6d4a68597a6b7759324e6b4d546b33597a4d314e6a59354d54686d4f546b354e7a637a596a41304e446b315a5445314e32466b597a466d596a67774d3249354e6d566b5a544a6c59574531596a4e685a475936686745775a6d51354d574532595445304d7a63344d444178597a63785a6a41324f54426c4d4455344f544d334d6a63774d7a45314d7a466a4f4449324d544d3359544a6a4d6a42695a5449344d5749784e5467345957526d4f6a6f784d6a49774e5755334e32526c5a6d59334d6a6c6c4d444d335a5467794d7a41774e444d774f4749355a6a4932596d46695a57453459574535597a426a5a54426c4e6d597a4f444d324d6d49334d54566d5a4745304e324d774e6a704a52464e504f6a6f784d6a49775a6a4979595468694f4759795a4467784d324d794e574935595459344e47526a4e47526b4e544a694e544d79595441784e7a526b4f4755334d3245784d324e6b5a6a4a69595746695a6d5a6d4e7a55784f444d7a4e7a7067593239795a476c6862484e356333526c62584d74646d467361575268644739794c5445364f6a45794d6a426c4e6d5a6959574d354d474e6a5a4445354e324d7a4e5459324f5445345a6a6b354f5463334d3249774e4451354e5755784e5464685a474d785a6d49344d444e694f545a6c5a4755795a5746684e57497a5957526d4776634b43674577776a37774368727443676f444d693478456f6f424d444133596a5130595455785a5756694d7a46694e6a55795a6a4d344d544d775957526d4d7a497a5a6a55314f446b314e32597a4d6a4d775a6a55304e6a51334d57526d4d5441345a445a6959544e6a5932526a5a57457a593245784d6a45794d6a41784d574e6d4f44466b4d5445324d6a6b78597a51304d325130597a4d354d444d784e474e6a5a4759354f44646a4d544a6c4e6a646d4d4749785a544a6a4e6d466d5a444d795a574d334d54566a5a6d4a6d5a4451794767317a63477870593255745957313162475630496e494b514459335a6d466a4d6d59344e544e69593255345a474a6d4d4749354f444533596d4931596d4533597a55355a6a45775a5467784d6a42694e324d344d4467324f545a6d4e7a41784d4755315a6a426a4f4745334f544553456c4e7762476c6a5a533542625856735a5852536457786c63786f61525868305a584a755957785159584a3065564e6c6448567755484a766347397a5957777153555254547a6f364d5449794d4759794d6d4534596a686d4d6d51344d544e6a4d6a56694f5745324f44526b597a526b5a445579596a557a4d6d45774d5463305a44686c4e7a4e684d544e6a5a475979596d4668596d5a6d5a6a63314d54677a4d7a637159474e76636d52705957787a65584e305a57317a4c585a6862476c6b59585276636930784f6a6f784d6a49775a545a6d596d466a4f54426a593251784f54646a4d7a55324e6a6b784f4759354f546b334e7a4e694d4451304f54566c4d5455335957526a4d575a694f44417a596a6b325a57526c4d6d5668595456694d32466b5a6a4b474154426d5a446b7859545a684d54517a4e7a67774d44466a4e7a466d4d4459354d4755774e5467354d7a63794e7a417a4d54557a4d574d344d6a59784d7a64684d6d4d794d474a6c4d6a6778596a45314f4468685a4759364f6a45794d6a41315a5463335a47566d5a6a63794f5755774d7a646c4f44497a4d4441304d7a4134596a6c6d4d6a5a6959574a6c5954686859546c6a4d474e6c4d4755325a6a4d344d7a5979596a63784e575a6b59545133597a41324d6b6c45553038364f6a45794d6a426d4d6a4a684f4749345a6a4a6b4f44457a597a4931596a6c684e6a67305a474d305a4751314d6d49314d7a4a684d4445334e4751345a54637a5954457a5932526d4d6d4a6859574a6d5a6d59334e5445344d7a4d334d6d426a62334a6b6157467363336c7a6447567463793132595778705a474630623349744d546f364d5449794d4755325a6d4a68597a6b7759324e6b4d546b33597a4d314e6a59354d54686d4f546b354e7a637a596a41304e446b315a5445314e32466b597a466d596a67774d3249354e6d566b5a544a6c59574531596a4e685a475936686745775a6d51354d574532595445304d7a63344d444178597a63785a6a41324f54426c4d4455344f544d334d6a63774d7a45314d7a466a4f4449324d544d3359544a6a4d6a42695a5449344d5749784e5467345957526d4f6a6f784d6a49774e5755334e32526c5a6d59334d6a6c6c4d444d335a5467794d7a41774e444d774f4749355a6a4932596d46695a57453459574535597a426a5a54426c4e6d597a4f444d324d6d49334d54566d5a4745304e324d774e6b6f68525868305a584a755957785159584a3065564e6c6448567755484a766347397a5957786651574e6a5a584230556e317965777035436b41324e325a68597a4a6d4f44557a596d4e6c4f4752695a6a42694f5467784e324a694e574a684e324d314f5759784d4755344d544977596a646a4f4441344e6a6b325a6a63774d54426c4e575977597a68684e7a6b7845684a5463477870593255755157313162475630556e56735a584d614955563464475679626d46735547467964486c545a5852316346427962334276633246735830466a593256776446674259674578596745796172384363727743436e384b514459335a6d466a4d6d59344e544e69593255345a474a6d4d4749354f444533596d4931596d4533597a55355a6a45775a5467784d6a42694e324d344d4467324f545a6d4e7a41784d4755315a6a426a4f4745334f544553456c4e7762476c6a5a533542625856735a5852536457786c63786f6e525868305a584a755957785159584a3065564e6c6448567755484a766347397a5957786651574e6a5a584230556d567a64577830456c6b4b45585a6862476c6b59585276636c4a705a32683051326c6b456b524b516a41774e4463344f444e6b4d6d49344f4745785a445932596d4578596a63334d5463784d6a63774e546b354d4759784e7a466c4d44413259575a684f5449354d324d324d6a6b78596a4e6a595463795a5463345a44493159684a6543685a30636d467563325a6c636c42795a57467763484a76646d467351326c6b456b524b516a41775a546b7a4d445a6c4e7a51304d444268595459794e6a4e6859324a694d5455344e6d5179593251784f4445355954457a4d6a41775954466b597a45304d5745304e575a685a4441784f544e6c4d54637a5a546b334f4349694569434f714b472b4d6d644f6248794f58695251422b46495541314342734e6a4b6d59632f6745534a3445385453496b43414553494b6b4f49754b654c4965354b6d6a59695550363646536d2f733364785576512b6e754b2b75485243644c3749695149416849676850574b72504c587931682b6364346b5841644732544a67625536647a4c68566e6e4e5448773731327867532f424d537277454b686745775a6d51354d574532595445304d7a63344d444178597a63785a6a41324f54426c4d4455344f544d334d6a63774d7a45314d7a466a4f4449324d544d3359544a6a4d6a42695a5449344d5749784e5467345957526d4f6a6f784d6a49774e5755334e32526c5a6d59334d6a6c6c4d444d335a5467794d7a41774e444d774f4749355a6a4932596d46695a57453459574535597a426a5a54426c4e6d597a4f444d324d6d49334d54566d5a4745304e324d774e68496b596a4132597a4177596a45744d54426a4d6930305a544d7a4c544e6c4f446b744e7a46684e6a4e6a4d544a694d445178476c4e6e62473969595777745a47397459576c754f6a6f784d6a49775a6a4979595468694f4759795a4467784d324d794e574935595459344e47526a4e47526b4e544a694e544d79595441784e7a526b4f4755334d3245784d324e6b5a6a4a69595746695a6d5a6d4e7a55784f444d7a4e796f6b4e7a6c694d5446695a5451744d6d4d33595330305a47466d4c5745774d5749744d57466d4e6a51774e4749794d7a49344d4e43667834626e70704d444f726f527744376e344e5436343661544139492b6f67634b417a49754d524b614277704641487445705237724d625a533834457772664d6a39566956667a497739555a484866454931726f387a63366a7968495349424850676445574b527845505577354178544d3335683845755a2f4378347361763079374846632b2f31434567317a63477870593255745957313162475630476e4d4b514459335a6d466a4d6d59344e544e69593255345a474a6d4d4749354f444533596d4931596d4533597a55355a6a45775a5467784d6a42694e324d344d4467324f545a6d4e7a41784d4755315a6a426a4f4745334f544553426c4e7762476c6a5a52494c5157313162475630556e56735a584d61476b563464475679626d46735547467964486c545a5852316346427962334276633246734975454361743443436d514b596a7067593239795a476c6862484e356333526c62584d74646d467361575268644739794c5445364f6a45794d6a426c4e6d5a6959574d354d474e6a5a4445354e324d7a4e5459324f5445345a6a6b354f5463334d3249774e4451354e5755784e5464685a474d785a6d49344d444e694f545a6c5a4755795a5746684e57497a5957526d436f7742436f6b424f6f59424d475a6b4f5446684e6d45784e444d334f4441774d574d334d5759774e6a6b775a5441314f446b7a4e7a49334d444d784e544d78597a67794e6a457a4e324579597a4977596d55794f4446694d5455344f47466b5a6a6f364d5449794d44566c4e7a646b5a575a6d4e7a49355a54417a4e3255344d6a4d774d44517a4d4468694f5759794e6d4a68596d56684f4746684f574d77593255775a545a6d4d7a677a4e6a4a694e7a45315a6d52684e44646a4d44594b5451704c4f6b6c45553038364f6a45794d6a426d4d6a4a684f4749345a6a4a6b4f44457a597a4931596a6c684e6a67305a474d305a4751314d6d49314d7a4a684d4445334e4751345a54637a5954457a5932526d4d6d4a6859574a6d5a6d59334e5445344d7a4d334367734b43536c6e4d46552f4e6b304741416f4c43676b70454a344d765568554267417153555254547a6f364d5449794d4759794d6d4534596a686d4d6d51344d544e6a4d6a56694f5745324f44526b597a526b5a445579596a557a4d6d45774d5463305a44686c4e7a4e684d544e6a5a475979596d4668596d5a6d5a6a63314d54677a4d7a637159474e76636d52705957787a65584e305a57317a4c585a6862476c6b59585276636930784f6a6f784d6a49775a545a6d596d466a4f54426a593251784f54646a4d7a55324e6a6b784f4759354f546b334e7a4e694d4451304f54566c4d5455335957526a4d575a694f44417a596a6b325a57526c4d6d5668595456694d32466b5a6a4b474154426d5a446b7859545a684d54517a4e7a67774d44466a4e7a466d4d4459354d4755774e5467354d7a63794e7a417a4d54557a4d574d344d6a59784d7a64684d6d4d794d474a6c4d6a6778596a45314f4468685a4759364f6a45794d6a41315a5463335a47566d5a6a63794f5755774d7a646c4f44497a4d4441304d7a4134596a6c6d4d6a5a6959574a6c5954686859546c6a4d474e6c4d4755325a6a4d344d7a5979596a63784e575a6b59545133597a41324f576377565438325451594151696f4b4a676f6b4341455349483243442f63646c4d38376a55545a5141426a5a6b6764686a7645463376597131686944516c4f46564b6f4542344b68776f4b417a49754d524b4b415441774e3249304e4745314d57566c596a4d78596a59314d6d597a4f44457a4d47466b5a6a4d794d3259314e5467354e54646d4d7a497a4d4759314e4459304e7a466b5a6a45774f475132596d457a59324e6b593256684d324e684d5449784d6a49774d54466a5a6a67785a4445784e6a49354d574d304e444e6b4e474d7a4f54417a4d54526a5932526d4f546733597a45795a5459335a6a42694d575579597a5a685a6d517a4d6d566a4e7a453159325a695a6d51304d686f4e6333427361574e6c4c5746746457786c64434a79436b41324e325a68597a4a6d4f44557a596d4e6c4f4752695a6a42694f5467784e324a694e574a684e324d314f5759784d4755344d544977596a646a4f4441344e6a6b325a6a63774d54426c4e575977597a68684e7a6b7845684a5463477870593255755157313162475630556e56735a584d61476b563464475679626d46735547467964486c545a5852316346427962334276633246734b6f7745636f6b45436e494b514459335a6d466a4d6d59344e544e69593255345a474a6d4d4749354f444533596d4931596d4533597a55355a6a45775a5467784d6a42694e324d344d4467324f545a6d4e7a41784d4755315a6a426a4f4745334f544553456c4e7762476c6a5a533542625856735a5852536457786c63786f61525868305a584a755957785159584a3065564e6c6448567755484a766347397a5957775362776f4a646d46736157526864473979456d493659474e76636d52705957787a65584e305a57317a4c585a6862476c6b59585276636930784f6a6f784d6a49775a545a6d596d466a4f54426a593251784f54646a4d7a55324e6a6b784f4759354f546b334e7a4e694d4451304f54566c4d5455335957526a4d575a694f44417a596a6b325a57526c4d6d5668595456694d32466b5a684b5341516f4564584e6c63684b4a415471474154426d5a446b7859545a684d54517a4e7a67774d44466a4e7a466d4d4459354d4755774e5467354d7a63794e7a417a4d54557a4d574d344d6a59784d7a64684d6d4d794d474a6c4d6a6778596a45314f4468685a4759364f6a45794d6a41315a5463335a47566d5a6a63794f5755774d7a646c4f44497a4d4441304d7a4134596a6c6d4d6a5a6959574a6c5954686859546c6a4d474e6c4d4755325a6a4d344d7a5979596a63784e575a6b59545133597a4132456c494b4132527a62784a4c4f6b6c45553038364f6a45794d6a426d4d6a4a684f4749345a6a4a6b4f44457a597a4931596a6c684e6a67305a474d305a4751314d6d49314d7a4a684d4445334e4751345a54637a5954457a5932526d4d6d4a6859574a6d5a6d59334e5445344d7a4d334568594b43574e795a5746305a5752426442494a4b57637756543832545159414569454b464842795a57467763484a76646d46735258687761584a6c6330463045676b70454a344d765568554267417953555254547a6f364d5449794d4759794d6d4534596a686d4d6d51344d544e6a4d6a56694f5745324f44526b597a526b5a445579596a557a4d6d45774d5463305a44686c4e7a4e684d544e6a5a475979596d4668596d5a6d5a6a63314d54677a4d7a637959474e76636d52705957787a65584e305a57317a4c585a6862476c6b59585276636930784f6a6f784d6a49775a545a6d596d466a4f54426a593251784f54646a4d7a55324e6a6b784f4759354f546b334e7a4e694d4451304f54566c4d5455335957526a4d575a694f44417a596a6b325a57526c4d6d5668595456694d32466b5a6a71474154426d5a446b7859545a684d54517a4e7a67774d44466a4e7a466d4d4459354d4755774e5467354d7a63794e7a417a4d54557a4d574d344d6a59784d7a64684d6d4d794d474a6c4d6a6778596a45314f4468685a4759364f6a45794d6a41315a5463335a47566d5a6a63794f5755774d7a646c4f44497a4d4441304d7a4134596a6c6d4d6a5a6959574a6c5954686859546c6a4d474e6c4d4755325a6a4d344d7a5979596a63784e575a6b59545133597a41324f6b6c45553038364f6a45794d6a426d4d6a4a684f4749345a6a4a6b4f44457a597a4931596a6c684e6a67305a474d305a4751314d6d49314d7a4a684d4445334e4751345a54637a5954457a5932526d4d6d4a6859574a6d5a6d59334e5445344d7a4d334f6d426a62334a6b6157467363336c7a6447567463793132595778705a474630623349744d546f364d5449794d4755325a6d4a68597a6b7759324e6b4d546b33597a4d314e6a59354d54686d4f546b354e7a637a596a41304e446b315a5445314e32466b597a466d596a67774d3249354e6d566b5a544a6c59574531596a4e685a475a516a3779793649754a6c514d3d222c2273657475705f70726f706f73616c5f68617368223a2271574d6d39662b4f76682b417143304f444a70793561714b7365316761554d34397a68397a6674364844453d222c2273657475705f70726f706f73616c5f68617368696e67223a322c2273657475705f70726f706f73616c5f7375626d697373696f6e5f6964223a2233333433366635612d363666642d663636652d343638392d336538613739316431633563227d" +} diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index 81a6d0fc..ede1f9ba 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -16,6 +16,9 @@ type TxInput struct { HashingSchemeVersion interactive.HashingSchemeVersion // SubmissionId for deduplication (UUID) SubmissionId string `json:"submission_id"` + // Decimals is the number of decimal places for the chain's native asset, + // used to convert human-readable amounts in the prepared transaction to blockchain units. + Decimals int32 `json:"decimals"` } var _ xc.TxInput = &TxInput{} diff --git a/client/account.go b/client/account.go new file mode 100644 index 00000000..fab8a242 --- /dev/null +++ b/client/account.go @@ -0,0 +1,67 @@ +package client + +import ( + "context" + + xc "github.com/cordialsys/crosschain" +) + +// CreateAccountInput holds the data required to create (register) an on-chain account. +// It may contain one or more payloads that must be signed by the party's private key +// before calling CreateAccount. +// +// The flow mirrors the Canton external-party registration process: +// 1. Call FetchCreateAccountInput to obtain the input and the hashes to sign. +// 2. Sign each hash returned by Sighashes(). +// 3. Call CreateAccount with the signed input. +type CreateAccountInput interface { + // Sighashes returns the ordered list of payloads the party must sign. + // Each entry corresponds to one signature that must be passed to SetSignatures. + Sighashes() ([]*xc.SignatureRequest, error) + + // SetSignatures attaches the signatures produced by the external signer. + // Signatures must be provided in the same order as Sighashes(). + SetSignatures(sigs ...*xc.SignatureResponse) error + + // VerifySignaturePayloads recomputes the expected hash(es) from the raw + // registration data stored in the input and checks they match what Sighashes() + // returned. This lets a caller confirm the input has not been tampered with + // before signing. + VerifySignaturePayloads() error + + // Serialize encodes the pending registration step so it can be signed and + // later submitted through the generic submit path. + Serialize() ([]byte, error) +} + +// AccountClient is an optional client interface for chains that require an explicit +// on-chain account creation or registration step before the account can receive funds +// or submit transactions. +type AccountClient interface { + // FetchCreateAccountInput advances all account-creation steps that do not need + // an external signature. If a signature is needed for the next step, it returns + // the corresponding CreateAccountInput; if registration is already complete, it + // returns nil. + FetchCreateAccountInput(ctx context.Context, args *CreateAccountArgs) (CreateAccountInput, error) + + // CreateAccount submits one previously signed registration step to the chain. + CreateAccount(ctx context.Context, input CreateAccountInput) error +} + +// CreateAccountArgs carries the parameters for an account creation request. +type CreateAccountArgs struct { + // Address (party ID) of the account to register. + address xc.Address + // Raw public key bytes of the account owner. + publicKey []byte +} + +func NewCreateAccountArgs(address xc.Address, publicKey []byte) *CreateAccountArgs { + return &CreateAccountArgs{ + address: address, + publicKey: publicKey, + } +} + +func (a *CreateAccountArgs) GetAddress() xc.Address { return a.address } +func (a *CreateAccountArgs) GetPublicKey() []byte { return a.publicKey } diff --git a/cmd/xc/commands/create_account.go b/cmd/xc/commands/create_account.go new file mode 100644 index 00000000..0e994111 --- /dev/null +++ b/cmd/xc/commands/create_account.go @@ -0,0 +1,123 @@ +package commands + +import ( + "context" + "encoding/hex" + "fmt" + + "github.com/cordialsys/crosschain/chain/canton/tx_input" + xclient "github.com/cordialsys/crosschain/client" + "github.com/cordialsys/crosschain/cmd/xc/setup" + "github.com/cordialsys/crosschain/config" + "github.com/cordialsys/crosschain/factory/signer" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +func CmdCreateAccount() *cobra.Command { + var privateKeyRef string + + cmd := &cobra.Command{ + Use: "create-account", + Short: "Advance account registration and return the next signature request when one is needed.", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + xcFactory := setup.UnwrapXc(cmd.Context()) + chainConfig := setup.UnwrapChain(cmd.Context()) + + privateKeyInput, err := config.GetSecret(privateKeyRef) + if err != nil { + return fmt.Errorf("could not get secret: %v", err) + } + if privateKeyInput == "" { + return fmt.Errorf("must set env %s", signer.EnvPrivateKey) + } + + xcSigner, err := xcFactory.NewSigner(chainConfig.Base(), privateKeyInput) + if err != nil { + return fmt.Errorf("could not import private key: %v", err) + } + publicKey, err := xcSigner.PublicKey() + if err != nil { + return fmt.Errorf("could not derive public key: %v", err) + } + addressBuilder, err := xcFactory.NewAddressBuilder(chainConfig.Base()) + if err != nil { + return fmt.Errorf("could not create address builder: %v", err) + } + address, err := addressBuilder.GetAddressFromPublicKey(publicKey) + if err != nil { + return fmt.Errorf("could not derive address: %v", err) + } + + logrus.WithField("address", address).Info("registering account") + + rpcClient, err := xcFactory.NewClient(chainConfig) + if err != nil { + return fmt.Errorf("could not load client: %v", err) + } + accountClient, ok := rpcClient.(xclient.AccountClient) + if !ok { + return fmt.Errorf("chain %s does not support account creation", chainConfig.Chain) + } + + createArgs := xclient.NewCreateAccountArgs(address, publicKey) + input, err := accountClient.FetchCreateAccountInput(context.Background(), createArgs) + if err != nil { + return fmt.Errorf("could not fetch create-account input: %v", err) + } + if input == nil { + fmt.Println(asJson(map[string]string{ + "address": string(address), + "chain": string(chainConfig.Chain), + "status": "registered", + })) + return nil + } + + if err := input.VerifySignaturePayloads(); err != nil { + return fmt.Errorf("hash verification failed: %v", err) + } + + sighashes, err := input.Sighashes() + if err != nil { + return fmt.Errorf("could not get sighashes: %v", err) + } + if len(sighashes) != 1 { + return fmt.Errorf("expected exactly 1 signature request, got %d", len(sighashes)) + } + + logrus.WithField("count", len(sighashes)).Info("signature required") + for i, sh := range sighashes { + logrus.WithField("index", i).WithField("payload", hex.EncodeToString(sh.Payload)).Debug("signature request") + } + + serializedInput, err := input.Serialize() + if err != nil { + return fmt.Errorf("could not serialize create-account input: %v", err) + } + stage := "" + description := "" + if cantonInput, ok := input.(*tx_input.CreateAccountInput); ok { + stage = cantonInput.Stage + description = cantonInput.Description + } + + fmt.Println(asJson(map[string]any{ + "address": string(address), + "chain": string(chainConfig.Chain), + "status": "signature_required", + "stage": stage, + "description": description, + "signature_request": map[string]any{ + "payload": hex.EncodeToString(sighashes[0].Payload), + }, + "create_account_input": hex.EncodeToString(serializedInput), + })) + return nil + }, + } + + cmd.Flags().StringVar(&privateKeyRef, "key", "env:"+signer.EnvPrivateKey, "Secret reference for the private key") + return cmd +} diff --git a/cmd/xc/main.go b/cmd/xc/main.go index 6b8939a3..46eb1565 100644 --- a/cmd/xc/main.go +++ b/cmd/xc/main.go @@ -95,6 +95,7 @@ func CmdXc() *cobra.Command { cmd.AddCommand(commands.CmdFund()) cmd.AddCommand(commands.CmdSign()) cmd.AddCommand(commands.CmdRpcSubmit()) + cmd.AddCommand(commands.CmdCreateAccount()) cmd.AddCommand(staking.CmdStaking()) cmd.AddCommand(commands.CmdTools()) diff --git a/cmd/xc/setup/config.go b/cmd/xc/setup/config.go index db7432a9..f999a98d 100644 --- a/cmd/xc/setup/config.go +++ b/cmd/xc/setup/config.go @@ -36,7 +36,7 @@ func OverwriteCrosschainSettings(overrides map[string]*ChainOverride, xcFactory if override.Rpc != "" { logrus.WithField("chain", chain.Chain).Info("overriding rpc") chain.URL = override.Rpc - if strings.Contains(override.Rpc, "cordialapis.com") { + if strings.Contains(override.Rpc, "cordialapis.com") && chain.Driver != xc.DriverCanton { logrus.WithField("chain", chain.Chain).WithField("rpc", chain.URL).Info("using cordialapis driver") // ensure crosschain driver is used chain.Driver = xc.DriverCrosschain From 85f6f1f396494bc629ea94874a978fe81bcf4bd1 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 19 Mar 2026 09:09:46 +0100 Subject: [PATCH 03/23] CANTON: Refactor create account transacction --- asset.go | 4 + builder/builder.go | 4 + builder/create_account.go | 44 +++++++ chain/canton/builder/builder.go | 9 ++ chain/canton/client/client.go | 34 +++--- chain/canton/client/client_test.go | 79 ++++++++++++ chain/canton/tx/create_account_tx.go | 114 ++++++++++++++++++ chain/canton/tx/create_account_tx_test.go | 91 ++++++++++++++ chain/canton/tx_input/create_account_input.go | 46 ++++++- .../tx_input/create_account_input_test.go | 68 +++++++++++ chain/canton/tx_input/tx_input.go | 4 + chain/crosschain/account.go | 35 ++++++ chain/crosschain/client.go | 1 + chain/crosschain/types/api.go | 5 + client/account.go | 43 +------ cmd/xc/commands/create_account.go | 43 ++++--- factory/drivers/registry/registry.go | 3 +- factory/drivers/tx_input.go | 12 ++ tx.go | 4 + 19 files changed, 569 insertions(+), 74 deletions(-) create mode 100644 builder/create_account.go create mode 100644 chain/canton/tx/create_account_tx.go create mode 100644 chain/canton/tx/create_account_tx_test.go create mode 100644 chain/canton/tx_input/create_account_input_test.go create mode 100644 chain/crosschain/account.go diff --git a/asset.go b/asset.go index d4e9ea56..ef9d5b7f 100644 --- a/asset.go +++ b/asset.go @@ -290,6 +290,10 @@ func NewWithdrawingInputType(driver Driver, variant string) TxVariantInputType { return TxVariantInputType(fmt.Sprintf("drivers/%s/withdrawing/%s", driver, variant)) } +func NewCreateAccountInputType(driver Driver, variant string) TxVariantInputType { + return TxVariantInputType(fmt.Sprintf("drivers/%s/create-account/%s", driver, variant)) +} + func NewCallingInputType(driver Driver) TxVariantInputType { return TxVariantInputType(fmt.Sprintf("drivers/%s/calling/%s", driver, driver)) } diff --git a/builder/builder.go b/builder/builder.go index d1528863..f5cd1a0c 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -49,3 +49,7 @@ type Staking interface { // Informational only MethodsUsed() []xc.StakingMethod } + +type AccountCreation interface { + CreateAccount(createAccountArgs CreateAccountArgs, input xc.CreateAccountTxInput) (xc.Tx, error) +} diff --git a/builder/create_account.go b/builder/create_account.go new file mode 100644 index 00000000..7ba2d92b --- /dev/null +++ b/builder/create_account.go @@ -0,0 +1,44 @@ +package builder + +import xc "github.com/cordialsys/crosschain" + +type CreateAccountArgs struct { + appliedOptions []BuilderOption + options builderOptions + chain xc.NativeAsset + address xc.Address + publicKey []byte +} + +var _ TransactionOptions = &CreateAccountArgs{} + +func NewCreateAccountArgs(chain xc.NativeAsset, address xc.Address, publicKey []byte, options ...BuilderOption) (CreateAccountArgs, error) { + builderOptions := newBuilderOptions() + args := CreateAccountArgs{ + appliedOptions: options, + options: builderOptions, + chain: chain, + address: address, + publicKey: append([]byte(nil), publicKey...), + } + for _, opt := range options { + if err := opt(&args.options); err != nil { + return args, err + } + } + return args, nil +} + +func (args *CreateAccountArgs) GetChain() xc.NativeAsset { return args.chain } +func (args *CreateAccountArgs) GetAddress() xc.Address { return args.address } +func (args *CreateAccountArgs) PublicKeyBytes() []byte { return append([]byte(nil), args.publicKey...) } +func (args *CreateAccountArgs) GetMemo() (string, bool) { return args.options.GetMemo() } +func (args *CreateAccountArgs) GetTimestamp() (int64, bool) { + return args.options.GetTimestamp() +} +func (args *CreateAccountArgs) GetPriority() (xc.GasFeePriority, bool) { + return args.options.GetPriority() +} +func (args *CreateAccountArgs) GetPublicKey() ([]byte, bool) { + return append([]byte(nil), args.publicKey...), len(args.publicKey) > 0 +} diff --git a/chain/canton/builder/builder.go b/chain/canton/builder/builder.go index 3c7a3178..9bc3a447 100644 --- a/chain/canton/builder/builder.go +++ b/chain/canton/builder/builder.go @@ -15,6 +15,7 @@ type TxBuilder struct { } var _ xcbuilder.FullTransferBuilder = TxBuilder{} +var _ xcbuilder.AccountCreation = TxBuilder{} // NewTxBuilder creates a new Canton TxBuilder func NewTxBuilder(cfgI *xc.ChainBaseConfig) (TxBuilder, error) { @@ -46,3 +47,11 @@ func (txBuilder TxBuilder) NewNativeTransfer(args xcbuilder.TransferArgs, input func (txBuilder TxBuilder) NewTokenTransfer(args xcbuilder.TransferArgs, contract xc.ContractAddress, input xc.TxInput) (xc.Tx, error) { return nil, fmt.Errorf("token transfers are not supported for %s", txBuilder.Asset.Chain) } + +func (txBuilder TxBuilder) CreateAccount(args xcbuilder.CreateAccountArgs, input xc.CreateAccountTxInput) (xc.Tx, error) { + return cantontx.NewCreateAccountTx(args, input) +} + +func (txBuilder TxBuilder) SupportsMemo() xc.MemoSupport { + return xc.MemoSupportNone +} diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index b52c432d..4e8b5f92 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -522,14 +522,14 @@ func (client *Client) FetchLegacyTxInput(ctx context.Context, from xc.Address, t } // SubmitTx accepts either a serialized Canton transfer submission or a -// serialized Canton create-account step and dispatches it accordingly. +// serialized Canton create-account transaction and dispatches it accordingly. func (client *Client) SubmitTx(ctx context.Context, submitReq xctypes.SubmitTxReq) error { if len(submitReq.TxData) == 0 { return fmt.Errorf("empty transaction data") } - if createAccountInput, err := tx_input.ParseCreateAccountInput(submitReq.TxData); err == nil { - return client.CreateAccount(ctx, createAccountInput) + if createAccountTx, err := cantontx.ParseCreateAccountTx(submitReq.TxData); err == nil { + return client.submitCreateAccountTx(ctx, createAccountTx) } var req interactive.ExecuteSubmissionRequest @@ -780,13 +780,13 @@ func TxFromInput(args xcbuilder.TransferArgs, input *tx_input.TxInput, decimals return cantontx.NewTx(input, args, decimals) } -var _ xclient.AccountClient = &Client{} +var _ xclient.CreateAccountInputClient = &Client{} // FetchCreateAccountInput fetches all on-chain data required to register a Canton external party // and advances all registration steps that do not require an explicit external // signature. If another signed step is needed, it returns the payload for that // step; otherwise it returns nil to signal that registration is complete. -func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient.CreateAccountArgs) (xclient.CreateAccountInput, error) { +func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient.CreateAccountArgs) (xc.CreateAccountTxInput, error) { publicKeyBytes := args.GetPublicKey() partyID := string(args.GetAddress()) @@ -819,7 +819,7 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient input := &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAllocate, - Description: "Sign signature_request.payload, append the raw signature hex to create_account_input, then submit the combined hex with `xc submit --chain canton `.", + Description: "Sign signature_request.payload, append the raw signature hex to tx, then submit the combined hex with `xc submit --chain canton `.", PartyID: partyID, PublicKeyFingerprint: topologyResp.GetPublicKeyFingerprint(), TopologyMultiHash: topologyResp.GetMultiHash(), @@ -883,7 +883,7 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient input := &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAccept, - Description: "Sign signature_request.payload, append the raw signature hex to create_account_input, then submit the combined hex with `xc submit --chain canton `.", + Description: "Sign signature_request.payload, append the raw signature hex to tx, then submit the combined hex with `xc submit --chain canton `.", PartyID: partyID, SetupProposalPreparedTransaction: preparedTxBz, SetupProposalHash: prepareResp.GetPreparedTransactionHash(), @@ -899,20 +899,14 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient return nil, nil } -// CreateAccount submits the signed Canton account-registration step described by -// the serialized CreateAccountInput. -func (client *Client) CreateAccount(ctx context.Context, createInput xclient.CreateAccountInput) error { - cantonInput, ok := createInput.(*tx_input.CreateAccountInput) - if !ok { - return fmt.Errorf("invalid CreateAccountInput type for Canton") +func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx *cantontx.CreateAccountTx) error { + if createAccountTx == nil || createAccountTx.Input == nil { + return fmt.Errorf("create-account tx is nil") } + cantonInput := createAccountTx.Input if len(cantonInput.Signature) == 0 { - return fmt.Errorf("CreateAccountInput has not been signed; call SetSignatures first") + return fmt.Errorf("create-account transaction is not signed") } - if err := cantonInput.VerifySignaturePayloads(); err != nil { - return fmt.Errorf("invalid CreateAccountInput: %w", err) - } - authCtx := client.ledgerClient.authCtx(ctx) switch cantonInput.Stage { @@ -941,9 +935,9 @@ func (client *Client) CreateAccount(ctx context.Context, createInput xclient.Cre if err := proto.Unmarshal(cantonInput.SetupProposalPreparedTransaction, &preparedTx); err != nil { return fmt.Errorf("failed to unmarshal setup proposal prepared transaction: %w", err) } - _, keyFingerprint, err := cantonaddress.ParsePartyID(xc.Address(cantonInput.PartyID)) + keyFingerprint, err := createAccountTx.KeyFingerprint() if err != nil { - return fmt.Errorf("failed to parse party ID for setup proposal accept: %w", err) + return fmt.Errorf("failed to determine signing fingerprint for setup proposal accept: %w", err) } executeReq := &interactive.ExecuteSubmissionAndWaitRequest{ PreparedTransaction: &preparedTx, diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index ebf26c8d..7b4fab43 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -1,10 +1,17 @@ package client import ( + "context" "testing" xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/chain/canton/tx_input" + xctypes "github.com/cordialsys/crosschain/client/types" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" ) func TestNewClient(t *testing.T) { @@ -42,3 +49,75 @@ func TestNewClient(t *testing.T) { require.Contains(t, err.Error(), "required environment variable") }) } + +func TestSubmitTxRoutesCreateAccountPayloadToCreateAccountTxPath(t *testing.T) { + t.Parallel() + + client := &Client{} + err := client.SubmitTx(context.Background(), xctypes.SubmitTxReq{ + TxData: mustSerializedCreateAccountInput(t), + }) + require.ErrorContains(t, err, "create-account transaction is not signed") +} + +func TestSubmitTxExecutesStandardCantonPayload(t *testing.T) { + t.Parallel() + + stub := &interactiveSubmissionStub{} + client := &Client{ + ledgerClient: &GrpcLedgerClient{ + authToken: "token", + interactiveSubmissionClient: stub, + logger: logrus.NewEntry(logrus.New()), + }, + } + + req := &interactive.ExecuteSubmissionRequest{ + SubmissionId: "submission-id", + } + payload, err := proto.Marshal(req) + require.NoError(t, err) + + err = client.SubmitTx(context.Background(), xctypes.SubmitTxReq{TxData: payload}) + require.NoError(t, err) + require.NotNil(t, stub.lastReq) + require.Equal(t, "submission-id", stub.lastReq.GetSubmissionId()) +} + +func mustSerializedCreateAccountInput(t *testing.T) []byte { + t.Helper() + input := &tx_input.CreateAccountInput{ + Stage: tx_input.CreateAccountStageAllocate, + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + TopologyMultiHash: []byte{0xaa, 0xbb}, + TopologyTransactions: [][]byte{{0x01}}, + } + bz, err := input.Serialize() + require.NoError(t, err) + return bz +} + +type interactiveSubmissionStub struct { + lastReq *interactive.ExecuteSubmissionAndWaitRequest +} + +func (s *interactiveSubmissionStub) PrepareSubmission(context.Context, *interactive.PrepareSubmissionRequest, ...grpc.CallOption) (*interactive.PrepareSubmissionResponse, error) { + panic("unexpected call") +} +func (s *interactiveSubmissionStub) ExecuteSubmission(context.Context, *interactive.ExecuteSubmissionRequest, ...grpc.CallOption) (*interactive.ExecuteSubmissionResponse, error) { + panic("unexpected call") +} +func (s *interactiveSubmissionStub) ExecuteSubmissionAndWait(_ context.Context, req *interactive.ExecuteSubmissionAndWaitRequest, _ ...grpc.CallOption) (*interactive.ExecuteSubmissionAndWaitResponse, error) { + s.lastReq = req + return &interactive.ExecuteSubmissionAndWaitResponse{}, nil +} +func (s *interactiveSubmissionStub) ExecuteSubmissionAndWaitForTransaction(context.Context, *interactive.ExecuteSubmissionAndWaitForTransactionRequest, ...grpc.CallOption) (*interactive.ExecuteSubmissionAndWaitForTransactionResponse, error) { + panic("unexpected call") +} +func (s *interactiveSubmissionStub) GetPreferredPackageVersion(context.Context, *interactive.GetPreferredPackageVersionRequest, ...grpc.CallOption) (*interactive.GetPreferredPackageVersionResponse, error) { + panic("unexpected call") +} +func (s *interactiveSubmissionStub) GetPreferredPackages(context.Context, *interactive.GetPreferredPackagesRequest, ...grpc.CallOption) (*interactive.GetPreferredPackagesResponse, error) { + panic("unexpected call") +} diff --git a/chain/canton/tx/create_account_tx.go b/chain/canton/tx/create_account_tx.go new file mode 100644 index 00000000..faf656a8 --- /dev/null +++ b/chain/canton/tx/create_account_tx.go @@ -0,0 +1,114 @@ +package tx + +import ( + "crypto/sha256" + "fmt" + + xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + "github.com/cordialsys/crosschain/chain/canton/tx_input" +) + +type CreateAccountTx struct { + Input *tx_input.CreateAccountInput +} + +var _ xc.Tx = &CreateAccountTx{} + +func NewCreateAccountTx(args xcbuilder.CreateAccountArgs, input xc.CreateAccountTxInput) (*CreateAccountTx, error) { + cantonInput, ok := input.(*tx_input.CreateAccountInput) + if !ok { + return nil, fmt.Errorf("invalid create-account tx input type for Canton: %T", input) + } + if err := cantonInput.VerifySignaturePayloads(); err != nil { + return nil, fmt.Errorf("invalid create-account tx input: %w", err) + } + if got := string(args.GetAddress()); got != cantonInput.PartyID { + return nil, fmt.Errorf("create-account input party mismatch: args=%q input=%q", got, cantonInput.PartyID) + } + return &CreateAccountTx{Input: cloneCreateAccountInput(cantonInput)}, nil +} + +func ParseCreateAccountTx(data []byte) (*CreateAccountTx, error) { + input, err := tx_input.ParseCreateAccountInput(data) + if err != nil { + return nil, err + } + if err := input.VerifySignaturePayloads(); err != nil { + return nil, fmt.Errorf("invalid create-account tx: %w", err) + } + return &CreateAccountTx{Input: input}, nil +} + +func (tx *CreateAccountTx) Hash() xc.TxHash { + if tx == nil || tx.Input == nil { + return "" + } + serialized, err := tx.Input.Serialize() + if err != nil { + return "" + } + sum := sha256.Sum256(serialized) + return xc.TxHash(fmt.Sprintf("%x", sum[:])) +} + +func (tx *CreateAccountTx) Sighashes() ([]*xc.SignatureRequest, error) { + if tx == nil || tx.Input == nil { + return nil, fmt.Errorf("create-account tx input is nil") + } + return tx.Input.Sighashes() +} + +func (tx *CreateAccountTx) SetSignatures(sigs ...*xc.SignatureResponse) error { + if tx == nil || tx.Input == nil { + return fmt.Errorf("create-account tx input is nil") + } + return tx.Input.SetSignatures(sigs...) +} + +func (tx *CreateAccountTx) Serialize() ([]byte, error) { + if tx == nil || tx.Input == nil { + return nil, fmt.Errorf("create-account tx input is nil") + } + return tx.Input.Serialize() +} + +func (tx *CreateAccountTx) KeyFingerprint() (string, error) { + if tx == nil || tx.Input == nil { + return "", fmt.Errorf("create-account tx input is nil") + } + switch tx.Input.Stage { + case tx_input.CreateAccountStageAllocate: + if tx.Input.PublicKeyFingerprint == "" { + return "", fmt.Errorf("public key fingerprint is empty") + } + return tx.Input.PublicKeyFingerprint, nil + case tx_input.CreateAccountStageAccept: + _, fingerprint, err := cantonaddress.ParsePartyID(xc.Address(tx.Input.PartyID)) + if err != nil { + return "", fmt.Errorf("failed to parse party ID: %w", err) + } + return fingerprint, nil + default: + return "", fmt.Errorf("unsupported create-account stage %q", tx.Input.Stage) + } +} + +func cloneCreateAccountInput(input *tx_input.CreateAccountInput) *tx_input.CreateAccountInput { + if input == nil { + return nil + } + cloned := *input + cloned.TopologyMultiHash = append([]byte(nil), input.TopologyMultiHash...) + cloned.Signature = append([]byte(nil), input.Signature...) + cloned.SetupProposalPreparedTransaction = append([]byte(nil), input.SetupProposalPreparedTransaction...) + cloned.SetupProposalHash = append([]byte(nil), input.SetupProposalHash...) + if len(input.TopologyTransactions) > 0 { + cloned.TopologyTransactions = make([][]byte, len(input.TopologyTransactions)) + for i, txn := range input.TopologyTransactions { + cloned.TopologyTransactions[i] = append([]byte(nil), txn...) + } + } + return &cloned +} diff --git a/chain/canton/tx/create_account_tx_test.go b/chain/canton/tx/create_account_tx_test.go new file mode 100644 index 00000000..c9cb314e --- /dev/null +++ b/chain/canton/tx/create_account_tx_test.go @@ -0,0 +1,91 @@ +package tx + +import ( + "encoding/hex" + "encoding/json" + "os" + "testing" + + xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + "github.com/cordialsys/crosschain/chain/canton/tx_input" + "github.com/stretchr/testify/require" +) + +func TestCreateAccountTxRoundTrip(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input *tx_input.CreateAccountInput + }{ + { + name: "allocate", + input: &tx_input.CreateAccountInput{ + Stage: tx_input.CreateAccountStageAllocate, + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + TopologyMultiHash: []byte{0xaa, 0xbb}, + TopologyTransactions: [][]byte{{0x01, 0x02}}, + }, + }, + { + name: "accept", + input: loadLiveAcceptInput(t), + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + args, err := xcbuilder.NewCreateAccountArgs(xc.CANTON, xc.Address(tt.input.PartyID), []byte{0x01, 0x02}) + require.NoError(t, err) + + tx, err := NewCreateAccountTx(args, tt.input) + require.NoError(t, err) + + sighashes, err := tx.Sighashes() + require.NoError(t, err) + require.Len(t, sighashes, 1) + + unsigned, err := tx.Serialize() + require.NoError(t, err) + + parsedUnsigned, err := ParseCreateAccountTx(unsigned) + require.NoError(t, err) + require.Equal(t, tt.input.Stage, parsedUnsigned.Input.Stage) + + err = tx.SetSignatures(&xc.SignatureResponse{Signature: []byte{0xde, 0xad}}) + require.NoError(t, err) + + signed, err := tx.Serialize() + require.NoError(t, err) + + parsedSigned, err := ParseCreateAccountTx(signed) + require.NoError(t, err) + require.Equal(t, "dead", hex.EncodeToString(parsedSigned.Input.Signature)) + require.NotEmpty(t, tx.Hash()) + }) + } +} + +func loadLiveAcceptInput(t *testing.T) *tx_input.CreateAccountInput { + t.Helper() + + data, err := os.ReadFile("../tx_input/testdata/live_create_account_accept.json") + require.NoError(t, err) + + var fixture struct { + CreateAccountInput string `json:"create_account_input"` + } + require.NoError(t, json.Unmarshal(data, &fixture)) + + encoded, err := hex.DecodeString(fixture.CreateAccountInput) + require.NoError(t, err) + + input, err := tx_input.ParseCreateAccountInput(encoded) + require.NoError(t, err) + return input +} diff --git a/chain/canton/tx_input/create_account_input.go b/chain/canton/tx_input/create_account_input.go index ce9384e2..f19324ae 100644 --- a/chain/canton/tx_input/create_account_input.go +++ b/chain/canton/tx_input/create_account_input.go @@ -6,7 +6,7 @@ import ( "fmt" xc "github.com/cordialsys/crosschain" - xclient "github.com/cordialsys/crosschain/client" + "github.com/cordialsys/crosschain/factory/drivers/registry" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "google.golang.org/protobuf/proto" ) @@ -41,7 +41,49 @@ type CreateAccountInput struct { Signature []byte `json:"signature,omitempty"` } -var _ xclient.CreateAccountInput = &CreateAccountInput{} +var _ xc.TxVariantInput = &CreateAccountInput{} +var _ xc.CreateAccountTxInput = &CreateAccountInput{} + +func init() { + registry.RegisterTxVariantInput(&CreateAccountInput{}) +} + +func (*CreateAccountInput) CreatingAccount() {} + +func (*CreateAccountInput) GetVariant() xc.TxVariantInputType { + return xc.NewCreateAccountInputType(xc.DriverCanton, string(xc.Native)) +} + +func (*CreateAccountInput) GetDriver() xc.Driver { + return xc.DriverCanton +} + +func (*CreateAccountInput) SetGasFeePriority(_ xc.GasFeePriority) error { + return nil +} + +func (*CreateAccountInput) GetFeeLimit() (xc.AmountBlockchain, xc.ContractAddress) { + return xc.NewAmountBlockchainFromUint64(0), "" +} + +func (*CreateAccountInput) IsFeeLimitAccurate() bool { + return true +} + +func (i *CreateAccountInput) IndependentOf(other xc.TxInput) bool { + otherInput, ok := other.(*CreateAccountInput) + if !ok { + return true + } + return i.PartyID != otherInput.PartyID || i.Stage != otherInput.Stage +} + +func (i *CreateAccountInput) SafeFromDoubleSend(other xc.TxInput) bool { + if i.IndependentOf(other) { + return false + } + return true +} func ParseCreateAccountInput(data []byte) (*CreateAccountInput, error) { if len(data) < 8 { diff --git a/chain/canton/tx_input/create_account_input_test.go b/chain/canton/tx_input/create_account_input_test.go new file mode 100644 index 00000000..8a85d2bc --- /dev/null +++ b/chain/canton/tx_input/create_account_input_test.go @@ -0,0 +1,68 @@ +package tx_input + +import ( + "encoding/hex" + "testing" + + xc "github.com/cordialsys/crosschain" + "github.com/stretchr/testify/require" +) + +func TestCreateAccountInputSerializeRoundTrip(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input *CreateAccountInput + }{ + { + name: "allocate", + input: &CreateAccountInput{ + Stage: CreateAccountStageAllocate, + Description: "allocate", + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + TopologyMultiHash: []byte{0xaa, 0xbb, 0xcc}, + TopologyTransactions: [][]byte{{0x01, 0x02}, {0x03, 0x04}}, + Signature: []byte{0x05, 0x06}, + }, + }, + { + name: "accept", + input: mustLoadLiveCreateAccountAcceptInput(t), + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + bz, err := tt.input.Serialize() + require.NoError(t, err) + + parsed, err := ParseCreateAccountInput(bz) + require.NoError(t, err) + require.Equal(t, tt.input.Stage, parsed.Stage) + require.Equal(t, tt.input.Description, parsed.Description) + require.Equal(t, tt.input.PartyID, parsed.PartyID) + require.Equal(t, hex.EncodeToString(tt.input.Signature), hex.EncodeToString(parsed.Signature)) + require.Equal(t, hex.EncodeToString(tt.input.TopologyMultiHash), hex.EncodeToString(parsed.TopologyMultiHash)) + require.Equal(t, hex.EncodeToString(tt.input.SetupProposalHash), hex.EncodeToString(parsed.SetupProposalHash)) + require.Equal(t, tt.input.SetupProposalSubmissionID, parsed.SetupProposalSubmissionID) + require.Equal(t, tt.input.TopologyTransactions, parsed.TopologyTransactions) + }) + } +} + +func TestCreateAccountInputSetSignatures(t *testing.T) { + t.Parallel() + + input := &CreateAccountInput{} + err := input.SetSignatures(&xc.SignatureResponse{Signature: []byte{0x01}}) + require.NoError(t, err) + require.Equal(t, []byte{0x01}, input.Signature) + + err = input.SetSignatures() + require.ErrorContains(t, err, "expected 1 signature") +} diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index ede1f9ba..87ef3478 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -48,6 +48,10 @@ func (input *TxInput) GetFeeLimit() (xc.AmountBlockchain, xc.ContractAddress) { return xc.NewAmountBlockchainFromUint64(0), "" } +func (input *TxInput) IsFeeLimitAccurate() bool { + return true +} + func (input *TxInput) IndependentOf(other xc.TxInput) (independent bool) { // Each Canton submission has a unique SubmissionId / command ID if cantonOther, ok := other.(*TxInput); ok { diff --git a/chain/crosschain/account.go b/chain/crosschain/account.go new file mode 100644 index 00000000..66585685 --- /dev/null +++ b/chain/crosschain/account.go @@ -0,0 +1,35 @@ +package crosschain + +import ( + "context" + "encoding/json" + "fmt" + + xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/chain/crosschain/types" + xclient "github.com/cordialsys/crosschain/client" + "github.com/cordialsys/crosschain/factory/drivers" +) + +func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient.CreateAccountArgs) (xc.CreateAccountTxInput, error) { + chain := client.Asset.GetChain().Chain + req := &types.CreateAccountInputReq{ + Address: string(args.GetAddress()), + PublicKey: args.GetPublicKey(), + } + + apiURL := fmt.Sprintf("%s/v1/chains/%s/accounts", client.URL, chain) + res, err := client.ApiCallWithUrl(ctx, "POST", apiURL, req) + if err != nil { + return nil, err + } + + r := types.TxInputRes{} + if err := json.Unmarshal(res, &r); err != nil { + return nil, err + } + if r.TxInput == "" { + return nil, nil + } + return drivers.UnmarshalCreateAccountInput([]byte(r.TxInput)) +} diff --git a/chain/crosschain/client.go b/chain/crosschain/client.go index 1995a840..5d6f281d 100644 --- a/chain/crosschain/client.go +++ b/chain/crosschain/client.go @@ -41,6 +41,7 @@ type Client struct { var _ xclient.Client = &Client{} var _ xclient.StakingClient = &Client{} var _ xclient.MultiTransferClient = &Client{} +var _ xclient.CreateAccountInputClient = &Client{} const ServiceApiKeyHeader = "x-service-api-key" diff --git a/chain/crosschain/types/api.go b/chain/crosschain/types/api.go index 405bf948..caa3e324 100644 --- a/chain/crosschain/types/api.go +++ b/chain/crosschain/types/api.go @@ -159,6 +159,11 @@ type StakingInputReq struct { Memo string `json:"memo,omitempty"` } +type CreateAccountInputReq struct { + Address string `json:"address"` + PublicKey hex.Hex `json:"public_key,omitempty"` +} + type LegacyTxInputRes struct { *TransferInputReq xc.TxInput `json:"raw_tx_input,omitempty"` diff --git a/client/account.go b/client/account.go index fab8a242..45a2cda8 100644 --- a/client/account.go +++ b/client/account.go @@ -6,46 +6,15 @@ import ( xc "github.com/cordialsys/crosschain" ) -// CreateAccountInput holds the data required to create (register) an on-chain account. -// It may contain one or more payloads that must be signed by the party's private key -// before calling CreateAccount. -// -// The flow mirrors the Canton external-party registration process: -// 1. Call FetchCreateAccountInput to obtain the input and the hashes to sign. -// 2. Sign each hash returned by Sighashes(). -// 3. Call CreateAccount with the signed input. -type CreateAccountInput interface { - // Sighashes returns the ordered list of payloads the party must sign. - // Each entry corresponds to one signature that must be passed to SetSignatures. - Sighashes() ([]*xc.SignatureRequest, error) - - // SetSignatures attaches the signatures produced by the external signer. - // Signatures must be provided in the same order as Sighashes(). - SetSignatures(sigs ...*xc.SignatureResponse) error - - // VerifySignaturePayloads recomputes the expected hash(es) from the raw - // registration data stored in the input and checks they match what Sighashes() - // returned. This lets a caller confirm the input has not been tampered with - // before signing. - VerifySignaturePayloads() error - - // Serialize encodes the pending registration step so it can be signed and - // later submitted through the generic submit path. - Serialize() ([]byte, error) -} - -// AccountClient is an optional client interface for chains that require an explicit -// on-chain account creation or registration step before the account can receive funds -// or submit transactions. -type AccountClient interface { +// CreateAccountInputClient is an optional client interface for chains that require +// an explicit on-chain account creation or registration step before the account can +// receive funds or submit transactions. +type CreateAccountInputClient interface { // FetchCreateAccountInput advances all account-creation steps that do not need // an external signature. If a signature is needed for the next step, it returns - // the corresponding CreateAccountInput; if registration is already complete, it + // the corresponding tx input; if registration is already complete, it // returns nil. - FetchCreateAccountInput(ctx context.Context, args *CreateAccountArgs) (CreateAccountInput, error) - - // CreateAccount submits one previously signed registration step to the chain. - CreateAccount(ctx context.Context, input CreateAccountInput) error + FetchCreateAccountInput(ctx context.Context, args *CreateAccountArgs) (xc.CreateAccountTxInput, error) } // CreateAccountArgs carries the parameters for an account creation request. diff --git a/cmd/xc/commands/create_account.go b/cmd/xc/commands/create_account.go index 0e994111..8d23ef94 100644 --- a/cmd/xc/commands/create_account.go +++ b/cmd/xc/commands/create_account.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" + xcbuilder "github.com/cordialsys/crosschain/builder" "github.com/cordialsys/crosschain/chain/canton/tx_input" xclient "github.com/cordialsys/crosschain/client" "github.com/cordialsys/crosschain/cmd/xc/setup" @@ -56,10 +57,18 @@ func CmdCreateAccount() *cobra.Command { if err != nil { return fmt.Errorf("could not load client: %v", err) } - accountClient, ok := rpcClient.(xclient.AccountClient) + accountClient, ok := rpcClient.(xclient.CreateAccountInputClient) if !ok { return fmt.Errorf("chain %s does not support account creation", chainConfig.Chain) } + txBuilder, err := xcFactory.NewTxBuilder(chainConfig.Base()) + if err != nil { + return fmt.Errorf("could not create tx builder: %v", err) + } + accountBuilder, ok := txBuilder.(xcbuilder.AccountCreation) + if !ok { + return fmt.Errorf("chain %s does not support create-account transactions", chainConfig.Chain) + } createArgs := xclient.NewCreateAccountArgs(address, publicKey) input, err := accountClient.FetchCreateAccountInput(context.Background(), createArgs) @@ -75,11 +84,23 @@ func CmdCreateAccount() *cobra.Command { return nil } - if err := input.VerifySignaturePayloads(); err != nil { + cantonInput, ok := input.(*tx_input.CreateAccountInput) + if !ok { + return fmt.Errorf("invalid create-account input type: %T", input) + } + if err := cantonInput.VerifySignaturePayloads(); err != nil { return fmt.Errorf("hash verification failed: %v", err) } + builderArgs, err := xcbuilder.NewCreateAccountArgs(chainConfig.Chain, address, publicKey) + if err != nil { + return fmt.Errorf("could not build create-account args: %v", err) + } + tx, err := accountBuilder.CreateAccount(builderArgs, input) + if err != nil { + return fmt.Errorf("could not build create-account tx: %v", err) + } - sighashes, err := input.Sighashes() + sighashes, err := tx.Sighashes() if err != nil { return fmt.Errorf("could not get sighashes: %v", err) } @@ -92,27 +113,21 @@ func CmdCreateAccount() *cobra.Command { logrus.WithField("index", i).WithField("payload", hex.EncodeToString(sh.Payload)).Debug("signature request") } - serializedInput, err := input.Serialize() + serializedInput, err := tx.Serialize() if err != nil { - return fmt.Errorf("could not serialize create-account input: %v", err) - } - stage := "" - description := "" - if cantonInput, ok := input.(*tx_input.CreateAccountInput); ok { - stage = cantonInput.Stage - description = cantonInput.Description + return fmt.Errorf("could not serialize create-account tx: %v", err) } fmt.Println(asJson(map[string]any{ "address": string(address), "chain": string(chainConfig.Chain), "status": "signature_required", - "stage": stage, - "description": description, + "stage": cantonInput.Stage, + "description": cantonInput.Description, "signature_request": map[string]any{ "payload": hex.EncodeToString(sighashes[0].Payload), }, - "create_account_input": hex.EncodeToString(serializedInput), + "tx": hex.EncodeToString(serializedInput), })) return nil }, diff --git a/factory/drivers/registry/registry.go b/factory/drivers/registry/registry.go index 5d6a0bee..fcc9b479 100644 --- a/factory/drivers/registry/registry.go +++ b/factory/drivers/registry/registry.go @@ -32,7 +32,8 @@ func RegisterTxVariantInput(variant xc.TxVariantInput) { _, ok3 := variant.(xc.WithdrawTxInput) _, ok4 := variant.(xc.MultiTransferInput) _, ok5 := variant.(xc.CallTxInput) - if !ok1 && !ok2 && !ok3 && !ok4 && !ok5 { + _, ok6 := variant.(xc.CreateAccountTxInput) + if !ok1 && !ok2 && !ok3 && !ok4 && !ok5 && !ok6 { panic(fmt.Sprintf("staking input %T must implement one of known variants", variant)) } diff --git a/factory/drivers/tx_input.go b/factory/drivers/tx_input.go index 5cebfa1b..df8b3a6c 100644 --- a/factory/drivers/tx_input.go +++ b/factory/drivers/tx_input.go @@ -201,3 +201,15 @@ func UnmarshalCallInput(data []byte) (xc.CallTxInput, error) { } return call, nil } + +func UnmarshalCreateAccountInput(data []byte) (xc.CreateAccountTxInput, error) { + inp, err := UnmarshalVariantInput(data) + if err != nil { + return nil, err + } + createAccount, ok := inp.(xc.CreateAccountTxInput) + if !ok { + return createAccount, fmt.Errorf("not a create-account input: %T", inp) + } + return createAccount, nil +} diff --git a/tx.go b/tx.go index cd5653e3..a9abe7b8 100644 --- a/tx.go +++ b/tx.go @@ -112,6 +112,10 @@ type WithdrawTxInput interface { TxVariantInput Withdrawing() } +type CreateAccountTxInput interface { + TxVariantInput + CreatingAccount() +} type CallTxInput interface { TxVariantInput Calling() From 56f9a4eb6cc42838e8774bf1d7c77975115a78b4 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Fri, 20 Mar 2026 10:17:22 +0100 Subject: [PATCH 04/23] CANTON: Improve logging --- chain/canton/client/client.go | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 4e8b5f92..934bcafe 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -789,11 +789,19 @@ var _ xclient.CreateAccountInputClient = &Client{} func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient.CreateAccountArgs) (xc.CreateAccountTxInput, error) { publicKeyBytes := args.GetPublicKey() partyID := string(args.GetAddress()) + logger := logrus.WithFields(logrus.Fields{ + "chain": client.Asset.GetChain().Chain, + "party_id": partyID, + "public_key_len": len(publicKeyBytes), + }) + logger.Info("create-account: checking external party registration") exists, err := client.ledgerClient.ExternalPartyExists(ctx, partyID) if err != nil { + logger.WithError(err).Error("create-account: external party registration check failed") return nil, fmt.Errorf("failed to check external party registration: %w", err) } + logger.WithField("exists", exists).Info("create-account: external party registration check completed") if !exists { authCtx := client.ledgerClient.authCtx(ctx) partyHint := hex.EncodeToString(publicKeyBytes) @@ -803,14 +811,20 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient KeySpec: v2.SigningKeySpec_SIGNING_KEY_SPEC_EC_CURVE25519, } + logger.WithField("party_hint", partyHint).Info("create-account: generating external party topology") topologyResp, err := client.ledgerClient.adminClient.GenerateExternalPartyTopology(authCtx, &admin.GenerateExternalPartyTopologyRequest{ Synchronizer: TestnetSynchronizerID, PartyHint: partyHint, PublicKey: signingPubKey, }) if err != nil { + logger.WithError(err).Error("create-account: generate external party topology failed") return nil, fmt.Errorf("GenerateExternalPartyTopology failed: %w", err) } + logger.WithFields(logrus.Fields{ + "topology_tx_count": len(topologyResp.GetTopologyTransactions()), + "multihash_len": len(topologyResp.GetMultiHash()), + }).Info("create-account: generated external party topology") txns := make([][]byte, 0, len(topologyResp.GetTopologyTransactions())) for _, txBytes := range topologyResp.GetTopologyTransactions() { @@ -827,27 +841,42 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient } if err := input.VerifySignaturePayloads(); err != nil { + logger.WithError(err).Error("create-account: allocate-stage input verification failed") return nil, fmt.Errorf("hash verification failed after fetch: %w", err) } + logger.Info("create-account: returning allocate-stage input") return input, nil } + logger.Info("create-account: granting validator service user rights") if err := client.ledgerClient.CreateUser(ctx, partyID); err != nil { + logger.WithError(err).Error("create-account: grant user rights failed") return nil, fmt.Errorf("CreateUser failed: %w", err) } + logger.Info("create-account: granted validator service user rights") + logger.Info("create-account: creating external party setup proposal") if err := client.ledgerClient.CreateExternalPartySetupProposal(ctx, partyID); err != nil { + logger.WithError(err).Error("create-account: create external party setup proposal failed") return nil, fmt.Errorf("CreateExternalPartySetupProposal failed: %w", err) } + logger.Info("create-account: created external party setup proposal") + logger.Info("create-account: fetching ledger end") ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) if err != nil { + logger.WithError(err).Error("create-account: get ledger end failed") return nil, fmt.Errorf("failed to get ledger end: %w", err) } + logger.WithField("ledger_end", ledgerEnd).Info("create-account: fetched ledger end") + logger.Info("create-account: fetching active contracts") contracts, err := client.ledgerClient.GetActiveContracts(ctx, partyID, ledgerEnd, true) if err != nil { + logger.WithError(err).Error("create-account: get active contracts failed") return nil, fmt.Errorf("failed to fetch active contracts: %w", err) } + logger.WithField("contract_count", len(contracts)).Info("create-account: fetched active contracts") if client.ledgerClient.HasTransferPreapprovalContract(ctx, contracts) { + logger.Info("create-account: transfer preapproval already exists") return nil, nil } @@ -872,12 +901,19 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient }, } commandID := newRegisterCommandId() + logger.WithFields(logrus.Fields{ + "contract_id": event.GetContractId(), + "template_id": tid.String(), + "command_id": commandID, + }).Info("create-account: preparing setup proposal accept submission") prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, partyID) if err != nil { + logger.WithError(err).Error("create-account: prepare setup proposal accept failed") return nil, fmt.Errorf("failed to prepare ExternalPartySetupProposal_Accept: %w", err) } preparedTxBz, err := proto.Marshal(prepareResp.GetPreparedTransaction()) if err != nil { + logger.WithError(err).Error("create-account: marshal setup proposal prepared transaction failed") return nil, fmt.Errorf("failed to marshal setup proposal prepared transaction: %w", err) } @@ -891,11 +927,17 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient SetupProposalSubmissionID: newRegisterCommandId(), } if err := input.VerifySignaturePayloads(); err != nil { + logger.WithError(err).Error("create-account: accept-stage input verification failed") return nil, fmt.Errorf("hash verification failed after fetch: %w", err) } + logger.WithFields(logrus.Fields{ + "stage": input.Stage, + "submission_id": input.SetupProposalSubmissionID, + }).Info("create-account: returning accept-stage input") return input, nil } + logger.Info("create-account: no further action required") return nil, nil } From d6f0df127a107836d521d8e6f7fb4aa29952cc98 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Mon, 23 Mar 2026 13:03:45 +0100 Subject: [PATCH 05/23] CANTON: Add GetAccountState method --- chain/canton/client/client.go | 58 ++++++++++++++++++++++++++++++- chain/crosschain/account.go | 20 +++++++++++ chain/crosschain/client.go | 2 +- chain/crosschain/client_test.go | 40 +++++++++++++++++++++ chain/crosschain/types/api.go | 6 ++++ client/account.go | 20 +++++++++-- cmd/xc/commands/create_account.go | 2 +- 7 files changed, 143 insertions(+), 5 deletions(-) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 934bcafe..5b204b4b 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -780,7 +780,63 @@ func TxFromInput(args xcbuilder.TransferArgs, input *tx_input.TxInput, decimals return cantontx.NewTx(input, args, decimals) } -var _ xclient.CreateAccountInputClient = &Client{} +var _ xclient.CreateAccountClient = &Client{} + +func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateAccountArgs) (*xclient.AccountState, error) { + partyID := string(args.GetAddress()) + logger := logrus.WithFields(logrus.Fields{ + "chain": client.Asset.GetChain().Chain, + "party_id": partyID, + }) + + exists, err := client.ledgerClient.ExternalPartyExists(ctx, partyID) + if err != nil { + logger.WithError(err).Error("get-account-state: external party registration check failed") + return nil, fmt.Errorf("failed to check external party registration: %w", err) + } + if !exists { + return &xclient.AccountState{ + State: xclient.CreateAccountCallRequired, + Description: "Account is not registered yet. Call create-account to continue.", + }, nil + } + + ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) + if err != nil { + logger.WithError(err).Error("get-account-state: get ledger end failed") + return nil, fmt.Errorf("failed to get ledger end: %w", err) + } + contracts, err := client.ledgerClient.GetActiveContracts(ctx, partyID, ledgerEnd, true) + if err != nil { + logger.WithError(err).Error("get-account-state: get active contracts failed") + return nil, fmt.Errorf("failed to fetch active contracts: %w", err) + } + if client.ledgerClient.HasTransferPreapprovalContract(ctx, contracts) { + return &xclient.AccountState{ + State: xclient.Created, + Description: "Account registration is complete.", + }, nil + } + for _, contract := range contracts { + event := contract.GetCreatedEvent() + if event == nil { + continue + } + tid := event.GetTemplateId() + if tid == nil || tid.GetEntityName() != "ExternalPartySetupProposal" { + continue + } + return &xclient.AccountState{ + State: xclient.CreateAccountCallRequired, + Description: "Account registration requires another create-account call to continue.", + }, nil + } + + return &xclient.AccountState{ + State: xclient.Pending, + Description: "Account registration is in progress. Retry create-account shortly.", + }, nil +} // FetchCreateAccountInput fetches all on-chain data required to register a Canton external party // and advances all registration steps that do not require an explicit external diff --git a/chain/crosschain/account.go b/chain/crosschain/account.go index 66585685..73c34d7d 100644 --- a/chain/crosschain/account.go +++ b/chain/crosschain/account.go @@ -33,3 +33,23 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient } return drivers.UnmarshalCreateAccountInput([]byte(r.TxInput)) } + +func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateAccountArgs) (*xclient.AccountState, error) { + chain := client.Asset.GetChain().Chain + req := &types.CreateAccountInputReq{ + Address: string(args.GetAddress()), + PublicKey: args.GetPublicKey(), + } + + apiURL := fmt.Sprintf("%s/v1/chains/%s/accounts/state", client.URL, chain) + res, err := client.ApiCallWithUrl(ctx, "POST", apiURL, req) + if err != nil { + return nil, err + } + + r := types.AccountStateRes{} + if err := json.Unmarshal(res, &r); err != nil { + return nil, err + } + return r.AccountState, nil +} diff --git a/chain/crosschain/client.go b/chain/crosschain/client.go index 5d6f281d..9c9aa404 100644 --- a/chain/crosschain/client.go +++ b/chain/crosschain/client.go @@ -41,7 +41,7 @@ type Client struct { var _ xclient.Client = &Client{} var _ xclient.StakingClient = &Client{} var _ xclient.MultiTransferClient = &Client{} -var _ xclient.CreateAccountInputClient = &Client{} +var _ xclient.CreateAccountClient = &Client{} const ServiceApiKeyHeader = "x-service-api-key" diff --git a/chain/crosschain/client_test.go b/chain/crosschain/client_test.go index f86fcba5..77d260cf 100644 --- a/chain/crosschain/client_test.go +++ b/chain/crosschain/client_test.go @@ -219,3 +219,43 @@ func (s *CrosschainTestSuite) TestFetchBalanceError() { _, err = client.FetchNativeBalance(s.Ctx, address) require.EqualError(err, "InvalidArgument: api-error") } + +func (s *CrosschainTestSuite) TestGetAccountState() { + require := s.Require() + + resObj := types.AccountStateRes{ + CreateAccountInputReq: &types.CreateAccountInputReq{}, + AccountState: &xclient.AccountState{ + State: xclient.CreateAccountCallRequired, + Description: "Account registration requires another create-account call to continue.", + }, + } + res, _ := json.Marshal(resObj) + + server, close := testtypes.MockHTTP(s.T(), string(res), 200) + defer close() + + client, _ := NewClient(s.Asset, "", "", "", 0) + client.URL = server.URL + + args := xclient.NewCreateAccountArgs(xc.Address("address"), []byte{0x01, 0x02}) + state, err := client.GetAccountState(s.Ctx, args) + require.NoError(err) + require.NotNil(state) + require.Equal(xclient.CreateAccountCallRequired, state.State) + require.Equal("Account registration requires another create-account call to continue.", state.Description) +} + +func (s *CrosschainTestSuite) TestGetAccountStateError() { + require := s.Require() + + server, close := testtypes.MockHTTP(s.T(), `{"code":3,"message":"api-error"}`, 400) + defer close() + + client, _ := NewClient(s.Asset, "", "", "", 0) + client.URL = server.URL + + args := xclient.NewCreateAccountArgs(xc.Address("address"), []byte{0x01, 0x02}) + _, err := client.GetAccountState(s.Ctx, args) + require.EqualError(err, "InvalidArgument: api-error") +} diff --git a/chain/crosschain/types/api.go b/chain/crosschain/types/api.go index caa3e324..c548e70c 100644 --- a/chain/crosschain/types/api.go +++ b/chain/crosschain/types/api.go @@ -7,6 +7,7 @@ import ( xc "github.com/cordialsys/crosschain" "github.com/cordialsys/crosschain/call" + accountclient "github.com/cordialsys/crosschain/client" xclient "github.com/cordialsys/crosschain/client/tx_info" xclient_types "github.com/cordialsys/crosschain/client/types" "github.com/cordialsys/crosschain/pkg/hex" @@ -164,6 +165,11 @@ type CreateAccountInputReq struct { PublicKey hex.Hex `json:"public_key,omitempty"` } +type AccountStateRes struct { + *CreateAccountInputReq + AccountState *accountclient.AccountState `json:"account_state,omitempty"` +} + type LegacyTxInputRes struct { *TransferInputReq xc.TxInput `json:"raw_tx_input,omitempty"` diff --git a/client/account.go b/client/account.go index 45a2cda8..02d603d6 100644 --- a/client/account.go +++ b/client/account.go @@ -6,15 +6,31 @@ import ( xc "github.com/cordialsys/crosschain" ) -// CreateAccountInputClient is an optional client interface for chains that require +// CreateAccountClient is an optional client interface for chains that require // an explicit on-chain account creation or registration step before the account can // receive funds or submit transactions. -type CreateAccountInputClient interface { +type CreateAccountClient interface { // FetchCreateAccountInput advances all account-creation steps that do not need // an external signature. If a signature is needed for the next step, it returns // the corresponding tx input; if registration is already complete, it // returns nil. FetchCreateAccountInput(ctx context.Context, args *CreateAccountArgs) (xc.CreateAccountTxInput, error) + + // GetAccountState returns the current create-account state without mutating it. + GetAccountState(ctx context.Context, args *CreateAccountArgs) (*AccountState, error) +} + +type AccountStateEnum string + +const ( + CreateAccountCallRequired AccountStateEnum = "CreateAccountCallRequired" + Pending AccountStateEnum = "Pending" + Created AccountStateEnum = "Created" +) + +type AccountState struct { + State AccountStateEnum `json:"state"` + Description string `json:"description"` } // CreateAccountArgs carries the parameters for an account creation request. diff --git a/cmd/xc/commands/create_account.go b/cmd/xc/commands/create_account.go index 8d23ef94..bb8e2e77 100644 --- a/cmd/xc/commands/create_account.go +++ b/cmd/xc/commands/create_account.go @@ -57,7 +57,7 @@ func CmdCreateAccount() *cobra.Command { if err != nil { return fmt.Errorf("could not load client: %v", err) } - accountClient, ok := rpcClient.(xclient.CreateAccountInputClient) + accountClient, ok := rpcClient.(xclient.CreateAccountClient) if !ok { return fmt.Errorf("chain %s does not support account creation", chainConfig.Chain) } From 5c43da56a6183f4e892bcf99d0ff23b93d8e89e7 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Tue, 24 Mar 2026 11:35:54 +0100 Subject: [PATCH 06/23] Add AddressBuilder.AddressRegistrationRequired() method --- address.go | 1 + chain/aptos/address.go | 4 ++++ chain/bitcoin/address/address.go | 4 ++++ chain/bitcoin_cash/address.go | 4 ++++ chain/canton/address/address.go | 4 ++++ chain/cardano/address/address.go | 4 ++++ chain/cosmos/address/address.go | 4 ++++ chain/dusk/address/address.go | 4 ++++ chain/egld/address/address.go | 4 ++++ chain/eos/address/address.go | 4 ++++ chain/evm/address/address.go | 4 ++++ chain/filecoin/address/address.go | 4 ++++ chain/hyperliquid/address/address.go | 4 ++++ chain/internet_computer/address/address.go | 4 ++++ chain/kaspa/address/address.go | 4 ++++ chain/near/address/address.go | 4 ++++ chain/solana/address/address.go | 4 ++++ chain/substrate/address/address.go | 4 ++++ chain/sui/address.go | 4 ++++ chain/template/address/address.go | 4 ++++ chain/ton/address/address.go | 4 ++++ chain/tron/address.go | 4 ++++ chain/xlm/address/address.go | 4 ++++ chain/xrp/address/address.go | 4 ++++ chain/zcash/address/encoder.go | 4 ++++ 25 files changed, 97 insertions(+) diff --git a/address.go b/address.go index bf151931..4d926721 100644 --- a/address.go +++ b/address.go @@ -12,6 +12,7 @@ type ContractAddress Address // AddressBuilder is the interface for building addresses type AddressBuilder interface { GetAddressFromPublicKey(publicKeyBytes []byte) (Address, error) + AddressRegistrationRequired(address Address) bool } type AddressBuilderWithFormats interface { diff --git a/chain/aptos/address.go b/chain/aptos/address.go index 9aefe35b..644dc29f 100644 --- a/chain/aptos/address.go +++ b/chain/aptos/address.go @@ -35,3 +35,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr address := "0x" + hex.EncodeToString(authKey[:]) return xc.Address(address), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/bitcoin/address/address.go b/chain/bitcoin/address/address.go index ca2781b4..675c5543 100644 --- a/chain/bitcoin/address/address.go +++ b/chain/bitcoin/address/address.go @@ -195,3 +195,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return "", errors.New("failed to determine bitcoin address type") } } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/bitcoin_cash/address.go b/chain/bitcoin_cash/address.go index fa927683..1c48c23e 100644 --- a/chain/bitcoin_cash/address.go +++ b/chain/bitcoin_cash/address.go @@ -97,6 +97,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(prefix + ":" + encoded), nil } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + func (ab AddressBuilder) GetLegacyAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { addressPubKey, err := NewBchAddressPubKey(publicKeyBytes, ab.params) if err != nil { diff --git a/chain/canton/address/address.go b/chain/canton/address/address.go index 393b24af..096e6067 100644 --- a/chain/canton/address/address.go +++ b/chain/canton/address/address.go @@ -37,6 +37,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return GetAddressFromPublicKey(publicKeyBytes) } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return true +} + func GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { if len(publicKeyBytes) != 32 { return "", fmt.Errorf("invalid ed25519 public key length: expected 32 bytes, got %d", len(publicKeyBytes)) diff --git a/chain/cardano/address/address.go b/chain/cardano/address/address.go index fb4a6cb5..91f01d06 100644 --- a/chain/cardano/address/address.go +++ b/chain/cardano/address/address.go @@ -87,6 +87,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(""), InvalidAddressf(ab.Format) } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + func GetPaymentAddress(publicKeyBytes []byte, withStakeKeyHash bool, isMainnet bool) (xc.Address, error) { // Header consists of 2 parts: // - [0..4] bits: Address type diff --git a/chain/cosmos/address/address.go b/chain/cosmos/address/address.go index 2e80f61f..211c15aa 100644 --- a/chain/cosmos/address/address.go +++ b/chain/cosmos/address/address.go @@ -33,3 +33,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr bech32Addr, err := sdk.Bech32ifyAddressBytes(string(ab.Asset.ChainPrefix), rawAddress) return xc.Address(bech32Addr), err } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/dusk/address/address.go b/chain/dusk/address/address.go index 4380cbce..ebafdfba 100644 --- a/chain/dusk/address/address.go +++ b/chain/dusk/address/address.go @@ -22,6 +22,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(base58.Encode(publicKeyBytes)), nil } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + func GetPublicKeyFromAddress(address xc.Address) (bls.PublicKey[bls.G2], error) { bytes := base58.Decode(string(address)) diff --git a/chain/egld/address/address.go b/chain/egld/address/address.go index cdd254d1..989a0b96 100644 --- a/chain/egld/address/address.go +++ b/chain/egld/address/address.go @@ -28,3 +28,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr bech32Addr, err := bech32.EncodeFromBase256(HRP, publicKeyBytes) return xc.Address(bech32Addr), err } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/eos/address/address.go b/chain/eos/address/address.go index 44239f4b..3b223e9e 100644 --- a/chain/eos/address/address.go +++ b/chain/eos/address/address.go @@ -45,6 +45,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(prefixed), nil } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return true +} + func Ripemd160Checksum(in []byte, curve ecc.CurveID) []byte { h := ripemd160.New() _, _ = h.Write(in) // this implementation has no error path diff --git a/chain/evm/address/address.go b/chain/evm/address/address.go index 5b8d25b3..b37f365d 100644 --- a/chain/evm/address/address.go +++ b/chain/evm/address/address.go @@ -41,6 +41,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(strings.ToLower(address)), nil } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + // FromHex returns a go-ethereum Address decoded Crosschain address (hex string). func FromHex(address xc.Address) (common.Address, error) { str := TrimPrefixes(string(address)) diff --git a/chain/filecoin/address/address.go b/chain/filecoin/address/address.go index ffb81f95..fa42f718 100644 --- a/chain/filecoin/address/address.go +++ b/chain/filecoin/address/address.go @@ -138,6 +138,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(""), fmt.Errorf("invalid algorithm: %s", ab.alghoritm) } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + func hash(ingest []byte, hashSize int) ([]byte, error) { hash, err := blake2b.New(hashSize, nil) if err != nil { diff --git a/chain/hyperliquid/address/address.go b/chain/hyperliquid/address/address.go index 05d9de30..ac5468d0 100644 --- a/chain/hyperliquid/address/address.go +++ b/chain/hyperliquid/address/address.go @@ -40,3 +40,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr // Lowercase the address is our normalized format return xc.Address(strings.ToLower(address)), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/internet_computer/address/address.go b/chain/internet_computer/address/address.go index 8f581719..9192a677 100644 --- a/chain/internet_computer/address/address.go +++ b/chain/internet_computer/address/address.go @@ -95,6 +95,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr } } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + func DerEncodePublicKey(publicKey []byte) ([]byte, error) { return asn1.Marshal(publicKeyInfo{ Algorithm: pkix.AlgorithmIdentifier{ diff --git a/chain/kaspa/address/address.go b/chain/kaspa/address/address.go index 641d6635..5ef4bfcf 100644 --- a/chain/kaspa/address/address.go +++ b/chain/kaspa/address/address.go @@ -29,3 +29,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(asStr), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/near/address/address.go b/chain/near/address/address.go index e54d98cf..b36ca651 100644 --- a/chain/near/address/address.go +++ b/chain/near/address/address.go @@ -21,3 +21,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr hexPk := hex.EncodeToString(publicKeyBytes) return xc.Address(hexPk), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/solana/address/address.go b/chain/solana/address/address.go index ee39ff1e..59db13a8 100644 --- a/chain/solana/address/address.go +++ b/chain/solana/address/address.go @@ -23,3 +23,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr } return xc.Address(base58.Encode(publicKeyBytes)), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/substrate/address/address.go b/chain/substrate/address/address.go index 9b55055d..2202f7f0 100644 --- a/chain/substrate/address/address.go +++ b/chain/substrate/address/address.go @@ -39,6 +39,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(addr), nil } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + func DecodeMulti(addr xc.Address) (types.MultiAddress, error) { decodedVal := base58.Decode(string(addr)) if len(decodedVal) < 34 { diff --git a/chain/sui/address.go b/chain/sui/address.go index 66676186..ea51dd03 100644 --- a/chain/sui/address.go +++ b/chain/sui/address.go @@ -43,3 +43,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr address := "0x" + hex.EncodeToString(addrBytes[:])[:ADDRESS_LENGTH] return xc.Address(address), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/template/address/address.go b/chain/template/address/address.go index 4302db2e..0fe77621 100644 --- a/chain/template/address/address.go +++ b/chain/template/address/address.go @@ -21,3 +21,7 @@ func NewAddressBuilder(cfgI *xc.ChainBaseConfig) (xc.AddressBuilder, error) { func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { return xc.Address(""), errors.New("not implemented") } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/ton/address/address.go b/chain/ton/address/address.go index d17637a3..48a5cea6 100644 --- a/chain/ton/address/address.go +++ b/chain/ton/address/address.go @@ -40,6 +40,10 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(addr.String()), nil } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} + func ParseAddress(addr xc.Address, net string) (*address.Address, error) { addrS := string(addr) if len(strings.Split(addrS, ":")) == 2 { diff --git a/chain/tron/address.go b/chain/tron/address.go index 93603fb6..2c6aff8d 100644 --- a/chain/tron/address.go +++ b/chain/tron/address.go @@ -46,3 +46,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr address, err := GetAddressByPublicKey(hex.EncodeToString(publicKeyBytes)) return xc.Address(address), err } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/xlm/address/address.go b/chain/xlm/address/address.go index 954bba73..3f36cc55 100644 --- a/chain/xlm/address/address.go +++ b/chain/xlm/address/address.go @@ -46,3 +46,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(encoded), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/xrp/address/address.go b/chain/xrp/address/address.go index 47e04703..be0ba0e8 100644 --- a/chain/xrp/address/address.go +++ b/chain/xrp/address/address.go @@ -112,3 +112,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(address), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} diff --git a/chain/zcash/address/encoder.go b/chain/zcash/address/encoder.go index c6fa5bd4..5b44638f 100644 --- a/chain/zcash/address/encoder.go +++ b/chain/zcash/address/encoder.go @@ -56,3 +56,7 @@ func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Addr return xc.Address(address.EncodeAddress()), nil } + +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return false +} From 397efa282befd85e21640cf7381815141cea8270 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Wed, 25 Mar 2026 09:53:46 +0100 Subject: [PATCH 07/23] CANTON: Refactor inputs --- chain/canton/client/client.go | 2 - chain/canton/client/client_test.go | 1 - chain/canton/tx/create_account_tx.go | 14 +++- chain/canton/tx/create_account_tx_test.go | 8 ++- chain/canton/tx/tx.go | 50 +++++++++------ chain/canton/tx/tx_test.go | 34 ++++------ chain/canton/tx_input/create_account_input.go | 10 +-- .../tx_input/create_account_input_test.go | 15 ++++- chain/canton/tx_input/hash_validation.go | 27 +++++--- chain/canton/tx_input/hash_validation_test.go | 22 +++++-- chain/canton/tx_input/topology_hash.go | 64 +++++++++++++++++++ chain/canton/tx_input/topology_hash_test.go | 39 +++++++++++ chain/canton/tx_input/tx_input.go | 1 - 13 files changed, 215 insertions(+), 72 deletions(-) create mode 100644 chain/canton/tx_input/topology_hash.go create mode 100644 chain/canton/tx_input/topology_hash_test.go diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 5b204b4b..a4f24bcd 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -507,7 +507,6 @@ func (client *Client) FetchTransferInput(ctx context.Context, args xcbuilder.Tra } input.PreparedTransaction = *resp.GetPreparedTransaction() - input.Sighash = resp.GetPreparedTransactionHash() input.SubmissionId = NewCommandId() input.HashingSchemeVersion = resp.GetHashingSchemeVersion() @@ -892,7 +891,6 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient Description: "Sign signature_request.payload, append the raw signature hex to tx, then submit the combined hex with `xc submit --chain canton `.", PartyID: partyID, PublicKeyFingerprint: topologyResp.GetPublicKeyFingerprint(), - TopologyMultiHash: topologyResp.GetMultiHash(), TopologyTransactions: txns, } diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index 7b4fab43..ae93529c 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -90,7 +90,6 @@ func mustSerializedCreateAccountInput(t *testing.T) []byte { Stage: tx_input.CreateAccountStageAllocate, PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - TopologyMultiHash: []byte{0xaa, 0xbb}, TopologyTransactions: [][]byte{{0x01}}, } bz, err := input.Serialize() diff --git a/chain/canton/tx/create_account_tx.go b/chain/canton/tx/create_account_tx.go index faf656a8..7d543a39 100644 --- a/chain/canton/tx/create_account_tx.go +++ b/chain/canton/tx/create_account_tx.go @@ -57,7 +57,18 @@ func (tx *CreateAccountTx) Sighashes() ([]*xc.SignatureRequest, error) { if tx == nil || tx.Input == nil { return nil, fmt.Errorf("create-account tx input is nil") } - return tx.Input.Sighashes() + switch tx.Input.Stage { + case tx_input.CreateAccountStageAllocate: + hash, err := tx_input.ComputeTopologyMultiHash(tx.Input.TopologyTransactions) + if err != nil { + return nil, err + } + return []*xc.SignatureRequest{xc.NewSignatureRequest(hash)}, nil + case tx_input.CreateAccountStageAccept: + return tx.Input.Sighashes() + default: + return nil, fmt.Errorf("unsupported create-account stage %q", tx.Input.Stage) + } } func (tx *CreateAccountTx) SetSignatures(sigs ...*xc.SignatureResponse) error { @@ -100,7 +111,6 @@ func cloneCreateAccountInput(input *tx_input.CreateAccountInput) *tx_input.Creat return nil } cloned := *input - cloned.TopologyMultiHash = append([]byte(nil), input.TopologyMultiHash...) cloned.Signature = append([]byte(nil), input.Signature...) cloned.SetupProposalPreparedTransaction = append([]byte(nil), input.SetupProposalPreparedTransaction...) cloned.SetupProposalHash = append([]byte(nil), input.SetupProposalHash...) diff --git a/chain/canton/tx/create_account_tx_test.go b/chain/canton/tx/create_account_tx_test.go index c9cb314e..afa21a80 100644 --- a/chain/canton/tx/create_account_tx_test.go +++ b/chain/canton/tx/create_account_tx_test.go @@ -25,7 +25,6 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { Stage: tx_input.CreateAccountStageAllocate, PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - TopologyMultiHash: []byte{0xaa, 0xbb}, TopologyTransactions: [][]byte{{0x01, 0x02}}, }, }, @@ -49,6 +48,13 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { sighashes, err := tx.Sighashes() require.NoError(t, err) require.Len(t, sighashes, 1) + if tt.input.Stage == tx_input.CreateAccountStageAllocate { + expectedHash, err := tx_input.ComputeTopologyMultiHash(tt.input.TopologyTransactions) + require.NoError(t, err) + require.Equal(t, expectedHash, sighashes[0].Payload) + } else { + require.Equal(t, tt.input.SetupProposalHash, sighashes[0].Payload) + } unsigned, err := tx.Serialize() require.NoError(t, err) diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go index 0cae14bc..ef8e044d 100644 --- a/chain/canton/tx/tx.go +++ b/chain/canton/tx/tx.go @@ -17,12 +17,9 @@ import ( // Tx for Canton holds the data needed for the external-party signing flow: // 1. PreparedTransaction: the proto from InteractiveSubmissionService.PrepareSubmission -// 2. PreparedTransactionHash: raw bytes to sign (Ed25519) -// 3. After SetSignatures: Serialize() marshals the ExecuteSubmissionRequest proto +// 2. After SetSignatures: Serialize() marshals the ExecuteSubmissionRequest proto type Tx struct { PreparedTransaction *interactive.PreparedTransaction - // Raw hash bytes of the prepared transaction (what the party signs) - PreparedTransactionHash []byte // Hashing scheme version returned by prepare endpoint HashingSchemeVersion interactive.HashingSchemeVersion // Party (Canton party ID / address) that is authorizing this transaction @@ -37,9 +34,8 @@ type Tx struct { var _ xc.Tx = &Tx{} -// NewTx constructs a Tx from a TxInput and transfer args, validating that: -// 1. The PreparedTransactionHash matches SHA-256(proto.Marshal(PreparedTransaction)) -// 2. The receiver and amount encoded in the prepared transaction match the transfer args +// NewTx constructs a Tx from a TxInput and transfer args, validating that the +// receiver and amount encoded in the prepared transaction match the transfer args. // // decimals is the chain's native asset decimal places, used to compare blockchain amounts // against the human-readable amounts encoded in the prepared transaction. @@ -50,19 +46,21 @@ func NewTx(input *tx_input.TxInput, args xcbuilder.TransferArgs, decimals int32) } preparedTx := &input.PreparedTransaction - if err := tx_input.ValidatePreparedTransactionHash(preparedTx, input.Sighash); err != nil { + if preparedTx == nil || preparedTx.GetTransaction() == nil { + return nil, fmt.Errorf("prepared transaction is nil") + } + if _, err := tx_input.ComputePreparedTransactionHash(preparedTx); err != nil { return nil, err } if err := validateTransferArgs(preparedTx, args, decimals); err != nil { return nil, err } return &Tx{ - PreparedTransaction: preparedTx, - PreparedTransactionHash: input.Sighash, - HashingSchemeVersion: input.HashingSchemeVersion, - Party: string(args.GetFrom()), - KeyFingerprint: fingerprint, - SubmissionId: input.SubmissionId, + PreparedTransaction: preparedTx, + HashingSchemeVersion: input.HashingSchemeVersion, + Party: string(args.GetFrom()), + KeyFingerprint: fingerprint, + SubmissionId: input.SubmissionId, }, nil } @@ -215,17 +213,29 @@ func compareNumericToBlockchain(numeric string, wantAmount xc.AmountBlockchain, return nil } -// Hash returns a hex string of the prepared transaction hash +func (tx Tx) computedSighash() ([]byte, error) { + if tx.PreparedTransaction == nil { + return nil, fmt.Errorf("prepared transaction is nil") + } + return tx_input.ComputePreparedTransactionHash(tx.PreparedTransaction) +} + +// Hash returns a hex string of the locally derived prepared transaction hash. func (tx Tx) Hash() xc.TxHash { - return xc.TxHash(fmt.Sprintf("%x", tx.PreparedTransactionHash)) + hash, err := tx.computedSighash() + if err != nil { + return "" + } + return xc.TxHash(fmt.Sprintf("%x", hash)) } -// Sighashes returns the raw prepared transaction hash bytes for the party to sign +// Sighashes returns the locally derived prepared transaction hash bytes for the party to sign. func (tx Tx) Sighashes() ([]*xc.SignatureRequest, error) { - if len(tx.PreparedTransactionHash) == 0 { - return nil, fmt.Errorf("prepared transaction hash is empty") + hash, err := tx.computedSighash() + if err != nil { + return nil, err } - return []*xc.SignatureRequest{xc.NewSignatureRequest(tx.PreparedTransactionHash)}, nil + return []*xc.SignatureRequest{xc.NewSignatureRequest(hash)}, nil } // SetSignatures stores the Ed25519 signature from the external party diff --git a/chain/canton/tx/tx_test.go b/chain/canton/tx/tx_test.go index 4f7ef48a..037e8c7d 100644 --- a/chain/canton/tx/tx_test.go +++ b/chain/canton/tx/tx_test.go @@ -1,7 +1,7 @@ package tx import ( - "crypto/sha256" + "fmt" "testing" xc "github.com/cordialsys/crosschain" @@ -11,10 +11,9 @@ import ( "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" ) -func TestNewTx_ValidatesPreparedTransactionHashForTransferFlows(t *testing.T) { +func TestNewTx_UsesPreparedTransactionForTransferFlows(t *testing.T) { t.Parallel() from := xc.Address("sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") @@ -46,16 +45,20 @@ func TestNewTx_ValidatesPreparedTransactionHashForTransferFlows(t *testing.T) { input := &tx_input.TxInput{ PreparedTransaction: *vector.preparedTx, - Sighash: txPreparedTransactionHash(t, vector.preparedTx), SubmissionId: "submission-id", } - _, err = NewTx(input, args, 1) + tx, err := NewTx(input, args, 1) require.NoError(t, err) - input.Sighash[len(input.Sighash)-1] ^= 0xff - _, err = NewTx(input, args, 1) - require.ErrorContains(t, err, "prepared transaction hash mismatch") + hash, err := tx_input.ComputePreparedTransactionHash(vector.preparedTx) + require.NoError(t, err) + + sighashes, err := tx.Sighashes() + require.NoError(t, err) + require.Len(t, sighashes, 1) + require.Equal(t, hash, sighashes[0].Payload) + require.Equal(t, xc.TxHash(fmt.Sprintf("%x", hash)), tx.Hash()) }) } } @@ -77,21 +80,6 @@ func txPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTr } } -func txPreparedTransactionHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { - t.Helper() - hash := mustExpectedHash(t, preparedTx) - require.NoError(t, tx_input.ValidatePreparedTransactionHash(preparedTx, hash)) - return hash -} - -func mustExpectedHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { - t.Helper() - data, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) - require.NoError(t, err) - sum := sha256.Sum256(data) - return sum[:] -} - func txCreateNode(entity string, argument *v2.Value) *v1.Node { return &v1.Node{ NodeType: &v1.Node_Create{ diff --git a/chain/canton/tx_input/create_account_input.go b/chain/canton/tx_input/create_account_input.go index f19324ae..b860ce0b 100644 --- a/chain/canton/tx_input/create_account_input.go +++ b/chain/canton/tx_input/create_account_input.go @@ -30,7 +30,6 @@ type CreateAccountInput struct { PartyID string `json:"party_id"` PublicKeyFingerprint string `json:"public_key_fingerprint,omitempty"` - TopologyMultiHash []byte `json:"topology_multi_hash,omitempty"` TopologyTransactions [][]byte `json:"topology_transactions,omitempty"` SetupProposalPreparedTransaction []byte `json:"setup_proposal_prepared_transaction,omitempty"` @@ -124,10 +123,7 @@ func (i *CreateAccountInput) Serialize() ([]byte, error) { func (i *CreateAccountInput) Sighashes() ([]*xc.SignatureRequest, error) { switch i.Stage { case CreateAccountStageAllocate: - if len(i.TopologyMultiHash) == 0 { - return nil, fmt.Errorf("topology multi-hash is empty") - } - return []*xc.SignatureRequest{xc.NewSignatureRequest(i.TopologyMultiHash)}, nil + return nil, fmt.Errorf("allocate-stage sighash is derived by the Canton create-account tx") case CreateAccountStageAccept: if len(i.SetupProposalHash) == 0 { return nil, fmt.Errorf("setup proposal hash is empty") @@ -152,8 +148,8 @@ func (i *CreateAccountInput) VerifySignaturePayloads() error { } switch i.Stage { case CreateAccountStageAllocate: - if len(i.TopologyMultiHash) == 0 { - return fmt.Errorf("topology multi-hash is empty") + if i.PublicKeyFingerprint == "" { + return fmt.Errorf("public key fingerprint is empty") } if len(i.TopologyTransactions) == 0 { return fmt.Errorf("topology transactions are empty") diff --git a/chain/canton/tx_input/create_account_input_test.go b/chain/canton/tx_input/create_account_input_test.go index 8a85d2bc..b9055907 100644 --- a/chain/canton/tx_input/create_account_input_test.go +++ b/chain/canton/tx_input/create_account_input_test.go @@ -22,7 +22,6 @@ func TestCreateAccountInputSerializeRoundTrip(t *testing.T) { Description: "allocate", PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - TopologyMultiHash: []byte{0xaa, 0xbb, 0xcc}, TopologyTransactions: [][]byte{{0x01, 0x02}, {0x03, 0x04}}, Signature: []byte{0x05, 0x06}, }, @@ -47,7 +46,6 @@ func TestCreateAccountInputSerializeRoundTrip(t *testing.T) { require.Equal(t, tt.input.Description, parsed.Description) require.Equal(t, tt.input.PartyID, parsed.PartyID) require.Equal(t, hex.EncodeToString(tt.input.Signature), hex.EncodeToString(parsed.Signature)) - require.Equal(t, hex.EncodeToString(tt.input.TopologyMultiHash), hex.EncodeToString(parsed.TopologyMultiHash)) require.Equal(t, hex.EncodeToString(tt.input.SetupProposalHash), hex.EncodeToString(parsed.SetupProposalHash)) require.Equal(t, tt.input.SetupProposalSubmissionID, parsed.SetupProposalSubmissionID) require.Equal(t, tt.input.TopologyTransactions, parsed.TopologyTransactions) @@ -66,3 +64,16 @@ func TestCreateAccountInputSetSignatures(t *testing.T) { err = input.SetSignatures() require.ErrorContains(t, err, "expected 1 signature") } + +func TestCreateAccountInputVerifySignaturePayloadsAllocateStage(t *testing.T) { + t.Parallel() + + input := &CreateAccountInput{ + Stage: CreateAccountStageAllocate, + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + TopologyTransactions: [][]byte{{0x01, 0x02}}, + } + + require.NoError(t, input.VerifySignaturePayloads()) +} diff --git a/chain/canton/tx_input/hash_validation.go b/chain/canton/tx_input/hash_validation.go index 0a094c53..9e8ff2bb 100644 --- a/chain/canton/tx_input/hash_validation.go +++ b/chain/canton/tx_input/hash_validation.go @@ -9,24 +9,35 @@ import ( "google.golang.org/protobuf/proto" ) +// ComputePreparedTransactionHash returns the current local hash of a prepared +// transaction. This is the payload Canton transfer txs sign today. +func ComputePreparedTransactionHash(preparedTx *interactive.PreparedTransaction) ([]byte, error) { + if preparedTx == nil { + return nil, fmt.Errorf("prepared transaction is nil") + } + + encoded, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) + if err != nil { + return nil, fmt.Errorf("failed to marshal prepared transaction for hashing: %w", err) + } + digest := sha256.Sum256(encoded) + return digest[:], nil +} + // ValidatePreparedTransactionHash recomputes SHA-256 over the canonical proto // encoding of PreparedTransaction and checks it matches the hash supplied by the // prepare endpoint. func ValidatePreparedTransactionHash(preparedTx *interactive.PreparedTransaction, expectedHash []byte) error { - if preparedTx == nil { - return fmt.Errorf("prepared transaction is nil") - } if len(expectedHash) == 0 { return fmt.Errorf("prepared transaction hash is empty") } - encoded, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) + digest, err := ComputePreparedTransactionHash(preparedTx) if err != nil { - return fmt.Errorf("failed to marshal prepared transaction for hash verification: %w", err) + return err } - digest := sha256.Sum256(encoded) - if !bytes.Equal(digest[:], expectedHash) { - return fmt.Errorf("prepared transaction hash mismatch: expected %x, got %x", expectedHash, digest[:]) + if !bytes.Equal(digest, expectedHash) { + return fmt.Errorf("prepared transaction hash mismatch: expected %x, got %x", expectedHash, digest) } return nil diff --git a/chain/canton/tx_input/hash_validation_test.go b/chain/canton/tx_input/hash_validation_test.go index a5cb795f..6c4a70cd 100644 --- a/chain/canton/tx_input/hash_validation_test.go +++ b/chain/canton/tx_input/hash_validation_test.go @@ -1,7 +1,6 @@ package tx_input import ( - "crypto/sha256" "encoding/hex" "encoding/json" "os" @@ -14,6 +13,21 @@ import ( "google.golang.org/protobuf/proto" ) +func TestComputePreparedTransactionHash(t *testing.T) { + t.Parallel() + + preparedTx := testPreparedTransaction("node-1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))) + + hash1, err := ComputePreparedTransactionHash(preparedTx) + require.NoError(t, err) + + hash2, err := ComputePreparedTransactionHash(preparedTx) + require.NoError(t, err) + + require.Equal(t, hash1, hash2) + require.NotEmpty(t, hash1) +} + func TestValidatePreparedTransactionHash_Flows(t *testing.T) { t.Parallel() @@ -146,11 +160,9 @@ func testPreparedTransaction(nodeID string, node *v1.Node) *interactive.Prepared func testPreparedTransactionHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { t.Helper() - data, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) + hash, err := ComputePreparedTransactionHash(preparedTx) require.NoError(t, err) - - sum := sha256.Sum256(data) - return sum[:] + return hash } func testCreateNode(entity string, argument *v2.Value) *v1.Node { diff --git a/chain/canton/tx_input/topology_hash.go b/chain/canton/tx_input/topology_hash.go new file mode 100644 index 00000000..57979125 --- /dev/null +++ b/chain/canton/tx_input/topology_hash.go @@ -0,0 +1,64 @@ +package tx_input + +import ( + "crypto/sha256" + "encoding/binary" + "fmt" + "slices" +) + +const ( + topologyTransactionHashPurpose = 11 + topologyMultiHashPurpose = 55 +) + +var sha256MultihashPrefix = []byte{0x12, 0x20} + +func ComputeTopologyTransactionHash(serializedTx []byte) ([]byte, error) { + if len(serializedTx) == 0 { + return nil, fmt.Errorf("topology transaction is empty") + } + return computeCantonHash(topologyTransactionHashPurpose, serializedTx), nil +} + +func ComputeTopologyMultiHash(serializedTxs [][]byte) ([]byte, error) { + if len(serializedTxs) == 0 { + return nil, fmt.Errorf("topology transactions are empty") + } + + hashes := make([][]byte, 0, len(serializedTxs)) + for _, tx := range serializedTxs { + hash, err := ComputeTopologyTransactionHash(tx) + if err != nil { + return nil, err + } + hashes = append(hashes, hash) + } + + slices.SortFunc(hashes, func(a, b []byte) int { + return slices.Compare(a, b) + }) + + combined := make([]byte, 4) + binary.BigEndian.PutUint32(combined, uint32(len(hashes))) + for _, hash := range hashes { + size := make([]byte, 4) + binary.BigEndian.PutUint32(size, uint32(len(hash))) + combined = append(combined, size...) + combined = append(combined, hash...) + } + + return computeCantonHash(topologyMultiHashPurpose, combined), nil +} + +func computeCantonHash(purpose uint32, content []byte) []byte { + payload := make([]byte, 4+len(content)) + binary.BigEndian.PutUint32(payload[:4], purpose) + copy(payload[4:], content) + sum := sha256.Sum256(payload) + + result := make([]byte, 0, len(sha256MultihashPrefix)+len(sum)) + result = append(result, sha256MultihashPrefix...) + result = append(result, sum[:]...) + return result +} diff --git a/chain/canton/tx_input/topology_hash_test.go b/chain/canton/tx_input/topology_hash_test.go new file mode 100644 index 00000000..d5b41959 --- /dev/null +++ b/chain/canton/tx_input/topology_hash_test.go @@ -0,0 +1,39 @@ +package tx_input + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestComputeTopologyTransactionHash(t *testing.T) { + t.Parallel() + + hash, err := ComputeTopologyTransactionHash([]byte{0x01, 0x02, 0x03}) + require.NoError(t, err) + require.Equal(t, "1220c1467c073293cec489633f24df12269d37f5fc14c5e7793119703965b001b751", hex.EncodeToString(hash)) +} + +func TestComputeTopologyMultiHash(t *testing.T) { + t.Parallel() + + hash1, err := ComputeTopologyMultiHash([][]byte{{0x01, 0x02}, {0x03, 0x04}}) + require.NoError(t, err) + + hash2, err := ComputeTopologyMultiHash([][]byte{{0x03, 0x04}, {0x01, 0x02}}) + require.NoError(t, err) + + require.Equal(t, hash1, hash2) + require.Equal(t, "122086be10f2f6a61410ec823c4350eb8eef35b66481a0dd080f2607f15f7d3b57ef", hex.EncodeToString(hash1)) +} + +func TestComputeTopologyMultiHashFailures(t *testing.T) { + t.Parallel() + + _, err := ComputeTopologyMultiHash(nil) + require.ErrorContains(t, err, "topology transactions are empty") + + _, err = ComputeTopologyMultiHash([][]byte{{}}) + require.ErrorContains(t, err, "topology transaction is empty") +} diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index 87ef3478..80da75de 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -12,7 +12,6 @@ type TxInput struct { xc.TxInputEnvelope IsExternalTransfer bool `json:"is_external_transfer"` PreparedTransaction interactive.PreparedTransaction - Sighash []byte `json:"sighash"` HashingSchemeVersion interactive.HashingSchemeVersion // SubmissionId for deduplication (UUID) SubmissionId string `json:"submission_id"` From e548a61f0849544af4652b1c8919633b2a6fa545 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:29:57 +0100 Subject: [PATCH 08/23] CANTON: Fix tx-info lookup --- chain/canton/client/client.go | 649 ++++++++---------- chain/canton/client/client_test.go | 409 +++++++++++ chain/canton/client/command_builders.go | 213 ++++++ chain/canton/client/ledger.go | 104 ++- chain/canton/proto/helpers.go | 118 ++++ chain/canton/proto/helpers_test.go | 63 ++ chain/canton/tx/tx.go | 38 +- chain/canton/tx/tx_test.go | 38 +- chain/canton/tx_input/hash_validation.go | 648 ++++++++++++++++- chain/canton/tx_input/hash_validation_test.go | 42 +- chain/canton/tx_input/tx_input.go | 1 + 11 files changed, 1866 insertions(+), 457 deletions(-) create mode 100644 chain/canton/client/command_builders.go create mode 100644 chain/canton/proto/helpers.go create mode 100644 chain/canton/proto/helpers_test.go diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index a4f24bcd..e7b91392 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -13,6 +13,7 @@ import ( xcbuilder "github.com/cordialsys/crosschain/builder" cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" cantonkc "github.com/cordialsys/crosschain/chain/canton/keycloak" + cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" xclient "github.com/cordialsys/crosschain/client" @@ -23,7 +24,6 @@ import ( "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/durationpb" ) // Client for Canton using the gRPC Ledger API @@ -111,74 +111,8 @@ func (client *Client) cantonUIToken(ctx context.Context) (string, error) { } func (client *Client) PrepareTransferOfferCommand(ctx context.Context, args xcbuilder.TransferArgs, amuletRules AmuletRules) (*interactive.PrepareSubmissionResponse, error) { - // amount := args.GetAmount() - // amountStr := amount.ToHuman(10) - commandID := newRegisterCommandId() - cmd := &v2.Command{ - Command: &v2.Command_Create{ - Create: &v2.CreateCommand{ - TemplateId: &v2.Identifier{ - // TODO: Fetch via KnownPackages and match on splice-wallet version from amulet rules - PackageId: "fd57252dda29e3ce90028114c91b521cb661df5a9d6e87c41a9e91518215fa5b", - ModuleName: "Splice.Wallet.TransferOffer", - EntityName: "TransferOffer", - }, - CreateArguments: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "sender", - Value: &v2.Value{Sum: &v2.Value_Party{Party: string(args.GetFrom())}}, - }, - { - Label: "receiver", - Value: &v2.Value{Sum: &v2.Value_Party{Party: string(args.GetTo())}}, - }, - { - Label: "dso", - Value: &v2.Value{Sum: &v2.Value_Party{Party: amuletRules.AmuletRulesUpdate.Contract.Payload.DSO}}, - }, - { - Label: "amount", - Value: &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "amount", - Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: "10.0"}}, // hardcode for now - }, - { - Label: "unit", - Value: &v2.Value{ - Sum: &v2.Value_Enum{ - Enum: &v2.Enum{ - Constructor: "AmuletUnit", - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - Label: "description", - Value: &v2.Value{Sum: &v2.Value_Text{Text: ""}}, - }, - { - Label: "expiresAt", - Value: &v2.Value{Sum: &v2.Value_Timestamp{Timestamp: time.Now().UTC().Add(24 * time.Hour).UnixMicro()}}, - }, - { - Label: "trackingId", - Value: &v2.Value{Sum: &v2.Value_Text{Text: commandID}}, - }, - }, - }, - }, - }, - } + commandID := cantonproto.NewCommandID() + cmd := buildTransferOfferCreateCommand(args, amuletRules, commandID) prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, string(args.GetFrom())) if err != nil { @@ -203,248 +137,12 @@ func (client *Client) PrepareTransferPreapprovalCommand( recipientContracts []*v2.ActiveContract, ) (*interactive.PrepareSubmissionResponse, error) { senderPartyID := string(args.GetFrom()) - - // Find the recipient's TransferPreapproval contract. - var preapprovalContractID string - var preapprovalTemplateID *v2.Identifier - for _, c := range recipientContracts { - event := c.GetCreatedEvent() - if event == nil { - continue - } - tid := event.GetTemplateId() - if tid != nil && isPreapprovalTemplate(tid) { - preapprovalContractID = event.GetContractId() - preapprovalTemplateID = tid - break - } - } - if preapprovalContractID == "" { - return nil, fmt.Errorf("no TransferPreapproval contract found for recipient %s", args.GetTo()) - } - - // Build sender's amulet inputs. - transferInputs := make([]*v2.Value, 0) - for _, ac := range senderContracts { - event := ac.GetCreatedEvent() - if event == nil { - continue - } - if event.GetTemplateId().GetEntityName() != "Amulet" { - continue - } - transferInputs = append(transferInputs, &v2.Value{ - Sum: &v2.Value_Variant{ - Variant: &v2.Variant{ - Constructor: "InputAmulet", - Value: &v2.Value{ - Sum: &v2.Value_ContractId{ - ContractId: event.GetContractId(), - }, - }, - }, - }, - }) - } - - amuletRulesID := amuletRules.AmuletRulesUpdate.Contract.ContractID - openMiningRoundID := openMiningRound.Contract.ContractID - - rn, err := strconv.ParseInt(issuingMiningRound.Contract.Payload.Round.Number, 10, 64) + cmd, disclosedContracts, err := buildTransferPreapprovalExerciseCommand(args, amuletRules, openMiningRound, issuingMiningRound, senderContracts, recipientContracts) if err != nil { - return nil, fmt.Errorf("failed to parse issuing mining round number: %w", err) - } - issuingMiningRounds := &v2.Value{ - Sum: &v2.Value_GenMap{ - GenMap: &v2.GenMap{ - Entries: []*v2.GenMap_Entry{ - { - Key: &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "number", - Value: &v2.Value{Sum: &v2.Value_Int64{Int64: rn}}, - }, - }, - }, - }, - }, - Value: &v2.Value{ - Sum: &v2.Value_ContractId{ - ContractId: issuingMiningRound.Contract.ContractID, - }, - }, - }, - }, - }, - }, - } - - // Build disclosed contracts: TransferPreapproval + sender amulets + AmuletRules + OpenMiningRound + IssuingMiningRound. - disclosedContracts := make([]*v2.DisclosedContract, 0) - - // Disclose the recipient's TransferPreapproval contract (the one being exercised). - for _, ac := range recipientContracts { - event := ac.GetCreatedEvent() - if event == nil { - continue - } - if tid := event.GetTemplateId(); tid != nil && isPreapprovalTemplate(tid) { - disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ - TemplateId: tid, - ContractId: event.GetContractId(), - CreatedEventBlob: event.GetCreatedEventBlob(), - }) - break - } - } - - for _, ac := range senderContracts { - event := ac.GetCreatedEvent() - if event == nil || event.GetTemplateId().GetEntityName() != "Amulet" { - continue - } - disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ - TemplateId: event.GetTemplateId(), - ContractId: event.GetContractId(), - CreatedEventBlob: event.GetCreatedEventBlob(), - }) - } - - // Disclose AmuletRules. - amuletRulesTemplateParts := strings.SplitN(amuletRules.AmuletRulesUpdate.Contract.TemplateID, ":", 3) - if len(amuletRulesTemplateParts) == 3 { - disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ - TemplateId: &v2.Identifier{ - PackageId: amuletRulesTemplateParts[0], - ModuleName: amuletRulesTemplateParts[1], - EntityName: amuletRulesTemplateParts[2], - }, - ContractId: amuletRulesID, - CreatedEventBlob: amuletRules.AmuletRulesUpdate.Contract.CreatedEventBlob, - }) - } - - openParts := strings.Split(openMiningRound.Contract.TemplateID, ":") - if len(openParts) == 3 { - disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ - TemplateId: &v2.Identifier{ - PackageId: openParts[0], - ModuleName: openParts[1], - EntityName: openParts[2], - }, - ContractId: openMiningRoundID, - CreatedEventBlob: openMiningRound.Contract.CreatedEventBlob, - }) - } - - issuingParts := strings.Split(issuingMiningRound.Contract.TemplateID, ":") - if len(issuingParts) == 3 { - disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ - TemplateId: &v2.Identifier{ - PackageId: issuingParts[0], - ModuleName: issuingParts[1], - EntityName: issuingParts[2], - }, - ContractId: issuingMiningRound.Contract.ContractID, - CreatedEventBlob: issuingMiningRound.Contract.CreatedEventBlob, - }) - } - - cmd := &v2.Command{ - Command: &v2.Command_Exercise{ - Exercise: &v2.ExerciseCommand{ - TemplateId: preapprovalTemplateID, - ContractId: preapprovalContractID, - Choice: "TransferPreapproval_Send", - ChoiceArgument: &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "sender", - Value: &v2.Value{Sum: &v2.Value_Party{Party: senderPartyID}}, - }, - { - Label: "inputs", - Value: &v2.Value{ - Sum: &v2.Value_List{ - List: &v2.List{Elements: transferInputs}, - }, - }, - }, - { - Label: "amount", - Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: "10.0"}}, - }, - { - Label: "context", - Value: &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "amuletRules", - Value: &v2.Value{Sum: &v2.Value_ContractId{ContractId: amuletRulesID}}, - }, - { - Label: "context", - Value: &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "openMiningRound", - Value: &v2.Value{Sum: &v2.Value_ContractId{ContractId: openMiningRoundID}}, - }, - { - Label: "issuingMiningRounds", - Value: issuingMiningRounds, - }, - { - Label: "validatorRights", - Value: &v2.Value{ - Sum: &v2.Value_GenMap{ - GenMap: &v2.GenMap{Entries: []*v2.GenMap_Entry{}}, - }, - }, - }, - { - Label: "featuredAppRight", - Value: &v2.Value{ - Sum: &v2.Value_Optional{Optional: &v2.Optional{}}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - commandID := newRegisterCommandId() - prepareReq := &interactive.PrepareSubmissionRequest{ - CommandId: commandID, - Commands: []*v2.Command{cmd}, - ActAs: []string{senderPartyID}, - ReadAs: []string{senderPartyID, ValidatorPartyId}, - SynchronizerId: TestnetSynchronizerID, - DisclosedContracts: disclosedContracts, - VerboseHashing: false, + return nil, err } + commandID := cantonproto.NewCommandID() + prepareReq := cantonproto.NewPrepareRequest(commandID, TestnetSynchronizerID, []string{senderPartyID}, []string{senderPartyID, ValidatorPartyId}, []*v2.Command{cmd}, disclosedContracts) authCtx := client.ledgerClient.authCtx(ctx) prepareResp, err := client.ledgerClient.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) @@ -478,6 +176,7 @@ func (client *Client) FetchTransferInput(ctx context.Context, args xcbuilder.Tra } isExternal := client.ledgerClient.HasTransferPreapprovalContract(ctx, recipientContracts) input.IsExternalTransfer = isExternal + input.LedgerEnd = ledgerEnd uiToken, err := client.cantonUIToken(ctx) if err != nil { @@ -581,15 +280,32 @@ func (client *Client) FetchLegacyTxInfo(ctx context.Context, txHash xc.TxHash) ( return txinfo.LegacyTxInfo{}, errors.New("not implemented") } +type amuletCreation struct { + owner string + amount xc.AmountBlockchain +} + // FetchTxInfo fetches and normalizes transaction info for a Canton update by its updateId. -// The txHash must be the Canton updateId returned after submission. +// Recovery tokens in the form "-" are resolved via the completion stream. func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinfo.TxInfo, error) { - updateId := string(args.TxHash()) + lookupId := string(args.TxHash()) + sender, hasSender := args.Sender() + if !hasSender { + return txinfo.TxInfo{}, fmt.Errorf("canton tx-info lookup for %q requires sender address", lookupId) + } + + updateId := lookupId + if beginExclusive, submissionId, ok := parseRecoveryLookupId(lookupId); ok { + resolvedUpdateId, err := client.ledgerClient.RecoverUpdateIdBySubmissionId(ctx, beginExclusive, string(sender), submissionId) + if err != nil { + return txinfo.TxInfo{}, fmt.Errorf("failed to resolve Canton recovery token %q: %w", lookupId, err) + } + updateId = resolvedUpdateId + } chainCfg := client.Asset.GetChain() decimals := chainCfg.Decimals - // Use admin token for lookup — the updateId is ledger-global - resp, err := client.ledgerClient.GetUpdateById(ctx, updateId) + resp, err := client.ledgerClient.GetUpdateById(ctx, string(sender), updateId) if err != nil { return txinfo.TxInfo{}, fmt.Errorf("failed to fetch update: %w", err) } @@ -614,24 +330,31 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf if ts := tx.GetEffectiveAt(); ts != nil { blockTime = ts.AsTime() } - block := txinfo.NewBlock(chainCfg.Chain, uint64(txOffset), tx.GetSynchronizerId(), blockTime) + blockIdentifier := fmt.Sprintf("%s/%d", tx.GetSynchronizerId(), txOffset) + block := txinfo.NewBlock(chainCfg.Chain, uint64(txOffset), blockIdentifier, blockTime) txInfo := txinfo.NewTxInfo(block, client.Asset, updateId, confirmations, nil) - - // Scan events: find the acting party (sender) from exercised events and - // new Amulet owner (receiver) + amount from created Amulet events. - var senderParty string - type amuletCreation struct { - owner string - amount xc.AmountBlockchain + if lookupId != updateId { + txInfo.LookupId = lookupId } + + // Use the caller-provided sender as the source of truth for Canton tx-info. + senderParty := string(sender) + zero := xc.NewAmountBlockchainFromUint64(0) + var transferOutputs []amuletCreation + totalFee := xc.NewAmountBlockchainFromUint64(0) var amuletCreations []amuletCreation for _, event := range tx.GetEvents() { if ex := event.GetExercised(); ex != nil { - // The acting party on transfer-related choices is the sender if len(ex.GetActingParties()) > 0 && senderParty == "" { senderParty = ex.GetActingParties()[0] } + if outputs, ok := extractTransferOutputs(ex, decimals); ok { + transferOutputs = append(transferOutputs, outputs...) + } + if fee, ok := extractTransferFee(ex, decimals); ok { + totalFee = totalFee.Add(&fee) + } } if cr := event.GetCreated(); cr != nil { tid := cr.GetTemplateId() @@ -660,10 +383,21 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf } } - // Build movements: one per new Amulet contract created for a non-sender owner + if len(transferOutputs) > 0 { + for _, out := range transferOutputs { + txInfo.AddSimpleTransfer(xc.Address(senderParty), xc.Address(out.owner), "", out.amount, nil, "") + } + if totalFee.Cmp(&zero) > 0 { + txInfo.AddFee(xc.Address(senderParty), "", totalFee, nil) + } + txInfo.Fees = txInfo.CalculateFees() + txInfo.SyncDeprecatedFields() + return *txInfo, nil + } + + // Fall back to created Amulets only when there is no explicit transfer exercise payload. for _, ac := range amuletCreations { if ac.owner == senderParty { - // This is change going back to the sender, not the primary transfer destination continue } from := xc.Address(senderParty) @@ -671,8 +405,8 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf txInfo.AddSimpleTransfer(from, to, "", ac.amount, nil, "") } - // If we couldn't distinguish sender from receiver (e.g. self-transfer or change only), - // fall back to reporting all creations + // If we couldn't distinguish sender from receiver (e.g. self-transfer), fall back to + // reporting all sender-visible created Amulets. if len(txInfo.Movements) == 0 && len(amuletCreations) > 0 { for _, ac := range amuletCreations { from := xc.Address(senderParty) @@ -680,12 +414,221 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf txInfo.AddSimpleTransfer(from, to, "", ac.amount, nil, "") } } + if totalFee.Cmp(&zero) > 0 { + txInfo.AddFee(xc.Address(senderParty), "", totalFee, nil) + } txInfo.Fees = txInfo.CalculateFees() txInfo.SyncDeprecatedFields() return *txInfo, nil } +func extractTransferOutputs(ex *v2.ExercisedEvent, decimals int32) ([]amuletCreation, bool) { + tid := ex.GetTemplateId() + if tid == nil || tid.GetModuleName() != "Splice.AmuletRules" || ex.GetChoice() != "AmuletRules_Transfer" { + return nil, false + } + + arg := ex.GetChoiceArgument() + if arg == nil { + return nil, false + } + root := arg.GetRecord() + if root == nil { + return nil, false + } + + var transferRecord *v2.Record + for _, field := range root.GetFields() { + if field.GetLabel() == "transfer" { + transferRecord = field.GetValue().GetRecord() + break + } + } + if transferRecord == nil { + return nil, false + } + + var outputs []*v2.Value + for _, field := range transferRecord.GetFields() { + if field.GetLabel() == "outputs" { + if list := field.GetValue().GetList(); list != nil { + outputs = list.GetElements() + } + break + } + } + if len(outputs) == 0 { + return nil, false + } + + parsed := make([]amuletCreation, 0, len(outputs)) + for _, output := range outputs { + record := output.GetRecord() + if record == nil { + continue + } + var receiver string + var amount xc.AmountBlockchain + var ok bool + for _, field := range record.GetFields() { + switch field.GetLabel() { + case "receiver": + receiver = field.GetValue().GetParty() + case "amount": + amount, ok = extractNumericValue(field.GetValue(), decimals) + } + } + if receiver == "" || !ok { + continue + } + parsed = append(parsed, amuletCreation{owner: receiver, amount: amount}) + } + if len(parsed) == 0 { + return nil, false + } + return parsed, true +} + +func extractNumericValue(value *v2.Value, decimals int32) (xc.AmountBlockchain, bool) { + if value == nil { + return xc.AmountBlockchain{}, false + } + numeric := value.GetNumeric() + if numeric == "" { + return xc.AmountBlockchain{}, false + } + human, err := xc.NewAmountHumanReadableFromStr(numeric) + if err != nil { + return xc.AmountBlockchain{}, false + } + return human.ToBlockchain(decimals), true +} + +func extractTransferFee(ex *v2.ExercisedEvent, decimals int32) (xc.AmountBlockchain, bool) { + tid := ex.GetTemplateId() + if tid == nil || tid.GetModuleName() != "Splice.AmuletRules" || ex.GetChoice() != "AmuletRules_Transfer" { + return xc.AmountBlockchain{}, false + } + + result := ex.GetExerciseResult() + if result == nil { + return xc.AmountBlockchain{}, false + } + record := result.GetRecord() + if record == nil { + return xc.AmountBlockchain{}, false + } + + if burned, ok := extractBurnedFee(record, decimals); ok { + return burned, true + } + if summaryFee, ok := extractSummaryFee(record, decimals); ok { + return summaryFee, true + } + return xc.AmountBlockchain{}, false +} + +func extractBurnedFee(record *v2.Record, decimals int32) (xc.AmountBlockchain, bool) { + metaRecord := findRecordField(record, "meta") + if metaRecord == nil { + return xc.AmountBlockchain{}, false + } + valuesRecord := findRecordField(metaRecord, "values") + if valuesRecord == nil { + return xc.AmountBlockchain{}, false + } + burnedText, ok := extractTextMapValue(valuesRecord, "splice.lfdecentralizedtrust.org/burned") + if !ok || burnedText == "" { + return xc.AmountBlockchain{}, false + } + return parseHumanAmountToBlockchain(burnedText, decimals) +} + +func extractSummaryFee(record *v2.Record, decimals int32) (xc.AmountBlockchain, bool) { + summaryRecord := findRecordField(record, "summary") + if summaryRecord == nil { + return xc.AmountBlockchain{}, false + } + + total := xc.NewAmountBlockchainFromUint64(0) + found := false + + if senderChangeFeeValue, ok := findValueField(summaryRecord, "senderChangeFee"); ok { + if fee, ok := extractNumericValue(senderChangeFeeValue, decimals); ok { + total = total.Add(&fee) + found = true + } + } + if outputFeesValue, ok := findValueField(summaryRecord, "outputFees"); ok { + if list := outputFeesValue.GetList(); list != nil { + for _, elem := range list.GetElements() { + fee, ok := extractNumericValue(elem, decimals) + if !ok { + continue + } + total = total.Add(&fee) + found = true + } + } + } + + if !found { + return xc.AmountBlockchain{}, false + } + return total, true +} + +func findRecordField(record *v2.Record, label string) *v2.Record { + value, ok := findValueField(record, label) + if !ok { + return nil + } + return value.GetRecord() +} + +func findValueField(record *v2.Record, label string) (*v2.Value, bool) { + if record == nil { + return nil, false + } + for _, field := range record.GetFields() { + if field.GetLabel() == label { + return field.GetValue(), true + } + } + return nil, false +} + +func extractTextMapValue(record *v2.Record, key string) (string, bool) { + for _, field := range record.GetFields() { + if field.GetLabel() != key { + continue + } + return field.GetValue().GetText(), true + } + return "", false +} + +func parseHumanAmountToBlockchain(value string, decimals int32) (xc.AmountBlockchain, bool) { + human, err := xc.NewAmountHumanReadableFromStr(value) + if err != nil { + return xc.AmountBlockchain{}, false + } + return human.ToBlockchain(decimals), true +} + +func parseRecoveryLookupId(value string) (int64, string, bool) { + idx := strings.Index(value, "-") + if idx <= 0 || idx == len(value)-1 { + return 0, "", false + } + beginExclusive, err := strconv.ParseInt(value[:idx], 10, 64) + if err != nil { + return 0, "", false + } + return beginExclusive, value[idx+1:], true +} + func (client *Client) FetchBalance(ctx context.Context, args *xclient.BalanceArgs) (xc.AmountBlockchain, error) { zero := xc.NewAmountBlockchainFromUint64(0) if contract, ok := args.Contract(); ok { @@ -944,17 +887,8 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient continue } - cmd := &v2.Command{ - Command: &v2.Command_Exercise{ - Exercise: &v2.ExerciseCommand{ - TemplateId: tid, - ContractId: event.GetContractId(), - Choice: "ExternalPartySetupProposal_Accept", - ChoiceArgument: &v2.Value{Sum: &v2.Value_Record{Record: &v2.Record{}}}, - }, - }, - } - commandID := newRegisterCommandId() + cmd := buildExternalPartySetupProposalAcceptCommand(tid, event.GetContractId()) + commandID := cantonproto.NewCommandID() logger.WithFields(logrus.Fields{ "contract_id": event.GetContractId(), "template_id": tid.String(), @@ -1007,21 +941,8 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx switch cantonInput.Stage { case tx_input.CreateAccountStageAllocate: - txns := make([]*admin.AllocateExternalPartyRequest_SignedTransaction, 0, len(cantonInput.TopologyTransactions)) - for _, txBytes := range cantonInput.TopologyTransactions { - txns = append(txns, &admin.AllocateExternalPartyRequest_SignedTransaction{Transaction: txBytes}) - } - sig := &v2.Signature{ - Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, - Signature: cantonInput.Signature, - SignedBy: cantonInput.PublicKeyFingerprint, - SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, - } - _, err := client.ledgerClient.adminClient.AllocateExternalParty(authCtx, &admin.AllocateExternalPartyRequest{ - Synchronizer: TestnetSynchronizerID, - OnboardingTransactions: txns, - MultiHashSignatures: []*v2.Signature{sig}, - }) + req := cantonproto.NewAllocateExternalPartyRequest(TestnetSynchronizerID, cantonInput.TopologyTransactions, cantonInput.Signature, cantonInput.PublicKeyFingerprint) + _, err := client.ledgerClient.adminClient.AllocateExternalParty(authCtx, req) if err != nil && !isAlreadyExists(err) { return fmt.Errorf("AllocateExternalParty failed: %w", err) } @@ -1035,29 +956,7 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx if err != nil { return fmt.Errorf("failed to determine signing fingerprint for setup proposal accept: %w", err) } - executeReq := &interactive.ExecuteSubmissionAndWaitRequest{ - PreparedTransaction: &preparedTx, - PartySignatures: &interactive.PartySignatures{ - Signatures: []*interactive.SinglePartySignatures{ - { - Party: cantonInput.PartyID, - Signatures: []*v2.Signature{ - { - Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, - Signature: cantonInput.Signature, - SignedBy: keyFingerprint, - SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, - }, - }, - }, - }, - }, - DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ - DeduplicationDuration: durationpb.New(300 * time.Second), - }, - SubmissionId: cantonInput.SetupProposalSubmissionID, - HashingSchemeVersion: cantonInput.SetupProposalHashing, - } + executeReq := cantonproto.NewExecuteSubmissionAndWaitRequest(&preparedTx, cantonInput.PartyID, cantonInput.Signature, keyFingerprint, cantonInput.SetupProposalSubmissionID, cantonInput.SetupProposalHashing) _, err = client.ledgerClient.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) if err != nil && !isAlreadyExists(err) { return fmt.Errorf("ExternalPartySetupProposal_Accept failed: %w", err) diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index ae93529c..ba0e9121 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -2,16 +2,22 @@ package client import ( "context" + "io" "testing" + "time" xc "github.com/cordialsys/crosschain" "github.com/cordialsys/crosschain/chain/canton/tx_input" + txinfo "github.com/cordialsys/crosschain/client/tx_info" xctypes "github.com/cordialsys/crosschain/client/types" + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/timestamppb" ) func TestNewClient(t *testing.T) { @@ -84,6 +90,202 @@ func TestSubmitTxExecutesStandardCantonPayload(t *testing.T) { require.Equal(t, "submission-id", stub.lastReq.GetSubmissionId()) } +func TestFetchTxInfoResolvesRecoveryLookupId(t *testing.T) { + t.Parallel() + + sender := "sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + updateStub := &updateServiceStub{ + resp: &v2.GetUpdateResponse{ + Update: &v2.GetUpdateResponse_Transaction{ + Transaction: &v2.Transaction{ + UpdateId: "update-123", + Offset: 105, + SynchronizerId: "sync-id", + EffectiveAt: timestamppb.New(time.Unix(1700000000, 0)), + }, + }, + }, + } + completionStub := &completionServiceStub{ + responses: []*v2.CompletionStreamResponse{ + { + CompletionResponse: &v2.CompletionStreamResponse_Completion{ + Completion: &v2.Completion{ + SubmissionId: "submission-id", + UpdateId: "update-123", + Offset: 105, + }, + }, + }, + }, + } + client := &Client{ + Asset: &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + Decimals: 18, + }, + ChainClientConfig: &xc.ChainClientConfig{ + Confirmations: xc.ConfirmationsConfig{Final: 1}, + }, + }, + ledgerClient: &GrpcLedgerClient{ + authToken: "token", + stateClient: &stateServiceStub{ledgerEnd: 110}, + updateClient: updateStub, + completionClient: completionStub, + logger: logrus.NewEntry(logrus.New()), + }, + } + + info, err := client.FetchTxInfo(context.Background(), txinfo.NewArgs("100-submission-id", txinfo.OptionSender(xc.Address(sender)))) + require.NoError(t, err) + require.Equal(t, "update-123", info.Hash) + require.Equal(t, "100-submission-id", info.LookupId) + require.Equal(t, "update-123", updateStub.lastUpdateID) + require.NotNil(t, updateStub.lastReq) + require.Nil(t, updateStub.lastReq.GetUpdateFormat().GetIncludeTransactions().GetEventFormat().GetFiltersForAnyParty()) + require.Contains(t, updateStub.lastReq.GetUpdateFormat().GetIncludeTransactions().GetEventFormat().GetFiltersByParty(), sender) + require.NotNil(t, completionStub.lastReq) + require.Equal(t, int64(100), completionStub.lastReq.GetBeginExclusive()) + require.Equal(t, ValidatorServiceUserId, completionStub.lastReq.GetUserId()) + require.Equal(t, []string{sender}, completionStub.lastReq.GetParties()) +} + +func TestFetchTxInfoRecoveryLookupRequiresSender(t *testing.T) { + t.Parallel() + + client := &Client{ + Asset: &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + Decimals: 18, + }, + ChainClientConfig: &xc.ChainClientConfig{ + Confirmations: xc.ConfirmationsConfig{Final: 1}, + }, + }, + ledgerClient: &GrpcLedgerClient{ + logger: logrus.NewEntry(logrus.New()), + }, + } + + _, err := client.FetchTxInfo(context.Background(), txinfo.NewArgs("100-submission-id")) + require.ErrorContains(t, err, "requires sender address") +} + +func TestFetchTxInfoDirectUpdateLookupUsesSenderScopedRead(t *testing.T) { + t.Parallel() + + sender := "sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + receiver := "receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + updateStub := &updateServiceStub{ + resp: &v2.GetUpdateResponse{ + Update: &v2.GetUpdateResponse_Transaction{ + Transaction: &v2.Transaction{ + UpdateId: "update-123", + Offset: 105, + SynchronizerId: "sync-id", + EffectiveAt: timestamppb.New(time.Unix(1700000000, 0)), + Events: []*v2.Event{ + { + Event: &v2.Event_Exercised{ + Exercised: testAmuletRulesTransferEvent(sender, receiver, "20.0"), + }, + }, + }, + }, + }, + }, + } + client := &Client{ + Asset: &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + Decimals: 18, + }, + ChainClientConfig: &xc.ChainClientConfig{ + Confirmations: xc.ConfirmationsConfig{Final: 1}, + }, + }, + ledgerClient: &GrpcLedgerClient{ + authToken: "token", + stateClient: &stateServiceStub{ledgerEnd: 110}, + updateClient: updateStub, + logger: logrus.NewEntry(logrus.New()), + }, + } + + info, err := client.FetchTxInfo(context.Background(), txinfo.NewArgs("update-123", txinfo.OptionSender(xc.Address(sender)))) + require.NoError(t, err) + require.Equal(t, "update-123", info.Hash) + require.Empty(t, info.LookupId) + require.Equal(t, "sync-id/105", info.Block.Hash) + require.Len(t, info.Movements, 2) + require.Equal(t, xc.Address(sender), info.Movements[0].From[0].AddressId) + require.Equal(t, xc.Address(receiver), info.Movements[0].To[0].AddressId) + require.Len(t, info.Fees, 1) + require.Equal(t, "3000000000000000000", info.Fees[0].Balance.String()) + require.NotNil(t, updateStub.lastReq) + require.Equal(t, v2.TransactionShape_TRANSACTION_SHAPE_LEDGER_EFFECTS, updateStub.lastReq.GetUpdateFormat().GetIncludeTransactions().GetTransactionShape()) + require.Nil(t, updateStub.lastReq.GetUpdateFormat().GetIncludeTransactions().GetEventFormat().GetFiltersForAnyParty()) + require.Contains(t, updateStub.lastReq.GetUpdateFormat().GetIncludeTransactions().GetEventFormat().GetFiltersByParty(), sender) +} + +func TestFetchTxInfoUsesProvidedSenderWhenEventsDoNotExposeOne(t *testing.T) { + t.Parallel() + + sender := "f0bb6fd00a035b6b6ec18bbb2739265b80f319c0634333fe678928f40750cade::1220769b6eab2a4cc2b324e0c407b27cc7589074052c946b01aab0b1ca9b806627c6" + updateStub := &updateServiceStub{ + resp: &v2.GetUpdateResponse{ + Update: &v2.GetUpdateResponse_Transaction{ + Transaction: &v2.Transaction{ + UpdateId: "update-self", + Offset: 105, + SynchronizerId: "sync-id", + EffectiveAt: timestamppb.New(time.Unix(1700000000, 0)), + Events: []*v2.Event{ + { + Event: &v2.Event_Created{ + Created: testAmuletCreatedEvent(sender, "20.0"), + }, + }, + }, + }, + }, + }, + } + client := &Client{ + Asset: &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + Decimals: 18, + }, + ChainClientConfig: &xc.ChainClientConfig{ + Confirmations: xc.ConfirmationsConfig{Final: 1}, + }, + }, + ledgerClient: &GrpcLedgerClient{ + authToken: "token", + stateClient: &stateServiceStub{ledgerEnd: 110}, + updateClient: updateStub, + logger: logrus.NewEntry(logrus.New()), + }, + } + + info, err := client.FetchTxInfo(context.Background(), txinfo.NewArgs("update-self", txinfo.OptionSender(xc.Address(sender)))) + require.NoError(t, err) + require.Len(t, info.Movements, 1) + require.Len(t, info.Movements[0].From, 1) + require.Len(t, info.Movements[0].To, 1) + require.Equal(t, xc.Address(sender), info.Movements[0].From[0].AddressId) + require.Equal(t, xc.Address(sender), info.Movements[0].To[0].AddressId) +} + func mustSerializedCreateAccountInput(t *testing.T) []byte { t.Helper() input := &tx_input.CreateAccountInput{ @@ -120,3 +322,210 @@ func (s *interactiveSubmissionStub) GetPreferredPackageVersion(context.Context, func (s *interactiveSubmissionStub) GetPreferredPackages(context.Context, *interactive.GetPreferredPackagesRequest, ...grpc.CallOption) (*interactive.GetPreferredPackagesResponse, error) { panic("unexpected call") } + +type completionServiceStub struct { + lastReq *v2.CompletionStreamRequest + responses []*v2.CompletionStreamResponse + streamErr error +} + +func (s *completionServiceStub) CompletionStream(_ context.Context, req *v2.CompletionStreamRequest, _ ...grpc.CallOption) (grpc.ServerStreamingClient[v2.CompletionStreamResponse], error) { + s.lastReq = req + if s.streamErr != nil { + return nil, s.streamErr + } + return &completionStreamClientStub{responses: s.responses}, nil +} + +type completionStreamClientStub struct { + grpc.ClientStream + responses []*v2.CompletionStreamResponse + index int +} + +func (s *completionStreamClientStub) Recv() (*v2.CompletionStreamResponse, error) { + if s.index >= len(s.responses) { + return nil, io.EOF + } + resp := s.responses[s.index] + s.index++ + return resp, nil +} + +func (s *completionStreamClientStub) Header() (metadata.MD, error) { return metadata.MD{}, nil } +func (s *completionStreamClientStub) Trailer() metadata.MD { return metadata.MD{} } +func (s *completionStreamClientStub) CloseSend() error { return nil } +func (s *completionStreamClientStub) Context() context.Context { return context.Background() } +func (s *completionStreamClientStub) SendMsg(any) error { return nil } +func (s *completionStreamClientStub) RecvMsg(any) error { return nil } + +type updateServiceStub struct { + lastUpdateID string + lastReq *v2.GetUpdateByIdRequest + resp *v2.GetUpdateResponse + err error +} + +func (s *updateServiceStub) GetUpdateById(_ context.Context, req *v2.GetUpdateByIdRequest, _ ...grpc.CallOption) (*v2.GetUpdateResponse, error) { + s.lastUpdateID = req.GetUpdateId() + s.lastReq = req + return s.resp, s.err +} + +func (s *updateServiceStub) GetUpdates(context.Context, *v2.GetUpdatesRequest, ...grpc.CallOption) (grpc.ServerStreamingClient[v2.GetUpdatesResponse], error) { + panic("unexpected call") +} + +func (s *updateServiceStub) GetUpdateByOffset(context.Context, *v2.GetUpdateByOffsetRequest, ...grpc.CallOption) (*v2.GetUpdateResponse, error) { + panic("unexpected call") +} + +type stateServiceStub struct { + ledgerEnd int64 +} + +func (s *stateServiceStub) GetActiveContracts(context.Context, *v2.GetActiveContractsRequest, ...grpc.CallOption) (grpc.ServerStreamingClient[v2.GetActiveContractsResponse], error) { + panic("unexpected call") +} + +func (s *stateServiceStub) GetConnectedSynchronizers(context.Context, *v2.GetConnectedSynchronizersRequest, ...grpc.CallOption) (*v2.GetConnectedSynchronizersResponse, error) { + panic("unexpected call") +} + +func (s *stateServiceStub) GetLedgerEnd(context.Context, *v2.GetLedgerEndRequest, ...grpc.CallOption) (*v2.GetLedgerEndResponse, error) { + return &v2.GetLedgerEndResponse{Offset: s.ledgerEnd}, nil +} + +func (s *stateServiceStub) GetLatestPrunedOffsets(context.Context, *v2.GetLatestPrunedOffsetsRequest, ...grpc.CallOption) (*v2.GetLatestPrunedOffsetsResponse, error) { + panic("unexpected call") +} + +func testAmuletCreatedEvent(owner string, initialAmount string) *v2.CreatedEvent { + return &v2.CreatedEvent{ + ContractId: "contract-id", + TemplateId: &v2.Identifier{ + ModuleName: "Splice.Amulet", + EntityName: "Amulet", + }, + CreateArguments: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "owner", + Value: &v2.Value{ + Sum: &v2.Value_Party{Party: owner}, + }, + }, + { + Label: "amount", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "initialAmount", + Value: &v2.Value{ + Sum: &v2.Value_Numeric{Numeric: initialAmount}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func testAmuletRulesTransferEvent(sender string, receiver string, amount string) *v2.ExercisedEvent { + return &v2.ExercisedEvent{ + TemplateId: &v2.Identifier{ + ModuleName: "Splice.AmuletRules", + EntityName: "AmuletRules", + }, + Choice: "AmuletRules_Transfer", + ActingParties: []string{ + sender, + }, + ChoiceArgument: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "transfer", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "outputs", + Value: &v2.Value{ + Sum: &v2.Value_List{ + List: &v2.List{ + Elements: []*v2.Value{ + { + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "receiver", + Value: &v2.Value{Sum: &v2.Value_Party{Party: receiver}}, + }, + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + ExerciseResult: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "meta", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "values", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "splice.lfdecentralizedtrust.org/burned", + Value: &v2.Value{Sum: &v2.Value_Text{Text: "3.0"}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} diff --git a/chain/canton/client/command_builders.go b/chain/canton/client/command_builders.go new file mode 100644 index 00000000..bf598f3b --- /dev/null +++ b/chain/canton/client/command_builders.go @@ -0,0 +1,213 @@ +package client + +import ( + "fmt" + "strconv" + "strings" + "time" + + xcbuilder "github.com/cordialsys/crosschain/builder" + cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" +) + +func buildTransferOfferCreateCommand(args xcbuilder.TransferArgs, amuletRules AmuletRules, commandID string) *v2.Command { + return &v2.Command{ + Command: &v2.Command_Create{ + Create: &v2.CreateCommand{ + TemplateId: &v2.Identifier{ + PackageId: "fd57252dda29e3ce90028114c91b521cb661df5a9d6e87c41a9e91518215fa5b", + ModuleName: "Splice.Wallet.TransferOffer", + EntityName: "TransferOffer", + }, + CreateArguments: &v2.Record{ + Fields: []*v2.RecordField{ + cantonproto.Field("sender", cantonproto.PartyValue(string(args.GetFrom()))), + cantonproto.Field("receiver", cantonproto.PartyValue(string(args.GetTo()))), + cantonproto.Field("dso", cantonproto.PartyValue(amuletRules.AmuletRulesUpdate.Contract.Payload.DSO)), + cantonproto.Field("amount", cantonproto.RecordValue( + cantonproto.Field("amount", cantonproto.NumericValue("10.0")), + cantonproto.Field("unit", &v2.Value{ + Sum: &v2.Value_Enum{Enum: &v2.Enum{Constructor: "AmuletUnit"}}, + }), + )), + cantonproto.Field("description", cantonproto.TextValue("")), + cantonproto.Field("expiresAt", &v2.Value{Sum: &v2.Value_Timestamp{Timestamp: time.Now().UTC().Add(24 * time.Hour).UnixMicro()}}), + cantonproto.Field("trackingId", cantonproto.TextValue(commandID)), + }, + }, + }, + }, + } +} + +func buildExternalPartySetupProposalAcceptCommand(templateID *v2.Identifier, contractID string) *v2.Command { + return &v2.Command{ + Command: &v2.Command_Exercise{ + Exercise: &v2.ExerciseCommand{ + TemplateId: templateID, + ContractId: contractID, + Choice: "ExternalPartySetupProposal_Accept", + ChoiceArgument: cantonproto.EmptyRecordValue(), + }, + }, + } +} + +func buildTransferPreapprovalExerciseCommand( + args xcbuilder.TransferArgs, + amuletRules AmuletRules, + openMiningRound *RoundEntry, + issuingMiningRound *RoundEntry, + senderContracts []*v2.ActiveContract, + recipientContracts []*v2.ActiveContract, +) (*v2.Command, []*v2.DisclosedContract, error) { + var preapprovalContractID string + var preapprovalTemplateID *v2.Identifier + for _, c := range recipientContracts { + event := c.GetCreatedEvent() + if event == nil { + continue + } + tid := event.GetTemplateId() + if tid != nil && isPreapprovalTemplate(tid) { + preapprovalContractID = event.GetContractId() + preapprovalTemplateID = tid + break + } + } + if preapprovalContractID == "" { + return nil, nil, fmt.Errorf("no TransferPreapproval contract found for recipient %s", args.GetTo()) + } + + transferInputs := make([]*v2.Value, 0) + disclosedContracts := make([]*v2.DisclosedContract, 0) + + for _, ac := range recipientContracts { + event := ac.GetCreatedEvent() + if event == nil { + continue + } + if tid := event.GetTemplateId(); tid != nil && isPreapprovalTemplate(tid) { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: tid, + ContractId: event.GetContractId(), + CreatedEventBlob: event.GetCreatedEventBlob(), + }) + break + } + } + + for _, ac := range senderContracts { + event := ac.GetCreatedEvent() + if event == nil || event.GetTemplateId().GetEntityName() != "Amulet" { + continue + } + transferInputs = append(transferInputs, &v2.Value{ + Sum: &v2.Value_Variant{ + Variant: &v2.Variant{ + Constructor: "InputAmulet", + Value: cantonproto.ContractIDValue(event.GetContractId()), + }, + }, + }) + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: event.GetTemplateId(), + ContractId: event.GetContractId(), + CreatedEventBlob: event.GetCreatedEventBlob(), + }) + } + + amuletRulesID := amuletRules.AmuletRulesUpdate.Contract.ContractID + openMiningRoundID := openMiningRound.Contract.ContractID + + amuletRulesTemplateParts := strings.SplitN(amuletRules.AmuletRulesUpdate.Contract.TemplateID, ":", 3) + if len(amuletRulesTemplateParts) == 3 { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: amuletRulesTemplateParts[0], + ModuleName: amuletRulesTemplateParts[1], + EntityName: amuletRulesTemplateParts[2], + }, + ContractId: amuletRulesID, + CreatedEventBlob: amuletRules.AmuletRulesUpdate.Contract.CreatedEventBlob, + }) + } + + openParts := strings.Split(openMiningRound.Contract.TemplateID, ":") + if len(openParts) == 3 { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: openParts[0], + ModuleName: openParts[1], + EntityName: openParts[2], + }, + ContractId: openMiningRoundID, + CreatedEventBlob: openMiningRound.Contract.CreatedEventBlob, + }) + } + + rn, err := strconv.ParseInt(issuingMiningRound.Contract.Payload.Round.Number, 10, 64) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse issuing mining round number: %w", err) + } + issuingMiningRounds := &v2.Value{ + Sum: &v2.Value_GenMap{ + GenMap: &v2.GenMap{ + Entries: []*v2.GenMap_Entry{ + { + Key: cantonproto.RecordValue( + cantonproto.Field("number", &v2.Value{Sum: &v2.Value_Int64{Int64: rn}}), + ), + Value: cantonproto.ContractIDValue(issuingMiningRound.Contract.ContractID), + }, + }, + }, + }, + } + + issuingParts := strings.Split(issuingMiningRound.Contract.TemplateID, ":") + if len(issuingParts) == 3 { + disclosedContracts = append(disclosedContracts, &v2.DisclosedContract{ + TemplateId: &v2.Identifier{ + PackageId: issuingParts[0], + ModuleName: issuingParts[1], + EntityName: issuingParts[2], + }, + ContractId: issuingMiningRound.Contract.ContractID, + CreatedEventBlob: issuingMiningRound.Contract.CreatedEventBlob, + }) + } + + cmd := &v2.Command{ + Command: &v2.Command_Exercise{ + Exercise: &v2.ExerciseCommand{ + TemplateId: preapprovalTemplateID, + ContractId: preapprovalContractID, + Choice: "TransferPreapproval_Send", + ChoiceArgument: cantonproto.RecordValue( + cantonproto.Field("sender", cantonproto.PartyValue(string(args.GetFrom()))), + cantonproto.Field("inputs", &v2.Value{ + Sum: &v2.Value_List{List: &v2.List{Elements: transferInputs}}, + }), + cantonproto.Field("amount", cantonproto.NumericValue("10.0")), + cantonproto.Field("context", cantonproto.RecordValue( + cantonproto.Field("amuletRules", cantonproto.ContractIDValue(amuletRulesID)), + cantonproto.Field("context", cantonproto.RecordValue( + cantonproto.Field("openMiningRound", cantonproto.ContractIDValue(openMiningRoundID)), + cantonproto.Field("issuingMiningRounds", issuingMiningRounds), + cantonproto.Field("validatorRights", &v2.Value{ + Sum: &v2.Value_GenMap{GenMap: &v2.GenMap{Entries: []*v2.GenMap_Entry{}}}, + }), + cantonproto.Field("featuredAppRight", &v2.Value{ + Sum: &v2.Value_Optional{Optional: &v2.Optional{}}, + }), + )), + )), + ), + }, + }, + } + + return cmd, disclosedContracts, nil +} diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index 85d4f031..7b914982 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "crypto/ed25519" - "crypto/rand" "crypto/tls" "encoding/hex" "encoding/json" @@ -19,6 +18,7 @@ import ( xc "github.com/cordialsys/crosschain" cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" @@ -79,6 +79,7 @@ type GrpcLedgerClient struct { authToken string adminClient admin.PartyManagementServiceClient commandClient v2.CommandServiceClient + completionClient v2.CommandCompletionServiceClient interactiveSubmissionClient interactive.InteractiveSubmissionServiceClient stateClient v2.StateServiceClient updateClient v2.UpdateServiceClient @@ -120,6 +121,7 @@ func NewGrpcLedgerClient(target string, authToken string) (*GrpcLedgerClient, er adminClient: admin.NewPartyManagementServiceClient(conn), stateClient: v2.NewStateServiceClient(conn), updateClient: v2.NewUpdateServiceClient(conn), + completionClient: v2.NewCommandCompletionServiceClient(conn), interactiveSubmissionClient: interactive.NewInteractiveSubmissionServiceClient(conn), userManagementClient: admin.NewUserManagementServiceClient(conn), commandClient: v2.NewCommandServiceClient(conn), @@ -583,21 +585,11 @@ func (c *GrpcLedgerClient) HasTransferPreapprovalContract(ctx context.Context, c // newRegisterCommandId generates a UUID-style command ID for registration calls. func newRegisterCommandId() string { - b := make([]byte, 16) - _, _ = rand.Read(b) - return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", - b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) + return cantonproto.NewCommandID() } func (c *GrpcLedgerClient) PrepareSubmissionRequest(ctx context.Context, command *v2.Command, commandID string, partyID string) (*interactive.PrepareSubmissionResponse, error) { - prepareReq := &interactive.PrepareSubmissionRequest{ - CommandId: commandID, - Commands: []*v2.Command{command}, - ActAs: []string{partyID}, - ReadAs: []string{partyID}, - SynchronizerId: TestnetSynchronizerID, - VerboseHashing: false, - } + prepareReq := cantonproto.NewPrepareRequest(commandID, TestnetSynchronizerID, []string{partyID}, []string{partyID}, []*v2.Command{command}, nil) authCtx := c.authCtx(ctx) prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) @@ -1029,21 +1021,27 @@ func (c *GrpcLedgerClient) CompleteAcceptedTransferOffer( return nil } -// GetUpdateById fetches a transaction (update) by its updateId from the Canton ledger. -func (c *GrpcLedgerClient) GetUpdateById(ctx context.Context, updateId string) (*v2.GetUpdateResponse, error) { +// GetUpdateById fetches a transaction (update) by its updateId from the Canton ledger, +// scoped to a specific party to avoid requiring super-reader permissions. +func (c *GrpcLedgerClient) GetUpdateById(ctx context.Context, partyID string, updateId string) (*v2.GetUpdateResponse, error) { + if partyID == "" { + return nil, errors.New("empty party id") + } authCtx := c.authCtx(ctx) req := &v2.GetUpdateByIdRequest{ UpdateId: updateId, UpdateFormat: &v2.UpdateFormat{ IncludeTransactions: &v2.TransactionFormat{ - TransactionShape: v2.TransactionShape_TRANSACTION_SHAPE_ACS_DELTA, + TransactionShape: v2.TransactionShape_TRANSACTION_SHAPE_LEDGER_EFFECTS, EventFormat: &v2.EventFormat{ - FiltersForAnyParty: &v2.Filters{ - Cumulative: []*v2.CumulativeFilter{{ - IdentifierFilter: &v2.CumulativeFilter_WildcardFilter{ - WildcardFilter: &v2.WildcardFilter{}, - }, - }}, + FiltersByParty: map[string]*v2.Filters{ + partyID: { + Cumulative: []*v2.CumulativeFilter{{ + IdentifierFilter: &v2.CumulativeFilter_WildcardFilter{ + WildcardFilter: &v2.WildcardFilter{}, + }, + }}, + }, }, Verbose: true, }, @@ -1052,11 +1050,66 @@ func (c *GrpcLedgerClient) GetUpdateById(ctx context.Context, updateId string) ( } resp, err := c.updateClient.GetUpdateById(authCtx, req) if err != nil { - return nil, fmt.Errorf("GetUpdateById(%s): %w", updateId, err) + return nil, fmt.Errorf("GetUpdateById(%s, %s): %w", partyID, updateId, err) } return resp, nil } +func (c *GrpcLedgerClient) RecoverUpdateIdBySubmissionId(ctx context.Context, beginExclusive int64, partyID string, submissionId string) (string, error) { + if partyID == "" { + return "", errors.New("empty party id") + } + if submissionId == "" { + return "", errors.New("empty submission id") + } + + upperBound, err := c.GetLedgerEnd(ctx) + if err != nil { + return "", fmt.Errorf("failed to get ledger end for recovery: %w", err) + } + if upperBound <= beginExclusive { + return "", fmt.Errorf("no ledger updates after offset %d", beginExclusive) + } + + streamCtx, cancel := context.WithTimeout(c.authCtx(ctx), 15*time.Second) + defer cancel() + + stream, err := c.completionClient.CompletionStream(streamCtx, &v2.CompletionStreamRequest{ + UserId: ValidatorServiceUserId, + Parties: []string{partyID}, + BeginExclusive: beginExclusive, + }) + if err != nil { + return "", fmt.Errorf("CompletionStream(%d): %w", beginExclusive, err) + } + + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return "", fmt.Errorf("completion stream recv: %w", err) + } + + if completion := resp.GetCompletion(); completion != nil { + if completion.GetSubmissionId() == submissionId && completion.GetUpdateId() != "" { + return completion.GetUpdateId(), nil + } + if completion.GetOffset() >= upperBound { + break + } + continue + } + + if checkpoint := resp.GetOffsetCheckpoint(); checkpoint != nil && checkpoint.GetOffset() >= upperBound { + break + } + } + + return "", fmt.Errorf("could not recover update id for submission %q in offsets (%d, %d]", submissionId, beginExclusive, upperBound) +} + func isAlreadyExists(err error) bool { if err == nil { return false @@ -1201,8 +1254,5 @@ func ExtractAmuletBalance(record *v2.Record, decimals int32) (xc.AmountBlockchai // NewCommandId generates a UUID-style unique command ID func NewCommandId() string { - b := make([]byte, 16) - _, _ = rand.Read(b) - return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", - b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) + return cantonproto.NewCommandID() } diff --git a/chain/canton/proto/helpers.go b/chain/canton/proto/helpers.go new file mode 100644 index 00000000..580e7de1 --- /dev/null +++ b/chain/canton/proto/helpers.go @@ -0,0 +1,118 @@ +package proto + +import ( + "crypto/rand" + "fmt" + "time" + + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "google.golang.org/protobuf/types/known/durationpb" +) + +const defaultDeduplicationWindow = 300 * time.Second + +func NewCommandID() string { + b := make([]byte, 16) + _, _ = rand.Read(b) + return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", + b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) +} + +func EmptyRecordValue() *v2.Value { + return RecordValue() +} + +func PartyValue(party string) *v2.Value { + return &v2.Value{Sum: &v2.Value_Party{Party: party}} +} + +func TextValue(text string) *v2.Value { + return &v2.Value{Sum: &v2.Value_Text{Text: text}} +} + +func NumericValue(numeric string) *v2.Value { + return &v2.Value{Sum: &v2.Value_Numeric{Numeric: numeric}} +} + +func ContractIDValue(contractID string) *v2.Value { + return &v2.Value{Sum: &v2.Value_ContractId{ContractId: contractID}} +} + +func RecordValue(fields ...*v2.RecordField) *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{Fields: fields}, + }, + } +} + +func Field(label string, value *v2.Value) *v2.RecordField { + return &v2.RecordField{Label: label, Value: value} +} + +func NewPrepareRequest(commandID string, synchronizerID string, actAs []string, readAs []string, commands []*v2.Command, disclosed []*v2.DisclosedContract) *interactive.PrepareSubmissionRequest { + return &interactive.PrepareSubmissionRequest{ + CommandId: commandID, + Commands: commands, + ActAs: actAs, + ReadAs: readAs, + SynchronizerId: synchronizerID, + DisclosedContracts: disclosed, + VerboseHashing: false, + } +} + +func NewRawSignature(signature []byte, signedBy string) *v2.Signature { + return &v2.Signature{ + Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, + Signature: signature, + SignedBy: signedBy, + SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, + } +} + +func NewPartySignatures(party string, sig *v2.Signature) *interactive.PartySignatures { + return &interactive.PartySignatures{ + Signatures: []*interactive.SinglePartySignatures{ + {Party: party, Signatures: []*v2.Signature{sig}}, + }, + } +} + +func NewExecuteSubmissionRequest(prepared *interactive.PreparedTransaction, party string, signature []byte, signedBy string, submissionID string, hashing interactive.HashingSchemeVersion) *interactive.ExecuteSubmissionRequest { + return &interactive.ExecuteSubmissionRequest{ + PreparedTransaction: prepared, + PartySignatures: NewPartySignatures(party, NewRawSignature(signature, signedBy)), + DeduplicationPeriod: &interactive.ExecuteSubmissionRequest_DeduplicationDuration{ + DeduplicationDuration: durationpb.New(defaultDeduplicationWindow), + }, + SubmissionId: submissionID, + HashingSchemeVersion: hashing, + } +} + +func NewExecuteSubmissionAndWaitRequest(prepared *interactive.PreparedTransaction, party string, signature []byte, signedBy string, submissionID string, hashing interactive.HashingSchemeVersion) *interactive.ExecuteSubmissionAndWaitRequest { + return &interactive.ExecuteSubmissionAndWaitRequest{ + PreparedTransaction: prepared, + PartySignatures: NewPartySignatures(party, NewRawSignature(signature, signedBy)), + DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ + DeduplicationDuration: durationpb.New(defaultDeduplicationWindow), + }, + SubmissionId: submissionID, + HashingSchemeVersion: hashing, + } +} + +func NewAllocateExternalPartyRequest(synchronizerID string, topologyTxs [][]byte, signature []byte, signedBy string) *admin.AllocateExternalPartyRequest { + onboardingTxs := make([]*admin.AllocateExternalPartyRequest_SignedTransaction, 0, len(topologyTxs)) + for _, tx := range topologyTxs { + onboardingTxs = append(onboardingTxs, &admin.AllocateExternalPartyRequest_SignedTransaction{Transaction: tx}) + } + return &admin.AllocateExternalPartyRequest{ + Synchronizer: synchronizerID, + OnboardingTransactions: onboardingTxs, + MultiHashSignatures: []*v2.Signature{NewRawSignature(signature, signedBy)}, + } +} diff --git a/chain/canton/proto/helpers_test.go b/chain/canton/proto/helpers_test.go new file mode 100644 index 00000000..12feb345 --- /dev/null +++ b/chain/canton/proto/helpers_test.go @@ -0,0 +1,63 @@ +package proto + +import ( + "testing" + "time" + + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "github.com/stretchr/testify/require" +) + +func TestNewPrepareRequest(t *testing.T) { + t.Parallel() + + req := NewPrepareRequest("cmd", "sync", []string{"act"}, []string{"read"}, []*v2.Command{{}}, []*v2.DisclosedContract{{}}) + require.Equal(t, "cmd", req.GetCommandId()) + require.Equal(t, "sync", req.GetSynchronizerId()) + require.Equal(t, []string{"act"}, req.GetActAs()) + require.Equal(t, []string{"read"}, req.GetReadAs()) + require.Len(t, req.GetCommands(), 1) + require.Len(t, req.GetDisclosedContracts(), 1) +} + +func TestNewRawSignatureAndPartySignatures(t *testing.T) { + t.Parallel() + + sig := NewRawSignature([]byte{0xaa}, "fingerprint") + require.Equal(t, v2.SignatureFormat_SIGNATURE_FORMAT_RAW, sig.GetFormat()) + require.Equal(t, v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, sig.GetSigningAlgorithmSpec()) + + partySigs := NewPartySignatures("party", sig) + require.Equal(t, "party", partySigs.GetSignatures()[0].GetParty()) + require.Equal(t, []byte{0xaa}, partySigs.GetSignatures()[0].GetSignatures()[0].GetSignature()) +} + +func TestNewExecuteRequests(t *testing.T) { + t.Parallel() + + prepared := &interactive.PreparedTransaction{} + hashing := interactive.HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED + + req := NewExecuteSubmissionRequest(prepared, "party", []byte{0xaa}, "fingerprint", "sub-id", hashing) + require.Equal(t, prepared, req.GetPreparedTransaction()) + require.Equal(t, "sub-id", req.GetSubmissionId()) + require.Equal(t, hashing, req.GetHashingSchemeVersion()) + require.Equal(t, 300*time.Second, req.GetDeduplicationDuration().AsDuration()) + + waitReq := NewExecuteSubmissionAndWaitRequest(prepared, "party", []byte{0xbb}, "fingerprint", "sub-id-2", hashing) + require.Equal(t, prepared, waitReq.GetPreparedTransaction()) + require.Equal(t, "sub-id-2", waitReq.GetSubmissionId()) + require.Equal(t, hashing, waitReq.GetHashingSchemeVersion()) + require.Equal(t, 300*time.Second, waitReq.GetDeduplicationDuration().AsDuration()) +} + +func TestNewAllocateExternalPartyRequest(t *testing.T) { + t.Parallel() + + req := NewAllocateExternalPartyRequest("sync", [][]byte{{0x01}, {0x02}}, []byte{0xaa}, "fingerprint") + require.Equal(t, "sync", req.GetSynchronizer()) + require.Len(t, req.GetOnboardingTransactions(), 2) + require.Equal(t, []byte{0xaa}, req.GetMultiHashSignatures()[0].GetSignature()) + require.Equal(t, "fingerprint", req.GetMultiHashSignatures()[0].GetSignedBy()) +} diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go index ef8e044d..b2eac965 100644 --- a/chain/canton/tx/tx.go +++ b/chain/canton/tx/tx.go @@ -2,17 +2,16 @@ package tx import ( "fmt" - "time" xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" + cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" "github.com/cordialsys/crosschain/chain/canton/tx_input" v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/durationpb" ) // Tx for Canton holds the data needed for the external-party signing flow: @@ -28,6 +27,8 @@ type Tx struct { KeyFingerprint string // SubmissionId for deduplication SubmissionId string + // LedgerEnd captured before submission, used as the lower-bound recovery cursor. + LedgerEnd int64 // Populated after SetSignatures is called signature []byte } @@ -61,6 +62,7 @@ func NewTx(input *tx_input.TxInput, args xcbuilder.TransferArgs, decimals int32) Party: string(args.GetFrom()), KeyFingerprint: fingerprint, SubmissionId: input.SubmissionId, + LedgerEnd: input.LedgerEnd, }, nil } @@ -220,13 +222,12 @@ func (tx Tx) computedSighash() ([]byte, error) { return tx_input.ComputePreparedTransactionHash(tx.PreparedTransaction) } -// Hash returns a hex string of the locally derived prepared transaction hash. +// Hash returns a recovery token in the form "-". func (tx Tx) Hash() xc.TxHash { - hash, err := tx.computedSighash() - if err != nil { + if tx.SubmissionId == "" { return "" } - return xc.TxHash(fmt.Sprintf("%x", hash)) + return xc.TxHash(fmt.Sprintf("%d-%s", tx.LedgerEnd, tx.SubmissionId)) } // Sighashes returns the locally derived prepared transaction hash bytes for the party to sign. @@ -256,30 +257,7 @@ func (tx Tx) Serialize() ([]byte, error) { return nil, fmt.Errorf("prepared transaction is nil") } - req := &interactive.ExecuteSubmissionRequest{ - PreparedTransaction: tx.PreparedTransaction, - PartySignatures: &interactive.PartySignatures{ - Signatures: []*interactive.SinglePartySignatures{ - { - Party: tx.Party, - Signatures: []*v2.Signature{ - { - Format: v2.SignatureFormat_SIGNATURE_FORMAT_RAW, - Signature: tx.signature, - SignedBy: tx.KeyFingerprint, - SigningAlgorithmSpec: v2.SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519, - }, - }, - }, - }, - }, - DeduplicationPeriod: &interactive.ExecuteSubmissionRequest_DeduplicationDuration{ - // TODO: Move to input - DeduplicationDuration: durationpb.New(300 * time.Second), - }, - SubmissionId: tx.SubmissionId, - HashingSchemeVersion: tx.HashingSchemeVersion, - } + req := cantonproto.NewExecuteSubmissionRequest(tx.PreparedTransaction, tx.Party, tx.signature, tx.KeyFingerprint, tx.SubmissionId, tx.HashingSchemeVersion) data, err := proto.Marshal(req) if err != nil { diff --git a/chain/canton/tx/tx_test.go b/chain/canton/tx/tx_test.go index 037e8c7d..fd4426c9 100644 --- a/chain/canton/tx/tx_test.go +++ b/chain/canton/tx/tx_test.go @@ -1,7 +1,8 @@ package tx import ( - "fmt" + "bytes" + "strconv" "testing" xc "github.com/cordialsys/crosschain" @@ -27,11 +28,11 @@ func TestNewTx_UsesPreparedTransactionForTransferFlows(t *testing.T) { }{ { name: "transfer_offer", - preparedTx: txPreparedTransaction("node-1", txCreateNode("TransferOffer", txTransferOfferArgument(string(to), "10.0"))), + preparedTx: txPreparedTransaction("1", txCreateNode("TransferOffer", txTransferOfferArgument(string(to), "10.0"))), }, { name: "transfer_preapproval_send", - preparedTx: txPreparedTransaction("node-1", txExerciseNode("TransferPreapproval_Send", txAmountRecord("10.0"))), + preparedTx: txPreparedTransaction("1", txExerciseNode("TransferPreapproval_Send", txAmountRecord("10.0"))), }, } @@ -45,6 +46,7 @@ func TestNewTx_UsesPreparedTransactionForTransferFlows(t *testing.T) { input := &tx_input.TxInput{ PreparedTransaction: *vector.preparedTx, + LedgerEnd: 12345, SubmissionId: "submission-id", } @@ -58,13 +60,13 @@ func TestNewTx_UsesPreparedTransactionForTransferFlows(t *testing.T) { require.NoError(t, err) require.Len(t, sighashes, 1) require.Equal(t, hash, sighashes[0].Payload) - require.Equal(t, xc.TxHash(fmt.Sprintf("%x", hash)), tx.Hash()) + require.Equal(t, xc.TxHash("12345-submission-id"), tx.Hash()) }) } } func txPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTransaction { - return &interactive.PreparedTransaction{ + tx := &interactive.PreparedTransaction{ Transaction: &interactive.DamlTransaction{ Version: "2", Roots: []string{nodeID}, @@ -77,7 +79,27 @@ func txPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTr }, }, }, + Metadata: &interactive.Metadata{ + SubmitterInfo: &interactive.Metadata_SubmitterInfo{ + ActAs: []string{"sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, + CommandId: "command-id", + }, + SynchronizerId: "sync-id", + TransactionUuid: "transaction-uuid", + PreparationTime: 1, + InputContracts: []*interactive.Metadata_InputContract{}, + }, + } + if node.GetExercise() != nil { + seedID, err := strconv.Atoi(nodeID) + if err != nil { + panic(err) + } + tx.Transaction.NodeSeeds = []*interactive.DamlTransaction_NodeSeed{ + {NodeId: int32(seedID), Seed: bytes.Repeat([]byte{0x11}, 32)}, + } } + return tx } func txCreateNode(entity string, argument *v2.Value) *v1.Node { @@ -89,7 +111,9 @@ func txCreateNode(entity string, argument *v2.Value) *v1.Node { ModuleName: "Splice.Wallet.TransferOffer", EntityName: entity, }, - Argument: argument, + ContractId: "001122", + PackageName: "splice-wallet", + Argument: argument, }, }, } @@ -104,6 +128,8 @@ func txExerciseNode(choice string, chosenValue *v2.Value) *v1.Node { ModuleName: "Splice.Wallet", EntityName: "Any", }, + ContractId: "001122", + PackageName: "splice-wallet", ChoiceId: choice, ChosenValue: chosenValue, }, diff --git a/chain/canton/tx_input/hash_validation.go b/chain/canton/tx_input/hash_validation.go index 9e8ff2bb..a6c01391 100644 --- a/chain/canton/tx_input/hash_validation.go +++ b/chain/canton/tx_input/hash_validation.go @@ -3,30 +3,46 @@ package tx_input import ( "bytes" "crypto/sha256" + "encoding/binary" + "encoding/hex" "fmt" + "strconv" + "strings" + v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" - "google.golang.org/protobuf/proto" + v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" ) -// ComputePreparedTransactionHash returns the current local hash of a prepared -// transaction. This is the payload Canton transfer txs sign today. +var preparedTransactionHashPurpose = []byte{0x00, 0x00, 0x00, 0x30} + +// ComputePreparedTransactionHash computes the Canton HASHING_SCHEME_VERSION_V2 +// hash for a PreparedTransaction. func ComputePreparedTransactionHash(preparedTx *interactive.PreparedTransaction) ([]byte, error) { if preparedTx == nil { return nil, fmt.Errorf("prepared transaction is nil") } - - encoded, err := proto.MarshalOptions{Deterministic: true}.Marshal(preparedTx) + nodes, err := createNodesDict(preparedTx) + if err != nil { + return nil, err + } + txHash, err := hashTransaction(preparedTx.GetTransaction(), nodes) if err != nil { - return nil, fmt.Errorf("failed to marshal prepared transaction for hashing: %w", err) + return nil, err } - digest := sha256.Sum256(encoded) - return digest[:], nil + metadataHash, err := hashMetadata(preparedTx.GetMetadata()) + if err != nil { + return nil, err + } + sum := sha256.Sum256(bytes.Join([][]byte{ + preparedTransactionHashPurpose, + {byte(interactive.HashingSchemeVersion_HASHING_SCHEME_VERSION_V2)}, + txHash, + metadataHash, + }, nil)) + return sum[:], nil } -// ValidatePreparedTransactionHash recomputes SHA-256 over the canonical proto -// encoding of PreparedTransaction and checks it matches the hash supplied by the -// prepare endpoint. func ValidatePreparedTransactionHash(preparedTx *interactive.PreparedTransaction, expectedHash []byte) error { if len(expectedHash) == 0 { return fmt.Errorf("prepared transaction hash is empty") @@ -42,3 +58,613 @@ func ValidatePreparedTransactionHash(preparedTx *interactive.PreparedTransaction return nil } + +func hashTransaction(transaction *interactive.DamlTransaction, nodes map[string]*interactive.DamlTransaction_Node) ([]byte, error) { + encoded, err := encodeTransaction(transaction, nodes, transaction.GetNodeSeeds()) + if err != nil { + return nil, err + } + sum := sha256.Sum256(append(append([]byte{}, preparedTransactionHashPurpose...), encoded...)) + return sum[:], nil +} + +func encodeTransaction(transaction *interactive.DamlTransaction, nodes map[string]*interactive.DamlTransaction_Node, nodeSeeds []*interactive.DamlTransaction_NodeSeed) ([]byte, error) { + if transaction == nil { + return nil, fmt.Errorf("prepared transaction contains no DamlTransaction") + } + version := encodeString(transaction.GetVersion()) + roots, err := encodeRepeatedStrings(transaction.GetRoots(), func(nodeID string) ([]byte, error) { + return encodeNodeID(nodeID, nodes, nodeSeeds) + }) + if err != nil { + return nil, err + } + return append(version, roots...), nil +} + +func encodeNodeID(nodeID string, nodes map[string]*interactive.DamlTransaction_Node, nodeSeeds []*interactive.DamlTransaction_NodeSeed) ([]byte, error) { + node, ok := nodes[nodeID] + if !ok { + return nil, fmt.Errorf("node %q not found in prepared transaction", nodeID) + } + encodedNode, err := encodeNode(node, nodes, nodeSeeds) + if err != nil { + return nil, err + } + sum := sha256.Sum256(encodedNode) + return sum[:], nil +} + +func encodeNode(node *interactive.DamlTransaction_Node, nodes map[string]*interactive.DamlTransaction_Node, nodeSeeds []*interactive.DamlTransaction_NodeSeed) ([]byte, error) { + if node == nil { + return nil, fmt.Errorf("node is nil") + } + v1Node := node.GetV1() + if v1Node == nil { + return nil, fmt.Errorf("unsupported node version") + } + switch n := v1Node.NodeType.(type) { + case *v1.Node_Create: + return encodeCreateNode(n.Create, node.GetNodeId(), nodeSeeds) + case *v1.Node_Exercise: + return encodeExerciseNode(n.Exercise, node.GetNodeId(), nodes, nodeSeeds) + case *v1.Node_Fetch: + return encodeFetchNode(n.Fetch) + case *v1.Node_Rollback: + return encodeRollbackNode(n.Rollback, nodes, nodeSeeds) + default: + return nil, fmt.Errorf("unsupported node type %T", v1Node.NodeType) + } +} + +func encodeCreateNode(create *v1.Create, nodeID string, nodeSeeds []*interactive.DamlTransaction_NodeSeed) ([]byte, error) { + if create == nil { + return nil, fmt.Errorf("create node is nil") + } + seed := findSeed(nodeID, nodeSeeds) + contractID, err := encodeHexString(create.GetContractId()) + if err != nil { + return nil, fmt.Errorf("create node contract id: %w", err) + } + templateID, err := encodeIdentifier(create.GetTemplateId()) + if err != nil { + return nil, err + } + argument, err := encodeValue(create.GetArgument()) + if err != nil { + return nil, err + } + signatories, err := encodeRepeated(create.GetSignatories(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + stakeholders, err := encodeRepeated(create.GetStakeholders(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + + return bytes.Join([][]byte{ + {0x01}, + encodeString(create.GetLfVersion()), + {0x00}, + encodeOptionalBytes(seed, encodeHash), + contractID, + encodeString(create.GetPackageName()), + templateID, + argument, + signatories, + stakeholders, + }, nil), nil +} + +func encodeExerciseNode(exercise *v1.Exercise, nodeID string, nodes map[string]*interactive.DamlTransaction_Node, nodeSeeds []*interactive.DamlTransaction_NodeSeed) ([]byte, error) { + if exercise == nil { + return nil, fmt.Errorf("exercise node is nil") + } + seed := findSeed(nodeID, nodeSeeds) + if seed == nil { + return nil, fmt.Errorf("missing seed for exercise node %q", nodeID) + } + contractID, err := encodeHexString(exercise.GetContractId()) + if err != nil { + return nil, fmt.Errorf("exercise node contract id: %w", err) + } + templateID, err := encodeIdentifier(exercise.GetTemplateId()) + if err != nil { + return nil, err + } + signatories, err := encodeRepeated(exercise.GetSignatories(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + stakeholders, err := encodeRepeated(exercise.GetStakeholders(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + actingParties, err := encodeRepeated(exercise.GetActingParties(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + interfaceID, err := encodeProtoOptionalIdentifier(exercise.GetInterfaceId()) + if err != nil { + return nil, err + } + chosenValue, err := encodeValue(exercise.GetChosenValue()) + if err != nil { + return nil, err + } + exerciseResult, err := encodeProtoOptionalValue(exercise.GetExerciseResult()) + if err != nil { + return nil, err + } + choiceObservers, err := encodeRepeated(exercise.GetChoiceObservers(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + children, err := encodeRepeatedStrings(exercise.GetChildren(), func(childID string) ([]byte, error) { + return encodeNodeID(childID, nodes, nodeSeeds) + }) + if err != nil { + return nil, err + } + + return bytes.Join([][]byte{ + {0x01}, + encodeString(exercise.GetLfVersion()), + {0x01}, + encodeHash(seed), + contractID, + encodeString(exercise.GetPackageName()), + templateID, + signatories, + stakeholders, + actingParties, + interfaceID, + encodeString(exercise.GetChoiceId()), + chosenValue, + encodeBool(exercise.GetConsuming()), + exerciseResult, + choiceObservers, + children, + }, nil), nil +} + +func encodeFetchNode(fetch *v1.Fetch) ([]byte, error) { + if fetch == nil { + return nil, fmt.Errorf("fetch node is nil") + } + contractID, err := encodeHexString(fetch.GetContractId()) + if err != nil { + return nil, fmt.Errorf("fetch node contract id: %w", err) + } + templateID, err := encodeIdentifier(fetch.GetTemplateId()) + if err != nil { + return nil, err + } + signatories, err := encodeRepeated(fetch.GetSignatories(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + stakeholders, err := encodeRepeated(fetch.GetStakeholders(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + interfaceID, err := encodeProtoOptionalIdentifier(fetch.GetInterfaceId()) + if err != nil { + return nil, err + } + actingParties, err := encodeRepeated(fetch.GetActingParties(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + + return bytes.Join([][]byte{ + {0x01}, + encodeString(fetch.GetLfVersion()), + {0x02}, + contractID, + encodeString(fetch.GetPackageName()), + templateID, + signatories, + stakeholders, + interfaceID, + actingParties, + }, nil), nil +} + +func encodeRollbackNode(rollback *v1.Rollback, nodes map[string]*interactive.DamlTransaction_Node, nodeSeeds []*interactive.DamlTransaction_NodeSeed) ([]byte, error) { + if rollback == nil { + return nil, fmt.Errorf("rollback node is nil") + } + children, err := encodeRepeatedStrings(rollback.GetChildren(), func(childID string) ([]byte, error) { + return encodeNodeID(childID, nodes, nodeSeeds) + }) + if err != nil { + return nil, err + } + return append([]byte{0x01, 0x03}, children...), nil +} + +func hashMetadata(metadata *interactive.Metadata) ([]byte, error) { + encoded, err := encodeMetadata(metadata) + if err != nil { + return nil, err + } + sum := sha256.Sum256(append(append([]byte{}, preparedTransactionHashPurpose...), encoded...)) + return sum[:], nil +} + +func encodeMetadata(metadata *interactive.Metadata) ([]byte, error) { + if metadata == nil { + return nil, fmt.Errorf("prepared transaction metadata is nil") + } + if metadata.GetSubmitterInfo() == nil { + return nil, fmt.Errorf("prepared transaction metadata submitter info is nil") + } + actAs, err := encodeRepeated(metadata.GetSubmitterInfo().GetActAs(), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + minLET := encodeOptionalUint64(metadata.MinLedgerEffectiveTime) + maxLET := encodeOptionalUint64(metadata.MaxLedgerEffectiveTime) + inputContracts, err := encodeRepeated(metadata.GetInputContracts(), encodeInputContract) + if err != nil { + return nil, err + } + + return bytes.Join([][]byte{ + {0x01}, + actAs, + encodeString(metadata.GetSubmitterInfo().GetCommandId()), + encodeString(metadata.GetTransactionUuid()), + encodeInt32(int32(metadata.GetMediatorGroup())), + encodeString(metadata.GetSynchronizerId()), + minLET, + maxLET, + encodeInt64(int64(metadata.GetPreparationTime())), + inputContracts, + }, nil), nil +} + +func encodeInputContract(contract *interactive.Metadata_InputContract) ([]byte, error) { + if contract == nil { + return nil, fmt.Errorf("input contract is nil") + } + create := contract.GetV1() + if create == nil { + return nil, fmt.Errorf("unsupported input contract version") + } + encodedCreate, err := encodeCreateNode(create, "unused_node_id", nil) + if err != nil { + return nil, err + } + sum := sha256.Sum256(encodedCreate) + return bytes.Join([][]byte{ + encodeInt64(int64(contract.GetCreatedAt())), + sum[:], + }, nil), nil +} + +func encodeValue(value *v2.Value) ([]byte, error) { + if value == nil { + return nil, fmt.Errorf("value is nil") + } + switch sum := value.Sum.(type) { + case *v2.Value_Unit: + return []byte{0x00}, nil + case *v2.Value_Bool: + return append([]byte{0x01}, encodeBool(sum.Bool)...), nil + case *v2.Value_Int64: + return append([]byte{0x02}, encodeInt64(sum.Int64)...), nil + case *v2.Value_Numeric: + return append([]byte{0x03}, encodeString(sum.Numeric)...), nil + case *v2.Value_Timestamp: + return append([]byte{0x04}, encodeInt64(sum.Timestamp)...), nil + case *v2.Value_Date: + return append([]byte{0x05}, encodeInt32(sum.Date)...), nil + case *v2.Value_Party: + return append([]byte{0x06}, encodeString(sum.Party)...), nil + case *v2.Value_Text: + return append([]byte{0x07}, encodeString(sum.Text)...), nil + case *v2.Value_ContractId: + encoded, err := encodeHexString(sum.ContractId) + if err != nil { + return nil, err + } + return append([]byte{0x08}, encoded...), nil + case *v2.Value_Optional: + return encodeOptionalValue(sum.Optional) + case *v2.Value_List: + encoded, err := encodeRepeated(sum.List.GetElements(), encodeValue) + if err != nil { + return nil, err + } + return append([]byte{0x0a}, encoded...), nil + case *v2.Value_TextMap: + encoded, err := encodeRepeated(sum.TextMap.GetEntries(), encodeTextMapEntry) + if err != nil { + return nil, err + } + return append([]byte{0x0b}, encoded...), nil + case *v2.Value_Record: + return encodeRecordValue(sum.Record) + case *v2.Value_Variant: + return encodeVariantValue(sum.Variant) + case *v2.Value_Enum: + return encodeEnumValue(sum.Enum) + case *v2.Value_GenMap: + encoded, err := encodeRepeated(sum.GenMap.GetEntries(), encodeGenMapEntry) + if err != nil { + return nil, err + } + return append([]byte{0x0f}, encoded...), nil + default: + return nil, fmt.Errorf("unsupported value type %T", sum) + } +} + +func encodeOptionalValue(optional *v2.Optional) ([]byte, error) { + var payload []byte + if optional != nil && optional.Value != nil { + encoded, err := encodeValue(optional.Value) + if err != nil { + return nil, err + } + payload = append([]byte{0x01}, encoded...) + } else { + payload = []byte{0x00} + } + return append([]byte{0x09}, payload...), nil +} + +func encodeRecordValue(record *v2.Record) ([]byte, error) { + if record == nil { + return nil, fmt.Errorf("record is nil") + } + recordID, err := encodeProtoOptionalIdentifier(record.GetRecordId()) + if err != nil { + return nil, err + } + fields, err := encodeRepeated(record.GetFields(), encodeRecordField) + if err != nil { + return nil, err + } + return bytes.Join([][]byte{{0x0c}, recordID, fields}, nil), nil +} + +func encodeVariantValue(variant *v2.Variant) ([]byte, error) { + if variant == nil { + return nil, fmt.Errorf("variant is nil") + } + variantID, err := encodeProtoOptionalIdentifier(variant.GetVariantId()) + if err != nil { + return nil, err + } + value, err := encodeValue(variant.GetValue()) + if err != nil { + return nil, err + } + return bytes.Join([][]byte{{0x0d}, variantID, encodeString(variant.GetConstructor()), value}, nil), nil +} + +func encodeEnumValue(enum *v2.Enum) ([]byte, error) { + if enum == nil { + return nil, fmt.Errorf("enum is nil") + } + enumID, err := encodeProtoOptionalIdentifier(enum.GetEnumId()) + if err != nil { + return nil, err + } + return bytes.Join([][]byte{{0x0e}, enumID, encodeString(enum.GetConstructor())}, nil), nil +} + +func encodeTextMapEntry(entry *v2.TextMap_Entry) ([]byte, error) { + if entry == nil { + return nil, fmt.Errorf("text map entry is nil") + } + value, err := encodeValue(entry.GetValue()) + if err != nil { + return nil, err + } + return bytes.Join([][]byte{encodeString(entry.GetKey()), value}, nil), nil +} + +func encodeRecordField(field *v2.RecordField) ([]byte, error) { + if field == nil { + return nil, fmt.Errorf("record field is nil") + } + label := encodeOptionalString(field.GetLabel()) + value, err := encodeValue(field.GetValue()) + if err != nil { + return nil, err + } + return append(label, value...), nil +} + +func encodeGenMapEntry(entry *v2.GenMap_Entry) ([]byte, error) { + if entry == nil { + return nil, fmt.Errorf("gen map entry is nil") + } + key, err := encodeValue(entry.GetKey()) + if err != nil { + return nil, err + } + value, err := encodeValue(entry.GetValue()) + if err != nil { + return nil, err + } + return append(key, value...), nil +} + +func createNodesDict(preparedTx *interactive.PreparedTransaction) (map[string]*interactive.DamlTransaction_Node, error) { + transaction := preparedTx.GetTransaction() + if transaction == nil { + return nil, fmt.Errorf("prepared transaction contains no DamlTransaction") + } + nodes := make(map[string]*interactive.DamlTransaction_Node, len(transaction.GetNodes())) + for _, node := range transaction.GetNodes() { + if node == nil { + return nil, fmt.Errorf("prepared transaction contains nil node") + } + nodes[node.GetNodeId()] = node + } + return nodes, nil +} + +func findSeed(nodeID string, nodeSeeds []*interactive.DamlTransaction_NodeSeed) []byte { + want, err := strconv.Atoi(nodeID) + if err != nil { + return nil + } + for _, nodeSeed := range nodeSeeds { + if int(nodeSeed.GetNodeId()) == want { + return nodeSeed.GetSeed() + } + } + return nil +} + +func encodeBool(value bool) []byte { + if value { + return []byte{0x01} + } + return []byte{0x00} +} + +func encodeInt32(value int32) []byte { + out := make([]byte, 4) + binary.BigEndian.PutUint32(out, uint32(value)) + return out +} + +func encodeInt64(value int64) []byte { + out := make([]byte, 8) + binary.BigEndian.PutUint64(out, uint64(value)) + return out +} + +func encodeString(value string) []byte { + return encodeBytes([]byte(value)) +} + +func encodeBytes(value []byte) []byte { + out := make([]byte, 4+len(value)) + copy(out[:4], encodeInt32(int32(len(value)))) + copy(out[4:], value) + return out +} + +func encodeHash(value []byte) []byte { + return append([]byte(nil), value...) +} + +func encodeHexString(value string) ([]byte, error) { + normalized := strings.TrimPrefix(value, "0x") + raw, err := hex.DecodeString(normalized) + if err != nil { + return nil, fmt.Errorf("invalid hex string %q: %w", value, err) + } + return encodeBytes(raw), nil +} + +func encodeOptionalBytes(value []byte, encodeFn func([]byte) []byte) []byte { + if value != nil { + return append([]byte{0x01}, encodeFn(value)...) + } + return []byte{0x00} +} + +func encodeOptionalString(value string) []byte { + if value != "" { + return append([]byte{0x01}, encodeString(value)...) + } + return []byte{0x00} +} + +func encodeOptionalUint64(value *uint64) []byte { + if value != nil { + return append([]byte{0x01}, encodeInt64(int64(*value))...) + } + return []byte{0x00} +} + +func encodeProtoOptionalIdentifier(identifier *v2.Identifier) ([]byte, error) { + if identifier == nil { + return []byte{0x00}, nil + } + encoded, err := encodeIdentifier(identifier) + if err != nil { + return nil, err + } + return append([]byte{0x01}, encoded...), nil +} + +func encodeProtoOptionalValue(value *v2.Value) ([]byte, error) { + if value == nil { + return []byte{0x00}, nil + } + encoded, err := encodeValue(value) + if err != nil { + return nil, err + } + return append([]byte{0x01}, encoded...), nil +} + +func encodeIdentifier(identifier *v2.Identifier) ([]byte, error) { + if identifier == nil { + return nil, fmt.Errorf("identifier is nil") + } + moduleParts, err := encodeRepeated(strings.Split(identifier.GetModuleName(), "."), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + entityParts, err := encodeRepeated(strings.Split(identifier.GetEntityName(), "."), func(v string) ([]byte, error) { + return encodeString(v), nil + }) + if err != nil { + return nil, err + } + return bytes.Join([][]byte{ + encodeString(identifier.GetPackageId()), + moduleParts, + entityParts, + }, nil), nil +} + +func encodeRepeated[T any](values []T, encodeFn func(T) ([]byte, error)) ([]byte, error) { + encodedValues := make([][]byte, 0, len(values)) + for _, value := range values { + encoded, err := encodeFn(value) + if err != nil { + return nil, err + } + encodedValues = append(encodedValues, encoded) + } + return bytes.Join(append([][]byte{encodeInt32(int32(len(values)))}, encodedValues...), nil), nil +} + +func encodeRepeatedStrings(values []string, encodeFn func(string) ([]byte, error)) ([]byte, error) { + return encodeRepeated(values, encodeFn) +} diff --git a/chain/canton/tx_input/hash_validation_test.go b/chain/canton/tx_input/hash_validation_test.go index 6c4a70cd..0dbe0fac 100644 --- a/chain/canton/tx_input/hash_validation_test.go +++ b/chain/canton/tx_input/hash_validation_test.go @@ -1,9 +1,11 @@ package tx_input import ( + "bytes" "encoding/hex" "encoding/json" "os" + "strconv" "testing" v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" @@ -16,7 +18,7 @@ import ( func TestComputePreparedTransactionHash(t *testing.T) { t.Parallel() - preparedTx := testPreparedTransaction("node-1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))) + preparedTx := testPreparedTransaction("1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))) hash1, err := ComputePreparedTransactionHash(preparedTx) require.NoError(t, err) @@ -38,7 +40,7 @@ func TestValidatePreparedTransactionHash_Flows(t *testing.T) { }{ { name: "transfer_preapproval_send", - preparedTx: testPreparedTransaction("node-1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))), + preparedTx: testPreparedTransaction("1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))), verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { t.Helper() require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) @@ -46,7 +48,7 @@ func TestValidatePreparedTransactionHash_Flows(t *testing.T) { }, { name: "transfer_offer_send", - preparedTx: testPreparedTransaction("node-1", testCreateNode("TransferOffer", testTransferOfferArgument("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "10.0"))), + preparedTx: testPreparedTransaction("1", testCreateNode("TransferOffer", testTransferOfferArgument("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "10.0"))), verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { t.Helper() require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) @@ -54,7 +56,7 @@ func TestValidatePreparedTransactionHash_Flows(t *testing.T) { }, { name: "create_account_accept", - preparedTx: testPreparedTransaction("node-1", testExerciseNode("ExternalPartySetupProposal_Accept", testEmptyRecord())), + preparedTx: testPreparedTransaction("1", testExerciseNode("ExternalPartySetupProposal_Accept", testEmptyRecord())), verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { t.Helper() preparedBz, err := proto.Marshal(preparedTx) @@ -71,7 +73,7 @@ func TestValidatePreparedTransactionHash_Flows(t *testing.T) { }, { name: "complete_transfer_offer", - preparedTx: testPreparedTransaction("node-1", testExerciseNode("AcceptedTransferOffer_Complete", testEmptyRecord())), + preparedTx: testPreparedTransaction("1", testExerciseNode("AcceptedTransferOffer_Complete", testEmptyRecord())), verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { t.Helper() require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) @@ -117,7 +119,7 @@ func TestValidatePreparedTransactionHash_LiveCreateAccountAcceptMismatch(t *test require.NoError(t, proto.Unmarshal(input.SetupProposalPreparedTransaction, &preparedTx)) err := ValidatePreparedTransactionHash(&preparedTx, input.SetupProposalHash) - require.ErrorContains(t, err, "prepared transaction hash mismatch") + require.NoError(t, err) require.NoError(t, input.VerifySignaturePayloads()) } @@ -142,7 +144,7 @@ func mustLoadLiveCreateAccountAcceptInput(t *testing.T) *CreateAccountInput { } func testPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTransaction { - return &interactive.PreparedTransaction{ + tx := &interactive.PreparedTransaction{ Transaction: &interactive.DamlTransaction{ Version: "2", Roots: []string{nodeID}, @@ -155,7 +157,27 @@ func testPreparedTransaction(nodeID string, node *v1.Node) *interactive.Prepared }, }, }, + Metadata: &interactive.Metadata{ + SubmitterInfo: &interactive.Metadata_SubmitterInfo{ + ActAs: []string{"sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, + CommandId: "command-id", + }, + SynchronizerId: "sync-id", + TransactionUuid: "transaction-uuid", + PreparationTime: 1, + InputContracts: []*interactive.Metadata_InputContract{}, + }, + } + if node.GetExercise() != nil { + seedID, err := strconv.Atoi(nodeID) + if err != nil { + panic(err) + } + tx.Transaction.NodeSeeds = []*interactive.DamlTransaction_NodeSeed{ + {NodeId: int32(seedID), Seed: bytes.Repeat([]byte{0x11}, 32)}, + } } + return tx } func testPreparedTransactionHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { @@ -174,7 +196,9 @@ func testCreateNode(entity string, argument *v2.Value) *v1.Node { ModuleName: "Splice.Wallet.TransferOffer", EntityName: entity, }, - Argument: argument, + ContractId: "001122", + PackageName: "splice-wallet", + Argument: argument, }, }, } @@ -189,6 +213,8 @@ func testExerciseNode(choice string, chosenValue *v2.Value) *v1.Node { ModuleName: "Splice.Wallet", EntityName: "Any", }, + ContractId: "001122", + PackageName: "splice-wallet", ChoiceId: choice, ChosenValue: chosenValue, }, diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index 80da75de..4e6bc3b5 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -11,6 +11,7 @@ import ( type TxInput struct { xc.TxInputEnvelope IsExternalTransfer bool `json:"is_external_transfer"` + LedgerEnd int64 `json:"ledger_end"` PreparedTransaction interactive.PreparedTransaction HashingSchemeVersion interactive.HashingSchemeVersion // SubmissionId for deduplication (UUID) From 7dc763dd91b2c941e1c47b0c8c35a5941f35dc8b Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Wed, 25 Mar 2026 22:44:48 +0100 Subject: [PATCH 09/23] CANTON: Fix tx-info fee report --- chain/canton/client/client.go | 35 +++++++++++------ chain/canton/client/client_test.go | 62 ++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 11 deletions(-) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index e7b91392..c7ca1352 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -424,8 +424,7 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf } func extractTransferOutputs(ex *v2.ExercisedEvent, decimals int32) ([]amuletCreation, bool) { - tid := ex.GetTemplateId() - if tid == nil || tid.GetModuleName() != "Splice.AmuletRules" || ex.GetChoice() != "AmuletRules_Transfer" { + if !isTransferExercise(ex) { return nil, false } @@ -438,13 +437,7 @@ func extractTransferOutputs(ex *v2.ExercisedEvent, decimals int32) ([]amuletCrea return nil, false } - var transferRecord *v2.Record - for _, field := range root.GetFields() { - if field.GetLabel() == "transfer" { - transferRecord = field.GetValue().GetRecord() - break - } - } + transferRecord := findRecordField(root, "transfer") if transferRecord == nil { return nil, false } @@ -506,8 +499,7 @@ func extractNumericValue(value *v2.Value, decimals int32) (xc.AmountBlockchain, } func extractTransferFee(ex *v2.ExercisedEvent, decimals int32) (xc.AmountBlockchain, bool) { - tid := ex.GetTemplateId() - if tid == nil || tid.GetModuleName() != "Splice.AmuletRules" || ex.GetChoice() != "AmuletRules_Transfer" { + if !isTransferExercise(ex) { return xc.AmountBlockchain{}, false } @@ -519,6 +511,7 @@ func extractTransferFee(ex *v2.ExercisedEvent, decimals int32) (xc.AmountBlockch if record == nil { return xc.AmountBlockchain{}, false } + record = unwrapTransferResultRecord(record) if burned, ok := extractBurnedFee(record, decimals); ok { return burned, true @@ -529,6 +522,26 @@ func extractTransferFee(ex *v2.ExercisedEvent, decimals int32) (xc.AmountBlockch return xc.AmountBlockchain{}, false } +func isTransferExercise(ex *v2.ExercisedEvent) bool { + tid := ex.GetTemplateId() + if tid == nil || tid.GetModuleName() != "Splice.AmuletRules" { + return false + } + switch ex.GetChoice() { + case "AmuletRules_Transfer", "TransferPreapproval_Send": + return true + default: + return false + } +} + +func unwrapTransferResultRecord(record *v2.Record) *v2.Record { + if nested := findRecordField(record, "result"); nested != nil { + return nested + } + return record +} + func extractBurnedFee(record *v2.Record, decimals int32) (xc.AmountBlockchain, bool) { metaRecord := findRecordField(record, "meta") if metaRecord == nil { diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index ba0e9121..cfcf6d1d 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -286,6 +286,68 @@ func TestFetchTxInfoUsesProvidedSenderWhenEventsDoNotExposeOne(t *testing.T) { require.Equal(t, xc.Address(sender), info.Movements[0].To[0].AddressId) } +func TestExtractTransferFeeSupportsTransferPreapprovalSendResult(t *testing.T) { + t.Parallel() + + ex := &v2.ExercisedEvent{ + TemplateId: &v2.Identifier{ + ModuleName: "Splice.AmuletRules", + EntityName: "TransferPreapproval", + }, + Choice: "TransferPreapproval_Send", + ExerciseResult: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "result", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "summary", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "senderChangeFee", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: "1.5"}}, + }, + { + Label: "outputFees", + Value: &v2.Value{ + Sum: &v2.Value_List{ + List: &v2.List{ + Elements: []*v2.Value{ + {Sum: &v2.Value_Numeric{Numeric: "0.5"}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + + fee, ok := extractTransferFee(ex, 18) + require.True(t, ok) + require.Equal(t, "2000000000000000000", fee.String()) +} + func mustSerializedCreateAccountInput(t *testing.T) []byte { t.Helper() input := &tx_input.CreateAccountInput{ From 4a118bc7cb6ad7018f26a2d2f12629285e3dddf2 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 26 Mar 2026 00:08:10 +0100 Subject: [PATCH 10/23] CANTON: Refactor create account command --- chain/canton/address/address.go | 12 +- chain/canton/address/address_test.go | 82 ++-------- chain/canton/client/client.go | 41 ++++- chain/canton/client/client_test.go | 101 ++++++++++-- chain/canton/tx/create_account_tx.go | 41 ++++- chain/canton/tx/create_account_tx_test.go | 11 +- chain/canton/tx/metadata.go | 102 ++++++++++++ chain/canton/tx/tx.go | 10 ++ .../tx_input/create_account_input_test.go | 46 ------ .../testdata/live_topology_vector.json | 7 + chain/canton/tx_input/topology_hash_test.go | 57 +++++-- cmd/xc/commands/create_account.go | 149 +++++++++++------- cmd/xc/commands/submit.go | 12 +- 13 files changed, 450 insertions(+), 221 deletions(-) create mode 100644 chain/canton/tx/metadata.go create mode 100644 chain/canton/tx_input/testdata/live_topology_vector.json diff --git a/chain/canton/address/address.go b/chain/canton/address/address.go index 096e6067..a865e24e 100644 --- a/chain/canton/address/address.go +++ b/chain/canton/address/address.go @@ -34,14 +34,6 @@ func NewAddressBuilder(cfgI *xc.ChainBaseConfig) (xc.AddressBuilder, error) { // - 0x12 = SHA-256 algorithm code (varint) // - 0x20 = 32-byte digest length (varint) func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { - return GetAddressFromPublicKey(publicKeyBytes) -} - -func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { - return true -} - -func GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { if len(publicKeyBytes) != 32 { return "", fmt.Errorf("invalid ed25519 public key length: expected 32 bytes, got %d", len(publicKeyBytes)) } @@ -52,6 +44,10 @@ func GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { return addr, nil } +func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { + return true +} + // computeFingerprint returns the Canton key fingerprint for a raw Ed25519 public key. // // fingerprint = "1220" + hex(SHA-256(bigEndianUint32(12) || rawPubKey)) diff --git a/chain/canton/address/address_test.go b/chain/canton/address/address_test.go index 1680cc71..1e6bc283 100644 --- a/chain/canton/address/address_test.go +++ b/chain/canton/address/address_test.go @@ -1,8 +1,6 @@ package address import ( - "crypto/sha256" - "encoding/binary" "encoding/hex" "testing" @@ -10,17 +8,6 @@ import ( "github.com/stretchr/testify/require" ) -// referenceFingerprint replicates Canton's fingerprint logic for test verification: -// SHA-256(bigEndianUint32(12) || rawPubKey), encoded as "1220" + hex(digest) -func referenceFingerprint(pubKey []byte) string { - var purposeBytes [4]byte - binary.BigEndian.PutUint32(purposeBytes[:], 12) - h := sha256.New() - h.Write(purposeBytes[:]) - h.Write(pubKey) - return "1220" + hex.EncodeToString(h.Sum(nil)) -} - func TestNewAddressBuilder(t *testing.T) { cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} builder, err := NewAddressBuilder(cfg) @@ -46,67 +33,19 @@ func TestGetAddressFromPublicKey(t *testing.T) { // Name must be the hex-encoded public key require.Equal(t, hex.EncodeToString(pubKey), name) - - // Fingerprint must be "1220" + 64 hex chars (SHA-256 multihash) - require.Equal(t, 68, len(fingerprint), "fingerprint must be 68 chars: 4 (1220) + 64 (SHA-256 hex)") - require.Equal(t, "1220", fingerprint[:4]) - - // Fingerprint value must match Canton's formula - require.Equal(t, referenceFingerprint(pubKey), fingerprint) -} - -func TestGetAddressFromPublicKeyInvalidLength(t *testing.T) { - cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} - builder, err := NewAddressBuilder(cfg) - require.NoError(t, err) - - for _, bad := range [][]byte{make([]byte, 16), make([]byte, 64), {}} { - _, err := builder.GetAddressFromPublicKey(bad) - require.Error(t, err) - require.Contains(t, err.Error(), "invalid ed25519 public key length") - } -} - -func TestAddressDeterminism(t *testing.T) { - cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} - builder, err := NewAddressBuilder(cfg) - require.NoError(t, err) - - pubKey := make([]byte, 32) - for i := range pubKey { - pubKey[i] = byte(i * 7 % 256) - } - - addr1, err := builder.GetAddressFromPublicKey(pubKey) - require.NoError(t, err) - addr2, err := builder.GetAddressFromPublicKey(pubKey) - require.NoError(t, err) - require.Equal(t, addr1, addr2) -} - -func TestDifferentKeysProduceDifferentAddresses(t *testing.T) { - cfg := &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton} - builder, _ := NewAddressBuilder(cfg) - - key1 := make([]byte, 32) - key2 := make([]byte, 32) - key2[0] = 1 - - addr1, _ := builder.GetAddressFromPublicKey(key1) - addr2, _ := builder.GetAddressFromPublicKey(key2) - require.NotEqual(t, addr1, addr2) + require.Equal(t, "122093aa96c5554371f0d1fd471ce282f3b590ab0758f35c124924c8e3715910bbe1", fingerprint) } func TestParsePartyID(t *testing.T) { validFP := "1220" + hex.EncodeToString(make([]byte, 32)) // "1220" + 64 zeros tests := []struct { - name string - addr xc.Address - expectErr bool - errContains string - expectedName string - expectedFP string + name string + addr xc.Address + expectErr bool + errContains string + expectedName string + expectedFP string }{ { name: "valid - pubkey hex name", @@ -170,5 +109,12 @@ func TestFingerprintLength(t *testing.T) { _, fp, err := ParsePartyID(addr) require.NoError(t, err) require.Equal(t, 68, len(fp), "fingerprint must always be 68 chars") + expected := map[byte]string{ + 0: "1220ea618da83b6c6b2c4557ffa17d722045169f52b8f50f3b31fc867e266de7e53d", + 1: "1220974cb80e78f2fea077628a02faa4c57d68a65036eea27fb3463088a1c8527a99", + 127: "122087fab42073577d1d066f0cc217b347aedf5a73ee5feaa75d5e96538dad977b91", + 255: "122044e19d94c296e8397d61e759ff1692e5dff8efbcd70d7a9b4033d8b4a259ccd0", + } + require.Equal(t, expected[seed], fp) } } diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index c7ca1352..7c73249a 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -219,19 +219,36 @@ func (client *Client) FetchLegacyTxInput(ctx context.Context, from xc.Address, t return client.FetchTransferInput(ctx, args) } -// SubmitTx accepts either a serialized Canton transfer submission or a -// serialized Canton create-account transaction and dispatches it accordingly. +// SubmitTx accepts a serialized Canton transaction together with metadata that +// identifies the Canton transaction type to submit. func (client *Client) SubmitTx(ctx context.Context, submitReq xctypes.SubmitTxReq) error { if len(submitReq.TxData) == 0 { return fmt.Errorf("empty transaction data") } - - if createAccountTx, err := cantontx.ParseCreateAccountTx(submitReq.TxData); err == nil { + if submitReq.BroadcastInput == "" { + return fmt.Errorf("missing Canton tx metadata") + } + metadata, err := cantontx.ParseMetadata([]byte(submitReq.BroadcastInput)) + if err != nil { + return fmt.Errorf("failed to parse Canton tx metadata: %w", err) + } + switch metadata.TxType { + case cantontx.TxTypeCreateAccount: + createAccountTx, err := cantontx.ParseCreateAccountTxWithMetadata(submitReq.TxData, metadata) + if err != nil { + return fmt.Errorf("failed to parse Canton create-account tx: %w", err) + } return client.submitCreateAccountTx(ctx, createAccountTx) + case cantontx.TxTypeTransfer: + return client.submitTransferTx(ctx, submitReq.TxData) + default: + return fmt.Errorf("unsupported Canton tx type %q", metadata.TxType) } +} +func (client *Client) submitTransferTx(ctx context.Context, payload []byte) error { var req interactive.ExecuteSubmissionRequest - if err := proto.Unmarshal(submitReq.TxData, &req); err != nil { + if err := proto.Unmarshal(payload, &req); err != nil { return fmt.Errorf("failed to unmarshal Canton execute request: %w", err) } @@ -763,6 +780,13 @@ func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateA } contracts, err := client.ledgerClient.GetActiveContracts(ctx, partyID, ledgerEnd, true) if err != nil { + if isPermissionDenied(err) { + logger.WithError(err).Info("get-account-state: party exists but contract visibility is not ready yet") + return &xclient.AccountState{ + State: xclient.CreateAccountCallRequired, + Description: "Account exists but registration is not complete yet. Call create-account again to continue.", + }, nil + } logger.WithError(err).Error("get-account-state: get active contracts failed") return nil, fmt.Errorf("failed to fetch active contracts: %w", err) } @@ -979,3 +1003,10 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx return fmt.Errorf("unsupported create-account stage %q", cantonInput.Stage) } } + +func isPermissionDenied(err error) bool { + if err == nil { + return false + } + return strings.Contains(err.Error(), "code = PermissionDenied") +} diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index cfcf6d1d..b1fc9e2c 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -7,6 +7,8 @@ import ( "time" xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" txinfo "github.com/cordialsys/crosschain/client/tx_info" xctypes "github.com/cordialsys/crosschain/client/types" @@ -56,17 +58,51 @@ func TestNewClient(t *testing.T) { }) } -func TestSubmitTxRoutesCreateAccountPayloadToCreateAccountTxPath(t *testing.T) { +func TestSubmitTxRequiresMetadata(t *testing.T) { t.Parallel() - client := &Client{} - err := client.SubmitTx(context.Background(), xctypes.SubmitTxReq{ - TxData: mustSerializedCreateAccountInput(t), - }) - require.ErrorContains(t, err, "create-account transaction is not signed") + stub := &interactiveSubmissionStub{} + client := &Client{ + ledgerClient: &GrpcLedgerClient{ + authToken: "token", + interactiveSubmissionClient: stub, + logger: logrus.NewEntry(logrus.New()), + }, + } + + req := &interactive.ExecuteSubmissionRequest{ + SubmissionId: "submission-id", + } + payload, err := proto.Marshal(req) + require.NoError(t, err) + + tests := []struct { + name string + payload []byte + }{ + { + name: "create-account payload", + payload: mustSerializedCreateAccountInput(t), + }, + { + name: "transfer payload", + payload: payload, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + err := client.SubmitTx(context.Background(), xctypes.SubmitTxReq{TxData: tt.payload}) + require.ErrorContains(t, err, "missing Canton tx metadata") + require.Nil(t, stub.lastReq) + }) + } } -func TestSubmitTxExecutesStandardCantonPayload(t *testing.T) { +func TestSubmitTxUsesMetadataToRouteTransferPayload(t *testing.T) { t.Parallel() stub := &interactiveSubmissionStub{} @@ -78,18 +114,35 @@ func TestSubmitTxExecutesStandardCantonPayload(t *testing.T) { }, } - req := &interactive.ExecuteSubmissionRequest{ - SubmissionId: "submission-id", - } + req := &interactive.ExecuteSubmissionRequest{SubmissionId: "submission-id"} payload, err := proto.Marshal(req) require.NoError(t, err) - err = client.SubmitTx(context.Background(), xctypes.SubmitTxReq{TxData: payload}) + metadata, err := cantontx.NewTransferMetadata().Bytes() + require.NoError(t, err) + + err = client.SubmitTx(context.Background(), xctypes.SubmitTxReq{ + TxData: payload, + BroadcastInput: string(metadata), + }) require.NoError(t, err) require.NotNil(t, stub.lastReq) require.Equal(t, "submission-id", stub.lastReq.GetSubmissionId()) } +func TestSubmitTxUsesMetadataToRouteCreateAccountPayload(t *testing.T) { + t.Parallel() + + client := &Client{} + payload, metadata := mustSerializedCreateAccountTx(t) + + err := client.SubmitTx(context.Background(), xctypes.SubmitTxReq{ + TxData: payload, + BroadcastInput: string(metadata), + }) + require.ErrorContains(t, err, "create-account transaction is not signed") +} + func TestFetchTxInfoResolvesRecoveryLookupId(t *testing.T) { t.Parallel() @@ -361,6 +414,26 @@ func mustSerializedCreateAccountInput(t *testing.T) []byte { return bz } +func mustSerializedCreateAccountTx(t *testing.T) ([]byte, []byte) { + t.Helper() + input := &tx_input.CreateAccountInput{ + Stage: tx_input.CreateAccountStageAllocate, + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + TopologyTransactions: [][]byte{{0x01}}, + } + args, err := xcbuilder.NewCreateAccountArgs(xc.CANTON, xc.Address(input.PartyID), []byte{0x01, 0x02}) + require.NoError(t, err) + tx, err := cantontx.NewCreateAccountTx(args, input) + require.NoError(t, err) + payload, err := tx.Serialize() + require.NoError(t, err) + metadata, ok, err := tx.GetMetadata() + require.NoError(t, err) + require.True(t, ok) + return payload, metadata +} + type interactiveSubmissionStub struct { lastReq *interactive.ExecuteSubmissionAndWaitRequest } @@ -386,9 +459,9 @@ func (s *interactiveSubmissionStub) GetPreferredPackages(context.Context, *inter } type completionServiceStub struct { - lastReq *v2.CompletionStreamRequest - responses []*v2.CompletionStreamResponse - streamErr error + lastReq *v2.CompletionStreamRequest + responses []*v2.CompletionStreamResponse + streamErr error } func (s *completionServiceStub) CompletionStream(_ context.Context, req *v2.CompletionStreamRequest, _ ...grpc.CallOption) (grpc.ServerStreamingClient[v2.CompletionStreamResponse], error) { diff --git a/chain/canton/tx/create_account_tx.go b/chain/canton/tx/create_account_tx.go index 7d543a39..acfb7d25 100644 --- a/chain/canton/tx/create_account_tx.go +++ b/chain/canton/tx/create_account_tx.go @@ -2,6 +2,7 @@ package tx import ( "crypto/sha256" + "encoding/binary" "fmt" xc "github.com/cordialsys/crosschain" @@ -15,6 +16,9 @@ type CreateAccountTx struct { } var _ xc.Tx = &CreateAccountTx{} +var _ xc.TxWithMetadata = &CreateAccountTx{} + +const createAccountPayloadPrefixLen = 8 func NewCreateAccountTx(args xcbuilder.CreateAccountArgs, input xc.CreateAccountTxInput) (*CreateAccountTx, error) { cantonInput, ok := input.(*tx_input.CreateAccountInput) @@ -30,13 +34,14 @@ func NewCreateAccountTx(args xcbuilder.CreateAccountArgs, input xc.CreateAccount return &CreateAccountTx{Input: cloneCreateAccountInput(cantonInput)}, nil } -func ParseCreateAccountTx(data []byte) (*CreateAccountTx, error) { - input, err := tx_input.ParseCreateAccountInput(data) +func ParseCreateAccountTxWithMetadata(data []byte, metadata *Metadata) (*CreateAccountTx, error) { + signature, err := parseCreateAccountSignaturePayload(data) if err != nil { return nil, err } - if err := input.VerifySignaturePayloads(); err != nil { - return nil, fmt.Errorf("invalid create-account tx: %w", err) + input, err := metadata.CreateAccountInput(signature) + if err != nil { + return nil, err } return &CreateAccountTx{Input: input}, nil } @@ -45,7 +50,7 @@ func (tx *CreateAccountTx) Hash() xc.TxHash { if tx == nil || tx.Input == nil { return "" } - serialized, err := tx.Input.Serialize() + serialized, err := tx.Serialize() if err != nil { return "" } @@ -82,7 +87,21 @@ func (tx *CreateAccountTx) Serialize() ([]byte, error) { if tx == nil || tx.Input == nil { return nil, fmt.Errorf("create-account tx input is nil") } - return tx.Input.Serialize() + payload := make([]byte, createAccountPayloadPrefixLen+len(tx.Input.Signature)) + copy(payload[createAccountPayloadPrefixLen:], tx.Input.Signature) + return payload, nil +} + +func (tx *CreateAccountTx) GetMetadata() ([]byte, bool, error) { + if tx == nil || tx.Input == nil { + return nil, false, fmt.Errorf("create-account tx input is nil") + } + metadata := NewCreateAccountMetadata(tx.Input) + bz, err := metadata.Bytes() + if err != nil { + return nil, false, err + } + return bz, true, nil } func (tx *CreateAccountTx) KeyFingerprint() (string, error) { @@ -122,3 +141,13 @@ func cloneCreateAccountInput(input *tx_input.CreateAccountInput) *tx_input.Creat } return &cloned } + +func parseCreateAccountSignaturePayload(data []byte) ([]byte, error) { + if len(data) < createAccountPayloadPrefixLen { + return nil, fmt.Errorf("create-account tx payload is too short") + } + if binary.BigEndian.Uint64(data[:createAccountPayloadPrefixLen]) != 0 { + return nil, fmt.Errorf("unsupported create-account tx payload format") + } + return append([]byte(nil), data[createAccountPayloadPrefixLen:]...), nil +} diff --git a/chain/canton/tx/create_account_tx_test.go b/chain/canton/tx/create_account_tx_test.go index afa21a80..1927406e 100644 --- a/chain/canton/tx/create_account_tx_test.go +++ b/chain/canton/tx/create_account_tx_test.go @@ -58,8 +58,15 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { unsigned, err := tx.Serialize() require.NoError(t, err) + require.Len(t, unsigned, 8) - parsedUnsigned, err := ParseCreateAccountTx(unsigned) + metadataBz, ok, err := tx.GetMetadata() + require.NoError(t, err) + require.True(t, ok) + metadata, err := ParseMetadata(metadataBz) + require.NoError(t, err) + + parsedUnsigned, err := ParseCreateAccountTxWithMetadata(unsigned, metadata) require.NoError(t, err) require.Equal(t, tt.input.Stage, parsedUnsigned.Input.Stage) @@ -69,7 +76,7 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { signed, err := tx.Serialize() require.NoError(t, err) - parsedSigned, err := ParseCreateAccountTx(signed) + parsedSigned, err := ParseCreateAccountTxWithMetadata(signed, metadata) require.NoError(t, err) require.Equal(t, "dead", hex.EncodeToString(parsedSigned.Input.Signature)) require.NotEmpty(t, tx.Hash()) diff --git a/chain/canton/tx/metadata.go b/chain/canton/tx/metadata.go new file mode 100644 index 00000000..36e21e90 --- /dev/null +++ b/chain/canton/tx/metadata.go @@ -0,0 +1,102 @@ +package tx + +import ( + "encoding/json" + "fmt" + + "github.com/cordialsys/crosschain/chain/canton/tx_input" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" +) + +const ( + TxTypeTransfer = "transfer" + TxTypeCreateAccount = "create_account" +) + +type Metadata struct { + TxType string `json:"tx_type"` + + CreateAccount *CreateAccountMetadata `json:"create_account,omitempty"` +} + +type CreateAccountMetadata struct { + Stage string `json:"stage"` + + PartyID string `json:"party_id"` + PublicKeyFingerprint string `json:"public_key_fingerprint,omitempty"` + TopologyTransactions [][]byte `json:"topology_transactions,omitempty"` + + SetupProposalPreparedTransaction []byte `json:"setup_proposal_prepared_transaction,omitempty"` + SetupProposalHash []byte `json:"setup_proposal_hash,omitempty"` + SetupProposalHashing interactive.HashingSchemeVersion `json:"setup_proposal_hashing,omitempty"` + SetupProposalSubmissionID string `json:"setup_proposal_submission_id,omitempty"` +} + +func ParseMetadata(data []byte) (*Metadata, error) { + var metadata Metadata + if err := json.Unmarshal(data, &metadata); err != nil { + return nil, err + } + return &metadata, nil +} + +func (m *Metadata) Bytes() ([]byte, error) { + return json.Marshal(m) +} + +func NewTransferMetadata() *Metadata { + return &Metadata{ + TxType: TxTypeTransfer, + } +} + +func NewCreateAccountMetadata(input *tx_input.CreateAccountInput) *Metadata { + if input == nil { + return &Metadata{TxType: TxTypeCreateAccount} + } + return &Metadata{ + TxType: TxTypeCreateAccount, + CreateAccount: &CreateAccountMetadata{ + Stage: input.Stage, + PartyID: input.PartyID, + PublicKeyFingerprint: input.PublicKeyFingerprint, + TopologyTransactions: cloneMetadataBytes2D(input.TopologyTransactions), + SetupProposalPreparedTransaction: append([]byte(nil), input.SetupProposalPreparedTransaction...), + SetupProposalHash: append([]byte(nil), input.SetupProposalHash...), + SetupProposalHashing: input.SetupProposalHashing, + SetupProposalSubmissionID: input.SetupProposalSubmissionID, + }, + } +} + +func (m *Metadata) CreateAccountInput(signature []byte) (*tx_input.CreateAccountInput, error) { + if m == nil || m.CreateAccount == nil { + return nil, fmt.Errorf("missing Canton create-account metadata") + } + input := &tx_input.CreateAccountInput{ + Stage: m.CreateAccount.Stage, + PartyID: m.CreateAccount.PartyID, + PublicKeyFingerprint: m.CreateAccount.PublicKeyFingerprint, + TopologyTransactions: cloneMetadataBytes2D(m.CreateAccount.TopologyTransactions), + SetupProposalPreparedTransaction: append([]byte(nil), m.CreateAccount.SetupProposalPreparedTransaction...), + SetupProposalHash: append([]byte(nil), m.CreateAccount.SetupProposalHash...), + SetupProposalHashing: m.CreateAccount.SetupProposalHashing, + SetupProposalSubmissionID: m.CreateAccount.SetupProposalSubmissionID, + Signature: append([]byte(nil), signature...), + } + if err := input.VerifySignaturePayloads(); err != nil { + return nil, fmt.Errorf("invalid create-account metadata payload: %w", err) + } + return input, nil +} + +func cloneMetadataBytes2D(values [][]byte) [][]byte { + if len(values) == 0 { + return nil + } + cloned := make([][]byte, len(values)) + for i, value := range values { + cloned[i] = append([]byte(nil), value...) + } + return cloned +} diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go index b2eac965..87a19c4a 100644 --- a/chain/canton/tx/tx.go +++ b/chain/canton/tx/tx.go @@ -34,6 +34,7 @@ type Tx struct { } var _ xc.Tx = &Tx{} +var _ xc.TxWithMetadata = &Tx{} // NewTx constructs a Tx from a TxInput and transfer args, validating that the // receiver and amount encoded in the prepared transaction match the transfer args. @@ -265,3 +266,12 @@ func (tx Tx) Serialize() ([]byte, error) { } return data, nil } + +func (tx Tx) GetMetadata() ([]byte, bool, error) { + metadata := NewTransferMetadata() + bz, err := metadata.Bytes() + if err != nil { + return nil, false, err + } + return bz, true, nil +} diff --git a/chain/canton/tx_input/create_account_input_test.go b/chain/canton/tx_input/create_account_input_test.go index b9055907..7c05c1ad 100644 --- a/chain/canton/tx_input/create_account_input_test.go +++ b/chain/canton/tx_input/create_account_input_test.go @@ -1,58 +1,12 @@ package tx_input import ( - "encoding/hex" "testing" xc "github.com/cordialsys/crosschain" "github.com/stretchr/testify/require" ) -func TestCreateAccountInputSerializeRoundTrip(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - input *CreateAccountInput - }{ - { - name: "allocate", - input: &CreateAccountInput{ - Stage: CreateAccountStageAllocate, - Description: "allocate", - PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - TopologyTransactions: [][]byte{{0x01, 0x02}, {0x03, 0x04}}, - Signature: []byte{0x05, 0x06}, - }, - }, - { - name: "accept", - input: mustLoadLiveCreateAccountAcceptInput(t), - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - bz, err := tt.input.Serialize() - require.NoError(t, err) - - parsed, err := ParseCreateAccountInput(bz) - require.NoError(t, err) - require.Equal(t, tt.input.Stage, parsed.Stage) - require.Equal(t, tt.input.Description, parsed.Description) - require.Equal(t, tt.input.PartyID, parsed.PartyID) - require.Equal(t, hex.EncodeToString(tt.input.Signature), hex.EncodeToString(parsed.Signature)) - require.Equal(t, hex.EncodeToString(tt.input.SetupProposalHash), hex.EncodeToString(parsed.SetupProposalHash)) - require.Equal(t, tt.input.SetupProposalSubmissionID, parsed.SetupProposalSubmissionID) - require.Equal(t, tt.input.TopologyTransactions, parsed.TopologyTransactions) - }) - } -} - func TestCreateAccountInputSetSignatures(t *testing.T) { t.Parallel() diff --git a/chain/canton/tx_input/testdata/live_topology_vector.json b/chain/canton/tx_input/testdata/live_topology_vector.json new file mode 100644 index 00000000..4d730121 --- /dev/null +++ b/chain/canton/tx_input/testdata/live_topology_vector.json @@ -0,0 +1,7 @@ +{ + "public_key_fingerprint": "1220fb837a9079c66e39bde8d45dfc6e79dc80f7c931940a01d6622e4fee0b40933c", + "multi_hash": "12206947cbe26cda1680526f5a6957927b9272bc5ca3d2af6dc7946d9c3182bfe8de", + "topology_transactions": [ + "0ab602080110011aaf024aac020a8601366166636665383630353565643562616636613437663537356636353566666162333836653032373938653332626463373736303363613233386239623635623a3a313232306662383337613930373963363665333962646538643435646663366537396463383066376339333139343061303164363632326534666565306234303933336310011a620a5e76616c696461746f722d636f726469616c73797374656d733a3a31323230653666626163393063636431393763333536363931386639393937373362303434393565313537616463316662383033623936656465326561613562336164661002323b0a3710041a2c302a300506032b65700321006afcfe86055ed5baf6a47f575f655ffab386e02798e32bdc77603ca238b9b65b2a0301050430011001101e" + ] +} diff --git a/chain/canton/tx_input/topology_hash_test.go b/chain/canton/tx_input/topology_hash_test.go index d5b41959..bc58e49d 100644 --- a/chain/canton/tx_input/topology_hash_test.go +++ b/chain/canton/tx_input/topology_hash_test.go @@ -2,38 +2,61 @@ package tx_input import ( "encoding/hex" + "encoding/json" + "os" "testing" "github.com/stretchr/testify/require" ) -func TestComputeTopologyTransactionHash(t *testing.T) { +func TestComputeTopologyMultiHashFailures(t *testing.T) { t.Parallel() - hash, err := ComputeTopologyTransactionHash([]byte{0x01, 0x02, 0x03}) - require.NoError(t, err) - require.Equal(t, "1220c1467c073293cec489633f24df12269d37f5fc14c5e7793119703965b001b751", hex.EncodeToString(hash)) + _, err := ComputeTopologyMultiHash(nil) + require.ErrorContains(t, err, "topology transactions are empty") + + _, err = ComputeTopologyMultiHash([][]byte{{}}) + require.ErrorContains(t, err, "topology transaction is empty") } -func TestComputeTopologyMultiHash(t *testing.T) { +func TestComputeTopologyMultiHash_LiveVector(t *testing.T) { t.Parallel() - hash1, err := ComputeTopologyMultiHash([][]byte{{0x01, 0x02}, {0x03, 0x04}}) - require.NoError(t, err) - - hash2, err := ComputeTopologyMultiHash([][]byte{{0x03, 0x04}, {0x01, 0x02}}) + vector := mustLoadLiveTopologyVector(t) + hash, err := ComputeTopologyMultiHash(vector.topologyTransactions) require.NoError(t, err) + require.Equal(t, vector.multiHash, hash) +} - require.Equal(t, hash1, hash2) - require.Equal(t, "122086be10f2f6a61410ec823c4350eb8eef35b66481a0dd080f2607f15f7d3b57ef", hex.EncodeToString(hash1)) +type liveTopologyVector struct { + multiHash []byte + topologyTransactions [][]byte } -func TestComputeTopologyMultiHashFailures(t *testing.T) { - t.Parallel() +func mustLoadLiveTopologyVector(t *testing.T) liveTopologyVector { + t.Helper() - _, err := ComputeTopologyMultiHash(nil) - require.ErrorContains(t, err, "topology transactions are empty") + data, err := os.ReadFile("testdata/live_topology_vector.json") + require.NoError(t, err) - _, err = ComputeTopologyMultiHash([][]byte{{}}) - require.ErrorContains(t, err, "topology transaction is empty") + var fixture struct { + MultiHash string `json:"multi_hash"` + TopologyTransactions []string `json:"topology_transactions"` + } + require.NoError(t, json.Unmarshal(data, &fixture)) + + multiHash, err := hex.DecodeString(fixture.MultiHash) + require.NoError(t, err) + + topologyTransactions := make([][]byte, 0, len(fixture.TopologyTransactions)) + for _, encoded := range fixture.TopologyTransactions { + tx, err := hex.DecodeString(encoded) + require.NoError(t, err) + topologyTransactions = append(topologyTransactions, tx) + } + + return liveTopologyVector{ + multiHash: multiHash, + topologyTransactions: topologyTransactions, + } } diff --git a/cmd/xc/commands/create_account.go b/cmd/xc/commands/create_account.go index bb8e2e77..c5a1ec25 100644 --- a/cmd/xc/commands/create_account.go +++ b/cmd/xc/commands/create_account.go @@ -1,28 +1,30 @@ package commands import ( - "context" - "encoding/hex" "fmt" + "time" + xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" - "github.com/cordialsys/crosschain/chain/canton/tx_input" xclient "github.com/cordialsys/crosschain/client" "github.com/cordialsys/crosschain/cmd/xc/setup" "github.com/cordialsys/crosschain/config" "github.com/cordialsys/crosschain/factory/signer" + fsigner "github.com/cordialsys/crosschain/factory/signer" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) func CmdCreateAccount() *cobra.Command { var privateKeyRef string + var timeout time.Duration cmd := &cobra.Command{ Use: "create-account", - Short: "Advance account registration and return the next signature request when one is needed.", + Short: "Create or register an account end-to-end when the chain requires it.", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() xcFactory := setup.UnwrapXc(cmd.Context()) chainConfig := setup.UnwrapChain(cmd.Context()) @@ -38,6 +40,8 @@ func CmdCreateAccount() *cobra.Command { if err != nil { return fmt.Errorf("could not import private key: %v", err) } + signerCollection := fsigner.NewCollection() + publicKey, err := xcSigner.PublicKey() if err != nil { return fmt.Errorf("could not derive public key: %v", err) @@ -50,6 +54,7 @@ func CmdCreateAccount() *cobra.Command { if err != nil { return fmt.Errorf("could not derive address: %v", err) } + signerCollection.AddMainSigner(xcSigner, address) logrus.WithField("address", address).Info("registering account") @@ -71,68 +76,104 @@ func CmdCreateAccount() *cobra.Command { } createArgs := xclient.NewCreateAccountArgs(address, publicKey) - input, err := accountClient.FetchCreateAccountInput(context.Background(), createArgs) - if err != nil { - return fmt.Errorf("could not fetch create-account input: %v", err) - } - if input == nil { - fmt.Println(asJson(map[string]string{ - "address": string(address), - "chain": string(chainConfig.Chain), - "status": "registered", - })) - return nil - } - - cantonInput, ok := input.(*tx_input.CreateAccountInput) - if !ok { - return fmt.Errorf("invalid create-account input type: %T", input) - } - if err := cantonInput.VerifySignaturePayloads(); err != nil { - return fmt.Errorf("hash verification failed: %v", err) - } builderArgs, err := xcbuilder.NewCreateAccountArgs(chainConfig.Chain, address, publicKey) if err != nil { return fmt.Errorf("could not build create-account args: %v", err) } - tx, err := accountBuilder.CreateAccount(builderArgs, input) - if err != nil { - return fmt.Errorf("could not build create-account tx: %v", err) - } - sighashes, err := tx.Sighashes() - if err != nil { - return fmt.Errorf("could not get sighashes: %v", err) - } - if len(sighashes) != 1 { - return fmt.Errorf("expected exactly 1 signature request, got %d", len(sighashes)) - } + start := time.Now() + for time.Since(start) < timeout { + state, err := accountClient.GetAccountState(ctx, createArgs) + if err != nil { + return fmt.Errorf("could not fetch account state: %v", err) + } - logrus.WithField("count", len(sighashes)).Info("signature required") - for i, sh := range sighashes { - logrus.WithField("index", i).WithField("payload", hex.EncodeToString(sh.Payload)).Debug("signature request") - } + switch state.State { + case xclient.Created: + fmt.Println(asJson(map[string]any{ + "address": string(address), + "chain": string(chainConfig.Chain), + "status": "registered", + "state": state.State, + "description": state.Description, + })) + return nil + case xclient.Pending: + logrus.WithField("description", state.Description).Info("account creation is pending, waiting 10s") + time.Sleep(10 * time.Second) + continue + case xclient.CreateAccountCallRequired: + logrus.WithField("description", state.Description).Info("account creation step required") - serializedInput, err := tx.Serialize() - if err != nil { - return fmt.Errorf("could not serialize create-account tx: %v", err) + input, err := accountClient.FetchCreateAccountInput(ctx, createArgs) + if err != nil { + return fmt.Errorf("could not fetch create-account input: %v", err) + } + if input == nil { + logrus.Info("account client reported no pending create-account step, re-checking state") + time.Sleep(2 * time.Second) + continue + } + + tx, err := prepareCreateAccountForSubmit(accountBuilder, builderArgs, input, signerCollection) + if err != nil { + return fmt.Errorf("could not prepare create-account tx: %v", err) + } + + if err := SubmitTransaction(chainConfig.Chain, rpcClient, tx, timeoutRemaining(start, timeout)); err != nil { + return fmt.Errorf("could not submit create-account tx: %v", err) + } + continue + default: + return fmt.Errorf("unsupported account state %q", state.State) + } } - fmt.Println(asJson(map[string]any{ - "address": string(address), - "chain": string(chainConfig.Chain), - "status": "signature_required", - "stage": cantonInput.Stage, - "description": cantonInput.Description, - "signature_request": map[string]any{ - "payload": hex.EncodeToString(sighashes[0].Payload), - }, - "tx": hex.EncodeToString(serializedInput), - })) - return nil + return fmt.Errorf("timed out waiting for account creation after %s", timeout) }, } cmd.Flags().StringVar(&privateKeyRef, "key", "env:"+signer.EnvPrivateKey, "Secret reference for the private key") + cmd.Flags().DurationVar(&timeout, "timeout", 2*time.Minute, "Amount of time to wait for account creation to complete.") return cmd } + +func prepareCreateAccountForSubmit(accountBuilder xcbuilder.AccountCreation, builderArgs xcbuilder.CreateAccountArgs, input xc.CreateAccountTxInput, signerCollection *fsigner.Collection) (xc.Tx, error) { + tx, err := accountBuilder.CreateAccount(builderArgs, input) + if err != nil { + return nil, fmt.Errorf("could not build create-account tx: %v", err) + } + + signatures := []*xc.SignatureResponse{} + sighashes, err := tx.Sighashes() + if err != nil { + return nil, fmt.Errorf("could not create payloads to sign: %v", err) + } + if len(sighashes) == 0 { + return nil, fmt.Errorf("create-account tx produced no sighashes") + } + for _, sighash := range sighashes { + signature, err := signerCollection.Sign(sighash.Signer, sighash.Payload) + if err != nil { + return nil, err + } + signatures = append(signatures, signature) + } + + tx, err = accountBuilder.CreateAccount(builderArgs, input) + if err != nil { + return nil, fmt.Errorf("could not rebuild create-account tx for serialization: %v", err) + } + if err := tx.SetSignatures(signatures...); err != nil { + return nil, fmt.Errorf("could not add signature(s): %v", err) + } + return tx, nil +} + +func timeoutRemaining(start time.Time, total time.Duration) time.Duration { + remaining := total - time.Since(start) + if remaining <= 0 { + return time.Second + } + return remaining +} diff --git a/cmd/xc/commands/submit.go b/cmd/xc/commands/submit.go index b9e1c7cf..58bb83c2 100644 --- a/cmd/xc/commands/submit.go +++ b/cmd/xc/commands/submit.go @@ -11,6 +11,8 @@ import ( ) func CmdRpcSubmit() *cobra.Command { + var inputHex string + cmd := &cobra.Command{ Use: "submit [hex-encoded-tx]", Aliases: []string{"broadcast"}, @@ -25,8 +27,15 @@ func CmdRpcSubmit() *cobra.Command { if err != nil { return fmt.Errorf("could not decode payload: %v", err) } + var broadcastInput []byte + if inputHex != "" { + broadcastInput, err = hex.DecodeString(inputHex) + if err != nil { + return fmt.Errorf("could not decode input: %v", err) + } + } - binaryTx := xctypes.NewBinaryTx(payload, nil) + binaryTx := xctypes.NewBinaryTx(payload, broadcastInput) req, err := xctypes.SubmitTxReqFromTx(chainConfig.Chain, binaryTx) if err != nil { return fmt.Errorf("failed to convert to SubmitTxReq: %w", err) @@ -44,5 +53,6 @@ func CmdRpcSubmit() *cobra.Command { return nil }, } + cmd.Flags().StringVar(&inputHex, "input", "", "Hex-encoded broadcast input / tx metadata") return cmd } From d6d6f03b959a8179742e5678de8cf1bf976f50f3 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 26 Mar 2026 09:24:11 +0100 Subject: [PATCH 11/23] CANTON: Fetch synchronizer id --- chain/canton/client/client.go | 79 ++++++++++++++++++++++++--- chain/canton/client/client_test.go | 15 +++--- chain/canton/client/ledger.go | 85 ++++++++++++++++++++---------- 3 files changed, 136 insertions(+), 43 deletions(-) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 7c73249a..75b6d776 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -67,6 +67,22 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { if err != nil { return nil, err } + validatorPartyID, err := cantonEnv("CANTON_VALIDATOR_PARTY_ID") + if err != nil { + return nil, err + } + restAPIURL, err := cantonEnv("CANTON_REST_API_URL") + if err != nil { + return nil, err + } + scanProxyURL, err := cantonEnv("CANTON_SCAN_API_URL") + if err != nil { + return nil, err + } + scanAPIURL, err := cantonEnv("CANTON_SCAN_NODE_URL") + if err != nil { + return nil, err + } cantonUiUsername, err := cantonEnv("CANTON_UI_ID") if err != nil { return nil, err @@ -92,7 +108,13 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { return nil, errors.New("invalid authToken") } - grpcClient, err := NewGrpcLedgerClient(cfg.URL, authToken) + grpcClient, err := NewGrpcLedgerClient(cfg.URL, authToken, runtimeIdentityConfig{ + validatorPartyID: validatorPartyID, + validatorServiceUserID: "service-account-" + adminClientID, + restAPIURL: restAPIURL, + scanProxyURL: scanProxyURL, + scanAPIURL: scanAPIURL, + }) if err != nil { return nil, fmt.Errorf("failed to create GrpcLedgerClient: %w", err) } @@ -110,11 +132,36 @@ func (client *Client) cantonUIToken(ctx context.Context) (string, error) { return resp.AccessToken, nil } +func (client *Client) resolveSynchronizerID(ctx context.Context, partyID string, fallback string) (string, error) { + return client.ledgerClient.ResolveSynchronizerID(ctx, partyID, fallback) +} + +func (client *Client) resolveValidatorSynchronizerID(ctx context.Context) (string, error) { + synchronizerID, err := client.resolveSynchronizerID(ctx, client.ledgerClient.validatorPartyID, "") + if err == nil { + return synchronizerID, nil + } + + uiToken, tokenErr := client.cantonUIToken(ctx) + if tokenErr != nil { + return "", fmt.Errorf("failed to resolve validator synchronizer via validator party (%w) and could not fetch UI token for fallback (%v)", err, tokenErr) + } + amuletRules, rulesErr := client.ledgerClient.GetAmuletRules(ctx, uiToken) + if rulesErr != nil { + return "", fmt.Errorf("failed to resolve validator synchronizer via validator party (%w) and could not fetch amulet rules fallback (%v)", err, rulesErr) + } + return client.resolveSynchronizerID(ctx, "", amuletRules.AmuletRulesUpdate.DomainID) +} + func (client *Client) PrepareTransferOfferCommand(ctx context.Context, args xcbuilder.TransferArgs, amuletRules AmuletRules) (*interactive.PrepareSubmissionResponse, error) { commandID := cantonproto.NewCommandID() cmd := buildTransferOfferCreateCommand(args, amuletRules, commandID) + synchronizerID, err := client.resolveSynchronizerID(ctx, string(args.GetFrom()), amuletRules.AmuletRulesUpdate.DomainID) + if err != nil { + return nil, fmt.Errorf("failed to resolve transfer synchronizer: %w", err) + } - prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, string(args.GetFrom())) + prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, string(args.GetFrom()), synchronizerID) if err != nil { return nil, fmt.Errorf("failed to prepare submission for party setup proposal accept: %w", err) } @@ -142,7 +189,11 @@ func (client *Client) PrepareTransferPreapprovalCommand( return nil, err } commandID := cantonproto.NewCommandID() - prepareReq := cantonproto.NewPrepareRequest(commandID, TestnetSynchronizerID, []string{senderPartyID}, []string{senderPartyID, ValidatorPartyId}, []*v2.Command{cmd}, disclosedContracts) + synchronizerID, err := client.resolveSynchronizerID(ctx, senderPartyID, amuletRules.AmuletRulesUpdate.DomainID) + if err != nil { + return nil, fmt.Errorf("failed to resolve transfer synchronizer: %w", err) + } + prepareReq := cantonproto.NewPrepareRequest(commandID, synchronizerID, []string{senderPartyID}, []string{senderPartyID, client.ledgerClient.validatorPartyID}, []*v2.Command{cmd}, disclosedContracts) authCtx := client.ledgerClient.authCtx(ctx) prepareResp, err := client.ledgerClient.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) @@ -847,8 +898,13 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient } logger.WithField("party_hint", partyHint).Info("create-account: generating external party topology") + synchronizerID, err := client.resolveValidatorSynchronizerID(ctx) + if err != nil { + logger.WithError(err).Error("create-account: resolve synchronizer failed") + return nil, fmt.Errorf("failed to resolve synchronizer for topology generation: %w", err) + } topologyResp, err := client.ledgerClient.adminClient.GenerateExternalPartyTopology(authCtx, &admin.GenerateExternalPartyTopologyRequest{ - Synchronizer: TestnetSynchronizerID, + Synchronizer: synchronizerID, PartyHint: partyHint, PublicKey: signingPubKey, }) @@ -931,7 +987,12 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient "template_id": tid.String(), "command_id": commandID, }).Info("create-account: preparing setup proposal accept submission") - prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, partyID) + synchronizerID, err := client.resolveSynchronizerID(ctx, partyID, "") + if err != nil { + logger.WithError(err).Error("create-account: resolve accept synchronizer failed") + return nil, fmt.Errorf("failed to resolve synchronizer for ExternalPartySetupProposal_Accept: %w", err) + } + prepareResp, err := client.ledgerClient.PrepareSubmissionRequest(ctx, cmd, commandID, partyID, synchronizerID) if err != nil { logger.WithError(err).Error("create-account: prepare setup proposal accept failed") return nil, fmt.Errorf("failed to prepare ExternalPartySetupProposal_Accept: %w", err) @@ -978,8 +1039,12 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx switch cantonInput.Stage { case tx_input.CreateAccountStageAllocate: - req := cantonproto.NewAllocateExternalPartyRequest(TestnetSynchronizerID, cantonInput.TopologyTransactions, cantonInput.Signature, cantonInput.PublicKeyFingerprint) - _, err := client.ledgerClient.adminClient.AllocateExternalParty(authCtx, req) + synchronizerID, err := client.resolveValidatorSynchronizerID(ctx) + if err != nil { + return fmt.Errorf("failed to resolve synchronizer for external party allocation: %w", err) + } + req := cantonproto.NewAllocateExternalPartyRequest(synchronizerID, cantonInput.TopologyTransactions, cantonInput.Signature, cantonInput.PublicKeyFingerprint) + _, err = client.ledgerClient.adminClient.AllocateExternalParty(authCtx, req) if err != nil && !isAlreadyExists(err) { return fmt.Errorf("AllocateExternalParty failed: %w", err) } diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index b1fc9e2c..476355a2 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -184,11 +184,12 @@ func TestFetchTxInfoResolvesRecoveryLookupId(t *testing.T) { }, }, ledgerClient: &GrpcLedgerClient{ - authToken: "token", - stateClient: &stateServiceStub{ledgerEnd: 110}, - updateClient: updateStub, - completionClient: completionStub, - logger: logrus.NewEntry(logrus.New()), + authToken: "token", + stateClient: &stateServiceStub{ledgerEnd: 110}, + updateClient: updateStub, + completionClient: completionStub, + validatorServiceUserID: "service-account-validator-id", + logger: logrus.NewEntry(logrus.New()), }, } @@ -202,7 +203,7 @@ func TestFetchTxInfoResolvesRecoveryLookupId(t *testing.T) { require.Contains(t, updateStub.lastReq.GetUpdateFormat().GetIncludeTransactions().GetEventFormat().GetFiltersByParty(), sender) require.NotNil(t, completionStub.lastReq) require.Equal(t, int64(100), completionStub.lastReq.GetBeginExclusive()) - require.Equal(t, ValidatorServiceUserId, completionStub.lastReq.GetUserId()) + require.Equal(t, "service-account-validator-id", completionStub.lastReq.GetUserId()) require.Equal(t, []string{sender}, completionStub.lastReq.GetParties()) } @@ -438,7 +439,7 @@ type interactiveSubmissionStub struct { lastReq *interactive.ExecuteSubmissionAndWaitRequest } -func (s *interactiveSubmissionStub) PrepareSubmission(context.Context, *interactive.PrepareSubmissionRequest, ...grpc.CallOption) (*interactive.PrepareSubmissionResponse, error) { +func (s *interactiveSubmissionStub) PrepareSubmission(_ context.Context, _ *interactive.PrepareSubmissionRequest, _ ...grpc.CallOption) (*interactive.PrepareSubmissionResponse, error) { panic("unexpected call") } func (s *interactiveSubmissionStub) ExecuteSubmission(context.Context, *interactive.ExecuteSubmissionRequest, ...grpc.CallOption) (*interactive.ExecuteSubmissionResponse, error) { diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index 7b914982..ef360d65 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -58,21 +58,13 @@ func cantonEnv(name string) (string, error) { return v, nil } -// TODO: Fetch instead of hardcoding -var ( - TestnetSynchronizerID = func() string { v, _ := cantonEnv("CANTON_TESTNET_SYNCHRONIZER_ID"); return v }() - ValidatorPartyId = func() string { v, _ := cantonEnv("CANTON_VALIDATOR_PARTY_ID"); return v }() - RestApiUrl = func() string { v, _ := cantonEnv("CANTON_REST_API_URL"); return v }() - ScanProxyUrl = func() string { v, _ := cantonEnv("CANTON_SCAN_API_URL"); return v }() - ScanApiUrl = func() string { v, _ := cantonEnv("CANTON_SCAN_NODE_URL"); return v }() - ValidatorServiceUserId = func() string { - v, _ := cantonEnv("CANTON_VALIDATOR_ID") - if v == "" { - return "" - } - return "service-account-" + v - }() -) +type runtimeIdentityConfig struct { + validatorPartyID string + validatorServiceUserID string + restAPIURL string + scanProxyURL string + scanAPIURL string +} type GrpcLedgerClient struct { // Bearer token injected into every gRPC call @@ -84,10 +76,15 @@ type GrpcLedgerClient struct { stateClient v2.StateServiceClient updateClient v2.UpdateServiceClient userManagementClient admin.UserManagementServiceClient + validatorPartyID string + validatorServiceUserID string + restAPIURL string + scanProxyURL string + scanAPIURL string logger *logrus.Entry } -func NewGrpcLedgerClient(target string, authToken string) (*GrpcLedgerClient, error) { +func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityConfig) (*GrpcLedgerClient, error) { if authToken == "" { return nil, errors.New("GrpcLedgerClient requires a valid authToken") } @@ -125,6 +122,11 @@ func NewGrpcLedgerClient(target string, authToken string) (*GrpcLedgerClient, er interactiveSubmissionClient: interactive.NewInteractiveSubmissionServiceClient(conn), userManagementClient: admin.NewUserManagementServiceClient(conn), commandClient: v2.NewCommandServiceClient(conn), + validatorPartyID: cfg.validatorPartyID, + validatorServiceUserID: cfg.validatorServiceUserID, + restAPIURL: cfg.restAPIURL, + scanProxyURL: cfg.scanProxyURL, + scanAPIURL: cfg.scanAPIURL, logger: logger, }, nil } @@ -210,6 +212,27 @@ func (c *GrpcLedgerClient) ExternalPartyExists(ctx context.Context, partyID stri return false, err } +func (c *GrpcLedgerClient) ResolveSynchronizerID(ctx context.Context, partyID string, fallback string) (string, error) { + if partyID != "" { + synchronizerID, err := c.GetSynchronizerId(ctx, partyID) + if err == nil { + return synchronizerID, nil + } + if fallback == "" { + return "", err + } + c.logger.WithError(err).WithFields(logrus.Fields{ + KeyParty: partyID, + KeySynchronizerId: fallback, + }).Warn("failed to resolve party synchronizer, using fallback") + return fallback, nil + } + if fallback == "" { + return "", errors.New("no synchronizer resolution inputs") + } + return fallback, nil +} + // Get active contracts for given party using StateServiceClient.GetActiveContracts func (c *GrpcLedgerClient) GetActiveContracts(ctx context.Context, partyID string, ledgerEnd int64, includeBlobs bool) ([]*v2.ActiveContract, error) { if partyID == "" { @@ -279,7 +302,7 @@ func (c *GrpcLedgerClient) GetActiveContracts(ctx context.Context, partyID strin func (c *GrpcLedgerClient) CreateUser(ctx context.Context, partyId string) error { authCtx := c.authCtx(ctx) req := &admin.GrantUserRightsRequest{ - UserId: ValidatorServiceUserId, + UserId: c.validatorServiceUserID, Rights: []*admin.Right{ { Kind: &admin.Right_CanReadAs_{ @@ -331,7 +354,7 @@ func (c *GrpcLedgerClient) CreateExternalPartySetupProposal(ctx context.Context, req, err := http.NewRequestWithContext( ctx, http.MethodPost, - RestApiUrl+endpoint, + c.restAPIURL+endpoint, bytes.NewReader(body), ) if err != nil { @@ -388,12 +411,12 @@ func (a AmuletRules) GetSpliceId() string { // Make sure to auth with canton-ui token func (c *GrpcLedgerClient) GetAmuletRules(ctx context.Context, token string) (*AmuletRules, error) { // We access the scan API through the http-proxy (CANTON_SCAN_API_URL) because direct access is not yet available. - body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/amulet-rules","headers":{"Content-Type":"application/json"},"body":"{}"}`, ScanApiUrl) + body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/amulet-rules","headers":{"Content-Type":"application/json"},"body":"{}"}`, c.scanAPIURL) req, err := http.NewRequestWithContext( ctx, http.MethodPost, - ScanProxyUrl, + c.scanProxyURL, strings.NewReader(body), ) if err != nil { @@ -517,12 +540,12 @@ func (r *OpenAndIssuingMiningRounds) GetLatestIssuingMiningRound() (*RoundEntry, } func (c *GrpcLedgerClient) GetOpenAndIssuingMiningRound(ctx context.Context, token string) (*RoundEntry, *RoundEntry, error) { - body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/open-and-issuing-mining-rounds","headers":{"Content-Type":"application/json"},"body":"{\"cached_open_mining_round_contract_ids\":[],\"cached_issuing_round_contract_ids\":[]}"}`, ScanApiUrl) + body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/open-and-issuing-mining-rounds","headers":{"Content-Type":"application/json"},"body":"{\"cached_open_mining_round_contract_ids\":[],\"cached_issuing_round_contract_ids\":[]}"}`, c.scanAPIURL) req, err := http.NewRequestWithContext( ctx, http.MethodPost, - ScanProxyUrl, + c.scanProxyURL, strings.NewReader(body), ) if err != nil { @@ -588,8 +611,8 @@ func newRegisterCommandId() string { return cantonproto.NewCommandID() } -func (c *GrpcLedgerClient) PrepareSubmissionRequest(ctx context.Context, command *v2.Command, commandID string, partyID string) (*interactive.PrepareSubmissionResponse, error) { - prepareReq := cantonproto.NewPrepareRequest(commandID, TestnetSynchronizerID, []string{partyID}, []string{partyID}, []*v2.Command{command}, nil) +func (c *GrpcLedgerClient) PrepareSubmissionRequest(ctx context.Context, command *v2.Command, commandID string, partyID string, synchronizerID string) (*interactive.PrepareSubmissionResponse, error) { + prepareReq := cantonproto.NewPrepareRequest(commandID, synchronizerID, []string{partyID}, []string{partyID}, []*v2.Command{command}, nil) authCtx := c.authCtx(ctx) prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) @@ -641,7 +664,11 @@ func (c *GrpcLedgerClient) AcceptExternalPartySetupProposal(ctx context.Context, authCtx := c.authCtx(ctx) commandID := newRegisterCommandId() - prepareResp, err := c.PrepareSubmissionRequest(authCtx, cmd, commandID, partyId) + synchronizerID, err := c.ResolveSynchronizerID(ctx, partyId, "") + if err != nil { + return fmt.Errorf("failed to resolve synchronizer: %w", err) + } + prepareResp, err := c.PrepareSubmissionRequest(authCtx, cmd, commandID, partyId, synchronizerID) if err != nil { return fmt.Errorf("failed to prepare submission for party setup proposal accept: %w", err) } @@ -965,14 +992,14 @@ func (c *GrpcLedgerClient) CompleteAcceptedTransferOffer( } prepareReq := &interactive.PrepareSubmissionRequest{ - UserId: ValidatorServiceUserId, + UserId: c.validatorServiceUserID, CommandId: newRegisterCommandId(), Commands: []*v2.Command{cmd}, // ActAs: []string{senderPartyID, ValidatorPartyId}, - ReadAs: []string{senderPartyID, ValidatorPartyId}, + ReadAs: []string{senderPartyID, c.validatorPartyID}, ActAs: []string{senderPartyID}, // ReadAs: []string{senderPartyID}, - SynchronizerId: TestnetSynchronizerID, + SynchronizerId: amuletRules.AmuletRulesUpdate.DomainID, DisclosedContracts: disclosedContracts, VerboseHashing: false, } @@ -1075,7 +1102,7 @@ func (c *GrpcLedgerClient) RecoverUpdateIdBySubmissionId(ctx context.Context, be defer cancel() stream, err := c.completionClient.CompletionStream(streamCtx, &v2.CompletionStreamRequest{ - UserId: ValidatorServiceUserId, + UserId: c.validatorServiceUserID, Parties: []string{partyID}, BeginExclusive: beginExclusive, }) From 8bce023dfb8171f70d78e70f7c0456aa459f5695 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 26 Mar 2026 10:29:16 +0100 Subject: [PATCH 12/23] CANTON: Remove hardcoded env vars and implement CustomConfig --- asset.go | 2 + asset_test.go | 24 +++++ chain/canton/client/client.go | 59 +++++++----- chain/canton/client/client_test.go | 123 ++++++++++++++++++++++-- chain/canton/client/command_builders.go | 14 ++- chain/canton/client/config.go | 63 ++++++++++++ chain/canton/client/ledger.go | 12 +-- chain/canton/keycloak/keycloak.go | 12 +-- chain/canton/validate.go | 9 ++ factory/config/config.go | 3 + factory/defaults/chains/testnet.yaml | 10 +- 11 files changed, 284 insertions(+), 47 deletions(-) create mode 100644 chain/canton/client/config.go diff --git a/asset.go b/asset.go index ef9d5b7f..de183dd6 100644 --- a/asset.go +++ b/asset.go @@ -527,6 +527,7 @@ func NewChainConfig(nativeAsset NativeAsset, driverMaybe ...Driver) *ChainConfig Driver: driver, }, ChainClientConfig: &ChainClientConfig{}, + CustomConfig: map[string]any{}, } cfg.Configure(0) return cfg @@ -629,6 +630,7 @@ func (chain *ChainConfig) DefaultHttpClient() *http.Client { type ChainConfig struct { *ChainBaseConfig `yaml:",inline"` *ChainClientConfig `yaml:",inline"` + CustomConfig map[string]any `yaml:"custom_config,omitempty"` } type MemoSupport string diff --git a/asset_test.go b/asset_test.go index 0ecb8870..5604d069 100644 --- a/asset_test.go +++ b/asset_test.go @@ -11,6 +11,7 @@ import ( "github.com/cordialsys/crosschain/address" xcbuilder "github.com/cordialsys/crosschain/builder" "github.com/cordialsys/crosschain/call" + "github.com/cordialsys/crosschain/chain/canton" "github.com/cordialsys/crosschain/chain/cosmos" "github.com/cordialsys/crosschain/chain/egld" "github.com/cordialsys/crosschain/chain/eos" @@ -308,6 +309,29 @@ func TestSupportedAddressFormats(t *testing.T) { } } +func TestCustomConfigValidation(t *testing.T) { + xcf1 := factory.NewDefaultFactory() + xcf2 := factory.NewNotMainnetsFactory(&factory.FactoryOptions{}) + for _, xcf := range []*factory.Factory{xcf1, xcf2} { + for _, chain := range xcf.GetAllChains() { + t.Run(fmt.Sprintf("%s_%s", chain.Chain, xcf.Config.Network), func(t *testing.T) { + if len(chain.CustomConfig) == 0 { + return + } + + switch chain.Driver { + case DriverCanton: + require.NoError(t, canton.ValidateCustomConfig(chain)) + case "": + require.Fail(t, "unknown driver", chain.Driver) + default: + require.Fail(t, fmt.Sprintf("missing ValidateCustomConfig() for %s driver", chain.Driver)) + } + }) + } + } +} + func TestExternalIdsAreSet(t *testing.T) { xcf1 := factory.NewDefaultFactory() for _, xcf := range []*factory.Factory{xcf1} { diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 75b6d776..c1015345 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -43,6 +43,14 @@ type Client struct { var _ xclient.Client = &Client{} +func parseBasicAuthSecret(value string, field string) (string, string, error) { + parts := strings.SplitN(value, ":", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("%s must resolve to id:secret", field) + } + return parts[0], parts[1], nil +} + // NewClient returns a new Canton gRPC Client func NewClient(cfgI *xc.ChainConfig) (*Client, error) { cfg := cfgI.GetChain() @@ -51,51 +59,58 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { return nil, fmt.Errorf("no URL configured for Canton client") } - keycloakURL, err := cantonEnv("CANTON_KEYCLOAK_URL") + cantonCfg, err := LoadCantonConfig(cfgI) if err != nil { return nil, err } - keycloakRealm, err := cantonEnv("CANTON_KEYCLOAK_REALM") - if err != nil { + if err := cantonCfg.Validate(); err != nil { return nil, err } - adminClientID, err := cantonEnv("CANTON_VALIDATOR_ID") + keycloakURL, err := cantonCfg.KeycloakURL.LoadNonEmpty() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load canton keycloak url: %w", err) } - adminClientSecret, err := cantonEnv("CANTON_VALIDATOR_SECRET") + keycloakRealm, err := cantonCfg.KeycloakRealm.LoadNonEmpty() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load canton keycloak realm: %w", err) } - validatorPartyID, err := cantonEnv("CANTON_VALIDATOR_PARTY_ID") + validatorAuthRaw, err := cantonCfg.ValidatorAuth.LoadNonEmpty() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load canton validator auth: %w", err) } - restAPIURL, err := cantonEnv("CANTON_REST_API_URL") + validatorAuthID, validatorAuthSecret, err := parseBasicAuthSecret(validatorAuthRaw, "validator_auth") if err != nil { return nil, err } - scanProxyURL, err := cantonEnv("CANTON_SCAN_API_URL") + validatorPartyID, err := cantonCfg.ValidatorPartyID.LoadNonEmpty() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load canton validator party id: %w", err) } - scanAPIURL, err := cantonEnv("CANTON_SCAN_NODE_URL") + restAPIURL, err := cantonCfg.RestAPIURL.LoadNonEmpty() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load canton rest api url: %w", err) } - cantonUiUsername, err := cantonEnv("CANTON_UI_ID") + scanProxyURL, err := cantonCfg.ScanProxyURL.LoadNonEmpty() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to load canton scan proxy url: %w", err) + } + scanAPIURL, err := cantonCfg.ScanAPIURL.LoadNonEmpty() + if err != nil { + return nil, fmt.Errorf("failed to load canton scan api url: %w", err) + } + cantonUIAuthRaw, err := cantonCfg.CantonUIAuth.LoadNonEmpty() + if err != nil { + return nil, fmt.Errorf("failed to load canton ui auth: %w", err) } - cantonUiPassword, err := cantonEnv("CANTON_UI_PASSWORD") + cantonUiUsername, cantonUiPassword, err := parseBasicAuthSecret(cantonUIAuthRaw, "canton_ui_auth") if err != nil { return nil, err } client := &Client{ Asset: cfgI, - adminKC: cantonkc.NewClient(keycloakURL, keycloakRealm, adminClientID, adminClientSecret), - walletKC: cantonkc.NewClient(keycloakURL, keycloakRealm, adminClientID, adminClientSecret), + adminKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), + walletKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), cantonUiUsername: cantonUiUsername, cantonUiPassword: cantonUiPassword, } @@ -110,7 +125,7 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { grpcClient, err := NewGrpcLedgerClient(cfg.URL, authToken, runtimeIdentityConfig{ validatorPartyID: validatorPartyID, - validatorServiceUserID: "service-account-" + adminClientID, + validatorServiceUserID: "service-account-" + validatorAuthID, restAPIURL: restAPIURL, scanProxyURL: scanProxyURL, scanAPIURL: scanAPIURL, @@ -155,7 +170,7 @@ func (client *Client) resolveValidatorSynchronizerID(ctx context.Context) (strin func (client *Client) PrepareTransferOfferCommand(ctx context.Context, args xcbuilder.TransferArgs, amuletRules AmuletRules) (*interactive.PrepareSubmissionResponse, error) { commandID := cantonproto.NewCommandID() - cmd := buildTransferOfferCreateCommand(args, amuletRules, commandID) + cmd := buildTransferOfferCreateCommand(args, amuletRules, commandID, client.Asset.GetChain().Decimals) synchronizerID, err := client.resolveSynchronizerID(ctx, string(args.GetFrom()), amuletRules.AmuletRulesUpdate.DomainID) if err != nil { return nil, fmt.Errorf("failed to resolve transfer synchronizer: %w", err) @@ -184,7 +199,7 @@ func (client *Client) PrepareTransferPreapprovalCommand( recipientContracts []*v2.ActiveContract, ) (*interactive.PrepareSubmissionResponse, error) { senderPartyID := string(args.GetFrom()) - cmd, disclosedContracts, err := buildTransferPreapprovalExerciseCommand(args, amuletRules, openMiningRound, issuingMiningRound, senderContracts, recipientContracts) + cmd, disclosedContracts, err := buildTransferPreapprovalExerciseCommand(args, amuletRules, openMiningRound, issuingMiningRound, senderContracts, recipientContracts, client.Asset.GetChain().Decimals) if err != nil { return nil, err } diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index 476355a2..88e0b7db 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -36,13 +36,7 @@ func TestNewClient(t *testing.T) { require.Contains(t, err.Error(), "no URL configured") }) - t.Run("missing env var", func(t *testing.T) { - t.Setenv("CANTON_KEYCLOAK_URL", "") - t.Setenv("CANTON_KEYCLOAK_REALM", "") - t.Setenv("CANTON_VALIDATOR_ID", "") - t.Setenv("CANTON_VALIDATOR_SECRET", "") - t.Setenv("CANTON_UI_ID", "") - t.Setenv("CANTON_UI_PASSWORD", "") + t.Run("missing custom config", func(t *testing.T) { cfg := &xc.ChainConfig{ ChainBaseConfig: &xc.ChainBaseConfig{ Chain: xc.CANTON, @@ -54,7 +48,7 @@ func TestNewClient(t *testing.T) { } _, err := NewClient(cfg) require.Error(t, err) - require.Contains(t, err.Error(), "required environment variable") + require.Contains(t, err.Error(), "missing canton custom config field") }) } @@ -402,6 +396,97 @@ func TestExtractTransferFeeSupportsTransferPreapprovalSendResult(t *testing.T) { require.Equal(t, "2000000000000000000", fee.String()) } +func TestBuildTransferOfferCreateCommandUsesArgsAmount(t *testing.T) { + t.Parallel() + + args, err := xcbuilder.NewTransferArgs( + &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton}, + xc.Address("sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + xc.Address("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), + xc.NewAmountBlockchainFromUint64(123), + ) + require.NoError(t, err) + + cmd := buildTransferOfferCreateCommand(args, AmuletRules{ + AmuletRulesUpdate: struct { + Contract AmuletRulesContract `json:"contract"` + DomainID string `json:"domain_id"` + }{ + Contract: AmuletRulesContract{Payload: struct { + DSO string `json:"dso"` + }{DSO: "validator-party"}}, + }, + }, "command-id", 1) + + create := cmd.GetCreate() + require.NotNil(t, create) + require.Equal(t, "12.3", extractCommandAmountNumeric(t, create.GetCreateArguments())) +} + +func TestBuildTransferPreapprovalExerciseCommandUsesArgsAmount(t *testing.T) { + t.Parallel() + + args, err := xcbuilder.NewTransferArgs( + &xc.ChainBaseConfig{Chain: xc.CANTON, Driver: xc.DriverCanton}, + xc.Address("sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + xc.Address("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), + xc.NewAmountBlockchainFromUint64(123), + ) + require.NoError(t, err) + + cmd, _, err := buildTransferPreapprovalExerciseCommand( + args, + AmuletRules{ + AmuletRulesUpdate: struct { + Contract AmuletRulesContract `json:"contract"` + DomainID string `json:"domain_id"` + }{ + Contract: AmuletRulesContract{ + ContractID: "amulet-rules-contract", + TemplateID: "pkg:Module:AmuletRules", + Payload: struct { + DSO string `json:"dso"` + }{DSO: "validator-party"}, + }, + }, + }, + &RoundEntry{Contract: RoundContract{ContractID: "open-round", TemplateID: "pkg:Module:OpenRound"}}, + &RoundEntry{Contract: RoundContract{ + ContractID: "issuing-round", + TemplateID: "pkg:Module:IssuingRound", + Payload: RoundPayload{Round: struct { + Number string `json:"number"` + }{Number: "1"}}, + }}, + []*v2.ActiveContract{ + { + CreatedEvent: &v2.CreatedEvent{ + ContractId: "sender-amulet", + TemplateId: &v2.Identifier{EntityName: "Amulet"}, + }, + }, + }, + []*v2.ActiveContract{ + { + CreatedEvent: &v2.CreatedEvent{ + ContractId: "preapproval-contract", + CreatedEventBlob: []byte{0x01}, + TemplateId: &v2.Identifier{ + ModuleName: "Splice.AmuletRules", + EntityName: "TransferPreapproval", + }, + }, + }, + }, + 1, + ) + require.NoError(t, err) + + exercise := cmd.GetExercise() + require.NotNil(t, exercise) + require.Equal(t, "12.3", extractCommandAmountNumeric(t, exercise.GetChoiceArgument().GetRecord())) +} + func mustSerializedCreateAccountInput(t *testing.T) []byte { t.Helper() input := &tx_input.CreateAccountInput{ @@ -573,6 +658,28 @@ func testAmuletCreatedEvent(owner string, initialAmount string) *v2.CreatedEvent } } +func extractCommandAmountNumeric(t *testing.T, record *v2.Record) string { + t.Helper() + + for _, field := range record.GetFields() { + if field.GetLabel() != "amount" { + continue + } + if numeric := field.GetValue().GetNumeric(); numeric != "" { + return numeric + } + if amountRecord := field.GetValue().GetRecord(); amountRecord != nil { + for _, nested := range amountRecord.GetFields() { + if nested.GetLabel() == "amount" { + return nested.GetValue().GetNumeric() + } + } + } + } + t.Fatalf("amount field not found") + return "" +} + func testAmuletRulesTransferEvent(sender string, receiver string, amount string) *v2.ExercisedEvent { return &v2.ExercisedEvent{ TemplateId: &v2.Identifier{ diff --git a/chain/canton/client/command_builders.go b/chain/canton/client/command_builders.go index bf598f3b..5afa026e 100644 --- a/chain/canton/client/command_builders.go +++ b/chain/canton/client/command_builders.go @@ -11,7 +11,13 @@ import ( v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" ) -func buildTransferOfferCreateCommand(args xcbuilder.TransferArgs, amuletRules AmuletRules, commandID string) *v2.Command { +func transferAmountNumeric(args xcbuilder.TransferArgs, decimals int32) string { + amount := args.GetAmount() + return amount.ToHuman(decimals).String() +} + +func buildTransferOfferCreateCommand(args xcbuilder.TransferArgs, amuletRules AmuletRules, commandID string, decimals int32) *v2.Command { + amountNumeric := transferAmountNumeric(args, decimals) return &v2.Command{ Command: &v2.Command_Create{ Create: &v2.CreateCommand{ @@ -26,7 +32,7 @@ func buildTransferOfferCreateCommand(args xcbuilder.TransferArgs, amuletRules Am cantonproto.Field("receiver", cantonproto.PartyValue(string(args.GetTo()))), cantonproto.Field("dso", cantonproto.PartyValue(amuletRules.AmuletRulesUpdate.Contract.Payload.DSO)), cantonproto.Field("amount", cantonproto.RecordValue( - cantonproto.Field("amount", cantonproto.NumericValue("10.0")), + cantonproto.Field("amount", cantonproto.NumericValue(amountNumeric)), cantonproto.Field("unit", &v2.Value{ Sum: &v2.Value_Enum{Enum: &v2.Enum{Constructor: "AmuletUnit"}}, }), @@ -61,6 +67,7 @@ func buildTransferPreapprovalExerciseCommand( issuingMiningRound *RoundEntry, senderContracts []*v2.ActiveContract, recipientContracts []*v2.ActiveContract, + decimals int32, ) (*v2.Command, []*v2.DisclosedContract, error) { var preapprovalContractID string var preapprovalTemplateID *v2.Identifier @@ -179,6 +186,7 @@ func buildTransferPreapprovalExerciseCommand( }) } + amountNumeric := transferAmountNumeric(args, decimals) cmd := &v2.Command{ Command: &v2.Command_Exercise{ Exercise: &v2.ExerciseCommand{ @@ -190,7 +198,7 @@ func buildTransferPreapprovalExerciseCommand( cantonproto.Field("inputs", &v2.Value{ Sum: &v2.Value_List{List: &v2.List{Elements: transferInputs}}, }), - cantonproto.Field("amount", cantonproto.NumericValue("10.0")), + cantonproto.Field("amount", cantonproto.NumericValue(amountNumeric)), cantonproto.Field("context", cantonproto.RecordValue( cantonproto.Field("amuletRules", cantonproto.ContractIDValue(amuletRulesID)), cantonproto.Field("context", cantonproto.RecordValue( diff --git a/chain/canton/client/config.go b/chain/canton/client/config.go new file mode 100644 index 00000000..aea88800 --- /dev/null +++ b/chain/canton/client/config.go @@ -0,0 +1,63 @@ +package client + +import ( + "fmt" + + xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/config" + "gopkg.in/yaml.v3" +) + +type CantonConfig struct { + KeycloakURL config.Secret `yaml:"keycloak_url,omitempty"` + KeycloakRealm config.Secret `yaml:"keycloak_realm,omitempty"` + ValidatorAuth config.Secret `yaml:"validator_auth,omitempty"` + ValidatorPartyID config.Secret `yaml:"validator_party_id,omitempty"` + RestAPIURL config.Secret `yaml:"rest_api_url,omitempty"` + ScanProxyURL config.Secret `yaml:"scan_proxy_url,omitempty"` + ScanAPIURL config.Secret `yaml:"scan_api_url,omitempty"` + CantonUIAuth config.Secret `yaml:"canton_ui_auth,omitempty"` +} + +func LoadCantonConfig(chain *xc.ChainConfig) (*CantonConfig, error) { + cfg := &CantonConfig{} + if chain != nil && len(chain.CustomConfig) > 0 { + bz, err := yaml.Marshal(chain.CustomConfig) + if err != nil { + return nil, fmt.Errorf("marshal canton custom config: %w", err) + } + if err := yaml.Unmarshal(bz, cfg); err != nil { + return nil, fmt.Errorf("unmarshal canton custom config: %w", err) + } + } + + return cfg, nil +} + +func (cfg *CantonConfig) Validate() error { + if cfg.KeycloakURL == "" { + return fmt.Errorf("missing canton custom config field keycloak_url") + } + if cfg.KeycloakRealm == "" { + return fmt.Errorf("missing canton custom config field keycloak_realm") + } + if cfg.ValidatorAuth == "" { + return fmt.Errorf("missing canton custom config field validator_auth") + } + if cfg.ValidatorPartyID == "" { + return fmt.Errorf("missing canton custom config field validator_party_id") + } + if cfg.RestAPIURL == "" { + return fmt.Errorf("missing canton custom config field rest_api_url") + } + if cfg.ScanProxyURL == "" { + return fmt.Errorf("missing canton custom config field scan_proxy_url") + } + if cfg.ScanAPIURL == "" { + return fmt.Errorf("missing canton custom config field scan_api_url") + } + if cfg.CantonUIAuth == "" { + return fmt.Errorf("missing canton custom config field canton_ui_auth") + } + return nil +} diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index ef360d65..b6170dab 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -131,7 +131,7 @@ func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityCon }, nil } -// authCtx injects the CANTON_AUTH bearer token into the gRPC context +// authCtx injects the Canton validator bearer token into the gRPC context. func (c *GrpcLedgerClient) authCtx(ctx context.Context) context.Context { if c.authToken == "" { c.logger.Warn("empty authToken") @@ -332,11 +332,8 @@ func (c *GrpcLedgerClient) CreateUser(ctx context.Context, partyId string) error } } -// curl -v -X POST \ -// -H "Authorization: Bearer $ADMIN_TOKEN" \ -// -H "Content-Type: application/json" \ -// -d '{"user_party_id": ""}' \ -// "$CANTON_REST_API_URL/api/validator/v0/admin/external-party/setup-proposal" +// CreateExternalPartySetupProposal calls the configured validator REST API to create +// an ExternalPartySetupProposal for the given party. func (c *GrpcLedgerClient) CreateExternalPartySetupProposal(ctx context.Context, partyID string) error { body, err := json.Marshal(map[string]string{ "user_party_id": partyID, @@ -410,7 +407,8 @@ func (a AmuletRules) GetSpliceId() string { // Make sure to auth with canton-ui token func (c *GrpcLedgerClient) GetAmuletRules(ctx context.Context, token string) (*AmuletRules, error) { - // We access the scan API through the http-proxy (CANTON_SCAN_API_URL) because direct access is not yet available. + // We access the configured scan API through the configured HTTP proxy because direct + // access to the scan node is not always available. body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/amulet-rules","headers":{"Content-Type":"application/json"},"body":"{}"}`, c.scanAPIURL) req, err := http.NewRequestWithContext( diff --git a/chain/canton/keycloak/keycloak.go b/chain/canton/keycloak/keycloak.go index fc29fa66..4ca1b3dc 100644 --- a/chain/canton/keycloak/keycloak.go +++ b/chain/canton/keycloak/keycloak.go @@ -7,7 +7,6 @@ import ( "io" "net/http" "net/url" - "os" "strings" "sync" "time" @@ -30,6 +29,7 @@ type Client struct { realm string clientID string clientSecret string + validatorPartyID string httpClient *http.Client mu sync.Mutex @@ -37,12 +37,13 @@ type Client struct { adminExpires time.Time } -func NewClient(baseURL, realm, clientID, clientSecret string) *Client { +func NewClient(baseURL, realm, clientID, clientSecret string, validatorPartyID string) *Client { return &Client{ baseURL: baseURL, realm: realm, clientID: clientID, clientSecret: clientSecret, + validatorPartyID: validatorPartyID, httpClient: &http.Client{Timeout: 10 * time.Second}, } } @@ -174,11 +175,10 @@ func (k *Client) SetPartyAttribute(ctx context.Context, userID, partyID string) return fmt.Errorf("getting admin token: %w", err) } - validatorPartyID := os.Getenv("CANTON_VALIDATOR_PARTY_ID") - if validatorPartyID == "" { - return fmt.Errorf("required environment variable CANTON_VALIDATOR_PARTY_ID is not set") + if k.validatorPartyID == "" { + return fmt.Errorf("validator party id is not configured") } - participantAud := "https://daml.com/jwt/aud/participant/" + validatorPartyID + participantAud := "https://daml.com/jwt/aud/participant/" + k.validatorPartyID payload, _ := json.Marshal(map[string]any{ "attributes": map[string][]string{ "canton_party_id": {partyID}, diff --git a/chain/canton/validate.go b/chain/canton/validate.go index 8eef23a2..205f4fb0 100644 --- a/chain/canton/validate.go +++ b/chain/canton/validate.go @@ -7,6 +7,7 @@ import ( "strings" xc "github.com/cordialsys/crosschain" + cantonclient "github.com/cordialsys/crosschain/chain/canton/client" ) // ValidateAddress validates a Canton party ID address format. @@ -42,6 +43,14 @@ func ValidateAddress(cfg *xc.ChainBaseConfig, addr xc.Address) error { return nil } +func ValidateCustomConfig(chainCfg *xc.ChainConfig) error { + cfg, err := cantonclient.LoadCantonConfig(chainCfg) + if err != nil { + return err + } + return cfg.Validate() +} + // validatePartyName validates the party name component func validatePartyName(name string) error { if len(name) == 0 { diff --git a/factory/config/config.go b/factory/config/config.go index 4e9aa9cf..075ab2a1 100644 --- a/factory/config/config.go +++ b/factory/config/config.go @@ -48,6 +48,9 @@ func (cfg *Config) MigrateFields() { if chain.ChainClientConfig == nil { chain.ChainClientConfig = &xc.ChainClientConfig{} } + if chain.CustomConfig == nil { + chain.CustomConfig = map[string]any{} + } chain.Configure(cfg.HttpTimeout) } } diff --git a/factory/defaults/chains/testnet.yaml b/factory/defaults/chains/testnet.yaml index c8188a51..ee0be674 100644 --- a/factory/defaults/chains/testnet.yaml +++ b/factory/defaults/chains/testnet.yaml @@ -218,10 +218,18 @@ chains: chain: CANTON driver: canton chain_name: Canton (Testnet) - auth: env:CANTON_AUTH decimals: 18 fee_limit: "100.0" confirmations_final: 1 + custom_config: + keycloak_url: "env:CANTON_KEYCLOAK_URL" + keycloak_realm: "env:CANTON_KEYCLOAK_REALM" + validator_auth: "env:CANTON_VALIDATOR_BASIC_AUTH" + validator_party_id: "env:CANTON_VALIDATOR_PARTY_ID" + rest_api_url: "env:CANTON_REST_API_URL" + scan_proxy_url: "env:CANTON_SCAN_API_URL" + scan_api_url: "env:CANTON_SCAN_NODE_URL" + canton_ui_auth: "env:CANTON_UI_BASIC_AUTH" CHZ: chain: CHZ driver: "evm-legacy" From ed36c9fbfcd5e700806bda7d2772495b128b8a64 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 26 Mar 2026 11:10:25 +0100 Subject: [PATCH 13/23] CANTON: Remove hardcoded username, read deduplication window from config --- chain/canton/client/client.go | 55 ++++++++++++++++++++++++------ chain/canton/client/client_test.go | 12 +++++++ chain/canton/client/ledger.go | 17 +++------ chain/canton/proto/helpers.go | 15 +++++--- chain/canton/proto/helpers_test.go | 4 +-- chain/canton/tx/tx.go | 6 +++- chain/canton/tx_input/tx_input.go | 4 +++ 7 files changed, 84 insertions(+), 29 deletions(-) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index c1015345..214ec379 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -2,7 +2,9 @@ package client import ( "context" + "encoding/base64" "encoding/hex" + "encoding/json" "errors" "fmt" "strconv" @@ -32,10 +34,10 @@ type Client struct { ledgerClient *GrpcLedgerClient - // adminKC fetches operator-level tokens (client_credentials grant). - adminKC *cantonkc.Client - // walletKC acquires canton-ui tokens for scan proxy HTTP calls. - walletKC *cantonkc.Client + // validatorKC fetches validator-level tokens (client_credentials grant). + validatorKC *cantonkc.Client + // cantonUiKC acquires canton-ui tokens for scan proxy HTTP calls. + cantonUiKC *cantonkc.Client cantonUiUsername string cantonUiPassword string @@ -51,6 +53,33 @@ func parseBasicAuthSecret(value string, field string) (string, string, error) { return parts[0], parts[1], nil } +func validatorServiceUserIDFromToken(token string) (string, error) { + parts := strings.Split(token, ".") + if len(parts) < 2 { + return "", errors.New("invalid validator auth token") + } + + payload, err := base64.RawURLEncoding.DecodeString(parts[1]) + if err != nil { + return "", fmt.Errorf("decode validator auth token payload: %w", err) + } + + var claims struct { + PreferredUsername string `json:"preferred_username"` + Subject string `json:"sub"` + } + if err := json.Unmarshal(payload, &claims); err != nil { + return "", fmt.Errorf("decode validator auth token claims: %w", err) + } + if claims.PreferredUsername == "" { + if claims.Subject == "" { + return "", errors.New("validator auth token missing preferred_username and sub") + } + return claims.Subject, nil + } + return claims.PreferredUsername, nil +} + // NewClient returns a new Canton gRPC Client func NewClient(cfgI *xc.ChainConfig) (*Client, error) { cfg := cfgI.GetChain() @@ -109,23 +138,28 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { client := &Client{ Asset: cfgI, - adminKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), - walletKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), + validatorKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), + cantonUiKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), cantonUiUsername: cantonUiUsername, cantonUiPassword: cantonUiPassword, } - authToken, err := client.adminKC.AdminToken(context.Background()) + authToken, err := client.validatorKC.AdminToken(context.Background()) if err != nil { return nil, fmt.Errorf("failed to fetch auth token: %w", err) } if authToken == "" { return nil, errors.New("invalid authToken") } + validatorServiceUserID, err := validatorServiceUserIDFromToken(authToken) + if err != nil { + return nil, fmt.Errorf("failed to derive validator service user id from token: %w", err) + } grpcClient, err := NewGrpcLedgerClient(cfg.URL, authToken, runtimeIdentityConfig{ validatorPartyID: validatorPartyID, - validatorServiceUserID: "service-account-" + validatorAuthID, + validatorServiceUserID: validatorServiceUserID, + deduplicationWindow: cfgI.TransactionActiveTime, restAPIURL: restAPIURL, scanProxyURL: scanProxyURL, scanAPIURL: scanAPIURL, @@ -140,7 +174,7 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { // cantonUIToken acquires a canton-ui Keycloak token used for scan proxy HTTP calls. func (client *Client) cantonUIToken(ctx context.Context) (string, error) { - resp, err := client.walletKC.AcquireCantonUiToken(ctx, client.cantonUiUsername, client.cantonUiPassword) + resp, err := client.cantonUiKC.AcquireCantonUiToken(ctx, client.cantonUiUsername, client.cantonUiPassword) if err != nil { return "", fmt.Errorf("failed to acquire canton-ui token: %w", err) } @@ -274,6 +308,7 @@ func (client *Client) FetchTransferInput(ctx context.Context, args xcbuilder.Tra input.PreparedTransaction = *resp.GetPreparedTransaction() input.SubmissionId = NewCommandId() input.HashingSchemeVersion = resp.GetHashingSchemeVersion() + input.DeduplicationWindow = cantonproto.ResolveDeduplicationWindow(client.Asset.TransactionActiveTime) return input, nil } @@ -1073,7 +1108,7 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx if err != nil { return fmt.Errorf("failed to determine signing fingerprint for setup proposal accept: %w", err) } - executeReq := cantonproto.NewExecuteSubmissionAndWaitRequest(&preparedTx, cantonInput.PartyID, cantonInput.Signature, keyFingerprint, cantonInput.SetupProposalSubmissionID, cantonInput.SetupProposalHashing) + executeReq := cantonproto.NewExecuteSubmissionAndWaitRequest(&preparedTx, cantonInput.PartyID, cantonInput.Signature, keyFingerprint, cantonInput.SetupProposalSubmissionID, cantonInput.SetupProposalHashing, client.ledgerClient.deduplicationWindow) _, err = client.ledgerClient.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) if err != nil && !isAlreadyExists(err) { return fmt.Errorf("ExternalPartySetupProposal_Accept failed: %w", err) diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index 88e0b7db..e631e6f8 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -2,6 +2,7 @@ package client import ( "context" + "encoding/base64" "io" "testing" "time" @@ -52,6 +53,17 @@ func TestNewClient(t *testing.T) { }) } +func TestValidatorServiceUserIDFromToken(t *testing.T) { + t.Parallel() + + header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"none"}`)) + payload := base64.RawURLEncoding.EncodeToString([]byte(`{"preferred_username":"service-account-validator-id"}`)) + + userID, err := validatorServiceUserIDFromToken(header + "." + payload + ".sig") + require.NoError(t, err) + require.Equal(t, "service-account-validator-id", userID) +} + func TestSubmitTxRequiresMetadata(t *testing.T) { t.Parallel() diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index b6170dab..107c5bf2 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -11,7 +11,6 @@ import ( "fmt" "io" "net/http" - "os" "strconv" "strings" "time" @@ -49,18 +48,10 @@ const ( ModuleSpliceAmulet = "SpliceAmulet" ) -// cantonEnv reads a required Canton environment variable, returning an error if unset. -func cantonEnv(name string) (string, error) { - v := os.Getenv(name) - if v == "" { - return "", fmt.Errorf("required environment variable %s is not set", name) - } - return v, nil -} - type runtimeIdentityConfig struct { validatorPartyID string validatorServiceUserID string + deduplicationWindow time.Duration restAPIURL string scanProxyURL string scanAPIURL string @@ -78,6 +69,7 @@ type GrpcLedgerClient struct { userManagementClient admin.UserManagementServiceClient validatorPartyID string validatorServiceUserID string + deduplicationWindow time.Duration restAPIURL string scanProxyURL string scanAPIURL string @@ -124,6 +116,7 @@ func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityCon commandClient: v2.NewCommandServiceClient(conn), validatorPartyID: cfg.validatorPartyID, validatorServiceUserID: cfg.validatorServiceUserID, + deduplicationWindow: cantonproto.ResolveDeduplicationWindow(cfg.deduplicationWindow), restAPIURL: cfg.restAPIURL, scanProxyURL: cfg.scanProxyURL, scanAPIURL: cfg.scanAPIURL, @@ -692,7 +685,7 @@ func (c *GrpcLedgerClient) AcceptExternalPartySetupProposal(ctx context.Context, }, }, DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ - DeduplicationDuration: durationpb.New(300 * time.Second), + DeduplicationDuration: durationpb.New(c.deduplicationWindow), }, SubmissionId: newRegisterCommandId(), HashingSchemeVersion: prepareResp.GetHashingSchemeVersion(), @@ -1032,7 +1025,7 @@ func (c *GrpcLedgerClient) CompleteAcceptedTransferOffer( }, }, DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ - DeduplicationDuration: durationpb.New(300 * time.Second), + DeduplicationDuration: durationpb.New(c.deduplicationWindow), }, SubmissionId: newRegisterCommandId(), HashingSchemeVersion: prepareResp.GetHashingSchemeVersion(), diff --git a/chain/canton/proto/helpers.go b/chain/canton/proto/helpers.go index 580e7de1..6affd91c 100644 --- a/chain/canton/proto/helpers.go +++ b/chain/canton/proto/helpers.go @@ -13,6 +13,13 @@ import ( const defaultDeduplicationWindow = 300 * time.Second +func ResolveDeduplicationWindow(window time.Duration) time.Duration { + if window <= 0 { + return defaultDeduplicationWindow + } + return window +} + func NewCommandID() string { b := make([]byte, 16) _, _ = rand.Read(b) @@ -81,24 +88,24 @@ func NewPartySignatures(party string, sig *v2.Signature) *interactive.PartySigna } } -func NewExecuteSubmissionRequest(prepared *interactive.PreparedTransaction, party string, signature []byte, signedBy string, submissionID string, hashing interactive.HashingSchemeVersion) *interactive.ExecuteSubmissionRequest { +func NewExecuteSubmissionRequest(prepared *interactive.PreparedTransaction, party string, signature []byte, signedBy string, submissionID string, hashing interactive.HashingSchemeVersion, deduplicationWindow time.Duration) *interactive.ExecuteSubmissionRequest { return &interactive.ExecuteSubmissionRequest{ PreparedTransaction: prepared, PartySignatures: NewPartySignatures(party, NewRawSignature(signature, signedBy)), DeduplicationPeriod: &interactive.ExecuteSubmissionRequest_DeduplicationDuration{ - DeduplicationDuration: durationpb.New(defaultDeduplicationWindow), + DeduplicationDuration: durationpb.New(ResolveDeduplicationWindow(deduplicationWindow)), }, SubmissionId: submissionID, HashingSchemeVersion: hashing, } } -func NewExecuteSubmissionAndWaitRequest(prepared *interactive.PreparedTransaction, party string, signature []byte, signedBy string, submissionID string, hashing interactive.HashingSchemeVersion) *interactive.ExecuteSubmissionAndWaitRequest { +func NewExecuteSubmissionAndWaitRequest(prepared *interactive.PreparedTransaction, party string, signature []byte, signedBy string, submissionID string, hashing interactive.HashingSchemeVersion, deduplicationWindow time.Duration) *interactive.ExecuteSubmissionAndWaitRequest { return &interactive.ExecuteSubmissionAndWaitRequest{ PreparedTransaction: prepared, PartySignatures: NewPartySignatures(party, NewRawSignature(signature, signedBy)), DeduplicationPeriod: &interactive.ExecuteSubmissionAndWaitRequest_DeduplicationDuration{ - DeduplicationDuration: durationpb.New(defaultDeduplicationWindow), + DeduplicationDuration: durationpb.New(ResolveDeduplicationWindow(deduplicationWindow)), }, SubmissionId: submissionID, HashingSchemeVersion: hashing, diff --git a/chain/canton/proto/helpers_test.go b/chain/canton/proto/helpers_test.go index 12feb345..db93bef0 100644 --- a/chain/canton/proto/helpers_test.go +++ b/chain/canton/proto/helpers_test.go @@ -39,13 +39,13 @@ func TestNewExecuteRequests(t *testing.T) { prepared := &interactive.PreparedTransaction{} hashing := interactive.HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED - req := NewExecuteSubmissionRequest(prepared, "party", []byte{0xaa}, "fingerprint", "sub-id", hashing) + req := NewExecuteSubmissionRequest(prepared, "party", []byte{0xaa}, "fingerprint", "sub-id", hashing, 0) require.Equal(t, prepared, req.GetPreparedTransaction()) require.Equal(t, "sub-id", req.GetSubmissionId()) require.Equal(t, hashing, req.GetHashingSchemeVersion()) require.Equal(t, 300*time.Second, req.GetDeduplicationDuration().AsDuration()) - waitReq := NewExecuteSubmissionAndWaitRequest(prepared, "party", []byte{0xbb}, "fingerprint", "sub-id-2", hashing) + waitReq := NewExecuteSubmissionAndWaitRequest(prepared, "party", []byte{0xbb}, "fingerprint", "sub-id-2", hashing, 0) require.Equal(t, prepared, waitReq.GetPreparedTransaction()) require.Equal(t, "sub-id-2", waitReq.GetSubmissionId()) require.Equal(t, hashing, waitReq.GetHashingSchemeVersion()) diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go index 87a19c4a..585c4d17 100644 --- a/chain/canton/tx/tx.go +++ b/chain/canton/tx/tx.go @@ -2,6 +2,7 @@ package tx import ( "fmt" + "time" xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" @@ -27,6 +28,8 @@ type Tx struct { KeyFingerprint string // SubmissionId for deduplication SubmissionId string + // DeduplicationWindow controls how long Canton deduplicates this submission ID. + DeduplicationWindow time.Duration // LedgerEnd captured before submission, used as the lower-bound recovery cursor. LedgerEnd int64 // Populated after SetSignatures is called @@ -63,6 +66,7 @@ func NewTx(input *tx_input.TxInput, args xcbuilder.TransferArgs, decimals int32) Party: string(args.GetFrom()), KeyFingerprint: fingerprint, SubmissionId: input.SubmissionId, + DeduplicationWindow: input.DeduplicationWindow, LedgerEnd: input.LedgerEnd, }, nil } @@ -258,7 +262,7 @@ func (tx Tx) Serialize() ([]byte, error) { return nil, fmt.Errorf("prepared transaction is nil") } - req := cantonproto.NewExecuteSubmissionRequest(tx.PreparedTransaction, tx.Party, tx.signature, tx.KeyFingerprint, tx.SubmissionId, tx.HashingSchemeVersion) + req := cantonproto.NewExecuteSubmissionRequest(tx.PreparedTransaction, tx.Party, tx.signature, tx.KeyFingerprint, tx.SubmissionId, tx.HashingSchemeVersion, tx.DeduplicationWindow) data, err := proto.Marshal(req) if err != nil { diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index 4e6bc3b5..208a63ac 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -1,6 +1,8 @@ package tx_input import ( + "time" + xc "github.com/cordialsys/crosschain" "github.com/cordialsys/crosschain/factory/drivers/registry" "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" @@ -16,6 +18,8 @@ type TxInput struct { HashingSchemeVersion interactive.HashingSchemeVersion // SubmissionId for deduplication (UUID) SubmissionId string `json:"submission_id"` + // DeduplicationWindow controls how long Canton treats the submission ID as deduplicatable. + DeduplicationWindow time.Duration `json:"deduplication_window"` // Decimals is the number of decimal places for the chain's native asset, // used to convert human-readable amounts in the prepared transaction to blockchain units. Decimals int32 `json:"decimals"` From fbfa736b1e44d53b2c4ae83de3a5bd925b1ab858 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 26 Mar 2026 12:39:57 +0100 Subject: [PATCH 14/23] CANTON: Refactor scan api interactions --- chain/canton/client/client.go | 83 +++++---- chain/canton/client/client_test.go | 147 ++++++++++++++- chain/canton/client/ledger.go | 175 ++++++++++-------- chain/canton/tx/create_account_tx.go | 1 - chain/canton/tx/create_account_tx_test.go | 9 +- chain/canton/tx/metadata.go | 3 - chain/canton/tx_input/create_account_input.go | 33 ++-- chain/canton/tx_input/hash_validation_test.go | 15 +- client/account.go | 3 +- cmd/xc/commands/create_account.go | 13 +- 10 files changed, 333 insertions(+), 149 deletions(-) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 214ec379..89d52e4f 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -244,8 +244,7 @@ func (client *Client) PrepareTransferPreapprovalCommand( } prepareReq := cantonproto.NewPrepareRequest(commandID, synchronizerID, []string{senderPartyID}, []string{senderPartyID, client.ledgerClient.validatorPartyID}, []*v2.Command{cmd}, disclosedContracts) - authCtx := client.ledgerClient.authCtx(ctx) - prepareResp, err := client.ledgerClient.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) + prepareResp, err := client.ledgerClient.PrepareSubmission(ctx, prepareReq) if err != nil { return nil, fmt.Errorf("failed to prepare TransferPreapproval_Send: %w", err) } @@ -384,8 +383,7 @@ func (client *Client) submitTransferTx(ctx context.Context, payload []byte) erro "parties": parties, }).Trace("canton request") - actx := client.ledgerClient.authCtx(ctx) - _, err := client.ledgerClient.interactiveSubmissionClient.ExecuteSubmissionAndWait(actx, andWaitReq) + _, err := client.ledgerClient.ExecuteSubmissionAndWait(ctx, andWaitReq) if err != nil { return fmt.Errorf("failed to submit Canton transaction: %w", err) } @@ -455,8 +453,8 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf txInfo.LookupId = lookupId } - // Use the caller-provided sender as the source of truth for Canton tx-info. - senderParty := string(sender) + // Use the ledger events as the source of truth for Canton tx-info movement reconstruction. + var senderParty string zero := xc.NewAmountBlockchainFromUint64(0) var transferOutputs []amuletCreation totalFee := xc.NewAmountBlockchainFromUint64(0) @@ -464,8 +462,8 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf for _, event := range tx.GetEvents() { if ex := event.GetExercised(); ex != nil { - if len(ex.GetActingParties()) > 0 && senderParty == "" { - senderParty = ex.GetActingParties()[0] + if eventSender, ok := extractTransferSender(ex); ok && senderParty == "" { + senderParty = eventSender } if outputs, ok := extractTransferOutputs(ex, decimals); ok { transferOutputs = append(transferOutputs, outputs...) @@ -502,6 +500,9 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf } if len(transferOutputs) > 0 { + if senderParty == "" { + return txinfo.TxInfo{}, fmt.Errorf("could not determine Canton transfer sender from events for update %s", updateId) + } for _, out := range transferOutputs { txInfo.AddSimpleTransfer(xc.Address(senderParty), xc.Address(out.owner), "", out.amount, nil, "") } @@ -514,6 +515,11 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf } // Fall back to created Amulets only when there is no explicit transfer exercise payload. + if senderParty == "" { + txInfo.Fees = txInfo.CalculateFees() + txInfo.SyncDeprecatedFields() + return *txInfo, nil + } for _, ac := range amuletCreations { if ac.owner == senderParty { continue @@ -541,6 +547,30 @@ func (client *Client) FetchTxInfo(ctx context.Context, args *txinfo.Args) (txinf return *txInfo, nil } +func extractTransferSender(ex *v2.ExercisedEvent) (string, bool) { + if !isTransferExercise(ex) { + return "", false + } + if len(ex.GetActingParties()) > 0 && ex.GetActingParties()[0] != "" { + return ex.GetActingParties()[0], true + } + + arg := ex.GetChoiceArgument() + if arg == nil { + return "", false + } + record := arg.GetRecord() + if record == nil { + return "", false + } + if senderValue, ok := findValueField(record, "sender"); ok { + if sender := senderValue.GetParty(); sender != "" { + return sender, true + } + } + return "", false +} + func extractTransferOutputs(ex *v2.ExercisedEvent, decimals int32) ([]amuletCreation, bool) { if !isTransferExercise(ex) { return nil, false @@ -832,7 +862,10 @@ func (client *Client) FetchNativeBalance(ctx context.Context, address xc.Address } func (client *Client) FetchDecimals(ctx context.Context, contract xc.ContractAddress) (int, error) { - return 0, errors.New("not implemented") + if client.Asset.GetChain().IsChain(contract) { + return int(client.Asset.GetChain().GetDecimals()), nil + } + return 0, fmt.Errorf("token decimals are not supported for Canton, contract: %s", contract) } func (client *Client) FetchBlock(ctx context.Context, args *xclient.BlockArgs) (*txinfo.BlockWithTransactions, error) { @@ -848,11 +881,6 @@ func KeyFingerprintFromAddress(addr xc.Address) (string, error) { return fingerprint, nil } -// TxFromInput builds a Tx from a TxInput and the transfer args, validating the hash and contents. -func TxFromInput(args xcbuilder.TransferArgs, input *tx_input.TxInput, decimals int32) (*cantontx.Tx, error) { - return cantontx.NewTx(input, args, decimals) -} - var _ xclient.CreateAccountClient = &Client{} func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateAccountArgs) (*xclient.AccountState, error) { @@ -869,8 +897,7 @@ func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateA } if !exists { return &xclient.AccountState{ - State: xclient.CreateAccountCallRequired, - Description: "Account is not registered yet. Call create-account to continue.", + State: xclient.CreateAccountCallRequired, }, nil } @@ -884,8 +911,7 @@ func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateA if isPermissionDenied(err) { logger.WithError(err).Info("get-account-state: party exists but contract visibility is not ready yet") return &xclient.AccountState{ - State: xclient.CreateAccountCallRequired, - Description: "Account exists but registration is not complete yet. Call create-account again to continue.", + State: xclient.CreateAccountCallRequired, }, nil } logger.WithError(err).Error("get-account-state: get active contracts failed") @@ -893,8 +919,7 @@ func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateA } if client.ledgerClient.HasTransferPreapprovalContract(ctx, contracts) { return &xclient.AccountState{ - State: xclient.Created, - Description: "Account registration is complete.", + State: xclient.Created, }, nil } for _, contract := range contracts { @@ -907,14 +932,12 @@ func (client *Client) GetAccountState(ctx context.Context, args *xclient.CreateA continue } return &xclient.AccountState{ - State: xclient.CreateAccountCallRequired, - Description: "Account registration requires another create-account call to continue.", + State: xclient.CreateAccountCallRequired, }, nil } return &xclient.AccountState{ - State: xclient.Pending, - Description: "Account registration is in progress. Retry create-account shortly.", + State: xclient.Pending, }, nil } @@ -939,7 +962,6 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient } logger.WithField("exists", exists).Info("create-account: external party registration check completed") if !exists { - authCtx := client.ledgerClient.authCtx(ctx) partyHint := hex.EncodeToString(publicKeyBytes) signingPubKey := &v2.SigningPublicKey{ Format: v2.CryptoKeyFormat_CRYPTO_KEY_FORMAT_RAW, @@ -953,7 +975,7 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient logger.WithError(err).Error("create-account: resolve synchronizer failed") return nil, fmt.Errorf("failed to resolve synchronizer for topology generation: %w", err) } - topologyResp, err := client.ledgerClient.adminClient.GenerateExternalPartyTopology(authCtx, &admin.GenerateExternalPartyTopologyRequest{ + topologyResp, err := client.ledgerClient.GenerateExternalPartyTopology(ctx, &admin.GenerateExternalPartyTopologyRequest{ Synchronizer: synchronizerID, PartyHint: partyHint, PublicKey: signingPubKey, @@ -974,7 +996,6 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient input := &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAllocate, - Description: "Sign signature_request.payload, append the raw signature hex to tx, then submit the combined hex with `xc submit --chain canton `.", PartyID: partyID, PublicKeyFingerprint: topologyResp.GetPublicKeyFingerprint(), TopologyTransactions: txns, @@ -1055,10 +1076,8 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient input := &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAccept, - Description: "Sign signature_request.payload, append the raw signature hex to tx, then submit the combined hex with `xc submit --chain canton `.", PartyID: partyID, SetupProposalPreparedTransaction: preparedTxBz, - SetupProposalHash: prepareResp.GetPreparedTransactionHash(), SetupProposalHashing: prepareResp.GetHashingSchemeVersion(), SetupProposalSubmissionID: newRegisterCommandId(), } @@ -1085,8 +1104,6 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx if len(cantonInput.Signature) == 0 { return fmt.Errorf("create-account transaction is not signed") } - authCtx := client.ledgerClient.authCtx(ctx) - switch cantonInput.Stage { case tx_input.CreateAccountStageAllocate: synchronizerID, err := client.resolveValidatorSynchronizerID(ctx) @@ -1094,7 +1111,7 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx return fmt.Errorf("failed to resolve synchronizer for external party allocation: %w", err) } req := cantonproto.NewAllocateExternalPartyRequest(synchronizerID, cantonInput.TopologyTransactions, cantonInput.Signature, cantonInput.PublicKeyFingerprint) - _, err = client.ledgerClient.adminClient.AllocateExternalParty(authCtx, req) + _, err = client.ledgerClient.AllocateExternalParty(ctx, req) if err != nil && !isAlreadyExists(err) { return fmt.Errorf("AllocateExternalParty failed: %w", err) } @@ -1109,7 +1126,7 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx return fmt.Errorf("failed to determine signing fingerprint for setup proposal accept: %w", err) } executeReq := cantonproto.NewExecuteSubmissionAndWaitRequest(&preparedTx, cantonInput.PartyID, cantonInput.Signature, keyFingerprint, cantonInput.SetupProposalSubmissionID, cantonInput.SetupProposalHashing, client.ledgerClient.deduplicationWindow) - _, err = client.ledgerClient.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) + _, err = client.ledgerClient.ExecuteSubmissionAndWait(ctx, executeReq) if err != nil && !isAlreadyExists(err) { return fmt.Errorf("ExternalPartySetupProposal_Accept failed: %w", err) } diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index e631e6f8..bc452551 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -3,7 +3,10 @@ package client import ( "context" "encoding/base64" + "encoding/json" "io" + "net/http" + "strings" "testing" "time" @@ -53,6 +56,31 @@ func TestNewClient(t *testing.T) { }) } +func TestFetchDecimals(t *testing.T) { + t.Parallel() + + client := &Client{ + Asset: &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + Decimals: 18, + }, + }, + } + + decimals, err := client.FetchDecimals(context.Background(), "") + require.NoError(t, err) + require.Equal(t, 18, decimals) + + decimals, err = client.FetchDecimals(context.Background(), xc.ContractAddress(xc.CANTON)) + require.NoError(t, err) + require.Equal(t, 18, decimals) + + _, err = client.FetchDecimals(context.Background(), xc.ContractAddress("SOME_TOKEN")) + require.ErrorContains(t, err, "token decimals are not supported for Canton") +} + func TestValidatorServiceUserIDFromToken(t *testing.T) { t.Parallel() @@ -295,7 +323,7 @@ func TestFetchTxInfoDirectUpdateLookupUsesSenderScopedRead(t *testing.T) { require.Contains(t, updateStub.lastReq.GetUpdateFormat().GetIncludeTransactions().GetEventFormat().GetFiltersByParty(), sender) } -func TestFetchTxInfoUsesProvidedSenderWhenEventsDoNotExposeOne(t *testing.T) { +func TestFetchTxInfoLeavesMovementsEmptyWhenEventsDoNotExposeSender(t *testing.T) { t.Parallel() sender := "f0bb6fd00a035b6b6ec18bbb2739265b80f319c0634333fe678928f40750cade::1220769b6eab2a4cc2b324e0c407b27cc7589074052c946b01aab0b1ca9b806627c6" @@ -339,11 +367,7 @@ func TestFetchTxInfoUsesProvidedSenderWhenEventsDoNotExposeOne(t *testing.T) { info, err := client.FetchTxInfo(context.Background(), txinfo.NewArgs("update-self", txinfo.OptionSender(xc.Address(sender)))) require.NoError(t, err) - require.Len(t, info.Movements, 1) - require.Len(t, info.Movements[0].From, 1) - require.Len(t, info.Movements[0].To, 1) - require.Equal(t, xc.Address(sender), info.Movements[0].From[0].AddressId) - require.Equal(t, xc.Address(sender), info.Movements[0].To[0].AddressId) + require.Empty(t, info.Movements) } func TestExtractTransferFeeSupportsTransferPreapprovalSendResult(t *testing.T) { @@ -408,6 +432,35 @@ func TestExtractTransferFeeSupportsTransferPreapprovalSendResult(t *testing.T) { require.Equal(t, "2000000000000000000", fee.String()) } +func TestExtractTransferSenderFallsBackToChoiceArgument(t *testing.T) { + t.Parallel() + + sender := "sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ex := &v2.ExercisedEvent{ + TemplateId: &v2.Identifier{ + ModuleName: "Splice.AmuletRules", + EntityName: "TransferPreapproval", + }, + Choice: "TransferPreapproval_Send", + ChoiceArgument: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "sender", + Value: &v2.Value{Sum: &v2.Value_Party{Party: sender}}, + }, + }, + }, + }, + }, + } + + got, ok := extractTransferSender(ex) + require.True(t, ok) + require.Equal(t, sender, got) +} + func TestBuildTransferOfferCreateCommandUsesArgsAmount(t *testing.T) { t.Parallel() @@ -499,6 +552,74 @@ func TestBuildTransferPreapprovalExerciseCommandUsesArgsAmount(t *testing.T) { require.Equal(t, "12.3", extractCommandAmountNumeric(t, exercise.GetChoiceArgument().GetRecord())) } +func TestGetAmuletRulesUsesStructuredScanProxyRequest(t *testing.T) { + client := &GrpcLedgerClient{ + scanProxyURL: "https://proxy.example", + scanAPIURL: "https://scan.example", + httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { + require.Equal(t, "https://proxy.example", req.URL.String()) + require.Equal(t, "Bearer token", req.Header.Get("Authorization")) + require.Equal(t, "application/json", req.Header.Get("Content-Type")) + + var envelope scanProxyRequest + require.NoError(t, json.NewDecoder(req.Body).Decode(&envelope)) + require.Equal(t, "POST", envelope.Method) + require.Equal(t, "https://scan.example/api/scan/v0/amulet-rules", envelope.URL) + require.Equal(t, "application/json", envelope.Headers["Content-Type"]) + require.JSONEq(t, `{}`, string(envelope.Body)) + + body := `{"amulet_rules_update":{"contract":{"template_id":"pkg:Mod:AmuletRules","contract_id":"cid","created_event_blob":"AQ==","payload":{"dso":"dso"}},"domain_id":"domain"}}` + return httpJSONResponse(http.StatusOK, body), nil + })}, + } + + result, err := client.GetAmuletRules(context.Background(), "token") + require.NoError(t, err) + require.Equal(t, "domain", result.AmuletRulesUpdate.DomainID) +} + +func TestGetOpenAndIssuingMiningRoundUsesStructuredScanProxyRequest(t *testing.T) { + client := &GrpcLedgerClient{ + scanProxyURL: "https://proxy.example", + scanAPIURL: "https://scan.example/", + httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { + var envelope scanProxyRequest + require.NoError(t, json.NewDecoder(req.Body).Decode(&envelope)) + require.Equal(t, "POST", envelope.Method) + require.Equal(t, "https://scan.example/api/scan/v0/open-and-issuing-mining-rounds", envelope.URL) + require.Equal(t, "application/json", envelope.Headers["Content-Type"]) + + var inner map[string][]string + require.NoError(t, json.Unmarshal(envelope.Body, &inner)) + require.Contains(t, inner, "cached_open_mining_round_contract_ids") + require.Contains(t, inner, "cached_issuing_round_contract_ids") + require.Empty(t, inner["cached_open_mining_round_contract_ids"]) + require.Empty(t, inner["cached_issuing_round_contract_ids"]) + + body := `{"open_mining_rounds":{"open":{"contract":{"contract_id":"open-cid","template_id":"pkg:Mod:Open","payload":{"round":{"number":"1"},"opensAt":"2000-01-01T00:00:00Z","targetClosesAt":"2999-01-01T00:00:00Z"},"created_event_blob":"AQ=="}, "domain_id":"domain"}},"issuing_mining_rounds":{"issuing":{"contract":{"contract_id":"issuing-cid","template_id":"pkg:Mod:Issuing","payload":{"round":{"number":"1"},"opensAt":"2000-01-01T00:00:00Z","targetClosesAt":"2999-01-01T00:00:00Z"},"created_event_blob":"AQ=="},"domain_id":"domain"}}}` + return httpJSONResponse(http.StatusOK, body), nil + })}, + } + + open, issuing, err := client.GetOpenAndIssuingMiningRound(context.Background(), "token") + require.NoError(t, err) + require.Equal(t, "open-cid", open.Contract.ContractID) + require.Equal(t, "issuing-cid", issuing.Contract.ContractID) +} + +func TestGetAmuletRulesPreservesScanProxyHTTPError(t *testing.T) { + client := &GrpcLedgerClient{ + scanProxyURL: "https://proxy.example", + scanAPIURL: "https://scan.example", + httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { + return httpJSONResponse(http.StatusBadGateway, `upstream failed`), nil + })}, + } + + _, err := client.GetAmuletRules(context.Background(), "token") + require.ErrorContains(t, err, "fetching amulet rules: status 502: upstream failed") +} + func mustSerializedCreateAccountInput(t *testing.T) []byte { t.Helper() input := &tx_input.CreateAccountInput{ @@ -692,6 +813,20 @@ func extractCommandAmountNumeric(t *testing.T, record *v2.Record) string { return "" } +type roundTripFunc func(*http.Request) (*http.Response, error) + +func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +func httpJSONResponse(status int, body string) *http.Response { + return &http.Response{ + StatusCode: status, + Body: io.NopCloser(strings.NewReader(body)), + Header: make(http.Header), + } +} + func testAmuletRulesTransferEvent(sender string, receiver string, amount string) *v2.ExercisedEvent { return &v2.ExercisedEvent{ TemplateId: &v2.Identifier{ diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index 107c5bf2..b550f5c9 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -73,9 +73,17 @@ type GrpcLedgerClient struct { restAPIURL string scanProxyURL string scanAPIURL string + httpClient *http.Client logger *logrus.Entry } +type scanProxyRequest struct { + Method string `json:"method"` + URL string `json:"url"` + Headers map[string]string `json:"headers,omitempty"` + Body json.RawMessage `json:"body"` +} + func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityConfig) (*GrpcLedgerClient, error) { if authToken == "" { return nil, errors.New("GrpcLedgerClient requires a valid authToken") @@ -120,6 +128,7 @@ func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityCon restAPIURL: cfg.restAPIURL, scanProxyURL: cfg.scanProxyURL, scanAPIURL: cfg.scanAPIURL, + httpClient: http.DefaultClient, logger: logger, }, nil } @@ -135,6 +144,22 @@ func (c *GrpcLedgerClient) authCtx(ctx context.Context) context.Context { return metadata.NewOutgoingContext(ctx, md) } +func (c *GrpcLedgerClient) GenerateExternalPartyTopology(ctx context.Context, req *admin.GenerateExternalPartyTopologyRequest) (*admin.GenerateExternalPartyTopologyResponse, error) { + return c.adminClient.GenerateExternalPartyTopology(c.authCtx(ctx), req) +} + +func (c *GrpcLedgerClient) AllocateExternalParty(ctx context.Context, req *admin.AllocateExternalPartyRequest) (*admin.AllocateExternalPartyResponse, error) { + return c.adminClient.AllocateExternalParty(c.authCtx(ctx), req) +} + +func (c *GrpcLedgerClient) PrepareSubmission(ctx context.Context, req *interactive.PrepareSubmissionRequest) (*interactive.PrepareSubmissionResponse, error) { + return c.interactiveSubmissionClient.PrepareSubmission(c.authCtx(ctx), req) +} + +func (c *GrpcLedgerClient) ExecuteSubmissionAndWait(ctx context.Context, req *interactive.ExecuteSubmissionAndWaitRequest) (*interactive.ExecuteSubmissionAndWaitResponse, error) { + return c.interactiveSubmissionClient.ExecuteSubmissionAndWait(c.authCtx(ctx), req) +} + // getLedgerEnd fetches the current ledger end offset via gRPC StateService func (c *GrpcLedgerClient) GetLedgerEnd(ctx context.Context) (int64, error) { authCtx := c.authCtx(ctx) @@ -354,8 +379,7 @@ func (c *GrpcLedgerClient) CreateExternalPartySetupProposal(ctx context.Context, req.Header.Set("Authorization", "Bearer "+c.authToken) req.Header.Set("Content-Type", "application/json") - client := http.DefaultClient - resp, err := client.Do(req) + resp, err := c.httpClient.Do(req) if err != nil { return fmt.Errorf("executing request: %w", err) } @@ -378,66 +402,87 @@ func (c *GrpcLedgerClient) CreateExternalPartySetupProposal(ctx context.Context, return nil } -type AmuletRulesContract struct { - TemplateID string `json:"template_id"` - ContractID string `json:"contract_id"` - CreatedEventBlob []byte `json:"created_event_blob"` - Payload struct { - DSO string `json:"dso"` - } `json:"payload"` -} - -type AmuletRules struct { - AmuletRulesUpdate struct { - Contract AmuletRulesContract `json:"contract"` - DomainID string `json:"domain_id"` - } `json:"amulet_rules_update"` -} - -func (a AmuletRules) GetSpliceId() string { - return strings.SplitN(a.AmuletRulesUpdate.Contract.TemplateID, ":", 2)[0] -} +func (c *GrpcLedgerClient) doScanProxyRequest(ctx context.Context, token string, path string, body any, out any) error { + requestBody, err := json.Marshal(body) + if err != nil { + return fmt.Errorf("marshal scan proxy inner body: %w", err) + } -// Make sure to auth with canton-ui token -func (c *GrpcLedgerClient) GetAmuletRules(ctx context.Context, token string) (*AmuletRules, error) { - // We access the configured scan API through the configured HTTP proxy because direct - // access to the scan node is not always available. - body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/amulet-rules","headers":{"Content-Type":"application/json"},"body":"{}"}`, c.scanAPIURL) + targetURL := strings.TrimRight(c.scanAPIURL, "/") + path + envelope := scanProxyRequest{ + Method: "POST", + URL: targetURL, + Headers: map[string]string{ + "Content-Type": "application/json", + }, + Body: json.RawMessage(requestBody), + } + payload, err := json.Marshal(envelope) + if err != nil { + return fmt.Errorf("marshal scan proxy request: %w", err) + } req, err := http.NewRequestWithContext( ctx, http.MethodPost, c.scanProxyURL, - strings.NewReader(body), + bytes.NewReader(payload), ) if err != nil { - return nil, fmt.Errorf("creating request: %w", err) + return fmt.Errorf("creating request: %w", err) } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") - client := http.DefaultClient - resp, err := client.Do(req) + resp, err := c.httpClient.Do(req) if err != nil { - return nil, fmt.Errorf("executing request: %w", err) + return fmt.Errorf("executing request: %w", err) } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { - return nil, fmt.Errorf("reading response body: %w", err) + return fmt.Errorf("reading response body: %w", err) } if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("fetching amulet rules: status %d: %s", resp.StatusCode, string(respBody)) + return fmt.Errorf("status %d: %s", resp.StatusCode, string(respBody)) } - var result AmuletRules - if err := json.Unmarshal(respBody, &result); err != nil { - return nil, fmt.Errorf("unmarshaling amulet rules: %w", err) + if err := json.Unmarshal(respBody, out); err != nil { + return fmt.Errorf("unmarshal response: %w", err) } + return nil +} + +type AmuletRulesContract struct { + TemplateID string `json:"template_id"` + ContractID string `json:"contract_id"` + CreatedEventBlob []byte `json:"created_event_blob"` + Payload struct { + DSO string `json:"dso"` + } `json:"payload"` +} + +type AmuletRules struct { + AmuletRulesUpdate struct { + Contract AmuletRulesContract `json:"contract"` + DomainID string `json:"domain_id"` + } `json:"amulet_rules_update"` +} + +func (a AmuletRules) GetSpliceId() string { + return strings.SplitN(a.AmuletRulesUpdate.Contract.TemplateID, ":", 2)[0] +} +// Make sure to auth with canton-ui token +func (c *GrpcLedgerClient) GetAmuletRules(ctx context.Context, token string) (*AmuletRules, error) { + var result AmuletRules + if err := c.doScanProxyRequest(ctx, token, "/api/scan/v0/amulet-rules", map[string]any{}, &result); err != nil { + return nil, fmt.Errorf("fetching amulet rules: %w", err) + } return &result, nil } @@ -531,40 +576,13 @@ func (r *OpenAndIssuingMiningRounds) GetLatestIssuingMiningRound() (*RoundEntry, } func (c *GrpcLedgerClient) GetOpenAndIssuingMiningRound(ctx context.Context, token string) (*RoundEntry, *RoundEntry, error) { - body := fmt.Sprintf(`{"method":"POST","url":"%s/api/scan/v0/open-and-issuing-mining-rounds","headers":{"Content-Type":"application/json"},"body":"{\"cached_open_mining_round_contract_ids\":[],\"cached_issuing_round_contract_ids\":[]}"}`, c.scanAPIURL) - - req, err := http.NewRequestWithContext( - ctx, - http.MethodPost, - c.scanProxyURL, - strings.NewReader(body), - ) - if err != nil { - return nil, nil, fmt.Errorf("creating request: %w", err) - } - - req.Header.Set("Authorization", "Bearer "+token) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, nil, fmt.Errorf("executing request: %w", err) - } - defer resp.Body.Close() - - respBody, err := io.ReadAll(resp.Body) - if err != nil { - return nil, nil, fmt.Errorf("reading response body: %w", err) - } - - if resp.StatusCode != http.StatusOK { - return nil, nil, fmt.Errorf("fetching mining rounds: status %d: %s", resp.StatusCode, string(respBody)) - } - var result OpenAndIssuingMiningRounds - if err := json.Unmarshal(respBody, &result); err != nil { - return nil, nil, fmt.Errorf("unmarshaling mining rounds: %w", err) + body := map[string]any{ + "cached_open_mining_round_contract_ids": []string{}, + "cached_issuing_round_contract_ids": []string{}, + } + if err := c.doScanProxyRequest(ctx, token, "/api/scan/v0/open-and-issuing-mining-rounds", body, &result); err != nil { + return nil, nil, fmt.Errorf("fetching mining rounds: %w", err) } latestOpenRound, err := result.GetLatestOpenMiningRound() @@ -604,10 +622,7 @@ func newRegisterCommandId() string { func (c *GrpcLedgerClient) PrepareSubmissionRequest(ctx context.Context, command *v2.Command, commandID string, partyID string, synchronizerID string) (*interactive.PrepareSubmissionResponse, error) { prepareReq := cantonproto.NewPrepareRequest(commandID, synchronizerID, []string{partyID}, []string{partyID}, []*v2.Command{command}, nil) - - authCtx := c.authCtx(ctx) - prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) - return prepareResp, err + return c.PrepareSubmission(ctx, prepareReq) } func (c *GrpcLedgerClient) AcceptExternalPartySetupProposal(ctx context.Context, partyId string, privateKey ed25519.PrivateKey) error { @@ -653,13 +668,12 @@ func (c *GrpcLedgerClient) AcceptExternalPartySetupProposal(ctx context.Context, }, } - authCtx := c.authCtx(ctx) commandID := newRegisterCommandId() synchronizerID, err := c.ResolveSynchronizerID(ctx, partyId, "") if err != nil { return fmt.Errorf("failed to resolve synchronizer: %w", err) } - prepareResp, err := c.PrepareSubmissionRequest(authCtx, cmd, commandID, partyId, synchronizerID) + prepareResp, err := c.PrepareSubmissionRequest(ctx, cmd, commandID, partyId, synchronizerID) if err != nil { return fmt.Errorf("failed to prepare submission for party setup proposal accept: %w", err) } @@ -692,7 +706,7 @@ func (c *GrpcLedgerClient) AcceptExternalPartySetupProposal(ctx context.Context, } logrus.WithField("rpc", "ExecuteSubmissionAndWait").Trace("ExternalPartySetupProposal_Accept") - _, err = c.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) + _, err = c.ExecuteSubmissionAndWait(ctx, executeReq) if err != nil { if isAlreadyExists(err) { logrus.WithField("party_id", partyId).Debug("canton: setup proposal already accepted") @@ -995,8 +1009,7 @@ func (c *GrpcLedgerClient) CompleteAcceptedTransferOffer( VerboseHashing: false, } - authCtx := c.authCtx(ctx) - prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(authCtx, prepareReq) + prepareResp, err := c.PrepareSubmission(ctx, prepareReq) if err != nil { return fmt.Errorf("preparing AcceptedTransferOffer_Complete: %w", err) } @@ -1031,7 +1044,7 @@ func (c *GrpcLedgerClient) CompleteAcceptedTransferOffer( HashingSchemeVersion: prepareResp.GetHashingSchemeVersion(), } - _, err = c.interactiveSubmissionClient.ExecuteSubmissionAndWait(authCtx, executeReq) + _, err = c.ExecuteSubmissionAndWait(ctx, executeReq) if err != nil { return fmt.Errorf("executing AcceptedTransferOffer_Complete: %w", err) } @@ -1174,7 +1187,7 @@ func (c *GrpcLedgerClient) ExecuteTransferInstructionSend( DisclosedContracts: []*v2.DisclosedContract{}, } - prepareResp, err := c.interactiveSubmissionClient.PrepareSubmission(ctx, prepareReq) + prepareResp, err := c.PrepareSubmission(ctx, prepareReq) if err != nil { return fmt.Errorf("prepare failed: %w", err) } @@ -1208,7 +1221,7 @@ func (c *GrpcLedgerClient) ExecuteTransferInstructionSend( }, } - _, err = c.interactiveSubmissionClient.ExecuteSubmissionAndWait(ctx, submitReq) + _, err = c.ExecuteSubmissionAndWait(ctx, submitReq) if err != nil { return fmt.Errorf("submit failed: %w", err) } diff --git a/chain/canton/tx/create_account_tx.go b/chain/canton/tx/create_account_tx.go index acfb7d25..953912b1 100644 --- a/chain/canton/tx/create_account_tx.go +++ b/chain/canton/tx/create_account_tx.go @@ -132,7 +132,6 @@ func cloneCreateAccountInput(input *tx_input.CreateAccountInput) *tx_input.Creat cloned := *input cloned.Signature = append([]byte(nil), input.Signature...) cloned.SetupProposalPreparedTransaction = append([]byte(nil), input.SetupProposalPreparedTransaction...) - cloned.SetupProposalHash = append([]byte(nil), input.SetupProposalHash...) if len(input.TopologyTransactions) > 0 { cloned.TopologyTransactions = make([][]byte, len(input.TopologyTransactions)) for i, txn := range input.TopologyTransactions { diff --git a/chain/canton/tx/create_account_tx_test.go b/chain/canton/tx/create_account_tx_test.go index 1927406e..afc6d90c 100644 --- a/chain/canton/tx/create_account_tx_test.go +++ b/chain/canton/tx/create_account_tx_test.go @@ -9,7 +9,9 @@ import ( xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" "github.com/cordialsys/crosschain/chain/canton/tx_input" + "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" ) func TestCreateAccountTxRoundTrip(t *testing.T) { @@ -53,7 +55,12 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { require.NoError(t, err) require.Equal(t, expectedHash, sighashes[0].Payload) } else { - require.Equal(t, tt.input.SetupProposalHash, sighashes[0].Payload) + var preparedTx interactive.PreparedTransaction + err := proto.Unmarshal(tt.input.SetupProposalPreparedTransaction, &preparedTx) + require.NoError(t, err) + expectedHash, err := tx_input.ComputePreparedTransactionHash(&preparedTx) + require.NoError(t, err) + require.Equal(t, expectedHash, sighashes[0].Payload) } unsigned, err := tx.Serialize() diff --git a/chain/canton/tx/metadata.go b/chain/canton/tx/metadata.go index 36e21e90..90d30898 100644 --- a/chain/canton/tx/metadata.go +++ b/chain/canton/tx/metadata.go @@ -27,7 +27,6 @@ type CreateAccountMetadata struct { TopologyTransactions [][]byte `json:"topology_transactions,omitempty"` SetupProposalPreparedTransaction []byte `json:"setup_proposal_prepared_transaction,omitempty"` - SetupProposalHash []byte `json:"setup_proposal_hash,omitempty"` SetupProposalHashing interactive.HashingSchemeVersion `json:"setup_proposal_hashing,omitempty"` SetupProposalSubmissionID string `json:"setup_proposal_submission_id,omitempty"` } @@ -62,7 +61,6 @@ func NewCreateAccountMetadata(input *tx_input.CreateAccountInput) *Metadata { PublicKeyFingerprint: input.PublicKeyFingerprint, TopologyTransactions: cloneMetadataBytes2D(input.TopologyTransactions), SetupProposalPreparedTransaction: append([]byte(nil), input.SetupProposalPreparedTransaction...), - SetupProposalHash: append([]byte(nil), input.SetupProposalHash...), SetupProposalHashing: input.SetupProposalHashing, SetupProposalSubmissionID: input.SetupProposalSubmissionID, }, @@ -79,7 +77,6 @@ func (m *Metadata) CreateAccountInput(signature []byte) (*tx_input.CreateAccount PublicKeyFingerprint: m.CreateAccount.PublicKeyFingerprint, TopologyTransactions: cloneMetadataBytes2D(m.CreateAccount.TopologyTransactions), SetupProposalPreparedTransaction: append([]byte(nil), m.CreateAccount.SetupProposalPreparedTransaction...), - SetupProposalHash: append([]byte(nil), m.CreateAccount.SetupProposalHash...), SetupProposalHashing: m.CreateAccount.SetupProposalHashing, SetupProposalSubmissionID: m.CreateAccount.SetupProposalSubmissionID, Signature: append([]byte(nil), signature...), diff --git a/chain/canton/tx_input/create_account_input.go b/chain/canton/tx_input/create_account_input.go index b860ce0b..01e34edc 100644 --- a/chain/canton/tx_input/create_account_input.go +++ b/chain/canton/tx_input/create_account_input.go @@ -26,14 +26,11 @@ const ( type CreateAccountInput struct { Stage string `json:"stage"` - Description string `json:"description,omitempty"` - PartyID string `json:"party_id"` PublicKeyFingerprint string `json:"public_key_fingerprint,omitempty"` TopologyTransactions [][]byte `json:"topology_transactions,omitempty"` SetupProposalPreparedTransaction []byte `json:"setup_proposal_prepared_transaction,omitempty"` - SetupProposalHash []byte `json:"setup_proposal_hash,omitempty"` SetupProposalHashing interactive.HashingSchemeVersion `json:"setup_proposal_hashing,omitempty"` SetupProposalSubmissionID string `json:"setup_proposal_submission_id,omitempty"` @@ -125,10 +122,15 @@ func (i *CreateAccountInput) Sighashes() ([]*xc.SignatureRequest, error) { case CreateAccountStageAllocate: return nil, fmt.Errorf("allocate-stage sighash is derived by the Canton create-account tx") case CreateAccountStageAccept: - if len(i.SetupProposalHash) == 0 { - return nil, fmt.Errorf("setup proposal hash is empty") + preparedTx, err := i.setupProposalPreparedTransaction() + if err != nil { + return nil, err + } + hash, err := ComputePreparedTransactionHash(preparedTx) + if err != nil { + return nil, err } - return []*xc.SignatureRequest{xc.NewSignatureRequest(i.SetupProposalHash)}, nil + return []*xc.SignatureRequest{xc.NewSignatureRequest(hash)}, nil default: return nil, fmt.Errorf("unsupported create-account stage %q", i.Stage) } @@ -158,12 +160,8 @@ func (i *CreateAccountInput) VerifySignaturePayloads() error { if len(i.SetupProposalPreparedTransaction) == 0 { return fmt.Errorf("setup proposal prepared transaction is empty") } - if len(i.SetupProposalHash) == 0 { - return fmt.Errorf("setup proposal hash is empty") - } - var prepared interactive.PreparedTransaction - if err := proto.Unmarshal(i.SetupProposalPreparedTransaction, &prepared); err != nil { - return fmt.Errorf("failed to unmarshal setup proposal prepared transaction: %w", err) + if _, err := i.setupProposalPreparedTransaction(); err != nil { + return err } default: return fmt.Errorf("unsupported create-account stage %q", i.Stage) @@ -171,6 +169,17 @@ func (i *CreateAccountInput) VerifySignaturePayloads() error { return nil } +func (i *CreateAccountInput) setupProposalPreparedTransaction() (*interactive.PreparedTransaction, error) { + if len(i.SetupProposalPreparedTransaction) == 0 { + return nil, fmt.Errorf("setup proposal prepared transaction is empty") + } + var prepared interactive.PreparedTransaction + if err := proto.Unmarshal(i.SetupProposalPreparedTransaction, &prepared); err != nil { + return nil, fmt.Errorf("failed to unmarshal setup proposal prepared transaction: %w", err) + } + return &prepared, nil +} + func (i *CreateAccountInput) metadataBytes() ([]byte, error) { metadata := *i metadata.Signature = nil diff --git a/chain/canton/tx_input/hash_validation_test.go b/chain/canton/tx_input/hash_validation_test.go index 0dbe0fac..3301cc50 100644 --- a/chain/canton/tx_input/hash_validation_test.go +++ b/chain/canton/tx_input/hash_validation_test.go @@ -66,9 +66,12 @@ func TestValidatePreparedTransactionHash_Flows(t *testing.T) { Stage: CreateAccountStageAccept, PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", SetupProposalPreparedTransaction: preparedBz, - SetupProposalHash: hash, } require.NoError(t, input.VerifySignaturePayloads()) + sighashes, err := input.Sighashes() + require.NoError(t, err) + require.Len(t, sighashes, 1) + require.Equal(t, hash, sighashes[0].Payload) }, }, { @@ -100,9 +103,12 @@ func TestValidatePreparedTransactionHash_Flows(t *testing.T) { Stage: CreateAccountStageAccept, PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", SetupProposalPreparedTransaction: preparedBz, - SetupProposalHash: wrongHash, } require.NoError(t, input.VerifySignaturePayloads()) + sighashes, err := input.Sighashes() + require.NoError(t, err) + require.Len(t, sighashes, 1) + require.NotEqual(t, wrongHash, sighashes[0].Payload) default: require.ErrorContains(t, ValidatePreparedTransactionHash(vector.preparedTx, wrongHash), "prepared transaction hash mismatch") } @@ -118,7 +124,10 @@ func TestValidatePreparedTransactionHash_LiveCreateAccountAcceptMismatch(t *test var preparedTx interactive.PreparedTransaction require.NoError(t, proto.Unmarshal(input.SetupProposalPreparedTransaction, &preparedTx)) - err := ValidatePreparedTransactionHash(&preparedTx, input.SetupProposalHash) + expectedHash, err := ComputePreparedTransactionHash(&preparedTx) + require.NoError(t, err) + + err = ValidatePreparedTransactionHash(&preparedTx, expectedHash) require.NoError(t, err) require.NoError(t, input.VerifySignaturePayloads()) diff --git a/client/account.go b/client/account.go index 02d603d6..723ff011 100644 --- a/client/account.go +++ b/client/account.go @@ -29,8 +29,7 @@ const ( ) type AccountState struct { - State AccountStateEnum `json:"state"` - Description string `json:"description"` + State AccountStateEnum `json:"state"` } // CreateAccountArgs carries the parameters for an account creation request. diff --git a/cmd/xc/commands/create_account.go b/cmd/xc/commands/create_account.go index c5a1ec25..5827618e 100644 --- a/cmd/xc/commands/create_account.go +++ b/cmd/xc/commands/create_account.go @@ -91,19 +91,18 @@ func CmdCreateAccount() *cobra.Command { switch state.State { case xclient.Created: fmt.Println(asJson(map[string]any{ - "address": string(address), - "chain": string(chainConfig.Chain), - "status": "registered", - "state": state.State, - "description": state.Description, + "address": string(address), + "chain": string(chainConfig.Chain), + "status": "registered", + "state": state.State, })) return nil case xclient.Pending: - logrus.WithField("description", state.Description).Info("account creation is pending, waiting 10s") + logrus.Info("account creation is pending, waiting 10s") time.Sleep(10 * time.Second) continue case xclient.CreateAccountCallRequired: - logrus.WithField("description", state.Description).Info("account creation step required") + logrus.Info("account creation step required") input, err := accountClient.FetchCreateAccountInput(ctx, createArgs) if err != nil { From 271876af4fe4336b1e4c964562f36a9e7faaaa5c Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 26 Mar 2026 12:58:03 +0100 Subject: [PATCH 15/23] CANTON: Test fixes and magic value fix Fix canton tests and remove hardcoded package id's from canton transfer creation path --- asset_test.go | 2 ++ chain/canton/client/client.go | 2 +- chain/canton/client/client_test.go | 10 +++++++--- chain/canton/client/command_builders.go | 3 ++- chain/canton/client/ledger.go | 7 +++++-- chain/canton/tx/tx.go | 2 +- chain/canton/tx/tx_test.go | 2 +- chain/canton/tx_input/tx_input.go | 4 ++-- chain/canton/validate.go | 7 +++++++ chain/crosschain/client_test.go | 2 -- factory/defaults/chains/mainnet.yaml | 17 +++++++++++++++++ factory/defaults/chains/testnet.yaml | 3 +++ factory/drivers/drivers_test.go | 19 ++++++++++++++++--- normalize/normalize_test.go | 6 ++++++ 14 files changed, 70 insertions(+), 16 deletions(-) diff --git a/asset_test.go b/asset_test.go index 5604d069..14be6098 100644 --- a/asset_test.go +++ b/asset_test.go @@ -71,6 +71,8 @@ func TestChains(t *testing.T) { hedera.Validate(t, chain) case DriverNear: near.Validate(t, chain) + case DriverCanton: + canton.Validate(t, chain) case "": require.Fail(t, "unknown driver", chain.Driver) default: diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 89d52e4f..0cbac790 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -304,7 +304,7 @@ func (client *Client) FetchTransferInput(ctx context.Context, args xcbuilder.Tra } } - input.PreparedTransaction = *resp.GetPreparedTransaction() + input.PreparedTransaction = resp.GetPreparedTransaction() input.SubmissionId = NewCommandId() input.HashingSchemeVersion = resp.GetHashingSchemeVersion() input.DeduplicationWindow = cantonproto.ResolveDeduplicationWindow(client.Asset.TransactionActiveTime) diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index bc452551..3e0d3f24 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -477,14 +477,18 @@ func TestBuildTransferOfferCreateCommandUsesArgsAmount(t *testing.T) { Contract AmuletRulesContract `json:"contract"` DomainID string `json:"domain_id"` }{ - Contract: AmuletRulesContract{Payload: struct { - DSO string `json:"dso"` - }{DSO: "validator-party"}}, + Contract: AmuletRulesContract{ + TemplateID: "pkg-from-amulet-rules:Splice.AmuletRules:AmuletRules", + Payload: struct { + DSO string `json:"dso"` + }{DSO: "validator-party"}, + }, }, }, "command-id", 1) create := cmd.GetCreate() require.NotNil(t, create) + require.Equal(t, "pkg-from-amulet-rules", create.GetTemplateId().GetPackageId()) require.Equal(t, "12.3", extractCommandAmountNumeric(t, create.GetCreateArguments())) } diff --git a/chain/canton/client/command_builders.go b/chain/canton/client/command_builders.go index 5afa026e..ac24cfeb 100644 --- a/chain/canton/client/command_builders.go +++ b/chain/canton/client/command_builders.go @@ -18,11 +18,12 @@ func transferAmountNumeric(args xcbuilder.TransferArgs, decimals int32) string { func buildTransferOfferCreateCommand(args xcbuilder.TransferArgs, amuletRules AmuletRules, commandID string, decimals int32) *v2.Command { amountNumeric := transferAmountNumeric(args, decimals) + packageID := amuletRules.GetSpliceId() return &v2.Command{ Command: &v2.Command_Create{ Create: &v2.CreateCommand{ TemplateId: &v2.Identifier{ - PackageId: "fd57252dda29e3ce90028114c91b521cb661df5a9d6e87c41a9e91518215fa5b", + PackageId: packageID, ModuleName: "Splice.Wallet.TransferOffer", EntityName: "TransferOffer", }, diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index b550f5c9..f6dacabd 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -578,8 +578,8 @@ func (r *OpenAndIssuingMiningRounds) GetLatestIssuingMiningRound() (*RoundEntry, func (c *GrpcLedgerClient) GetOpenAndIssuingMiningRound(ctx context.Context, token string) (*RoundEntry, *RoundEntry, error) { var result OpenAndIssuingMiningRounds body := map[string]any{ - "cached_open_mining_round_contract_ids": []string{}, - "cached_issuing_round_contract_ids": []string{}, + "cached_open_mining_round_contract_ids": []string{}, + "cached_issuing_round_contract_ids": []string{}, } if err := c.doScanProxyRequest(ctx, token, "/api/scan/v0/open-and-issuing-mining-rounds", body, &result); err != nil { return nil, nil, fmt.Errorf("fetching mining rounds: %w", err) @@ -681,6 +681,9 @@ func (c *GrpcLedgerClient) AcceptExternalPartySetupProposal(ctx context.Context, // Sign the prepared transaction hash with the external party's private key. txSig := ed25519.Sign(privateKey, prepareResp.GetPreparedTransactionHash()) _, keyFingerprint, err := cantonaddress.ParsePartyID(xc.Address(partyId)) + if err != nil { + return fmt.Errorf("failed to parse PartyID: %w", err) + } executeReq := &interactive.ExecuteSubmissionAndWaitRequest{ PreparedTransaction: prepareResp.GetPreparedTransaction(), PartySignatures: &interactive.PartySignatures{ diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go index 585c4d17..94826158 100644 --- a/chain/canton/tx/tx.go +++ b/chain/canton/tx/tx.go @@ -50,7 +50,7 @@ func NewTx(input *tx_input.TxInput, args xcbuilder.TransferArgs, decimals int32) return nil, fmt.Errorf("failed to parse sender party ID: %w", err) } - preparedTx := &input.PreparedTransaction + preparedTx := input.PreparedTransaction if preparedTx == nil || preparedTx.GetTransaction() == nil { return nil, fmt.Errorf("prepared transaction is nil") } diff --git a/chain/canton/tx/tx_test.go b/chain/canton/tx/tx_test.go index fd4426c9..b442be93 100644 --- a/chain/canton/tx/tx_test.go +++ b/chain/canton/tx/tx_test.go @@ -45,7 +45,7 @@ func TestNewTx_UsesPreparedTransactionForTransferFlows(t *testing.T) { require.NoError(t, err) input := &tx_input.TxInput{ - PreparedTransaction: *vector.preparedTx, + PreparedTransaction: vector.preparedTx, LedgerEnd: 12345, SubmissionId: "submission-id", } diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index 208a63ac..b6567138 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -12,9 +12,9 @@ import ( // interactive-submission (external-party signing) flow. type TxInput struct { xc.TxInputEnvelope - IsExternalTransfer bool `json:"is_external_transfer"` + IsExternalTransfer bool `json:"is_external_transfer"` LedgerEnd int64 `json:"ledger_end"` - PreparedTransaction interactive.PreparedTransaction + PreparedTransaction *interactive.PreparedTransaction HashingSchemeVersion interactive.HashingSchemeVersion // SubmissionId for deduplication (UUID) SubmissionId string `json:"submission_id"` diff --git a/chain/canton/validate.go b/chain/canton/validate.go index 205f4fb0..2ea3a418 100644 --- a/chain/canton/validate.go +++ b/chain/canton/validate.go @@ -5,9 +5,11 @@ import ( "fmt" "regexp" "strings" + "testing" xc "github.com/cordialsys/crosschain" cantonclient "github.com/cordialsys/crosschain/chain/canton/client" + "github.com/stretchr/testify/require" ) // ValidateAddress validates a Canton party ID address format. @@ -51,6 +53,11 @@ func ValidateCustomConfig(chainCfg *xc.ChainConfig) error { return cfg.Validate() } +func Validate(t *testing.T, chainCfg *xc.ChainConfig) { + require := require.New(t) + require.NoError(ValidateCustomConfig(chainCfg)) +} + // validatePartyName validates the party name component func validatePartyName(name string) error { if len(name) == 0 { diff --git a/chain/crosschain/client_test.go b/chain/crosschain/client_test.go index 77d260cf..373f4de8 100644 --- a/chain/crosschain/client_test.go +++ b/chain/crosschain/client_test.go @@ -227,7 +227,6 @@ func (s *CrosschainTestSuite) TestGetAccountState() { CreateAccountInputReq: &types.CreateAccountInputReq{}, AccountState: &xclient.AccountState{ State: xclient.CreateAccountCallRequired, - Description: "Account registration requires another create-account call to continue.", }, } res, _ := json.Marshal(resObj) @@ -243,7 +242,6 @@ func (s *CrosschainTestSuite) TestGetAccountState() { require.NoError(err) require.NotNil(state) require.Equal(xclient.CreateAccountCallRequired, state.State) - require.Equal("Account registration requires another create-account call to continue.", state.Description) } func (s *CrosschainTestSuite) TestGetAccountStateError() { diff --git a/factory/defaults/chains/mainnet.yaml b/factory/defaults/chains/mainnet.yaml index 123603c8..aef9ddee 100644 --- a/factory/defaults/chains/mainnet.yaml +++ b/factory/defaults/chains/mainnet.yaml @@ -445,11 +445,28 @@ chains: chain_id: celo CANTON: chain: CANTON + support: + fee: + accurate: true driver: canton chain_name: Canton decimals: 18 fee_limit: "100.0" confirmations_final: 1 + external: + coin_market_cap: + asset_id: "37263" + coin_gecko: + asset_id: "canton-network" + custom_config: + keycloak_url: "env:CANTON_KEYCLOAK_URL" + keycloak_realm: "env:CANTON_KEYCLOAK_REALM" + validator_auth: "env:CANTON_VALIDATOR_BASIC_AUTH" + validator_party_id: "env:CANTON_VALIDATOR_PARTY_ID" + rest_api_url: "env:CANTON_REST_API_URL" + scan_proxy_url: "env:CANTON_SCAN_API_URL" + scan_api_url: "env:CANTON_SCAN_NODE_URL" + canton_ui_auth: "env:CANTON_UI_BASIC_AUTH" CHZ: chain: CHZ driver: evm-legacy diff --git a/factory/defaults/chains/testnet.yaml b/factory/defaults/chains/testnet.yaml index ee0be674..1c1083ce 100644 --- a/factory/defaults/chains/testnet.yaml +++ b/factory/defaults/chains/testnet.yaml @@ -216,6 +216,9 @@ chains: decimals: 18 CANTON: chain: CANTON + support: + fee: + accurate: true driver: canton chain_name: Canton (Testnet) decimals: 18 diff --git a/factory/drivers/drivers_test.go b/factory/drivers/drivers_test.go index fbeebf4f..a5b6bf8d 100644 --- a/factory/drivers/drivers_test.go +++ b/factory/drivers/drivers_test.go @@ -93,6 +93,16 @@ func createChainFor(driver xc.Driver) *xc.ChainConfig { } if driver == xc.DriverCanton { fakeAsset.URL = "https://canton.example.com" + fakeAsset.CustomConfig = map[string]any{ + "keycloak_url": "raw:https://keycloak.example.com/auth", + "keycloak_realm": "raw:test-realm", + "validator_auth": "raw:validator:test-secret", + "validator_party_id": "raw:validator::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "rest_api_url": "raw:https://wallet.example.com", + "scan_proxy_url": "raw:https://scan-proxy.example.com", + "scan_api_url": "raw:https://scan-api.example.com", + "canton_ui_auth": "raw:canton-ui:test-secret", + } } return fakeAsset } @@ -101,8 +111,8 @@ func (s *CrosschainTestSuite) TestAllNewClient() { require := s.Require() for _, driver := range xc.SupportedDrivers { - // TODO: these require custom params for NewClient - if driver == xc.DriverAptos || driver == xc.DriverSubstrate { + // TODO: these require custom params or live auth for NewClient + if driver == xc.DriverAptos || driver == xc.DriverSubstrate || driver == xc.DriverCanton { continue } @@ -205,6 +215,9 @@ func (s *CrosschainTestSuite) TestAllNewStakingInput() { case "calling": _, err := drivers.UnmarshalCallInput(bz) require.NoError(err) + case "create-account": + _, err := drivers.UnmarshalCreateAccountInput(bz) + require.NoError(err) default: require.Fail("unexpected txType ", inputType) } @@ -218,7 +231,7 @@ func (s *CrosschainTestSuite) TestStakingVariants() { for _, variant := range registry.GetSupportedTxVariants() { variantType := variant.GetVariant() parts := strings.Split(string(variantType), "/") - inputColumns := []string{"staking", "unstaking", "withdrawing", "multi-transfer", "calling"} + inputColumns := []string{"staking", "unstaking", "withdrawing", "multi-transfer", "calling", "create-account"} require.Len(parts, 4, "variant must be in format drivers/:driver/[ "+strings.Join(inputColumns, "|")+" ]/:id") require.Equal("drivers", parts[0]) require.Contains(inputColumns, parts[2], "input type column must be one of: "+strings.Join(inputColumns, ", ")) diff --git a/normalize/normalize_test.go b/normalize/normalize_test.go index 021ab0d6..4accdb31 100644 --- a/normalize/normalize_test.go +++ b/normalize/normalize_test.go @@ -175,6 +175,12 @@ func TestNormalizeAddress(t *testing.T) { inp: "15BgrFpAb7kSBYCcCqZPbLDgNrqygmGumT", out: "15BgrFpAb7kSBYCcCqZPbLDgNrqygmGumT", }, + { + // Canton party IDs should be preserved as-is. + chain: xc.CANTON, + inp: "d6ed91f336502ff706d97729d7ab5521e230c39353ca79372d2b1fc239eaa72c::12203a20475db3ac28b1e0591c90de7826a205cacd9c7b724a2e5822851f029ee2fc", + out: "d6ed91f336502ff706d97729d7ab5521e230c39353ca79372d2b1fc239eaa72c::12203a20475db3ac28b1e0591c90de7826a205cacd9c7b724a2e5822851f029ee2fc", + }, { // base58, no variation chain: xc.DOT, From 1caa2fe461e1551c8acdfbfa075b08a4d9a4ec13 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:15:37 +0100 Subject: [PATCH 16/23] CANTON: Fix scan api regression --- chain/canton/client/client_test.go | 64 +++++++++++++++--------------- chain/canton/client/ledger.go | 4 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index 3e0d3f24..db7ae7e0 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -560,21 +560,21 @@ func TestGetAmuletRulesUsesStructuredScanProxyRequest(t *testing.T) { client := &GrpcLedgerClient{ scanProxyURL: "https://proxy.example", scanAPIURL: "https://scan.example", - httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { - require.Equal(t, "https://proxy.example", req.URL.String()) - require.Equal(t, "Bearer token", req.Header.Get("Authorization")) - require.Equal(t, "application/json", req.Header.Get("Content-Type")) - - var envelope scanProxyRequest - require.NoError(t, json.NewDecoder(req.Body).Decode(&envelope)) - require.Equal(t, "POST", envelope.Method) - require.Equal(t, "https://scan.example/api/scan/v0/amulet-rules", envelope.URL) - require.Equal(t, "application/json", envelope.Headers["Content-Type"]) - require.JSONEq(t, `{}`, string(envelope.Body)) - - body := `{"amulet_rules_update":{"contract":{"template_id":"pkg:Mod:AmuletRules","contract_id":"cid","created_event_blob":"AQ==","payload":{"dso":"dso"}},"domain_id":"domain"}}` - return httpJSONResponse(http.StatusOK, body), nil - })}, + httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { + require.Equal(t, "https://proxy.example", req.URL.String()) + require.Equal(t, "Bearer token", req.Header.Get("Authorization")) + require.Equal(t, "application/json", req.Header.Get("Content-Type")) + + var envelope scanProxyRequest + require.NoError(t, json.NewDecoder(req.Body).Decode(&envelope)) + require.Equal(t, "POST", envelope.Method) + require.Equal(t, "https://scan.example/api/scan/v0/amulet-rules", envelope.URL) + require.Equal(t, "application/json", envelope.Headers["Content-Type"]) + require.JSONEq(t, `{}`, envelope.Body) + + body := `{"amulet_rules_update":{"contract":{"template_id":"pkg:Mod:AmuletRules","contract_id":"cid","created_event_blob":"AQ==","payload":{"dso":"dso"}},"domain_id":"domain"}}` + return httpJSONResponse(http.StatusOK, body), nil + })}, } result, err := client.GetAmuletRules(context.Background(), "token") @@ -586,23 +586,23 @@ func TestGetOpenAndIssuingMiningRoundUsesStructuredScanProxyRequest(t *testing.T client := &GrpcLedgerClient{ scanProxyURL: "https://proxy.example", scanAPIURL: "https://scan.example/", - httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { - var envelope scanProxyRequest - require.NoError(t, json.NewDecoder(req.Body).Decode(&envelope)) - require.Equal(t, "POST", envelope.Method) - require.Equal(t, "https://scan.example/api/scan/v0/open-and-issuing-mining-rounds", envelope.URL) - require.Equal(t, "application/json", envelope.Headers["Content-Type"]) - - var inner map[string][]string - require.NoError(t, json.Unmarshal(envelope.Body, &inner)) - require.Contains(t, inner, "cached_open_mining_round_contract_ids") - require.Contains(t, inner, "cached_issuing_round_contract_ids") - require.Empty(t, inner["cached_open_mining_round_contract_ids"]) - require.Empty(t, inner["cached_issuing_round_contract_ids"]) - - body := `{"open_mining_rounds":{"open":{"contract":{"contract_id":"open-cid","template_id":"pkg:Mod:Open","payload":{"round":{"number":"1"},"opensAt":"2000-01-01T00:00:00Z","targetClosesAt":"2999-01-01T00:00:00Z"},"created_event_blob":"AQ=="}, "domain_id":"domain"}},"issuing_mining_rounds":{"issuing":{"contract":{"contract_id":"issuing-cid","template_id":"pkg:Mod:Issuing","payload":{"round":{"number":"1"},"opensAt":"2000-01-01T00:00:00Z","targetClosesAt":"2999-01-01T00:00:00Z"},"created_event_blob":"AQ=="},"domain_id":"domain"}}}` - return httpJSONResponse(http.StatusOK, body), nil - })}, + httpClient: &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { + var envelope scanProxyRequest + require.NoError(t, json.NewDecoder(req.Body).Decode(&envelope)) + require.Equal(t, "POST", envelope.Method) + require.Equal(t, "https://scan.example/api/scan/v0/open-and-issuing-mining-rounds", envelope.URL) + require.Equal(t, "application/json", envelope.Headers["Content-Type"]) + + var inner map[string][]string + require.NoError(t, json.Unmarshal([]byte(envelope.Body), &inner)) + require.Contains(t, inner, "cached_open_mining_round_contract_ids") + require.Contains(t, inner, "cached_issuing_round_contract_ids") + require.Empty(t, inner["cached_open_mining_round_contract_ids"]) + require.Empty(t, inner["cached_issuing_round_contract_ids"]) + + body := `{"open_mining_rounds":{"open":{"contract":{"contract_id":"open-cid","template_id":"pkg:Mod:Open","payload":{"round":{"number":"1"},"opensAt":"2000-01-01T00:00:00Z","targetClosesAt":"2999-01-01T00:00:00Z"},"created_event_blob":"AQ=="}, "domain_id":"domain"}},"issuing_mining_rounds":{"issuing":{"contract":{"contract_id":"issuing-cid","template_id":"pkg:Mod:Issuing","payload":{"round":{"number":"1"},"opensAt":"2000-01-01T00:00:00Z","targetClosesAt":"2999-01-01T00:00:00Z"},"created_event_blob":"AQ=="},"domain_id":"domain"}}}` + return httpJSONResponse(http.StatusOK, body), nil + })}, } open, issuing, err := client.GetOpenAndIssuingMiningRound(context.Background(), "token") diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index f6dacabd..72659d71 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -81,7 +81,7 @@ type scanProxyRequest struct { Method string `json:"method"` URL string `json:"url"` Headers map[string]string `json:"headers,omitempty"` - Body json.RawMessage `json:"body"` + Body string `json:"body"` } func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityConfig) (*GrpcLedgerClient, error) { @@ -415,7 +415,7 @@ func (c *GrpcLedgerClient) doScanProxyRequest(ctx context.Context, token string, Headers: map[string]string{ "Content-Type": "application/json", }, - Body: json.RawMessage(requestBody), + Body: string(requestBody), } payload, err := json.Marshal(envelope) if err != nil { From 41a5b3a27d0366284c19ceffadd1f92e2e7de09b Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Tue, 31 Mar 2026 20:00:00 +0200 Subject: [PATCH 17/23] CANTON: Remove CustomConfig.validator_party_id --- chain/canton/client/client.go | 41 +++++++++++++++++++++++++--- chain/canton/client/config.go | 4 --- factory/defaults/chains/mainnet.yaml | 1 - factory/defaults/chains/testnet.yaml | 1 - factory/drivers/drivers_test.go | 1 - 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 0cbac790..f27686ed 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -7,6 +7,8 @@ import ( "encoding/json" "errors" "fmt" + "io" + "net/http" "strconv" "strings" "time" @@ -80,6 +82,37 @@ func validatorServiceUserIDFromToken(token string) (string, error) { return claims.PreferredUsername, nil } +func fetchValidatorPartyID(ctx context.Context, restAPIURL string) (string, error) { + endpoint := strings.TrimRight(restAPIURL, "/") + "/api/validator/v0/validator-user" + req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) + if err != nil { + return "", fmt.Errorf("create validator user request: %w", err) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", fmt.Errorf("fetch validator user: %w", err) + } + defer resp.Body.Close() + + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("fetch validator user returned %d: %s", resp.StatusCode, body) + } + + var payload struct { + PartyID string `json:"party_id"` + } + if err := json.Unmarshal(body, &payload); err != nil { + return "", fmt.Errorf("decode validator user response: %w", err) + } + if payload.PartyID == "" { + return "", errors.New("validator user response missing party_id") + } + + return payload.PartyID, nil +} + // NewClient returns a new Canton gRPC Client func NewClient(cfgI *xc.ChainConfig) (*Client, error) { cfg := cfgI.GetChain() @@ -111,14 +144,14 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { if err != nil { return nil, err } - validatorPartyID, err := cantonCfg.ValidatorPartyID.LoadNonEmpty() - if err != nil { - return nil, fmt.Errorf("failed to load canton validator party id: %w", err) - } restAPIURL, err := cantonCfg.RestAPIURL.LoadNonEmpty() if err != nil { return nil, fmt.Errorf("failed to load canton rest api url: %w", err) } + validatorPartyID, err := fetchValidatorPartyID(context.Background(), restAPIURL) + if err != nil { + return nil, fmt.Errorf("failed to fetch canton validator party id: %w", err) + } scanProxyURL, err := cantonCfg.ScanProxyURL.LoadNonEmpty() if err != nil { return nil, fmt.Errorf("failed to load canton scan proxy url: %w", err) diff --git a/chain/canton/client/config.go b/chain/canton/client/config.go index aea88800..1fe24cd9 100644 --- a/chain/canton/client/config.go +++ b/chain/canton/client/config.go @@ -12,7 +12,6 @@ type CantonConfig struct { KeycloakURL config.Secret `yaml:"keycloak_url,omitempty"` KeycloakRealm config.Secret `yaml:"keycloak_realm,omitempty"` ValidatorAuth config.Secret `yaml:"validator_auth,omitempty"` - ValidatorPartyID config.Secret `yaml:"validator_party_id,omitempty"` RestAPIURL config.Secret `yaml:"rest_api_url,omitempty"` ScanProxyURL config.Secret `yaml:"scan_proxy_url,omitempty"` ScanAPIURL config.Secret `yaml:"scan_api_url,omitempty"` @@ -44,9 +43,6 @@ func (cfg *CantonConfig) Validate() error { if cfg.ValidatorAuth == "" { return fmt.Errorf("missing canton custom config field validator_auth") } - if cfg.ValidatorPartyID == "" { - return fmt.Errorf("missing canton custom config field validator_party_id") - } if cfg.RestAPIURL == "" { return fmt.Errorf("missing canton custom config field rest_api_url") } diff --git a/factory/defaults/chains/mainnet.yaml b/factory/defaults/chains/mainnet.yaml index aef9ddee..ba597b68 100644 --- a/factory/defaults/chains/mainnet.yaml +++ b/factory/defaults/chains/mainnet.yaml @@ -462,7 +462,6 @@ chains: keycloak_url: "env:CANTON_KEYCLOAK_URL" keycloak_realm: "env:CANTON_KEYCLOAK_REALM" validator_auth: "env:CANTON_VALIDATOR_BASIC_AUTH" - validator_party_id: "env:CANTON_VALIDATOR_PARTY_ID" rest_api_url: "env:CANTON_REST_API_URL" scan_proxy_url: "env:CANTON_SCAN_API_URL" scan_api_url: "env:CANTON_SCAN_NODE_URL" diff --git a/factory/defaults/chains/testnet.yaml b/factory/defaults/chains/testnet.yaml index 1c1083ce..9aacfff4 100644 --- a/factory/defaults/chains/testnet.yaml +++ b/factory/defaults/chains/testnet.yaml @@ -228,7 +228,6 @@ chains: keycloak_url: "env:CANTON_KEYCLOAK_URL" keycloak_realm: "env:CANTON_KEYCLOAK_REALM" validator_auth: "env:CANTON_VALIDATOR_BASIC_AUTH" - validator_party_id: "env:CANTON_VALIDATOR_PARTY_ID" rest_api_url: "env:CANTON_REST_API_URL" scan_proxy_url: "env:CANTON_SCAN_API_URL" scan_api_url: "env:CANTON_SCAN_NODE_URL" diff --git a/factory/drivers/drivers_test.go b/factory/drivers/drivers_test.go index a5b6bf8d..d70d0cb1 100644 --- a/factory/drivers/drivers_test.go +++ b/factory/drivers/drivers_test.go @@ -97,7 +97,6 @@ func createChainFor(driver xc.Driver) *xc.ChainConfig { "keycloak_url": "raw:https://keycloak.example.com/auth", "keycloak_realm": "raw:test-realm", "validator_auth": "raw:validator:test-secret", - "validator_party_id": "raw:validator::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "rest_api_url": "raw:https://wallet.example.com", "scan_proxy_url": "raw:https://scan-proxy.example.com", "scan_api_url": "raw:https://scan-api.example.com", From 46834f10970195bc445720ca35ef06a4f3fa43a1 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:01:35 +0200 Subject: [PATCH 18/23] CANTON: Add CustomConfig comments --- chain/canton/client/config.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/chain/canton/client/config.go b/chain/canton/client/config.go index 1fe24cd9..cc87cee6 100644 --- a/chain/canton/client/config.go +++ b/chain/canton/client/config.go @@ -9,13 +9,20 @@ import ( ) type CantonConfig struct { - KeycloakURL config.Secret `yaml:"keycloak_url,omitempty"` - KeycloakRealm config.Secret `yaml:"keycloak_realm,omitempty"` - ValidatorAuth config.Secret `yaml:"validator_auth,omitempty"` - RestAPIURL config.Secret `yaml:"rest_api_url,omitempty"` - ScanProxyURL config.Secret `yaml:"scan_proxy_url,omitempty"` - ScanAPIURL config.Secret `yaml:"scan_api_url,omitempty"` - CantonUIAuth config.Secret `yaml:"canton_ui_auth,omitempty"` + // KeycloakURL is the Keycloak base URL used for validator and canton-ui token acquisition. + KeycloakURL config.Secret `yaml:"keycloak_url,omitempty"` + // KeycloakRealm is the Keycloak realm that issues validator and canton-ui tokens. + KeycloakRealm config.Secret `yaml:"keycloak_realm,omitempty"` + // ValidatorAuth is validator client_credentials auth in id:secret form. + ValidatorAuth config.Secret `yaml:"validator_auth,omitempty"` + // RestAPIURL is the validator REST base URL used for validator-admin and public validator endpoints. + RestAPIURL config.Secret `yaml:"rest_api_url,omitempty"` + // ScanProxyURL is the validator-hosted scan proxy endpoint we call from the Canton client. + ScanProxyURL config.Secret `yaml:"scan_proxy_url,omitempty"` + // ScanAPIURL is the upstream Scan node base URL that the proxy targets on our behalf. + ScanAPIURL config.Secret `yaml:"scan_api_url,omitempty"` + // CantonUIAuth is canton-ui password-grant auth in id:secret form, used to obtain scan proxy tokens. + CantonUIAuth config.Secret `yaml:"canton_ui_auth,omitempty"` } func LoadCantonConfig(chain *xc.ChainConfig) (*CantonConfig, error) { From f464fbb7d462a567ff5faa9b308fae05460c49d6 Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Thu, 2 Apr 2026 16:26:34 -0400 Subject: [PATCH 19/23] canton: drop using secrets for urls --- chain/canton/client/client.go | 35 ++++-------- chain/canton/client/config.go | 53 ++++++++++--------- chain/canton/tx_input/create_account_input.go | 16 +++++- chain/canton/tx_input/hash_validation.go | 1 + factory/defaults/chains/mainnet.yaml | 11 ++-- factory/defaults/chains/testnet.yaml | 11 ++-- 6 files changed, 63 insertions(+), 64 deletions(-) diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index f27686ed..d22470e5 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -128,14 +128,7 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { if err := cantonCfg.Validate(); err != nil { return nil, err } - keycloakURL, err := cantonCfg.KeycloakURL.LoadNonEmpty() - if err != nil { - return nil, fmt.Errorf("failed to load canton keycloak url: %w", err) - } - keycloakRealm, err := cantonCfg.KeycloakRealm.LoadNonEmpty() - if err != nil { - return nil, fmt.Errorf("failed to load canton keycloak realm: %w", err) - } + validatorAuthRaw, err := cantonCfg.ValidatorAuth.LoadNonEmpty() if err != nil { return nil, fmt.Errorf("failed to load canton validator auth: %w", err) @@ -144,22 +137,12 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { if err != nil { return nil, err } - restAPIURL, err := cantonCfg.RestAPIURL.LoadNonEmpty() - if err != nil { - return nil, fmt.Errorf("failed to load canton rest api url: %w", err) - } - validatorPartyID, err := fetchValidatorPartyID(context.Background(), restAPIURL) + + validatorPartyID, err := fetchValidatorPartyID(context.Background(), cantonCfg.RestAPIURL) if err != nil { return nil, fmt.Errorf("failed to fetch canton validator party id: %w", err) } - scanProxyURL, err := cantonCfg.ScanProxyURL.LoadNonEmpty() - if err != nil { - return nil, fmt.Errorf("failed to load canton scan proxy url: %w", err) - } - scanAPIURL, err := cantonCfg.ScanAPIURL.LoadNonEmpty() - if err != nil { - return nil, fmt.Errorf("failed to load canton scan api url: %w", err) - } + cantonUIAuthRaw, err := cantonCfg.CantonUIAuth.LoadNonEmpty() if err != nil { return nil, fmt.Errorf("failed to load canton ui auth: %w", err) @@ -171,8 +154,8 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { client := &Client{ Asset: cfgI, - validatorKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), - cantonUiKC: cantonkc.NewClient(keycloakURL, keycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), + validatorKC: cantonkc.NewClient(cantonCfg.KeycloakURL, cantonCfg.KeycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), + cantonUiKC: cantonkc.NewClient(cantonCfg.KeycloakURL, cantonCfg.KeycloakRealm, validatorAuthID, validatorAuthSecret, validatorPartyID), cantonUiUsername: cantonUiUsername, cantonUiPassword: cantonUiPassword, } @@ -193,9 +176,9 @@ func NewClient(cfgI *xc.ChainConfig) (*Client, error) { validatorPartyID: validatorPartyID, validatorServiceUserID: validatorServiceUserID, deduplicationWindow: cfgI.TransactionActiveTime, - restAPIURL: restAPIURL, - scanProxyURL: scanProxyURL, - scanAPIURL: scanAPIURL, + restAPIURL: cantonCfg.RestAPIURL, + scanProxyURL: cantonCfg.ScanProxyURL, + scanAPIURL: cantonCfg.ScanAPIURL, }) if err != nil { return nil, fmt.Errorf("failed to create GrpcLedgerClient: %w", err) diff --git a/chain/canton/client/config.go b/chain/canton/client/config.go index cc87cee6..1fafe034 100644 --- a/chain/canton/client/config.go +++ b/chain/canton/client/config.go @@ -10,34 +10,20 @@ import ( type CantonConfig struct { // KeycloakURL is the Keycloak base URL used for validator and canton-ui token acquisition. - KeycloakURL config.Secret `yaml:"keycloak_url,omitempty"` + KeycloakURL string `yaml:"keycloak_url,omitempty"` // KeycloakRealm is the Keycloak realm that issues validator and canton-ui tokens. - KeycloakRealm config.Secret `yaml:"keycloak_realm,omitempty"` - // ValidatorAuth is validator client_credentials auth in id:secret form. - ValidatorAuth config.Secret `yaml:"validator_auth,omitempty"` + KeycloakRealm string `yaml:"keycloak_realm,omitempty"` // RestAPIURL is the validator REST base URL used for validator-admin and public validator endpoints. - RestAPIURL config.Secret `yaml:"rest_api_url,omitempty"` + RestAPIURL string `yaml:"rest_api_url,omitempty"` // ScanProxyURL is the validator-hosted scan proxy endpoint we call from the Canton client. - ScanProxyURL config.Secret `yaml:"scan_proxy_url,omitempty"` + ScanProxyURL string `yaml:"scan_proxy_url,omitempty"` // ScanAPIURL is the upstream Scan node base URL that the proxy targets on our behalf. - ScanAPIURL config.Secret `yaml:"scan_api_url,omitempty"` - // CantonUIAuth is canton-ui password-grant auth in id:secret form, used to obtain scan proxy tokens. - CantonUIAuth config.Secret `yaml:"canton_ui_auth,omitempty"` -} + ScanAPIURL string `yaml:"scan_api_url,omitempty"` -func LoadCantonConfig(chain *xc.ChainConfig) (*CantonConfig, error) { - cfg := &CantonConfig{} - if chain != nil && len(chain.CustomConfig) > 0 { - bz, err := yaml.Marshal(chain.CustomConfig) - if err != nil { - return nil, fmt.Errorf("marshal canton custom config: %w", err) - } - if err := yaml.Unmarshal(bz, cfg); err != nil { - return nil, fmt.Errorf("unmarshal canton custom config: %w", err) - } - } - - return cfg, nil + // ValidatorAuth is validator client_credentials auth in id:secret form. + ValidatorAuth config.Secret `yaml:"validator_auth,omitempty"` + // CantonUIAuth is canton-ui password-grant auth in id:secret form, used to obtain scan proxy tokens. + CantonUIAuth config.Secret `yaml:"canton_ui_auth,omitempty"` } func (cfg *CantonConfig) Validate() error { @@ -47,9 +33,6 @@ func (cfg *CantonConfig) Validate() error { if cfg.KeycloakRealm == "" { return fmt.Errorf("missing canton custom config field keycloak_realm") } - if cfg.ValidatorAuth == "" { - return fmt.Errorf("missing canton custom config field validator_auth") - } if cfg.RestAPIURL == "" { return fmt.Errorf("missing canton custom config field rest_api_url") } @@ -59,8 +42,26 @@ func (cfg *CantonConfig) Validate() error { if cfg.ScanAPIURL == "" { return fmt.Errorf("missing canton custom config field scan_api_url") } + if cfg.ValidatorAuth == "" { + return fmt.Errorf("missing canton custom config field validator_auth") + } if cfg.CantonUIAuth == "" { return fmt.Errorf("missing canton custom config field canton_ui_auth") } return nil } + +func LoadCantonConfig(chain *xc.ChainConfig) (*CantonConfig, error) { + cfg := &CantonConfig{} + if chain != nil && len(chain.CustomConfig) > 0 { + bz, err := yaml.Marshal(chain.CustomConfig) + if err != nil { + return nil, fmt.Errorf("marshal canton custom config: %w", err) + } + if err := yaml.Unmarshal(bz, cfg); err != nil { + return nil, fmt.Errorf("unmarshal canton custom config: %w", err) + } + } + + return cfg, nil +} diff --git a/chain/canton/tx_input/create_account_input.go b/chain/canton/tx_input/create_account_input.go index 01e34edc..b87688fd 100644 --- a/chain/canton/tx_input/create_account_input.go +++ b/chain/canton/tx_input/create_account_input.go @@ -26,10 +26,22 @@ const ( type CreateAccountInput struct { Stage string `json:"stage"` - PartyID string `json:"party_id"` - PublicKeyFingerprint string `json:"public_key_fingerprint,omitempty"` + // Used only for conflict checking, but not actually in the transaction? + PartyID string `json:"party_id"` + // Need to make the tx submit -- likely we can compute this on our own + // and drop it from the input + PublicKeyFingerprint string `json:"public_key_fingerprint,omitempty"` + + // This is generated by the canton node and is rather opaque. TopologyTransactions [][]byte `json:"topology_transactions,omitempty"` + // This seems like a total mess: + // * encoded as protobuf (despite JSON being used elsewhere) + // * Used via Sighashes on the input? + // * Unmarshals to interactive.PreparedTransaction on use + // * really seems like blind signing + // It's really unclear what the minimal inputs are and how transaction construction should occur. + // It's done entirely by the server/node. SetupProposalPreparedTransaction []byte `json:"setup_proposal_prepared_transaction,omitempty"` SetupProposalHashing interactive.HashingSchemeVersion `json:"setup_proposal_hashing,omitempty"` SetupProposalSubmissionID string `json:"setup_proposal_submission_id,omitempty"` diff --git a/chain/canton/tx_input/hash_validation.go b/chain/canton/tx_input/hash_validation.go index a6c01391..1342d4e3 100644 --- a/chain/canton/tx_input/hash_validation.go +++ b/chain/canton/tx_input/hash_validation.go @@ -516,6 +516,7 @@ func encodeGenMapEntry(entry *v2.GenMap_Entry) ([]byte, error) { return append(key, value...), nil } +// dont use mapping since unsafe func createNodesDict(preparedTx *interactive.PreparedTransaction) (map[string]*interactive.DamlTransaction_Node, error) { transaction := preparedTx.GetTransaction() if transaction == nil { diff --git a/factory/defaults/chains/mainnet.yaml b/factory/defaults/chains/mainnet.yaml index ba597b68..11aadc92 100644 --- a/factory/defaults/chains/mainnet.yaml +++ b/factory/defaults/chains/mainnet.yaml @@ -459,13 +459,14 @@ chains: coin_gecko: asset_id: "canton-network" custom_config: - keycloak_url: "env:CANTON_KEYCLOAK_URL" - keycloak_realm: "env:CANTON_KEYCLOAK_REALM" + keycloak_url: "" + keycloak_realm: "" + rest_api_url: "" + scan_proxy_url: "" + scan_api_url: "" validator_auth: "env:CANTON_VALIDATOR_BASIC_AUTH" - rest_api_url: "env:CANTON_REST_API_URL" - scan_proxy_url: "env:CANTON_SCAN_API_URL" - scan_api_url: "env:CANTON_SCAN_NODE_URL" canton_ui_auth: "env:CANTON_UI_BASIC_AUTH" + CHZ: chain: CHZ driver: evm-legacy diff --git a/factory/defaults/chains/testnet.yaml b/factory/defaults/chains/testnet.yaml index 9aacfff4..9f307c8c 100644 --- a/factory/defaults/chains/testnet.yaml +++ b/factory/defaults/chains/testnet.yaml @@ -225,13 +225,14 @@ chains: fee_limit: "100.0" confirmations_final: 1 custom_config: - keycloak_url: "env:CANTON_KEYCLOAK_URL" - keycloak_realm: "env:CANTON_KEYCLOAK_REALM" + keycloak_url: "" + keycloak_realm: "" + rest_api_url: "" + scan_proxy_url: "" + scan_api_url: "" validator_auth: "env:CANTON_VALIDATOR_BASIC_AUTH" - rest_api_url: "env:CANTON_REST_API_URL" - scan_proxy_url: "env:CANTON_SCAN_API_URL" - scan_api_url: "env:CANTON_SCAN_NODE_URL" canton_ui_auth: "env:CANTON_UI_BASIC_AUTH" + CHZ: chain: CHZ driver: "evm-legacy" From 67ac7d222c1121020a90d40ecb7cd615cb33479b Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Thu, 2 Apr 2026 17:44:22 -0400 Subject: [PATCH 20/23] canton: generate protobuf types locally --- chain/canton/Justfile | 6 + chain/canton/client/client.go | 8 +- chain/canton/client/client_test.go | 4 +- chain/canton/client/command_builders.go | 4 +- chain/canton/client/ledger.go | 8 +- chain/canton/proto/buf.gen.yaml | 12 + chain/canton/proto/buf.lock | 8 + chain/canton/proto/buf.yaml | 3 + .../proto/com/daml/ledger/api/v2/README.md | 172 + .../v2/admin/command_inspection_service.proto | 147 + .../identity_provider_config_service.proto | 165 + .../ledger/api/v2/admin/object_meta.proto | 57 + .../v2/admin/package_management_service.proto | 296 ++ .../admin/participant_pruning_service.proto | 57 + .../v2/admin/party_management_service.proto | 449 +++ .../v2/admin/user_management_service.proto | 415 +++ .../api/v2/command_completion_service.proto | 66 + .../daml/ledger/api/v2/command_service.proto | 101 + .../api/v2/command_submission_service.proto | 54 + .../com/daml/ledger/api/v2/commands.proto | 287 ++ .../com/daml/ledger/api/v2/completion.proto | 136 + .../daml/ledger/api/v2/contract_service.proto | 55 + .../proto/com/daml/ledger/api/v2/crypto.proto | 121 + .../proto/com/daml/ledger/api/v2/event.proto | 373 +++ .../ledger/api/v2/event_query_service.proto | 78 + .../ledger/api/v2/experimental_features.proto | 41 + .../interactive_submission_common_data.proto | 25 + .../interactive_submission_service.proto | 770 +++++ .../v1/interactive_submission_data.proto | 116 + .../ledger/api/v2/offset_checkpoint.proto | 39 + .../ledger/api/v2/package_reference.proto | 96 + .../daml/ledger/api/v2/package_service.proto | 194 ++ .../com/daml/ledger/api/v2/reassignment.proto | 202 ++ .../ledger/api/v2/reassignment_commands.proto | 107 + .../daml/ledger/api/v2/state_service.proto | 256 ++ .../ledger/api/v2/testing/time_service.proto | 50 + .../ledger/api/v2/topology_transaction.proto | 110 + .../daml/ledger/api/v2/trace_context.proto | 20 + .../com/daml/ledger/api/v2/transaction.proto | 86 + .../ledger/api/v2/transaction_filter.proto | 205 ++ .../daml/ledger/api/v2/update_service.proto | 131 + .../proto/com/daml/ledger/api/v2/value.proto | 206 ++ .../daml/ledger/api/v2/version_service.proto | 120 + chain/canton/tx/create_account_tx_test.go | 2 +- chain/canton/tx/metadata.go | 2 +- chain/canton/tx/tx.go | 8 +- chain/canton/tx/tx_test.go | 6 +- chain/canton/tx_input/create_account_input.go | 2 +- chain/canton/tx_input/hash_validation.go | 6 +- chain/canton/tx_input/hash_validation_test.go | 6 +- chain/canton/tx_input/tx_input.go | 2 +- chain/canton/types/README.md | 17 + .../v2/admin/command_inspection_service.pb.go | 732 +++++ .../command_inspection_service_grpc.pb.go | 149 + .../identity_provider_config_service.pb.go | 708 +++++ ...dentity_provider_config_service_grpc.pb.go | 339 ++ .../ledger/api/v2/admin/object_meta.pb.go | 182 ++ .../v2/admin/package_management_service.pb.go | 1171 +++++++ .../package_management_service_grpc.pb.go | 279 ++ .../admin/participant_pruning_service.pb.go | 204 ++ .../participant_pruning_service_grpc.pb.go | 147 + .../v2/admin/party_management_service.pb.go | 1450 +++++++++ .../admin/party_management_service_grpc.pb.go | 539 ++++ .../v2/admin/user_management_service.pb.go | 1847 +++++++++++ .../admin/user_management_service_grpc.pb.go | 508 +++ .../api/v2/command_completion_service.pb.go | 267 ++ .../v2/command_completion_service_grpc.pb.go | 160 + .../daml/ledger/api/v2/command_service.pb.go | 452 +++ .../ledger/api/v2/command_service_grpc.pb.go | 224 ++ .../api/v2/command_submission_service.pb.go | 269 ++ .../v2/command_submission_service_grpc.pb.go | 197 ++ .../com/daml/ledger/api/v2/commands.pb.go | 1052 +++++++ .../com/daml/ledger/api/v2/completion.pb.go | 369 +++ .../daml/ledger/api/v2/contract_service.pb.go | 212 ++ .../ledger/api/v2/contract_service_grpc.pb.go | 140 + .../types/com/daml/ledger/api/v2/crypto.pb.go | 507 +++ .../types/com/daml/ledger/api/v2/event.pb.go | 1016 ++++++ .../ledger/api/v2/event_query_service.pb.go | 344 ++ .../api/v2/event_query_service_grpc.pb.go | 142 + .../ledger/api/v2/experimental_features.pb.go | 288 ++ .../interactive_submission_common_data.pb.go | 165 + .../interactive_submission_service.pb.go | 2796 +++++++++++++++++ .../interactive_submission_service_grpc.pb.go | 407 +++ .../v1/interactive_submission_data.pb.go | 705 +++++ .../ledger/api/v2/offset_checkpoint.pb.go | 213 ++ .../ledger/api/v2/package_reference.pb.go | 451 +++ .../daml/ledger/api/v2/package_service.pb.go | 838 +++++ .../ledger/api/v2/package_service_grpc.pb.go | 252 ++ .../com/daml/ledger/api/v2/reassignment.pb.go | 665 ++++ .../ledger/api/v2/reassignment_commands.pb.go | 459 +++ .../daml/ledger/api/v2/state_service.pb.go | 1023 ++++++ .../ledger/api/v2/state_service_grpc.pb.go | 264 ++ .../ledger/api/v2/testing/time_service.pb.go | 244 ++ .../api/v2/testing/time_service_grpc.pb.go | 171 + .../ledger/api/v2/topology_transaction.pb.go | 610 ++++ .../daml/ledger/api/v2/trace_context.pb.go | 144 + .../com/daml/ledger/api/v2/transaction.pb.go | 273 ++ .../ledger/api/v2/transaction_filter.pb.go | 889 ++++++ .../daml/ledger/api/v2/update_service.pb.go | 571 ++++ .../ledger/api/v2/update_service_grpc.pb.go | 250 ++ .../types/com/daml/ledger/api/v2/value.pb.go | 1148 +++++++ .../daml/ledger/api/v2/version_service.pb.go | 538 ++++ .../ledger/api/v2/version_service_grpc.pb.go | 130 + chain/canton/{proto => types}/helpers.go | 8 +- chain/canton/{proto => types}/helpers_test.go | 6 +- go.mod | 2 - go.sum | 48 +- 107 files changed, 32993 insertions(+), 78 deletions(-) create mode 100644 chain/canton/Justfile create mode 100644 chain/canton/proto/buf.gen.yaml create mode 100644 chain/canton/proto/buf.lock create mode 100644 chain/canton/proto/buf.yaml create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/README.md create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/admin/command_inspection_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/admin/identity_provider_config_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/admin/object_meta.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/admin/package_management_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/admin/participant_pruning_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/admin/party_management_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/admin/user_management_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/command_completion_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/command_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/command_submission_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/commands.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/completion.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/contract_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/crypto.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/event.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/event_query_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/experimental_features.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/offset_checkpoint.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/package_reference.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/package_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/reassignment.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/reassignment_commands.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/state_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/testing/time_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/topology_transaction.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/trace_context.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/transaction.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/transaction_filter.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/update_service.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/value.proto create mode 100644 chain/canton/proto/com/daml/ledger/api/v2/version_service.proto create mode 100644 chain/canton/types/README.md create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/object_meta.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/command_completion_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/command_completion_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/command_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/command_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/command_submission_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/command_submission_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/commands.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/completion.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/contract_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/contract_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/crypto.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/event.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/event_query_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/event_query_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/experimental_features.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/offset_checkpoint.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/package_reference.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/package_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/package_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/reassignment.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/reassignment_commands.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/state_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/state_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/testing/time_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/testing/time_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/topology_transaction.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/trace_context.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/transaction.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/transaction_filter.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/update_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/update_service_grpc.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/value.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/version_service.pb.go create mode 100644 chain/canton/types/com/daml/ledger/api/v2/version_service_grpc.pb.go rename chain/canton/{proto => types}/helpers.go (94%) rename chain/canton/{proto => types}/helpers_test.go (92%) diff --git a/chain/canton/Justfile b/chain/canton/Justfile new file mode 100644 index 00000000..f2e6b97a --- /dev/null +++ b/chain/canton/Justfile @@ -0,0 +1,6 @@ +# Regenerate protobuf types +pb: + rm -rf types/com/daml/ledger/api/v2 types/google/rpc + cd proto && buf mod update && buf generate + # Use google.golang.org/genproto/googleapis/rpc/status rather than any local types. + for file in `rg -l 'github.com/cordialsys/crosschain/chain/canton/types/google/rpc' types/com/daml/ledger/api/v2 -g '*.go'`; do perl -0pi -e 's#github.com/cordialsys/crosschain/chain/canton/types/google/rpc#google.golang.org/genproto/googleapis/rpc/status#g' "$file"; done diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index d22470e5..069cee35 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -17,15 +17,15 @@ import ( xcbuilder "github.com/cordialsys/crosschain/builder" cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" cantonkc "github.com/cordialsys/crosschain/chain/canton/keycloak" - cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" + cantonproto "github.com/cordialsys/crosschain/chain/canton/types" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" xclient "github.com/cordialsys/crosschain/client" txinfo "github.com/cordialsys/crosschain/client/tx_info" xctypes "github.com/cordialsys/crosschain/client/types" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" ) diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index db7ae7e0..f1d4cb22 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -14,10 +14,10 @@ import ( xcbuilder "github.com/cordialsys/crosschain/builder" cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" txinfo "github.com/cordialsys/crosschain/client/tx_info" xctypes "github.com/cordialsys/crosschain/client/types" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "google.golang.org/grpc" diff --git a/chain/canton/client/command_builders.go b/chain/canton/client/command_builders.go index ac24cfeb..658fede7 100644 --- a/chain/canton/client/command_builders.go +++ b/chain/canton/client/command_builders.go @@ -7,8 +7,8 @@ import ( "time" xcbuilder "github.com/cordialsys/crosschain/builder" - cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + cantonproto "github.com/cordialsys/crosschain/chain/canton/types" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" ) func transferAmountNumeric(args xcbuilder.TransferArgs, decimals int32) string { diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index 72659d71..5601cbd4 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -17,10 +17,10 @@ import ( xc "github.com/cordialsys/crosschain" cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" - cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + cantonproto "github.com/cordialsys/crosschain/chain/canton/types" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/credentials" diff --git a/chain/canton/proto/buf.gen.yaml b/chain/canton/proto/buf.gen.yaml new file mode 100644 index 00000000..da4f9cf1 --- /dev/null +++ b/chain/canton/proto/buf.gen.yaml @@ -0,0 +1,12 @@ +version: v1 +managed: + enabled: true + go_package_prefix: + default: github.com/cordialsys/crosschain/chain/canton/types +plugins: + - plugin: buf.build/protocolbuffers/go:v1.36.10 + out: ../types + opt: paths=source_relative + - plugin: buf.build/grpc/go:v1.5.1 + out: ../types + opt: paths=source_relative diff --git a/chain/canton/proto/buf.lock b/chain/canton/proto/buf.lock new file mode 100644 index 00000000..5cfa9d83 --- /dev/null +++ b/chain/canton/proto/buf.lock @@ -0,0 +1,8 @@ +# Generated by buf. DO NOT EDIT. +version: v1 +deps: + - remote: buf.build + owner: googleapis + repository: googleapis + commit: 536964a08a534d51b8f30f2d6751f1f9 + digest: shake256:b6d518a50df43704333587967830344b49247ac8cf0953847d710f2d72246f677aeba56593dcd78f9199afff8ae9498f8dd5efe54107e5a09c60fff872456ca9 diff --git a/chain/canton/proto/buf.yaml b/chain/canton/proto/buf.yaml new file mode 100644 index 00000000..87f59f83 --- /dev/null +++ b/chain/canton/proto/buf.yaml @@ -0,0 +1,3 @@ +version: v1 +deps: + - buf.build/googleapis/googleapis diff --git a/chain/canton/proto/com/daml/ledger/api/v2/README.md b/chain/canton/proto/com/daml/ledger/api/v2/README.md new file mode 100644 index 00000000..94dce91e --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/README.md @@ -0,0 +1,172 @@ +# Ledger API version V2 + +This package contains the modified protobuf services and messages from V1 and new V2 protobuf definitions. +V1 services which are not explicitly marked with "In V2 Ledger API this service is not available anymore", +will be part of the V2 Ledger API, and served with unchanged semantics. Several V1 messages are reused in +V2 services as well. + +Please note: this file will be removed before the Daml SDK 3.0GA release, the change/migration list will be +moved to official daml documentation, the to be revisited list won't be applicable anymore. + +## Changes from version V1, and migration recommendations: + +### 1. Virtual shared ledger and participant offsets + +Ledger API is a gateway for a Canton participant which can be connected to several synchronizers. +To experience this aggregation of changes synchronized over many synchronizers, the synchronizer id +is introduced to several V1 messages: +- command_completion_service/CompletionStreamResponse - each completion belongs to exactly one synchronizer. +- commands/Commands - a Command will be synchronized via exactly one synchronizer. +- transaction/Transaction, TransactionTree - Each transaction is synchronized via exactly one synchronizer. +- event_query_service/Created,Archived - transitively: each event synchronized via exactly one synchronizer. + +Virtual shared ledger also means a local ordering is established: the participant offset +(see more in participant_offset.proto for the semantics). Syntactically this means no change +on the Ledger API: all ledger offset became participant offset. + +### 2. Reassignment commands + +To support reassignment of a contract (unassigning from one synchronizer, then assigning to another), the +CommandSubmissionService.SubmitReassignment synchronous rpc endpoint was added. + +Completions for Reassignment commands are returned by the CommandCompletionService the same way as for +transactions. + +### 3. Update service + +In V1 the TransactionService provided access to Transaction and TransactionTree streams. In V2 these +streams are also include Reassignment-s as well (which can be an UnassignedEvent or an AssignedEvent). +To accommodate this unification, the Update notation is introduced: +- TransactionService became UpdateService, and the GetTransactions, GetTransactionTrees endpoints +became GetUpdates, GetUpdateTrees respectively. +- What was called in V1 transaction ID is called in v2 update ID (the semantics did not change). +Affected V1 messages: + - command_service/SubmitAndWait + - completion/Completion + - transaction/Transaction + - transaction/TransactionTree + - update_service/GetTransactionByIdRequest + +The point-wise lookup queries for transactions are renamed to follow naming convention wih streams: +GetTransaction* to GetTransactionTree* and GetFlatTransaction* to GetTransaction*. + +### 4. State service + +All ledger state related endpoints moved to StateService: +- ActiveContractsService.GetActiveContracts +- CommandCompletionService.CompletionEnd +- TransactionService.GetLedgerEnd +- TransactionService.GetLatestPrunedOffsets + +GetActiveContracts service is enhanced to provide a snapshot for the virtual shared ledger (see more in +state_service.proto): +- Contract activeness is defined per synchronizer. +- State stream includes IncompleteAssigned, IncompleteUnassigned to bootstrap applications +reassigning contracts. + +A new endpoint is introduced: GetConnectedSynchronizers. This is an initial version to make Canton topology +state accessible over the Ledger API. This endpoint likely will change/improve before 3.0GA (see +To be revisited #6 below). + +### 5. EventQueryService + +The GetEventsByContractKey endpoint is dropped because of the lack of contract key support. + +### 6. TimeService + +The GetTime endpoint is made synchronous due to lack of correct support for streaming updates. + +### 7. Interface subscription for transaction trees + +Support is added in a backwards compatible way: previously template/interface filters were not +allowed for TransactionTree-s. In V2 this is allowed, but only configures how the CreatedEvent +results are rendered, still all parties treated as wildcard filters for filtration. +(see TransactionFilter) + +### 8. Simplified stream entries + +In V1 all streaming endpoints were returning repeated results, but implementation was always giving +a single entry per stream element. This has been made explicit on the Ledger API - all streaming +results returning a single value. Affected messages: +- command_completion_service/CompletionStreamResponse +- update_service/GetUpdatesResponse, GetUpdateTreesResponse +- state_service/GetActiveContractsResponse + +### 9. Removed Ledger Identity + +Ledger Identity was a deprecated concept, therefore in V2 the ledger_id is removed from all +request messages: +- testing/time_service/GetTimeRequest, SetTimeRequest +- command_completion_service/CompletionStreamRequest +- commands/Commands +- package_service/ListPackagesRequest, GetPackageRequest, GetPackageStatusRequest +- version_service/GetLedgerApiVersionRequest + +Also the LedgerIdentityService is not available anymore. + +### 10. Removed Ledger Configuration + +LedgerConfigurationService and the admin/ConfigManagementService is not available anymore. The +maximum deduplication period (the default deduplication period for daml command interpretation) +for the participant can be set statically in Canton configuration instead. + + +| Endpoint migration table | V1 | V2 | +| ---- | ---- | ---- | +| Not supported in V2 | admin/ConfigManagementService.* | | +| Not supported in V2 | EventQueryService.GetEventsByContractKey | | +| Not supported in V2 | LedgerConfigurationService.* | | +| Not supported in V2 | LedgerIdentityService.* | | +| Same in V2 (service in v1 namespace) | admin/IdentityProviderConfigService.* | +| Same in V2 (service in v1 namespace) | admin/MeteringReportService.* | +| Same in V2 (service in v1 namespace) | admin/PackageManagementService.* | +| Same in V2 (service in v1 namespace) | admin/ParticipantPruningService.* | +| Same in V2 (service in v1 namespace) | admin/PartyManagementService.* | +| Same in V2 (service in v1 namespace) | admin/UserManagementService.* | +| Supported in V2 (service in v2 namespace) | testing/TimeService.* | testing/TimeService.* | +| Supported in V2 (service in v2 namespace) | ActiveContractsService.GetActiveContracts | StateService.GetActiveContracts | +| Supported in V2 (service in v2 namespace) | CommandCompletionService.CompletionStream | CommandCompletionService.CompletionStream | +| Supported in V2 (service in v2 namespace) | CommandCompletionService.CompletionEnd | StateService.GetLedgerEnd | +| Supported in V2 (service in v2 namespace) | CommandSubmissionService.Submit | CommandSubmissionService.Submit | +| Supported in V2 (service in v2 namespace) | CommandService.* | CommandService.* | +| Supported in V2 (service in v2 namespace) | EventQueryService.GetEventsByContractId | EventQueryService.GetEventsByContractId | +| Supported in V2 (service in v2 namespace) | PackageService.* | PackageService.* | +| Supported in V2 (service in v2 namespace) | TransactionService.GetTransactions | UpdateService.GetUpdates | +| Supported in V2 (service in v2 namespace) | TransactionService.GetTransactionTrees | UpdateService.GetUpdateTrees | +| Supported in V2 (service in v2 namespace) | TransactionService.GetTransactionByEventId | UpdateService.GetTransactionTreeByEventId | +| Supported in V2 (service in v2 namespace) | TransactionService.GetTransactionById | UpdateService.GetTransactionTreeById | +| Supported in V2 (service in v2 namespace) | TransactionService.GetFlatTransactionByEventId | UpdateService.GetTransactionByEventId | +| Supported in V2 (service in v2 namespace) | TransactionService.GetFlatTransactionById | UpdateService.GetTransactionById | +| Supported in V2 (service in v2 namespace) | TransactionService.GetLedgerEnd | StateService.GetLedgerEnd | +| Supported in V2 (service in v2 namespace) | TransactionService.GetLatestPrunedOffsets | StateService.GetLatestPrunedOffsets | +| Supported in V2 (service in v2 namespace) | VersionService.* | VersionService.* | +| New in V2 | | CommandSubmissionService.SubmitReassignment | +| New in V2 | | StateService.GetConnectedSynchronizers | + +## To be revisited (potential changes) until Daml SDK 3.0GA: + +1. **Removing application_id**: This is already the user ID, if the authentication token provides it. Making this +mandatory on the authorization layer could mean we can remove the custom application ID in favor of the user ID +all places. +2. **Enhance EventQueryService**: With contract key support for the virtual shared ledger the +EventQueryService.GetEventsByContractKey endpoint can be re-added with adapted semantics. Also the +GetEventsByContractId could be enhanced to also return all reassignment events for a contract. +3. **Simplifying offset usage**: The ParticipantOffset.boundary values could be removed in favor of the optional +absolute (plain string) value, and the streaming endpoints could be simplified not to allow streaming from +an accidental ledger end state. +4. **Change offset data type to int64**: This would give simplifications on client side, implementation code and +in database with a trade-off on future upgrading. +5. **Remove verbose mode**: A simplification on the API and in implementation which might be acceptable for clients. +6. **Introduction of topology events**: Canton topology is introduced in a limited fashion with +StateService.GetConnectedSynchronizers. For complex topologies and multi-hosted parties proper offset based snapshot +endpoint is needed alongside with adding topology events to the update streams. +7. **Introduction of reassigning parties**: With complex topologies the information of which querying users can +conduct assignments for an IncompleteUnassigned entry might be needed for bootstrapping proper reassignment +operations. +8. **Deduplication for reassignments**: Adding this feature might include enriching reassignment commands (and events) +with more deduplication related fields. +9. **Completing the API for reassignments**: Currently the CommandService offers submit-and-wait endpoints for +transactions and Update service offers point-wise lookup endpoints for transactions only. This is about to +extend these features naturally for reassignments. +10. **Improving party and package management admin endpoints**: add streaming capabilities, and streamline capabilities +considering improved topology information and Canton admin API features. diff --git a/chain/canton/proto/com/daml/ledger/api/v2/admin/command_inspection_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/admin/command_inspection_service.proto new file mode 100644 index 00000000..d7af813a --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/admin/command_inspection_service.proto @@ -0,0 +1,147 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.admin; + +import "com/daml/ledger/api/v2/commands.proto"; +import "com/daml/ledger/api/v2/completion.proto"; +import "com/daml/ledger/api/v2/value.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Admin"; +option java_outer_classname = "CommandInspectionServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.admin"; + +// Status: experimental interface, will change before it is deemed production +// ready +// +// The inspection service provides methods for the ledger administrator +// to look under the hood of a running system. +// In V2 Ledger API this service is not available. +service CommandInspectionService { + // Inquire about the status of a command. + // This service is used for debugging only. The command status is only tracked in memory and is not persisted. + // The service can be used to understand the failure status and the structure of a command. + // Requires admin privileges + // The service is alpha without backward compatibility guarantees. + rpc GetCommandStatus(GetCommandStatusRequest) returns (GetCommandStatusResponse); +} + +enum CommandState { + COMMAND_STATE_UNSPECIFIED = 0; // This value acts as wildcard in the queries + COMMAND_STATE_PENDING = 1; + COMMAND_STATE_SUCCEEDED = 2; + COMMAND_STATE_FAILED = 3; +} + +message GetCommandStatusRequest { + // Filter by command id + // + // Optional + string command_id_prefix = 1; + // Filter by state + // + // Optional + CommandState state = 2; + // Limit the number of returned statuses + // Defaults to 100 if not set + // + // Optional + uint32 limit = 3; +} + +message GetCommandStatusResponse { + // Optional: can be empty + repeated CommandStatus command_status = 1; +} +message Timing { + // Description of the timing stage (may be subject to change) + // + // Required + string description = 1; + // Required + uint32 duration_ms = 2; +} + +message CommandStatus { + // Time at which the command was received for interpretation by the participant. + // + // Required + google.protobuf.Timestamp started = 1; + // Time at which the command was completed. + // + // Optional + google.protobuf.Timestamp completed = 2; + // The completion associated with the command + // Contains only default values if the command is still pending + // + // Optional + Completion completion = 3; + // The state of the command + // + // Required + CommandState state = 4; + // The individual submitted commands + // + // Required: must be non-empty + repeated Command commands = 5; + // Statistics about the command request + // + // Optional + RequestStatistics request_statistics = 6; + // The ledger updates effected by the command + // + // Optional + CommandUpdates updates = 7; + // Synchronizer-ID. May be optional if the transaction was not yet routed. + // + // Optional + string synchronizer_id = 8; + + // Timings for the individual stages + // + // Optional: can be empty + repeated Timing timings = 9; +} + +message RequestStatistics { + // Optional + uint32 envelopes = 1; + // Optional + uint32 request_size = 2; + // Optional + uint32 recipients = 3; +} + +message CommandUpdates { + // Optional: can be empty + repeated Contract created = 1; + // Optional: can be empty + repeated Contract archived = 2; + // Required + uint32 exercised = 3; + // Required + uint32 fetched = 4; + // Required + uint32 looked_up_by_key = 5; +} + +message Contract { + // The identifier of the template used to create the contract. + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 1; + + // The contract's ID + // + // Required + string contract_id = 2; + + // The contract key, if defined + // + // Optional + Value contract_key = 3; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/admin/identity_provider_config_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/admin/identity_provider_config_service.proto new file mode 100644 index 00000000..2f1c9f45 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/admin/identity_provider_config_service.proto @@ -0,0 +1,165 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.admin; + +import "google/protobuf/field_mask.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Admin"; +option java_outer_classname = "IdentityProviderConfigServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.admin"; + +// Identity Provider Config Service makes it possible for participant node administrators +// to setup and manage additional identity providers at runtime. +// +// This allows using access tokens from identity providers unknown at deployment time. When an identity +// provider is configured, independent IDP administrators can manage their own set of parties and users. +// Such parties and users have a matching `identity_provider_id` defined and are inaccessible to +// administrators from other identity providers. A user will only be authenticated if the corresponding JWT +// token is issued by the appropriate identity provider. +// Users and parties without `identity_provider_id` defined are assumed to be using the default identity provider, +// which is configured statically at the participant node's deployment time. +// +// The Ledger API uses the "iss" claim of a JWT token to match the token to a specific IDP. If there is no match, +// the default IDP is assumed. +// +// The fields of request messages (and sub-messages) are marked either as ``Optional`` or ``Required``: +// +// 1. ``Optional`` denoting the client may leave the field unset when sending a request. +// 2. ``Required`` denoting the client must set the field to a non-default value when sending a request. +// +// An identity provider config resource is described by the ``IdentityProviderConfig`` message, +// An identity provider config resource, once it has been created, can be modified. +// In order to update the properties represented by the ``IdentityProviderConfig`` message use the ``UpdateIdentityProviderConfig`` RPC. +// The only fields that can be modified are those marked as ``Modifiable``. +service IdentityProviderConfigService { + // Create a new identity provider configuration. + // The request will fail if the maximum allowed number of separate configurations is reached. + rpc CreateIdentityProviderConfig(CreateIdentityProviderConfigRequest) returns (CreateIdentityProviderConfigResponse); + + // Get the identity provider configuration data by id. + rpc GetIdentityProviderConfig(GetIdentityProviderConfigRequest) returns (GetIdentityProviderConfigResponse); + + // Update selected modifiable attribute of an identity provider config resource described + // by the ``IdentityProviderConfig`` message. + rpc UpdateIdentityProviderConfig(UpdateIdentityProviderConfigRequest) returns (UpdateIdentityProviderConfigResponse); + + // List all existing identity provider configurations. + rpc ListIdentityProviderConfigs(ListIdentityProviderConfigsRequest) returns (ListIdentityProviderConfigsResponse); + + // Delete an existing identity provider configuration. + rpc DeleteIdentityProviderConfig(DeleteIdentityProviderConfigRequest) returns (DeleteIdentityProviderConfigResponse); +} + +message IdentityProviderConfig { + // The identity provider identifier + // Must be a valid LedgerString (as describe in ``value.proto``). + // + // Required + string identity_provider_id = 1; + + // When set, the callers using JWT tokens issued by this identity provider are denied all access + // to the Ledger API. + // Modifiable + // + // Optional + bool is_deactivated = 2; + + // Specifies the issuer of the JWT token. + // The issuer value is a case sensitive URL using the https scheme that contains scheme, host, + // and optionally, port number and path components and no query or fragment components. + // Modifiable + // + // Can be left empty when used in `UpdateIdentityProviderConfigRequest` if the issuer is not being updated. + // + // Required + string issuer = 3; + + // The JWKS (JSON Web Key Set) URL. + // The Ledger API uses JWKs (JSON Web Keys) from the provided URL to verify that the JWT has been + // signed with the loaded JWK. Only RS256 (RSA Signature with SHA-256) signing algorithm is supported. + // Modifiable + // + // Required + string jwks_url = 4; + + // Specifies the audience of the JWT token. + // When set, the callers using JWT tokens issued by this identity provider are allowed to get an access + // only if the "aud" claim includes the string specified here + // Modifiable + // + // Optional + string audience = 5; +} + +message CreateIdentityProviderConfigRequest { + // Required + IdentityProviderConfig identity_provider_config = 1; +} + +message CreateIdentityProviderConfigResponse { + // Required + IdentityProviderConfig identity_provider_config = 1; +} + +message GetIdentityProviderConfigRequest { + // Required + string identity_provider_id = 1; +} + +message GetIdentityProviderConfigResponse { + // Required + IdentityProviderConfig identity_provider_config = 1; +} + +message ListIdentityProviderConfigsRequest { + // Pagination is not required as the resulting data set is small enough to be returned in a single call +} + +message ListIdentityProviderConfigsResponse { + // The list of identity provider configs + // + // Required: must be non-empty + repeated IdentityProviderConfig identity_provider_configs = 1; +} + +message UpdateIdentityProviderConfigRequest { + // The identity provider config to update. + // Modifiable + // + // Required + IdentityProviderConfig identity_provider_config = 1; + + // An update mask specifies how and which properties of the ``IdentityProviderConfig`` message are to be updated. + // An update mask consists of a set of update paths. + // A valid update path points to a field or a subfield relative to the ``IdentityProviderConfig`` message. + // A valid update mask must: + // + // 1. contain at least one update path, + // 2. contain only valid update paths. + // + // Fields that can be updated are marked as ``Modifiable``. + // For additional information see the documentation for standard protobuf3's ``google.protobuf.FieldMask``. + // + // Required + google.protobuf.FieldMask update_mask = 2; +} + +message UpdateIdentityProviderConfigResponse { + // Updated identity provider config + // + // Required + IdentityProviderConfig identity_provider_config = 1; +} + +message DeleteIdentityProviderConfigRequest { + // The identity provider config to delete. + // + // Required + string identity_provider_id = 1; +} + +// Does not (yet) contain any data. +message DeleteIdentityProviderConfigResponse {} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/admin/object_meta.proto b/chain/canton/proto/com/daml/ledger/api/v2/admin/object_meta.proto new file mode 100644 index 00000000..7cf96b73 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/admin/object_meta.proto @@ -0,0 +1,57 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.admin; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Admin"; +option java_outer_classname = "ObjectMetaOuterClass"; +option java_package = "com.daml.ledger.api.v2.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, non-empty 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. + // + // 3. 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. + // Modifiable + // + // Optional: can be empty + map annotations = 12; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/admin/package_management_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/admin/package_management_service.proto new file mode 100644 index 00000000..4656c328 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/admin/package_management_service.proto @@ -0,0 +1,296 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.admin; + +import "com/daml/ledger/api/v2/package_reference.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Admin"; +option java_outer_classname = "PackageManagementServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.admin"; + +// Status: experimental interface, will change before it is deemed production +// ready +// +// Query the Daml-LF packages supported by the ledger participant and upload +// DAR files. We use 'backing participant' to refer to this specific participant +// in the methods of this API. +service PackageManagementService { + // Returns the details of all Daml-LF packages known to the backing participant. + rpc ListKnownPackages(ListKnownPackagesRequest) returns (ListKnownPackagesResponse); + + // Upload a DAR file to the participant. + // + // If vetting is enabled in the request, the DAR is checked for upgrade compatibility + // with the set of the already vetted packages on the target vetting synchronizer + // See UploadDarFileRequest for details regarding vetting and the target vetting synchronizer. + rpc UploadDarFile(UploadDarFileRequest) returns (UploadDarFileResponse); + + // Validates the DAR and checks the upgrade compatibility of the DAR's packages + // with the set of the already vetted packages on the target vetting synchronizer. + // See ValidateDarFileRequest for details regarding the target vetting synchronizer. + // + // The operation has no effect on the state of the participant or the Canton ledger: + // the DAR payload and its packages are not persisted neither are the packages vetted. + rpc ValidateDarFile(ValidateDarFileRequest) returns (ValidateDarFileResponse); + + // Update the vetted packages of this participant + rpc UpdateVettedPackages(UpdateVettedPackagesRequest) returns (UpdateVettedPackagesResponse); +} + +message ListKnownPackagesRequest {} + +message ListKnownPackagesResponse { + // The details of all Daml-LF packages known to backing participant. + // + // Required: must be non-empty + repeated PackageDetails package_details = 1; +} + +message PackageDetails { + // The identity of the Daml-LF package. + // Must be a valid PackageIdString (as describe in ``value.proto``). + // + // Required + string package_id = 1; + + // Size of the package in bytes. + // The size of the package is given by the size of the ``daml_lf`` + // ArchivePayload. See further details in ``daml_lf.proto``. + // + // Required + uint64 package_size = 2; + + // Indicates since when the package is known to the backing participant. + // Required + google.protobuf.Timestamp known_since = 3; + + // Name of the package as defined by the package metadata + // + // Required + string name = 4; + + // Version of the package as defined by the package metadata + // + // Required + string version = 5; +} + +message UploadDarFileRequest { + // Contains a Daml archive DAR file, which in turn is a jar like zipped + // container for ``daml_lf`` archives. See further details in + // ``daml_lf.proto``. + // + // Required: must be non-empty + bytes dar_file = 1; + + // Unique submission identifier. + // If not populated, a random identifier will be generated. + // + // Optional + string submission_id = 2; + + enum VettingChange { + // Vetting change field left unspecified, defaults to vetting all the + // packages in the DAR. + VETTING_CHANGE_UNSPECIFIED = 0; + // Vet all the packages in the DAR. + VETTING_CHANGE_VET_ALL_PACKAGES = 1; + // Do not vet any packages in the DAR. + VETTING_CHANGE_DONT_VET_ANY_PACKAGES = 2; + } + + // How to vet packages in the DAR being uploaded + // + // Optional + VettingChange vetting_change = 3; + + // Only used if VettingChange is set to VETTING_CHANGE_VET_ALL_PACKAGES, in + // order to specify which synchronizer to vet on. + // + // If synchronizer_id is set, the synchronizer with this ID will be used. If + // synchronizer_id is unset and the participant is only connected to a single + // synchronizer, that synchronizer will be used by default. If synchronizer_id + // is unset and the participant is connected to multiple synchronizers, the + // request will error out with PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. + // + // Optional + string synchronizer_id = 4; +} + +// A message that is received when the upload operation succeeded. +message UploadDarFileResponse {} + +// Performs the same checks that UploadDarFileRequest would perform, but doesn't +// upload the DAR. +message ValidateDarFileRequest { + // Contains a Daml archive DAR file, which in turn is a jar like zipped + // container for ``daml_lf`` archives. See further details in + // ``daml_lf.proto``. + // + // Required: must be non-empty + bytes dar_file = 1; + + // Unique submission identifier. If not defined, defaults to a random identifier. + // + // Optional + string submission_id = 2; + + // If synchronizer_id is set, the synchronizer with this ID will be used. If + // synchronizer_id is unset and the participant is only connected to a single + // synchronizer, that synchronizer will be used by default. If synchronizer_id + // is unset and the participant is connected to multiple synchronizers, the + // request will error out with PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. + // + // Optional + string synchronizer_id = 4; +} + +message ValidateDarFileResponse {} + +// A change to the set of vetted packages. +message VettedPackagesChange { + // Remove packages from the set of vetted packages + message Unvet { + // Packages to be unvetted. + // + // If a reference in this list matches multiple packages, they are all + // unvetted. + // + // Required: must be non-empty + repeated VettedPackagesRef packages = 1; + } + + // Set vetting bounds of a list of packages. Packages that were not previously + // vetted have their bounds added, previous vetting bounds are overwritten. + message Vet { + // Packages to be vetted. + // + // If a reference in this list matches more than one package, the change is + // considered ambiguous and the entire update request is rejected. In other + // words, every reference must match exactly one package. + // + // Required: must be non-empty + repeated VettedPackagesRef packages = 1; + + // The time from which these packages should be vetted, prior lower bounds + // are overwritten. + // Optional + google.protobuf.Timestamp new_valid_from_inclusive = 2; + + // The time until which these packages should be vetted, prior upper bounds + // are overwritten. + // Optional + google.protobuf.Timestamp new_valid_until_exclusive = 3; + } + + // Required + oneof operation { + // Add packages to or update packages in the set of vetted packages. + Vet vet = 1; + // Remove packages from the set of vetted packages. + Unvet unvet = 2; + } +} + +// A reference to identify one or more packages. +// +// A reference matches a package if its ``package_id`` matches the package's ID, +// its ``package_name`` matches the package's name, and its ``package_version`` +// matches the package's version. If an attribute in the reference is left +// unspecified (i.e. as an empty string), that attribute is treated as a +// wildcard. At a minimum, ``package_id`` or the ``package_name`` must be +// specified. +// +// If a reference does not match any package, the reference is considered +// unresolved and the entire update request is rejected. +message VettedPackagesRef { + // Package's package id must be the same as this field. + // + // Optional + string package_id = 1; + + // Package's name must be the same as this field. + // + // Optional + string package_name = 2; + + // Package's version must be the same as this field. + // + // Optional + string package_version = 3; +} + +message UpdateVettedPackagesRequest { + // Changes to apply to the current vetting state of the participant on the + // specified synchronizer. The changes are applied in order. + // Any package not changed will keep their previous vetting state. + // + // Required: must be non-empty + repeated VettedPackagesChange changes = 1; + + // If dry_run is true, then the changes are only prepared, but not applied. If + // a request would trigger an error when run (e.g. TOPOLOGY_DEPENDENCIES_NOT_VETTED), + // it will also trigger an error when dry_run. + // + // Use this flag to preview a change before applying it. + // Defaults to false. + // + // Optional + bool dry_run = 2; + + // If set, the requested changes will take place on the specified + // synchronizer. If synchronizer_id is unset and the participant is only + // connected to a single synchronizer, that synchronizer will be used by + // default. If synchronizer_id is unset and the participant is connected to + // multiple synchronizers, the request will error out with + // PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. + // + // Optional + string synchronizer_id = 3; + + // The serial of the last ``VettedPackages`` topology transaction of this + // participant and on this synchronizer. + // + // Execution of the request fails if this is not correct. Use this to guard + // against concurrent changes. + // + // If left unspecified, no validation is done against the last transaction's + // serial. + // + // Optional + PriorTopologySerial expected_topology_serial = 4; + + // Controls whether potentially unsafe vetting updates are allowed. + // + // Optional: can be empty + repeated UpdateVettedPackagesForceFlag update_vetted_packages_force_flags = 5; +} + +enum UpdateVettedPackagesForceFlag { + // Force flag left unspecified, defaults to no force flag used in the backend. + UPDATE_VETTED_PACKAGES_FORCE_FLAG_UNSPECIFIED = 0; + // Formerly UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_UNVET_PACKAGE_WITH_ACTIVE_CONTRACTS; + reserved 1; + /** Allow vetting a package that is upgrade-incompatible with other vetted packages */ + UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_VET_INCOMPATIBLE_UPGRADES = 2; + /** Allow vetting a package without vetting one or more of its dependencies */ + UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_UNVETTED_DEPENDENCIES = 3; +} + +message UpdateVettedPackagesResponse { + // All vetted packages on this participant and synchronizer, before the + // specified changes. Empty if no vetting state existed beforehand. + // + // Not populated if no vetted topology state exists prior to the update. + // + // Optional + VettedPackages past_vetted_packages = 1; + // All vetted packages on this participant and synchronizer, after the specified changes. + // + // Required + VettedPackages new_vetted_packages = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/admin/participant_pruning_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/admin/participant_pruning_service.proto new file mode 100644 index 00000000..dab9d5b4 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/admin/participant_pruning_service.proto @@ -0,0 +1,57 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.admin; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Admin"; +option java_outer_classname = "ParticipantPruningServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.admin"; + +// Status: experimental interface, will change before it is deemed production +// ready + +// Prunes/truncates the "oldest" transactions from the participant (the participant Ledger Api Server plus any other +// participant-local state) by removing a portion of the ledger in such a way that the set of future, allowed +// commands are not affected. +// +// This enables: +// +// 1. keeping the "inactive" portion of the ledger to a manageable size and +// 2. removing inactive state to honor the right to be forgotten. +service ParticipantPruningService { + // Prune the ledger specifying the offset before and at which ledger transactions should be removed. Only returns when + // the potentially long-running prune request ends successfully or with an error. + rpc Prune(PruneRequest) returns (PruneResponse); +} + +message PruneRequest { + // Inclusive valid absolute offset (positive integer) up to which the ledger is to be pruned. + // By default the following data is pruned: + // + // 1. All normal and divulged contracts that have been archived before + // `prune_up_to`. + // 2. All transaction events and completions before `prune_up_to` + // 3. All immediately divulged contracts created before `prune_up_to` independent of whether + // they were archived before `prune_up_to`. + // + // Required + int64 prune_up_to = 1; + + // Unique submission identifier. + // If not populated, defaults to a random identifier, used for logging. + // + // Optional + string submission_id = 2; + + // Deprecated flag used to prune all immediately and retroactively divulged contracts. + // It is a no-op since the divulged contracts are pruned along with the deactivated contracts. + // + // Optional + bool prune_all_divulged_contracts = 3; +} + +message PruneResponse { + // Empty for now, but may contain fields in the future +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/admin/party_management_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/admin/party_management_service.proto new file mode 100644 index 00000000..4e3afecc --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/admin/party_management_service.proto @@ -0,0 +1,449 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.admin; + +import "com/daml/ledger/api/v2/admin/object_meta.proto"; +import "com/daml/ledger/api/v2/crypto.proto"; +import "google/protobuf/field_mask.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Admin"; +option java_outer_classname = "PartyManagementServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.admin"; + +// This service allows inspecting the party management state of the ledger known to the participant +// and managing the participant-local party metadata. +// +// The authorization rules for its RPCs are specified on the ``Request`` +// messages as boolean expressions over these facts: +// +// 1. ``HasRight(r)`` denoting whether the authenticated user has right ``r`` and +// 2. ``IsAuthenticatedIdentityProviderAdmin(idp)`` denoting whether ``idp`` is equal to the ``identity_provider_id`` +// of the authenticated user and the user has an IdentityProviderAdmin right. +// +// If `identity_provider_id` is set to an empty string, then it's effectively set to the value of access token's 'iss' field if that is provided. +// If `identity_provider_id` remains an empty string, the default identity provider will be assumed. +// +// The fields of request messages (and sub-messages) are marked either as ``Optional`` or ``Required``: +// +// 1. ``Optional`` denoting the client may leave the field unset when sending a request. +// 2. ``Required`` denoting the client must set the field to a non-default value when sending a request. +// +// A party details resource is described by the ``PartyDetails`` message, +// A party details resource, once it has been created, can be modified using the ``UpdatePartyDetails`` RPC. +// The only fields that can be modified are those marked as ``Modifiable``. +service PartyManagementService { + // Return the identifier of the participant. + // All horizontally scaled replicas should return the same id. + // daml-on-kv-ledger: returns an identifier supplied on command line at launch time + // canton: returns globally unique identifier of the participant + rpc GetParticipantId(GetParticipantIdRequest) returns (GetParticipantIdResponse); + + // Get the party details of the given parties. Only known parties will be + // returned in the list. + rpc GetParties(GetPartiesRequest) returns (GetPartiesResponse); + + // List the parties known by the participant. + // The list returned contains parties whose ledger access is facilitated by + // the participant and the ones maintained elsewhere. + rpc ListKnownParties(ListKnownPartiesRequest) returns (ListKnownPartiesResponse); + + // Allocates a new party on a ledger and adds it to the set managed by the participant. + // Caller specifies a party identifier suggestion, the actual identifier + // allocated might be different and is implementation specific. + // Caller can specify party metadata that is stored locally on the participant. + // This call may: + // + // - Succeed, in which case the actual allocated identifier is visible in + // the response. + // - Respond with a gRPC error + // + // daml-on-kv-ledger: suggestion's uniqueness is checked by the validators in + // the consensus layer and call rejected if the identifier is already present. + // canton: completely different globally unique identifier is allocated. + // Behind the scenes calls to an internal protocol are made. As that protocol + // is richer than the surface protocol, the arguments take implicit values + // The party identifier suggestion must be a valid party name. Party names are required to be non-empty US-ASCII strings built from letters, digits, space, + // colon, minus and underscore limited to 255 chars + rpc AllocateParty(AllocatePartyRequest) returns (AllocatePartyResponse); + + // Alpha 3.3: Endpoint to allocate a new external party on a synchronizer + // + // Expected to be stable in 3.5 + // + // The external party must be hosted (at least) on this node with either confirmation or observation permissions + // It can optionally be hosted on other nodes (then called a multi-hosted party). + // If hosted on additional nodes, explicit authorization of the hosting relationship must be performed on those nodes + // before the party can be used. + // Decentralized namespaces are supported but must be provided fully authorized by their owners. + // The individual owner namespace transactions can be submitted in the same call (fully authorized as well). + // In the simple case of a non-multi hosted, non-decentralized party, the RPC will return once the party is + // effectively allocated and ready to use, similarly to the AllocateParty behavior. + // For more complex scenarios applications may need to query the party status explicitly (only through the admin API as of now). + rpc AllocateExternalParty(AllocateExternalPartyRequest) returns (AllocateExternalPartyResponse); + + // Update selected modifiable participant-local attributes of a party details resource. + // Can update the participant's local information for local parties. + rpc UpdatePartyDetails(UpdatePartyDetailsRequest) returns (UpdatePartyDetailsResponse); + + // Update the assignment of a party from one IDP to another. + rpc UpdatePartyIdentityProviderId(UpdatePartyIdentityProviderIdRequest) returns (UpdatePartyIdentityProviderIdResponse); + + // Alpha 3.3: Convenience endpoint to generate topology transactions for external signing + // + // Expected to be stable in 3.5 + // + // You may use this endpoint to generate the common external topology transactions + // which can be signed externally and uploaded as part of the allocate party process + // + // Note that this request will create a normal namespace using the same key for the + // identity as for signing. More elaborate schemes such as multi-signature + // or decentralized parties require you to construct the topology transactions yourself. + rpc GenerateExternalPartyTopology(GenerateExternalPartyTopologyRequest) returns (GenerateExternalPartyTopologyResponse); +} + +// Required authorization: ``HasRight(ParticipantAdmin)`` +message GetParticipantIdRequest {} + +message GetParticipantIdResponse { + // Identifier of the participant, which SHOULD be globally unique. + // Must be a valid LedgerString (as describe in ``value.proto``). + // + // Required + string participant_id = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)`` +message GetPartiesRequest { + // The stable, unique identifier of the Daml parties. + // Must be valid PartyIdStrings (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string parties = 1; + + // The id of the ``Identity Provider`` whose parties should be retrieved. + // If not set, assume the party is managed by the default identity provider or party is not hosted by the participant. + // + // Optional + string identity_provider_id = 2; +} + +message GetPartiesResponse { + // The details of the requested Daml parties by the participant, if known. + // The party details may not be in the same order as requested. + // + // Required: must be non-empty + repeated PartyDetails party_details = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)`` +message ListKnownPartiesRequest { + // Pagination token to determine the specific page to fetch. Using the token guarantees that parties on a subsequent + // page are all lexically greater than the last party on a previous page. Server does not store intermediate results + // between calls chained by a series of page tokens. As a consequence, if new parties are being added and a page is + // requested twice using the same token, more parties can be returned on the second call. + // Leave empty to fetch the first page. + // + // Optional + string page_token = 2; + + // Maximum number of results to be returned by the server. The server will return no more than that many results, + // but it might return fewer. If the page_size is 0, the server will decide the number of results to be returned. + // If the page_size exceeds the maximum supported by the server, an error will be returned. To obtain the server's + // maximum consult the PartyManagementFeature descriptor available in the VersionService. + // + // Optional + int32 page_size = 3; + + // The id of the ``Identity Provider`` whose parties should be retrieved. + // If not set, assume the party is managed by the default identity provider or party is not hosted by the participant. + // + // Optional + string identity_provider_id = 1; + + // An optional filter for the party name, searching for all party names known to this node + // starting with the given prefix. This can either be just a string or extend up to the full + // identifier. + // + // Optional + string filter_party = 4; +} + +message ListKnownPartiesResponse { + // The details of all Daml parties known by the participant. + // + // Required: must be non-empty + repeated PartyDetails party_details = 1; + + // Pagination token to retrieve the next page. + // Empty, if there are no further results. + // + // Optional + string next_page_token = 2; +} + +// Required authorization: +// ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)`` +message AllocatePartyRequest { + // A hint to the participant which party ID to allocate. It can be + // ignored. + // Must be a valid PartyIdString (as described in ``value.proto``). + // + // Optional + string party_id_hint = 1; + + reserved 2; // Formerly "display_name" + + // Participant-local metadata to be stored in the ``PartyDetails`` of this newly allocated party. + // + // Optional + ObjectMeta local_metadata = 3; + + // The id of the ``Identity Provider`` + // If not set, assume the party is managed by the default identity provider or party is not hosted by the participant. + // + // Optional + string identity_provider_id = 4; + + // The synchronizer, on which the party should be allocated. + // For backwards compatibility, this field may be omitted, if the participant is connected to only one synchronizer. + // Otherwise a synchronizer must be specified. + // + // Optional + string synchronizer_id = 5; + + // The user who will get the act_as rights to the newly allocated party. + // If set to an empty string (the default), no user will get rights to the party. + // + // Optional + string user_id = 6; +} + +message AllocatePartyResponse { + // The allocated party details + // + // Required + PartyDetails party_details = 1; +} + +// Required authorization: +// ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)`` +message AllocateExternalPartyRequest { + message SignedTransaction { + // The serialized TopologyTransaction + // + // Required: must be non-empty + bytes transaction = 1; + // Additional signatures for this transaction specifically + // Use for transactions that require additional signatures beyond the namespace key signatures + // e.g: PartyToParticipant must be signed by all registered keys + // + // Optional: can be empty + repeated Signature signatures = 2; + } + + // TODO(#27670) support synchronizer aliases + // Synchronizer ID on which to onboard the party + // + // Required + string synchronizer = 1; + + // TopologyTransactions to onboard the external party + // Can contain: + // - A namespace for the party. + // This can be either a single NamespaceDelegation, + // or DecentralizedNamespaceDefinition along with its authorized namespace owners in the form of NamespaceDelegations. + // May be provided, if so it must be fully authorized by the signatures in this request combined with the existing topology state. + // - A PartyToParticipant to register the hosting relationship of the party, and the party's signing keys and threshold. + // Must be provided. + // + // Required: must be non-empty + repeated SignedTransaction onboarding_transactions = 2; + + // Optional signatures of the combined hash of all onboarding_transactions + // This may be used instead of providing signatures on each individual transaction + // + // Optional: can be empty + repeated Signature multi_hash_signatures = 3; + + // The id of the ``Identity Provider`` + // If not set, assume the party is managed by the default identity provider. + // + // Optional + string identity_provider_id = 4; + + // When true, this RPC will attempt to wait for the party to be allocated on the synchronizer before returning. + // When false, the allocation will happen asynchronously. + // This is a best effort only as this synchronization is only possible for non decentralized parties (single hosting node). + // For decentralized parties, this flag is ignored. + // Defaults to true. + // + // Optional + optional bool wait_for_allocation = 5; + + // The user who will get the act_as rights to the newly allocated party. + // If set to an empty string (the default), no user will get rights to the party. + // + // Optional + string user_id = 6; +} + +message AllocateExternalPartyResponse { + // The allocated party id + // + // Required + string party_id = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(party_details.identity_provider_id)`` +message UpdatePartyDetailsRequest { + // Party to be updated + // Modifiable + // + // Required + PartyDetails party_details = 1; + + // An update mask specifies how and which properties of the ``PartyDetails`` message are to be updated. + // An update mask consists of a set of update paths. + // A valid update path points to a field or a subfield relative to the ``PartyDetails`` message. + // A valid update mask must: + // + // 1. contain at least one update path, + // 2. contain only valid update paths. + // + // Fields that can be updated are marked as ``Modifiable``. + // An update path can also point to non-``Modifiable`` fields such as 'party' and 'local_metadata.resource_version' + // because they are used: + // + // 1. to identify the party details resource subject to the update, + // 2. for concurrent change control. + // + // An update path can also point to non-``Modifiable`` fields such as 'is_local' + // as long as the values provided in the update request match the server values. + // Examples of update paths: 'local_metadata.annotations', 'local_metadata'. + // For additional information see the documentation for standard protobuf3's ``google.protobuf.FieldMask``. + // For similar Ledger API see ``com.daml.ledger.api.v2.admin.UpdateUserRequest``. + // + // Required + google.protobuf.FieldMask update_mask = 2; +} + +message UpdatePartyDetailsResponse { + // Updated party details + // + // Required + PartyDetails party_details = 1; +} + +message PartyDetails { + // The stable unique identifier of a Daml party. + // Must be a valid PartyIdString (as described in ``value.proto``). + // + // Required + string party = 1; + + // true if party is hosted by the participant and the party shares the same identity provider as the user issuing the request. + // + // Optional + bool is_local = 3; + + // Participant-local metadata of this party. + // Modifiable + // + // Optional + ObjectMeta local_metadata = 4; + + // The id of the ``Identity Provider`` + // Optional, if not set, there could be 3 options: + // + // 1. the party is managed by the default identity provider. + // 2. party is not hosted by the participant. + // 3. party is hosted by the participant, but is outside of the user's identity provider. + // + // Optional + string identity_provider_id = 5; +} + +// Required authorization: ``HasRight(ParticipantAdmin)`` +message UpdatePartyIdentityProviderIdRequest { + // Party to update + // + // Required + string party = 1; + // Current identity provider id of the party + // + // Optional + string source_identity_provider_id = 2; + // Target identity provider id of the party + // + // Optional + string target_identity_provider_id = 3; +} + +message UpdatePartyIdentityProviderIdResponse {} + +message GenerateExternalPartyTopologyRequest { + // Synchronizer-id for which we are building this request. + // TODO(#27670) support synchronizer aliases + // + // Required + string synchronizer = 1; + + // The actual party id will be constructed from this hint and a fingerprint of the public key + // + // Required + string party_hint = 2; + + // Public key + // + // Required + com.daml.ledger.api.v2.SigningPublicKey public_key = 3; + + // If true, then the local participant will only be observing, not confirming. Default false. + // + // Optional + bool local_participant_observation_only = 4; + + // Other participant ids which should be confirming for this party + // + // Optional: can be empty + repeated string other_confirming_participant_uids = 5; + + // Confirmation threshold >= 1 for the party. Defaults to all available confirmers (or if set to 0). + // + // Optional + uint32 confirmation_threshold = 6; + + // Other observing participant ids for this party + // + // Optional: can be empty + repeated string observing_participant_uids = 7; +} + +// Response message with topology transactions and the multi-hash to be signed. +message GenerateExternalPartyTopologyResponse { + // The generated party id + // + // Required + string party_id = 1; + + // The fingerprint of the supplied public key + // + // Required + string public_key_fingerprint = 2; + + // The serialized topology transactions which need to be signed and submitted as part of the allocate party process + // Note that the serialization includes the versioning information. Therefore, the transaction here is serialized + // as an `UntypedVersionedMessage` which in turn contains the serialized `TopologyTransaction` in the version + // supported by the synchronizer. + // + // Required: must be non-empty + repeated bytes topology_transactions = 3; + + // the multi-hash which may be signed instead of each individual transaction + // + // Required: must be non-empty + bytes multi_hash = 4; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/admin/user_management_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/admin/user_management_service.proto new file mode 100644 index 00000000..91c8beda --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/admin/user_management_service.proto @@ -0,0 +1,415 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.admin; + +import "com/daml/ledger/api/v2/admin/object_meta.proto"; +import "google/protobuf/field_mask.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Admin"; +option java_outer_classname = "UserManagementServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.admin"; + +// Service to manage users and their rights for interacting with the Ledger API +// served by a participant node. +// +// The authorization rules for its RPCs are specified on the ``Request`` +// messages as boolean expressions over these facts: +// +// 1. ``HasRight(r)`` denoting whether the authenticated user has right ``r`` and +// 2. ``IsAuthenticatedUser(uid)`` denoting whether ``uid`` is the empty string or equal to the id of the authenticated user. +// 3. ``IsAuthenticatedIdentityProviderAdmin(idp)`` denoting whether ``idp`` is equal to the ``identity_provider_id`` +// of the authenticated user and the user has an IdentityProviderAdmin right. +// +// If `user_id` is set to the empty string (the default), then the data for the authenticated user will be retrieved. +// If `identity_provider_id` is set to an empty string, then it's effectively set to the value of access token's 'iss' field if that is provided. +// If `identity_provider_id` remains an empty string, the default identity provider will be assumed. +// +// The fields of request messages (and sub-messages) are marked either as ``Optional`` or ``Required``: +// +// 1. ``Optional`` denoting the client may leave the field unset when sending a request. +// 2. ``Required`` denoting the client must set the field to a non-default value when sending a request. +// +// A user resource consists of: +// +// 1. a set of properties represented by the ``User`` message, +// 2. a set of user rights, where each right is represented by the ``Right`` message. +// +// A user resource, once it has been created, can be modified. +// In order to update the properties represented by the ``User`` message use the ``UpdateUser`` RPC. The only fields that can be modified are those marked as ``Modifiable``. +// In order to grant or revoke user rights use ``GrantRights' and ``RevokeRights`` RPCs. +service UserManagementService { + // Create a new user. + rpc CreateUser(CreateUserRequest) returns (CreateUserResponse); + + // Get the user data of a specific user or the authenticated user. + rpc GetUser(GetUserRequest) returns (GetUserResponse); + + // Update selected modifiable attribute of a user resource described by the ``User`` message. + rpc UpdateUser(UpdateUserRequest) returns (UpdateUserResponse); + + // Delete an existing user and all its rights. + rpc DeleteUser(DeleteUserRequest) returns (DeleteUserResponse); + + // List all existing users. + rpc ListUsers(ListUsersRequest) returns (ListUsersResponse); + + // Grant rights to a user. + // Granting rights does not affect the resource version of the corresponding user. + rpc GrantUserRights(GrantUserRightsRequest) returns (GrantUserRightsResponse); + + // Revoke rights from a user. + // Revoking rights does not affect the resource version of the corresponding user. + rpc RevokeUserRights(RevokeUserRightsRequest) returns (RevokeUserRightsResponse); + + // List the set of all rights granted to a user. + rpc ListUserRights(ListUserRightsRequest) returns (ListUserRightsResponse); + + // Update the assignment of a user from one IDP to another. + rpc UpdateUserIdentityProviderId(UpdateUserIdentityProviderIdRequest) returns (UpdateUserIdentityProviderIdResponse); +} + +// Users and rights +/////////////////// + +// Users are used to dynamically manage the rights given to Daml applications. +// They are stored and managed per participant node. +message User { + // The user identifier, which must be a non-empty string of at most 128 + // characters that are either alphanumeric ASCII characters or one of the symbols "@^$.!`-#+'~_|:()". + // + // Required + string id = 1; + + // The primary party as which this user reads and acts by default on the ledger + // *provided* it has the corresponding ``CanReadAs(primary_party)`` or + // ``CanActAs(primary_party)`` rights. + // Ledger API clients SHOULD set this field to a non-empty value for all users to + // enable the users to act on the ledger using their own Daml party. + // Users for participant administrators MAY have an associated primary party. + // Modifiable + // + // Optional + string primary_party = 2; + + // When set, then the user is denied all access to the Ledger API. + // Otherwise, the user has access to the Ledger API as per the user's rights. + // Modifiable + // + // Optional + bool is_deactivated = 3; + + // The metadata of this user. + // Note that the ``metadata.resource_version`` tracks changes to the properties described by the ``User`` message and not the user's rights. + // Modifiable + // + // Optional + ObjectMeta metadata = 4; + + // The ID of the identity provider configured by ``Identity Provider Config`` + // If not set, assume the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 5; +} + +// A right granted to a user. +message Right { + // The right to administer the participant node. + message ParticipantAdmin {} + + message CanActAs { + // The right to authorize commands for this party. + // + // Required + string party = 1; + } + + message CanReadAs { + // The right to read ledger data visible to this party. + // + // Required + string party = 1; + } + + message CanExecuteAs { + // The right to prepare and execute submissions as this party. + // This right does not entitle the user to perform any reads. + // If reading is required, a separate ReadAs right must be added. + // Right to execute as a party is also implicitly contained in the CanActAs right. + // + // Required + string party = 1; + } + + // The right to administer the identity provider that the user is assigned to. + // It means, being able to manage users and parties that are also assigned + // to the same identity provider. + message IdentityProviderAdmin {} + + // The rights of a participant's super reader. Its utility is predominantly for + // feeding external tools, such as PQS, continually without the need to change subscriptions + // as new parties pop in and out of existence. + message CanReadAsAnyParty {} + + // The rights of a user to prepare and execute transactions as any party. + // Its utility is predominantly for users that perform interactive submissions + // on behalf of many parties. + message CanExecuteAsAnyParty {} + + // Required + oneof kind { + // The user can administer the participant node. + ParticipantAdmin participant_admin = 1; + // The user can act as a specific party. + CanActAs can_act_as = 2; + // The user can read ledger data visible to a specific party. + CanReadAs can_read_as = 3; + // The user can administer users and parties assigned to the same identity provider as the one of the user. + IdentityProviderAdmin identity_provider_admin = 4; + // The user can read as any party on a participant + CanReadAsAnyParty can_read_as_any_party = 5; + // The user can prepare and execute submissions as a specific party. + CanExecuteAs can_execute_as = 6; + // The user can prepare and execute submissions as any party on a participant. + CanExecuteAsAnyParty can_execute_as_any_party = 7; + } +} + +// RPC requests and responses +///////////////////////////// + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(user.identity_provider_id)`` +message CreateUserRequest { + // The user to create. + // + // Required + User user = 1; + + // The rights to be assigned to the user upon creation, + // which SHOULD include appropriate rights for the ``user.primary_party``. + // + // Optional: can be empty + repeated Right rights = 2; +} + +message CreateUserResponse { + // Created user. + // + // Required + User user = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)`` +message GetUserRequest { + // The user whose data to retrieve. + // If set to empty string (the default), then the data for the authenticated user will be retrieved. + // + // Optional + string user_id = 1; + + // The id of the ``Identity Provider`` + // If not set, assume the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 2; +} + +message GetUserResponse { + // Retrieved user. + // + // Required + User user = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(user.identity_provider_id)`` +message UpdateUserRequest { + // The user to update. + // Modifiable + // + // Required + User user = 1; + + // An update mask specifies how and which properties of the ``User`` message are to be updated. + // An update mask consists of a set of update paths. + // A valid update path points to a field or a subfield relative to the ``User`` message. + // A valid update mask must: + // + // 1. contain at least one update path, + // 2. contain only valid update paths. + // + // Fields that can be updated are marked as ``Modifiable``. + // An update path can also point to a non-``Modifiable`` fields such as 'id' and 'metadata.resource_version' + // because they are used: + // + // 1. to identify the user resource subject to the update, + // 2. for concurrent change control. + // + // Examples of valid update paths: 'primary_party', 'metadata', 'metadata.annotations'. + // For additional information see the documentation for standard protobuf3's ``google.protobuf.FieldMask``. + // For similar Ledger API see ``com.daml.ledger.api.v2.admin.UpdatePartyDetailsRequest``. + // + // Required + google.protobuf.FieldMask update_mask = 2; +} + +message UpdateUserResponse { + // Updated user + // + // Required + User user = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)`` +message DeleteUserRequest { + // The user to delete. + // + // Required + string user_id = 1; + + // The id of the ``Identity Provider`` + // If not set, assume the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 2; +} + +// Does not (yet) contain any data. +message DeleteUserResponse {} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)`` +message ListUsersRequest { + // Pagination token to determine the specific page to fetch. + // Leave empty to fetch the first page. + // + // Optional + string page_token = 2; + + // Maximum number of results to be returned by the server. The server will return no more than that many results, but it might return fewer. + // If 0, the server will decide the number of results to be returned. + // + // Optional + int32 page_size = 3; + + // The id of the ``Identity Provider`` + // If not set, assume the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 4; +} + +message ListUsersResponse { + // A subset of users of the participant node that fit into this page. + // Can be empty if no more users + // + // Optional: can be empty + repeated User users = 1; + + // Pagination token to retrieve the next page. + // Empty, if there are no further results. + // + // Optional + string next_page_token = 2; +} + +// Add the rights to the set of rights granted to the user. +// +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)`` +message GrantUserRightsRequest { + // The user to whom to grant rights. + // + // Required + string user_id = 1; + + // The rights to grant. + // + // Optional: can be empty + repeated Right rights = 2; + + // The id of the ``Identity Provider`` + // If not set, assume the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 3; +} + +message GrantUserRightsResponse { + // The rights that were newly granted by the request. + // + // Optional: can be empty + repeated Right newly_granted_rights = 1; +} + +// Remove the rights from the set of rights granted to the user. +// +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)`` +message RevokeUserRightsRequest { + // The user from whom to revoke rights. + // + // Required + string user_id = 1; + + // The rights to revoke. + // + // Optional: can be empty + repeated Right rights = 2; + + // The id of the ``Identity Provider`` + // If not set, assume the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 3; +} + +message RevokeUserRightsResponse { + // The rights that were actually revoked by the request. + // + // Optional: can be empty + repeated Right newly_revoked_rights = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)`` +message ListUserRightsRequest { + // The user for which to list the rights. + // If set to empty string (the default), then the rights for the authenticated user will be listed. + // + // Required + string user_id = 1; + + // The id of the ``Identity Provider`` + // If not set, assume the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 2; +} + +message ListUserRightsResponse { + // All rights of the user. + // + // Optional: can be empty + repeated Right rights = 1; +} + +// Required authorization: ``HasRight(ParticipantAdmin)`` +message UpdateUserIdentityProviderIdRequest { + // User to update + // + // Required + string user_id = 1; + + // Current identity provider ID of the user + // If omitted, the default IDP is assumed + // + // Optional + string source_identity_provider_id = 2; + + // Target identity provider ID of the user + // If omitted, the default IDP is assumed + // + // Optional + string target_identity_provider_id = 3; +} + +message UpdateUserIdentityProviderIdResponse {} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/command_completion_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/command_completion_service.proto new file mode 100644 index 00000000..77ad2e52 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/command_completion_service.proto @@ -0,0 +1,66 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/completion.proto"; +import "com/daml/ledger/api/v2/offset_checkpoint.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "CommandCompletionServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Allows clients to observe the status of their submissions. +// Commands may be submitted via the Command Submission Service. +// The on-ledger effects of their submissions are disclosed by the Update Service. +// +// Commands may fail in 2 distinct manners: +// +// 1. Failure communicated synchronously in the gRPC error of the submission. +// 2. Failure communicated asynchronously in a Completion, see ``completion.proto``. +// +// Note that not only successfully submitted commands MAY produce a completion event. For example, the participant MAY +// choose to produce a completion event for a rejection of a duplicate command. +// +// Clients that do not receive a successful completion about their submission MUST NOT assume that it was successful. +// Clients SHOULD subscribe to the CompletionStream before starting to submit commands to prevent race conditions. +service CommandCompletionService { + // Subscribe to command completion events. + rpc CompletionStream(CompletionStreamRequest) returns (stream CompletionStreamResponse); +} + +message CompletionStreamRequest { + // Only completions of commands submitted with the same user_id will be visible in the stream. + // Must be a valid UserIdString (as described in ``value.proto``). + // + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + string user_id = 1; + + // Non-empty list of parties whose data should be included. + // The stream shows only completions of commands for which at least one of the ``act_as`` parties is in the given set of parties. + // Must be a valid PartyIdString (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string parties = 2; + + // This optional field indicates the minimum offset for completions. This can be used to resume an earlier completion stream. + // If not set the ledger uses the ledger begin offset instead. + // If specified, it must be a valid absolute offset (positive integer) or zero (ledger begin offset). + // If the ledger has been pruned, this parameter must be specified and greater than the pruning offset. + // + // Optional + int64 begin_exclusive = 3; +} + +message CompletionStreamResponse { + // Required + oneof completion_response { + Completion completion = 1; + OffsetCheckpoint offset_checkpoint = 2; + } +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/command_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/command_service.proto new file mode 100644 index 00000000..1f5cac5b --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/command_service.proto @@ -0,0 +1,101 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/commands.proto"; +import "com/daml/ledger/api/v2/reassignment.proto"; +import "com/daml/ledger/api/v2/reassignment_commands.proto"; +import "com/daml/ledger/api/v2/transaction.proto"; +import "com/daml/ledger/api/v2/transaction_filter.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "CommandServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Command Service is able to correlate submitted commands with completion data, identify timeouts, and return contextual +// information with each tracking result. This supports the implementation of stateless clients. +// +// Note that submitted commands generally produce completion events as well, even in case a command gets rejected. +// For example, the participant SHOULD produce a completion event for a rejection of a duplicate command. +service CommandService { + // Submits a single composite command and waits for its result. + // Propagates the gRPC error of failed submissions including Daml interpretation errors. + rpc SubmitAndWait(SubmitAndWaitRequest) returns (SubmitAndWaitResponse); + + // Submits a single composite command, waits for its result, and returns the transaction. + // Propagates the gRPC error of failed submissions including Daml interpretation errors. + rpc SubmitAndWaitForTransaction(SubmitAndWaitForTransactionRequest) returns (SubmitAndWaitForTransactionResponse); + + // Submits a single composite reassignment command, waits for its result, and returns the reassignment. + // Propagates the gRPC error of failed submission. + rpc SubmitAndWaitForReassignment(SubmitAndWaitForReassignmentRequest) returns (SubmitAndWaitForReassignmentResponse); +} + +// These commands are executed as a single atomic transaction. +message SubmitAndWaitRequest { + // The commands to be submitted. + // + // Required + Commands commands = 1; +} + +// These commands are executed as a single atomic transaction. +message SubmitAndWaitForTransactionRequest { + // The commands to be submitted. + // + // Required + Commands commands = 1; + + // If no ``transaction_format`` is provided, a default will be used where ``transaction_shape`` is set to + // TRANSACTION_SHAPE_ACS_DELTA, ``event_format`` is defined with ``filters_by_party`` containing wildcard-template + // filter for all original ``act_as`` and ``read_as`` parties and the ``verbose`` flag is set. + // + // Optional + TransactionFormat transaction_format = 2; +} + +message SubmitAndWaitResponse { + // The id of the transaction that resulted from the submitted command. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string update_id = 1; + + // The details of the offset field are described in ``community/ledger-api/README.md``. + // + // Required + int64 completion_offset = 2; +} + +message SubmitAndWaitForTransactionResponse { + // The transaction that resulted from the submitted command. + // The transaction might contain no events (request conditions result in filtering out all of them). + // + // Required + Transaction transaction = 1; +} + +// This reassignment is executed as a single atomic update. +message SubmitAndWaitForReassignmentRequest { + // The reassignment commands to be submitted. + // + // Required + ReassignmentCommands reassignment_commands = 1; + + // If no event_format provided, the result will contain no events. + // The events in the result, will take shape TRANSACTION_SHAPE_ACS_DELTA. + // + // Optional + EventFormat event_format = 2; +} + +message SubmitAndWaitForReassignmentResponse { + // The reassignment that resulted from the submitted reassignment command. + // The reassignment might contain no events (request conditions result in filtering out all of them). + // + // Required + Reassignment reassignment = 1; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/command_submission_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/command_submission_service.proto new file mode 100644 index 00000000..16e2e335 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/command_submission_service.proto @@ -0,0 +1,54 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/commands.proto"; +import "com/daml/ledger/api/v2/reassignment_commands.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "CommandSubmissionServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Allows clients to attempt advancing the ledger's state by submitting commands. +// The final states of their submissions are disclosed by the Command Completion Service. +// The on-ledger effects of their submissions are disclosed by the Update Service. +// +// Commands may fail in 2 distinct manners: +// +// 1. Failure communicated synchronously in the gRPC error of the submission. +// 2. Failure communicated asynchronously in a Completion, see ``completion.proto``. +// +// Note that not only successfully submitted commands MAY produce a completion event. For example, the participant MAY +// choose to produce a completion event for a rejection of a duplicate command. +// +// Clients that do not receive a successful completion about their submission MUST NOT assume that it was successful. +// Clients SHOULD subscribe to the CompletionStream before starting to submit commands to prevent race conditions. +service CommandSubmissionService { + // Submit a single composite command. + rpc Submit(SubmitRequest) returns (SubmitResponse); + + // Submit a single reassignment. + rpc SubmitReassignment(SubmitReassignmentRequest) returns (SubmitReassignmentResponse); +} + +// The submitted commands will be processed atomically in a single transaction. Moreover, each ``Command`` in ``commands`` will be executed in the order specified by the request. +message SubmitRequest { + // The commands to be submitted in a single transaction. + // + // Required + Commands commands = 1; +} + +message SubmitResponse {} + +message SubmitReassignmentRequest { + // The reassignment command to be submitted. + // + // Required + ReassignmentCommands reassignment_commands = 1; +} + +message SubmitReassignmentResponse {} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/commands.proto b/chain/canton/proto/com/daml/ledger/api/v2/commands.proto new file mode 100644 index 00000000..c8449eae --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/commands.proto @@ -0,0 +1,287 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/value.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "CommandsOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// A command can either create a new contract or exercise a choice on an existing contract. +message Command { + // Required + oneof command { + CreateCommand create = 1; + ExerciseCommand exercise = 2; + ExerciseByKeyCommand exercise_by_key = 4; + CreateAndExerciseCommand create_and_exercise = 3; + } +} + +// Create a new contract instance based on a template. +message CreateCommand { + // The template of contract the client wants to create. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + Identifier template_id = 1; + + // The arguments required for creating a contract from this template. + // + // Required + Record create_arguments = 2; +} + +// Exercise a choice on an existing contract. +message ExerciseCommand { + // The template or interface of the contract the client wants to exercise. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // To exercise a choice on an interface, specify the interface identifier in the template_id field. + // + // Required + Identifier template_id = 1; + + // The ID of the contract the client wants to exercise upon. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string contract_id = 2; + + // The name of the choice the client wants to exercise. + // Must be a valid NameString (as described in ``value.proto``) + // + // Required + string choice = 3; + + // The argument for this choice. + // + // Required + Value choice_argument = 4; +} + +// Exercise a choice on an existing contract specified by its key. +message ExerciseByKeyCommand { + // The template of contract the client wants to exercise. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + Identifier template_id = 1; + + // The key of the contract the client wants to exercise upon. + // + // Required + Value contract_key = 2; + + // The name of the choice the client wants to exercise. + // Must be a valid NameString (as described in ``value.proto``) + // + // Required + string choice = 3; + + // The argument for this choice. + // + // Required + Value choice_argument = 4; +} + +// Create a contract and exercise a choice on it in the same transaction. +message CreateAndExerciseCommand { + // The template of the contract the client wants to create. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + Identifier template_id = 1; + + // The arguments required for creating a contract from this template. + // + // Required + Record create_arguments = 2; + + // The name of the choice the client wants to exercise. + // Must be a valid NameString (as described in ``value.proto``). + // + // Required + string choice = 3; + + // The argument for this choice. + // + // Required + Value choice_argument = 4; +} + +// An additional contract that is used to resolve +// contract & contract key lookups. +message DisclosedContract { + // The template id of the contract. + // The identifier uses the package-id reference format. + // + // If provided, used to validate the template id of the contract serialized in the created_event_blob. + // + // Optional + Identifier template_id = 1; + + // The contract id + // + // If provided, used to validate the contract id of the contract serialized in the created_event_blob. + // + // Optional + string contract_id = 2; + + // Opaque byte string containing the complete payload required by the Daml engine + // to reconstruct a contract not known to the receiving participant. + // + // Required: must be non-empty + bytes created_event_blob = 3; + + // The ID of the synchronizer where the contract is currently assigned + // + // Optional + string synchronizer_id = 4; +} + +// A composite command that groups multiple commands together. +message Commands { + // Identifier of the on-ledger workflow that this command is a part of. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string workflow_id = 1; + + // Uniquely identifies the participant user that issued the command. + // Must be a valid UserIdString (as described in ``value.proto``). + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + string user_id = 2; + + // Uniquely identifies the command. + // The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, + // where act_as is interpreted as a set of party names. + // The change ID can be used for matching the intended ledger changes with all their completions. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string command_id = 3; + + // Individual elements of this atomic command. Must be non-empty. + // + // Required: must be non-empty + repeated Command commands = 4; + + // Specifies the deduplication period for the change ID. + // If omitted, the participant will assume the configured maximum deduplication time. + // + // Optional + oneof deduplication_period { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + google.protobuf.Duration deduplication_duration = 5; + + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer) or participant begin (zero). + int64 deduplication_offset = 6; + } + + // Lower bound for the ledger time assigned to the resulting transaction. + // Note: The ledger time of a transaction is assigned as part of command interpretation. + // Use this property if you expect that command interpretation will take a considerate amount of time, such that by + // the time the resulting transaction is sequenced, its assigned ledger time is not valid anymore. + // Must not be set at the same time as min_ledger_time_rel. + // + // Optional + google.protobuf.Timestamp min_ledger_time_abs = 7; + + // Same as min_ledger_time_abs, but specified as a duration, starting from the time the command is received by the server. + // Must not be set at the same time as min_ledger_time_abs. + // + // Optional + google.protobuf.Duration min_ledger_time_rel = 8; + + // Set of parties on whose behalf the command should be executed. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to act on behalf of each of the given parties. + // Each element must be a valid PartyIdString (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string act_as = 9; + + // Set of parties on whose behalf (in addition to all parties listed in ``act_as``) contracts can be retrieved. + // This affects Daml operations such as ``fetch``, ``fetchByKey``, ``lookupByKey``, ``exercise``, and ``exerciseByKey``. + // Note: A participant node of a Daml network can host multiple parties. Each contract present on the participant + // node is only visible to a subset of these parties. A command can only use contracts that are visible to at least + // one of the parties in ``act_as`` or ``read_as``. This visibility check is independent from the Daml authorization + // rules for fetch operations. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to read contract data on behalf of each of the given parties. + // + // Optional: can be empty + repeated string read_as = 10; + + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // If omitted, the participant or the committer may set a value of their choice. + // + // Optional + string submission_id = 11; + + // Additional contracts used to resolve contract & contract key lookups. + // + // Optional: can be empty + repeated DisclosedContract disclosed_contracts = 12; + + // Must be a valid synchronizer id + // + // Optional + string synchronizer_id = 13; + + // The package-id selection preference of the client for resolving + // package names and interface instances in command submission and interpretation + // + // Optional: can be empty + repeated string package_id_selection_preference = 14; + + // Fetches the contract keys into the caches to speed up the command processing. + // Should only contain contract keys that are expected to be resolved during interpretation of the commands. + // Keys of disclosed contracts do not need prefetching. + // + // Optional: can be empty + repeated PrefetchContractKey prefetch_contract_keys = 15; + + // The maximum number of passes for the Topology-Aware Package Selection (TAPS). + // Higher values can increase the chance of successful package selection for routing of interpreted transactions. + // If unset, this defaults to the value defined in the participant configuration. + // The provided value must not exceed the limit specified in the participant configuration. + // + // Optional + optional uint32 taps_max_passes = 16; +} + +// Preload contracts +message PrefetchContractKey { + // The template of contract the client wants to prefetch. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + Identifier template_id = 1; + + // The key of the contract the client wants to prefetch. + // + // Required + Value contract_key = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/completion.proto b/chain/canton/proto/com/daml/ledger/api/v2/completion.proto new file mode 100644 index 00000000..b9de1e9d --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/completion.proto @@ -0,0 +1,136 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/offset_checkpoint.proto"; +import "com/daml/ledger/api/v2/trace_context.proto"; +import "google/protobuf/duration.proto"; +import "google/rpc/status.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "CompletionOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// A completion represents the status of a submitted command on the ledger: it can be successful or failed. +message Completion { + // The ID of the succeeded or failed command. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string command_id = 1; + + // Identifies the exact type of the error. + // It uses the same format of conveying error details as it is used for the RPC responses of the APIs. + // + // Optional + google.rpc.Status status = 2; + + // The update_id of the transaction or reassignment that resulted from the command with command_id. + // + // Only set for successfully executed commands. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string update_id = 3; + + // The user-id that was used for the submission, as described in ``commands.proto``. + // Must be a valid UserIdString (as described in ``value.proto``). + // + // Required + string user_id = 4; + + // The set of parties on whose behalf the commands were executed. + // Contains the ``act_as`` parties from ``commands.proto`` + // filtered to the requesting parties in CompletionStreamRequest. + // The order of the parties need not be the same as in the submission. + // Each element must be a valid PartyIdString (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string act_as = 5; + + // The submission ID this completion refers to, as described in ``commands.proto``. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string submission_id = 6; + + // The actual deduplication window used for the submission, which is derived from + // ``Commands.deduplication_period``. The ledger may convert the deduplication period into other + // descriptions and extend the period in implementation-specified ways. + // + // Used to audit the deduplication guarantee described in ``commands.proto``. + // + // The deduplication guarantee applies even if the completion omits this field. + // + // Optional + oneof deduplication_period { + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // + // Must be a valid absolute offset (positive integer) or participant begin (zero). + int64 deduplication_offset = 7; + + // Specifies the length of the deduplication period. + // It is measured in record time of completions. + // + // Must be non-negative. + google.protobuf.Duration deduplication_duration = 8; + } + + // The Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + TraceContext trace_context = 9; + + // May be used in a subsequent CompletionStreamRequest to resume the consumption of this stream at a later time. + // Must be a valid absolute offset (positive integer). + // + // Required + int64 offset = 10; + + // The synchronizer along with its record time. + // The synchronizer id provided, in case of + // + // - successful/failed transactions: identifies the synchronizer of the transaction + // - for successful/failed unassign commands: identifies the source synchronizer + // - for successful/failed assign commands: identifies the target synchronizer + // + // Required + SynchronizerTime synchronizer_time = 11; + + // The traffic cost paid by this participant node for the confirmation request + // for the submitted command. + // + // Commands whose execution is rejected before their corresponding + // confirmation request is ordered by the synchronizer will report a paid + // traffic cost of zero. + // If a confirmation request is ordered for a command, but the request fails + // (e.g., due to contention with a concurrent contract archival), the traffic + // cost is paid and reported on the failed completion for the request. + // + // If you want to correlate the traffic cost of a successful completion + // with the transaction that resulted from the command, you can use the + // ``offset`` field to retrieve the transaction using + // ``UpdateService.GetUpdateByOffset`` on the same participant node; or alternatively use the ``update_id`` + // field to retrieve the transaction using ``UpdateService.GetUpdateById`` on any participant node + // that sees the transaction. + // + // Note: for completions processed before the participant started serving + // traffic cost on the Ledger API, this field will be set to zero. + // Additionally, the total cost incurred by the submitting node for the submission of the transaction may be greater + // than the reported cost, for example if retries were issued due to failed submissions to the synchronizer. + // The cost reported here is the one paid for ordering the confirmation request. + // + // Optional + int64 paid_traffic_cost = 12; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/contract_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/contract_service.proto new file mode 100644 index 00000000..13608c62 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/contract_service.proto @@ -0,0 +1,55 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/event.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "ContractServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// This service is experimental / alpha, therefore no backwards compatibility is guaranteed. +service ContractService { + // Looking up contract data by contract ID. + // This endpoint is experimental / alpha, therefore no backwards compatibility is guaranteed. + // This endpoint must not be used to look up contracts which entered the participant via party replication + // or repair service. + // If there is no contract exist with the contract ID, or there is no intersection with the querying_parties, + // an CONTRACT_PAYLOAD_NOT_FOUND error will be raised. + rpc GetContract(GetContractRequest) returns (GetContractResponse); +} + +message GetContractRequest { + // The ID of the contract. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string contract_id = 1; + + // The list of querying parties + // The stakeholders of the referenced contract must have an intersection with any of these parties + // to return the result. + // If no querying_parties specified, all possible contracts could be returned. + // + // Optional: can be empty + repeated string querying_parties = 2; +} + +message GetContractResponse { + // The representative_package_id will be always set to the contract package ID, therefore this endpoint should + // not be used to lookup contract which entered the participant via party replication or repair service. + // The witnesses field will contain only the querying_parties which are also stakeholders of the contract as well. + // The following fields of the created event cannot be populated, so those should not be used / parsed: + // + // - offset + // - node_id + // - created_event_blob + // - interface_views + // - acs_delta + // + // Required + CreatedEvent created_event = 1; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/crypto.proto b/chain/canton/proto/com/daml/ledger/api/v2/crypto.proto new file mode 100644 index 00000000..c75bfbc8 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/crypto.proto @@ -0,0 +1,121 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "CryptoOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Note: these crypto data types are a subset of the ones used internally by Canton. +// They have been forked from the respective com.digitalasset.canton.crypto.v30 package. + +enum SigningKeySpec { + SIGNING_KEY_SPEC_UNSPECIFIED = 0; + + // Elliptic Curve Key from Curve25519 + // as defined in http://ed25519.cr.yp.to/ + SIGNING_KEY_SPEC_EC_CURVE25519 = 1; + + // Elliptic Curve Key from the NIST P-256 curve (aka secp256r1) + // as defined in https://doi.org/10.6028/NIST.FIPS.186-4 + SIGNING_KEY_SPEC_EC_P256 = 2; + + // Elliptic Curve Key from the NIST P-384 curve (aka secp384r1) + // as defined in https://doi.org/10.6028/NIST.FIPS.186-4 + SIGNING_KEY_SPEC_EC_P384 = 3; + + // Elliptic Curve Key from SECG P256k1 curve (aka secp256k1) + // commonly used in bitcoin and ethereum + // as defined in https://www.secg.org/sec2-v2.pdf + SIGNING_KEY_SPEC_EC_SECP256K1 = 4; +} + +// Serialization format for crypto keys and signatures +enum CryptoKeyFormat { + CRYPTO_KEY_FORMAT_UNSPECIFIED = 0; + + // ASN.1 + DER encoding + // Legacy format no longer used, except for migrations + CRYPTO_KEY_FORMAT_DER = 1; + + // Raw encoding of a key + CRYPTO_KEY_FORMAT_RAW = 2; + + // ASN.1 + DER-encoding of X.509 SubjectPublicKeyInfo structure: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 + CRYPTO_KEY_FORMAT_DER_X509_SUBJECT_PUBLIC_KEY_INFO = 3; + + // Symbolic crypto, must only be used for testing + reserved 10000; +} + +message SigningPublicKey { + // The serialization format of the public key + // + // Required + CryptoKeyFormat format = 1; + + // Serialized public key in the format specified above + // + // Required: must be non-empty + bytes key_data = 2; + + // The key specification + // + // Required + SigningKeySpec key_spec = 3; +} + +message Signature { + // Required + SignatureFormat format = 1; + + // Required: must be non-empty + bytes signature = 2; + + // The fingerprint/id of the keypair used to create this signature and needed to verify. + // + // Required + string signed_by = 3; + + // The signing algorithm specification used to produce this signature + // + // Required + SigningAlgorithmSpec signing_algorithm_spec = 4; +} + +enum SigningAlgorithmSpec { + SIGNING_ALGORITHM_SPEC_UNSPECIFIED = 0; + + // EdDSA Signature based on Curve25519 with SHA-512 + // http://ed25519.cr.yp.to/ + SIGNING_ALGORITHM_SPEC_ED25519 = 1; + + // Elliptic Curve Digital Signature Algorithm with SHA256 + SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_256 = 2; + + // Elliptic Curve Digital Signature Algorithm with SHA384 + SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_384 = 3; +} + +enum SignatureFormat { + SIGNATURE_FORMAT_UNSPECIFIED = 0; + + // Signature scheme specific signature format + // Legacy format no longer used, except for migrations + SIGNATURE_FORMAT_RAW = 1; + + // ASN.1 + DER-encoding of the `r` and `s` integers, as defined in https://datatracker.ietf.org/doc/html/rfc3279#section-2.2.3 + // Used for ECDSA signatures + SIGNATURE_FORMAT_DER = 2; + + // Concatenation of the integers `r || s` in little-endian form, as defined in https://datatracker.ietf.org/doc/html/rfc8032#section-3.3 + // Note that this is different from the format defined in IEEE P1363, which uses concatenation in big-endian form. + // Used for EdDSA signatures + SIGNATURE_FORMAT_CONCAT = 3; + + // Symbolic crypto, must only be used for testing + SIGNATURE_FORMAT_SYMBOLIC = 10000; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/event.proto b/chain/canton/proto/com/daml/ledger/api/v2/event.proto new file mode 100644 index 00000000..87b7672d --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/event.proto @@ -0,0 +1,373 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/value.proto"; +import "google/protobuf/timestamp.proto"; +import "google/rpc/status.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "EventOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Events in transactions can have two primary shapes: +// +// - ACS delta: events can be CreatedEvent or ArchivedEvent +// - ledger effects: events can be CreatedEvent or ExercisedEvent +// +// In the update service the events are restricted to the events +// visible for the parties specified in the transaction filter. Each +// event message type below contains a ``witness_parties`` field which +// indicates the subset of the requested parties that can see the event +// in question. +message Event { + // Required + oneof event { + // The event as it appeared in the context of its original daml transaction on this participant node. + // In particular, the offset, node_id pair of the daml transaction are preserved. + CreatedEvent created = 1; + ArchivedEvent archived = 2; + ExercisedEvent exercised = 3; + } +} + +// Records that a contract has been created, and choices may now be exercised on it. +message CreatedEvent { + // The offset of origin, which has contextual meaning, please see description at messages that include a CreatedEvent. + // Offsets are managed by the participant nodes. + // Transactions can thus NOT be assumed to have the same offsets on different participant nodes. + // It is a valid absolute offset (positive integer) + // + // Required + int64 offset = 1; + + // The position of this event in the originating transaction or reassignment. + // The origin has contextual meaning, please see description at messages that include a CreatedEvent. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of transactions. + // Must be valid node ID (non-negative integer) + // + // Required + int32 node_id = 2; + + // The ID of the created contract. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string contract_id = 3; + + // The template of the created contract. + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 4; + + // The key of the created contract. + // This will be set if and only if ``template_id`` defines a contract key. + // + // Optional + Value contract_key = 5; + + // The hash of contract_key. + // This will be set if and only if ``template_id`` defines a contract key. + // + // Optional: can be empty + bytes contract_key_hash = 16; + + // The arguments that have been used to create the contract. + // + // Required + Record create_arguments = 6; + + // Opaque representation of contract create event payload intended for forwarding + // to an API server as a contract disclosed as part of a command + // submission. + // + // Optional: can be empty + bytes created_event_blob = 7; + + // Interface views specified in the transaction filter. + // Includes an ``InterfaceView`` for each interface for which there is a ``InterfaceFilter`` with + // + // - its party in the ``witness_parties`` of this event, + // - and which is implemented by the template of this event, + // - and which has ``include_interface_view`` set. + // + // Optional: can be empty + repeated InterfaceView interface_views = 8; + + // The parties that are notified of this event. When a ``CreatedEvent`` + // is returned as part of a transaction tree or ledger-effects transaction, this will include all + // the parties specified in the ``TransactionFilter`` that are witnesses of the event + // (the stakeholders of the contract and all informees of all the ancestors + // of this create action that this participant knows about). + // If served as part of a ACS delta transaction those will + // be limited to all parties specified in the ``TransactionFilter`` that + // are stakeholders of the contract (i.e. either signatories or observers). + // If the ``CreatedEvent`` is returned as part of an AssignedEvent, + // ActiveContract or IncompleteUnassigned (so the event is related to + // an assignment or unassignment): this will include all parties of the + // ``TransactionFilter`` that are stakeholders of the contract. + // + // The behavior of reading create events visible to parties not hosted + // on the participant node serving the Ledger API is undefined. Concretely, + // there is neither a guarantee that the participant node will serve all their + // create events on the ACS stream, nor is there a guarantee that matching archive + // events are delivered for such create events. + // + // For most clients this is not a problem, as they only read events for parties + // that are hosted on the participant node. If you need to read events + // for parties that may not be hosted at all times on the participant node, + // subscribe to the ``TopologyEvent``s for that party by setting a corresponding + // ``UpdateFormat``. Using these events, query the ACS as-of an offset where the + // party is hosted on the participant node, and ignore create events at offsets + // where the party is not hosted on the participant node. + // + // Required: must be non-empty + repeated string witness_parties = 9; + + // The signatories for this contract as specified by the template. + // + // Required: must be non-empty + repeated string signatories = 10; + + // The observers for this contract as specified explicitly by the template or implicitly as choice controllers. + // This field never contains parties that are signatories. + // + // Optional: can be empty + repeated string observers = 11; + + // Ledger effective time of the transaction that created the contract. + // + // Required + google.protobuf.Timestamp created_at = 12; + + // The package name of the created contract. + // + // Required + string package_name = 13; + + // Whether this event would be part of respective ACS_DELTA shaped stream, + // and should therefore considered when tracking contract activeness on the client-side. + // + // Required + bool acs_delta = 14; + + // A package-id present in the participant package store that typechecks the contract's argument. + // This may differ from the package-id of the template used to create the contract. + // For contracts created before Canton 3.4, this field matches the contract's creation package-id. + // + // NOTE: Experimental, server internal concept, not for client consumption. Subject to change without notice. + // + // Required + string representative_package_id = 15; +} + +// View of a create event matched by an interface filter. +message InterfaceView { + // The interface implemented by the matched event. + // The identifier uses the package-id reference format. + // + // Required + Identifier interface_id = 1; + + // Whether the view was successfully computed, and if not, + // the reason for the error. The error is reported using the same rules + // for error codes and messages as the errors returned for API requests. + // + // Required + google.rpc.Status view_status = 2; + + // The value of the interface's view method on this event. + // Set if it was requested in the ``InterfaceFilter`` and it could be + // successfully computed. + // + // Optional + Record view_value = 3; + + // The package defining the interface implementation used to compute the view. + // Can be different from the package that was used to create the contract itself, + // as the contract arguments can be upgraded or downgraded using smart-contract upgrading + // as part of computing the interface view. + // Populated if the view computation is successful, otherwise empty. + // + // Optional + string implementation_package_id = 4; +} + +// Records that a contract has been archived, and choices may no longer be exercised on it. +message ArchivedEvent { + // The offset of origin. + // Offsets are managed by the participant nodes. + // Transactions can thus NOT be assumed to have the same offsets on different participant nodes. + // It is a valid absolute offset (positive integer) + // + // Required + int64 offset = 1; + + // The position of this event in the originating transaction or reassignment. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of transactions. + // Must be valid node ID (non-negative integer) + // + // Required + int32 node_id = 2; + + // The ID of the archived contract. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string contract_id = 3; + + // Identifies the template that defines the choice that archived the contract. + // This template's package-id may differ from the target contract's package-id + // if the target contract has been upgraded or downgraded. + // + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 4; + + // The parties that are notified of this event. For an ``ArchivedEvent``, + // these are the intersection of the stakeholders of the contract in + // question and the parties specified in the ``TransactionFilter``. The + // stakeholders are the union of the signatories and the observers of + // the contract. + // Each one of its elements must be a valid PartyIdString (as described + // in ``value.proto``). + // + // Required: must be non-empty + repeated string witness_parties = 5; + + // The package name of the contract. + // + // Required + string package_name = 6; + + // The interfaces implemented by the target template that have been + // matched from the interface filter query. + // Populated only in case interface filters with include_interface_view set. + // + // If defined, the identifier uses the package-id reference format. + // + // Optional: can be empty + repeated Identifier implemented_interfaces = 7; +} + +// Records that a choice has been exercised on a target contract. +message ExercisedEvent { + // The offset of origin. + // Offsets are managed by the participant nodes. + // Transactions can thus NOT be assumed to have the same offsets on different participant nodes. + // It is a valid absolute offset (positive integer) + // + // Required + int64 offset = 1; + + // The position of this event in the originating transaction or reassignment. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of transactions. + // Must be valid node ID (non-negative integer) + // + // Required + int32 node_id = 2; + + // The ID of the target contract. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string contract_id = 3; + + // Identifies the template that defines the executed choice. + // This template's package-id may differ from the target contract's package-id + // if the target contract has been upgraded or downgraded. + // + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 4; + + // The interface where the choice is defined, if inherited. + // If defined, the identifier uses the package-id reference format. + // + // Optional + Identifier interface_id = 5; + + // The choice that was exercised on the target contract. + // Must be a valid NameString (as described in ``value.proto``). + // + // Required + string choice = 6; + + // The argument of the exercised choice. + // + // Required + Value choice_argument = 7; + + // The parties that exercised the choice. + // Each element must be a valid PartyIdString (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string acting_parties = 8; + + // If true, the target contract may no longer be exercised. + // + // Required + bool consuming = 9; + + // The parties that are notified of this event. The witnesses of an exercise + // node will depend on whether the exercise was consuming or not. + // If consuming, the witnesses are the union of the stakeholders, + // the actors and all informees of all the ancestors of this event this + // participant knows about. + // If not consuming, the witnesses are the union of the signatories, + // the actors and all informees of all the ancestors of this event this + // participant knows about. + // In both cases the witnesses are limited to the querying parties, or not + // limited in case anyParty filters are used. + // Note that the actors might not necessarily be observers + // and thus stakeholders. This is the case when the controllers of a + // choice are specified using "flexible controllers", using the + // ``choice ... controller`` syntax, and said controllers are not + // explicitly marked as observers. + // Each element must be a valid PartyIdString (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string witness_parties = 10; + + // Specifies the upper boundary of the node ids of the events in the same transaction that appeared as a result of + // this ``ExercisedEvent``. This allows unambiguous identification of all the members of the subtree rooted at this + // node. A full subtree can be constructed when all descendant nodes are present in the stream. If nodes are heavily + // filtered, it is only possible to determine if a node is in a consequent subtree or not. + // + // Required + int32 last_descendant_node_id = 11; + + // The result of exercising the choice. + // + // Optional + Value exercise_result = 12; + + // The package name of the contract. + // + // Required + string package_name = 13; + + // If the event is consuming, the interfaces implemented by the target template that have been + // matched from the interface filter query. + // Populated only in case interface filters with include_interface_view set. + // + // The identifier uses the package-id reference format. + // + // Optional: can be empty + repeated Identifier implemented_interfaces = 14; + + // Whether this event would be part of respective ACS_DELTA shaped stream, + // and should therefore considered when tracking contract activeness on the client-side. + // + // Required + bool acs_delta = 15; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/event_query_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/event_query_service.proto new file mode 100644 index 00000000..1d45036b --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/event_query_service.proto @@ -0,0 +1,78 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/event.proto"; +import "com/daml/ledger/api/v2/transaction_filter.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "EventQueryServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +message GetEventsByContractIdRequest { + // The contract id being queried. + // + // Required + string contract_id = 1; + + reserved 2; + reserved "requesting_parties"; + + // Format of the events in the result, the presentation will be of TRANSACTION_SHAPE_ACS_DELTA. + // + // Required + EventFormat event_format = 3; +} + +// Query events by contract id. +// +// Note that querying by contract key is not (yet) supported, as contract keys +// are not supported (yet) in multi-synchronizer scenarios. +service EventQueryService { + // Get the create and the consuming exercise event for the contract with the provided ID. + // No events will be returned for contracts that have been pruned because they + // have already been archived before the latest pruning offset. + // If the contract cannot be found for the request, or all the contract-events are filtered, a CONTRACT_EVENTS_NOT_FOUND error will be raised. + rpc GetEventsByContractId(GetEventsByContractIdRequest) returns (GetEventsByContractIdResponse); +} + +message GetEventsByContractIdResponse { + // The create event for the contract with the ``contract_id`` given in the request + // provided it exists and has not yet been pruned. + // + // Optional + Created created = 1; + + // The archive event for the contract with the ``contract_id`` given in the request + // provided such an archive event exists and it has not yet been pruned. + // + // Optional + Archived archived = 2; +} + +message Created { + // The event as it appeared in the context of its original update (i.e. daml transaction or + // reassignment) on this participant node. You can use its offset and node_id to find the + // corresponding update and the node within it. + // + // Required + CreatedEvent created_event = 1; + + // The synchronizer which sequenced the creation of the contract + // + // Required + string synchronizer_id = 2; +} + +message Archived { + // Required + ArchivedEvent archived_event = 1; + + // The synchronizer which sequenced the archival of the contract + // + // Required + string synchronizer_id = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/experimental_features.proto b/chain/canton/proto/com/daml/ledger/api/v2/experimental_features.proto new file mode 100644 index 00000000..fa9d3803 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/experimental_features.proto @@ -0,0 +1,41 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "ExperimentalFeaturesOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +/* + IMPORTANT: in contrast to other parts of the Ledger API, only json-wire backwards + compatibility guarantees are given for the messages in this file. +*/ + +// See the feature message definitions for descriptions. +message ExperimentalFeatures { + // Optional + ExperimentalStaticTime static_time = 1; + // Optional + ExperimentalCommandInspectionService command_inspection_service = 2; +} + +// Ledger is in the static time mode and exposes a time service. +message ExperimentalStaticTime { + // Required + bool supported = 1; +} + +// Whether the Ledger API supports command inspection service +message ExperimentalCommandInspectionService { + // Required + bool supported = 1; +} + +// Whether the Ledger API supports party events +message ExperimentalPartyTopologyEvents { + // Required + bool supported = 1; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto b/chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto new file mode 100644 index 00000000..aa2ca20f --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto @@ -0,0 +1,25 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.interactive; + +import "com/daml/ledger/api/v2/value.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Interactive"; +option java_outer_classname = "InteractiveSubmissionCommonDataOuterClass"; +option java_package = "com.daml.ledger.api.v2.interactive"; + +message GlobalKey { + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 1; + // Required + string package_name = 2; + // Required + Value key = 3; + // Required: must be non-empty + bytes hash = 4; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_service.proto new file mode 100644 index 00000000..0f3104c1 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/interactive/interactive_submission_service.proto @@ -0,0 +1,770 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.interactive; + +import "com/daml/ledger/api/v2/commands.proto"; +import "com/daml/ledger/api/v2/crypto.proto"; +import "com/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto"; +import "com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto"; +import "com/daml/ledger/api/v2/package_reference.proto"; +import "com/daml/ledger/api/v2/transaction.proto"; +import "com/daml/ledger/api/v2/transaction_filter.proto"; +import "com/daml/ledger/api/v2/value.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Interactive"; +option java_outer_classname = "InteractiveSubmissionServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.interactive"; + +// Service allowing interactive construction of command submissions +// +// The prepare and execute endpoints allow to submit commands in 2-steps: +// +// 1. prepare transaction from commands, +// 2. submit the prepared transaction +// +// This gives callers the ability to sign the daml transaction with their own signing keys +service InteractiveSubmissionService { + // Requires `readAs` scope for the submitting party when LAPI User authorization is enabled + rpc PrepareSubmission(PrepareSubmissionRequest) returns (PrepareSubmissionResponse); + // Execute a prepared submission _asynchronously_ on the ledger. + // Requires a signature of the transaction from the submitting external party. + rpc ExecuteSubmission(ExecuteSubmissionRequest) returns (ExecuteSubmissionResponse); + // Similar to ExecuteSubmission but _synchronously_ wait for the completion of the transaction + // IMPORTANT: Relying on the response from this endpoint requires trusting the Participant Node to be honest. + // A malicious node could make a successfully committed request appeared failed and vice versa + rpc ExecuteSubmissionAndWait(ExecuteSubmissionAndWaitRequest) returns (ExecuteSubmissionAndWaitResponse); + // Similar to ExecuteSubmissionAndWait but additionally returns the transaction + // IMPORTANT: Relying on the response from this endpoint requires trusting the Participant Node to be honest. + // A malicious node could make a successfully committed request appear as failed and vice versa + rpc ExecuteSubmissionAndWaitForTransaction(ExecuteSubmissionAndWaitForTransactionRequest) returns (ExecuteSubmissionAndWaitForTransactionResponse); + + // A preferred package is the highest-versioned package for a provided package-name + // that is vetted by all the participants hosting the provided parties. + // + // Ledger API clients should use this endpoint for constructing command submissions + // that are compatible with the provided preferred package, by making informed decisions on: + // - which are the compatible packages that can be used to create contracts + // - which contract or exercise choice argument version can be used in the command + // - which choices can be executed on a template or interface of a contract + // + // Can be accessed by any Ledger API client with a valid token when Ledger API authorization is enabled. + // + // Provided for backwards compatibility, it will be removed in the Canton version 3.4.0 + rpc GetPreferredPackageVersion(GetPreferredPackageVersionRequest) returns (GetPreferredPackageVersionResponse); + + // Compute the preferred packages for the vetting requirements in the request. + // A preferred package is the highest-versioned package for a provided package-name + // that is vetted by all the participants hosting the provided parties. + // + // Ledger API clients should use this endpoint for constructing command submissions + // that are compatible with the provided preferred packages, by making informed decisions on: + // - which are the compatible packages that can be used to create contracts + // - which contract or exercise choice argument version can be used in the command + // - which choices can be executed on a template or interface of a contract + // + // If the package preferences could not be computed due to no selection satisfying the requirements, + // a `FAILED_PRECONDITION` error will be returned. + // + // Can be accessed by any Ledger API client with a valid token when Ledger API authorization is enabled. + // + // Experimental API: this endpoint is not guaranteed to provide backwards compatibility in future releases + rpc GetPreferredPackages(GetPreferredPackagesRequest) returns (GetPreferredPackagesResponse); +} + +// Hints to improve cost estimation precision of a prepared transaction +message CostEstimationHints { + // Disable cost estimation + // Default (not set) is false + // + // Optional + bool disabled = 1; + // Details on the keys that will be used to sign the transaction (how many and of which type). + // Signature size impacts the cost of the transaction. + // If empty, the signature sizes will be approximated with threshold-many signatures (where threshold is defined + // in the PartyToParticipant of the external party), using keys in the order they are registered. + // Empty list is equivalent to not providing this field + // + // Optional: can be empty + repeated SigningAlgorithmSpec expected_signatures = 2; +} + +// Estimation of the cost of submitting the prepared transaction +// The estimation is done against the synchronizer chosen during preparation of the transaction +// (or the one explicitly requested). +// The cost of re-assigning contracts to another synchronizer when necessary is not included in the estimation. +message CostEstimation { + // Timestamp at which the estimation was made + // + // Required + google.protobuf.Timestamp estimation_timestamp = 1; + // Estimated traffic cost of the confirmation request associated with the transaction + // + // Required + uint64 confirmation_request_traffic_cost_estimation = 2; + // Estimated traffic cost of the confirmation response associated with the transaction + // This field can also be used as an indication of the cost that other potential confirming nodes + // of the party will incur to approve or reject the transaction + // + // Required + uint64 confirmation_response_traffic_cost_estimation = 3; + // Sum of the fields above + // + // Required + uint64 total_traffic_cost_estimation = 4; +} + +message PrepareSubmissionRequest { + // Uniquely identifies the participant user that prepares the transaction. + // Must be a valid UserIdString (as described in ``value.proto``). + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + string user_id = 1; + + // Uniquely identifies the command. + // The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, + // where act_as is interpreted as a set of party names. + // The change ID can be used for matching the intended ledger changes with all their completions. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string command_id = 2; + + // Individual elements of this atomic command. Must be non-empty. + // Limitation: Only single command transaction are currently supported by the API. + // The field is marked as repeated in preparation for future support of multiple commands. + // + // Required: must be non-empty + repeated Command commands = 3; + + // Optional + MinLedgerTime min_ledger_time = 4; + + // Maximum timestamp at which the transaction can be recorded onto the ledger via the synchronizer specified in the `PrepareSubmissionResponse`. + // If submitted after it will be rejected even if otherwise valid, in which case it needs to be prepared and signed again + // with a new valid max_record_time. + // Use this to limit the time-to-life of a prepared transaction, + // which is useful to know when it can definitely not be accepted + // anymore and resorting to preparing another transaction for the same + // intent is safe again. + // + // Optional + optional google.protobuf.Timestamp max_record_time = 11; + + // Set of parties on whose behalf the command should be executed, if submitted. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to **read** (not act) on behalf of each of the given parties. This is because this RPC merely prepares a transaction + // and does not execute it. Therefore read authorization is sufficient even for actAs parties. + // Note: This may change, and more specific authorization scope may be introduced in the future. + // Each element must be a valid PartyIdString (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string act_as = 5; + + // Set of parties on whose behalf (in addition to all parties listed in ``act_as``) contracts can be retrieved. + // This affects Daml operations such as ``fetch``, ``fetchByKey``, ``lookupByKey``, ``exercise``, and ``exerciseByKey``. + // Note: A command can only use contracts that are visible to at least + // one of the parties in ``act_as`` or ``read_as``. This visibility check is independent from the Daml authorization + // rules for fetch operations. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to read contract data on behalf of each of the given parties. + // + // Optional: can be empty + repeated string read_as = 6; + + // Additional contracts used to resolve contract & contract key lookups. + // + // Optional: can be empty + repeated DisclosedContract disclosed_contracts = 7; + + // Must be a valid synchronizer id + // If not set, a suitable synchronizer that this node is connected to will be chosen + // + // Optional + string synchronizer_id = 8; + + // The package-id selection preference of the client for resolving + // package names and interface instances in command submission and interpretation + // + // Optional: can be empty + repeated string package_id_selection_preference = 9; + + // When true, the response will contain additional details on how the transaction was encoded and hashed + // This can be useful for troubleshooting of hash mismatches. Should only be used for debugging. + // Defaults to false + // + // Optional + bool verbose_hashing = 10; + + // Fetches the contract keys into the caches to speed up the command processing. + // Should only contain contract keys that are expected to be resolved during interpretation of the commands. + // Keys of disclosed contracts do not need prefetching. + // + // Optional: can be empty + repeated PrefetchContractKey prefetch_contract_keys = 15; + + // Hints to improve the accuracy of traffic cost estimation. + // The estimation logic assumes that this node will be used for the execution of the transaction + // If another node is used instead, the estimation may be less precise. + // Request amplification is not accounted for in the estimation: each amplified request will + // result in the cost of the confirmation request to be charged additionally. + // + // Traffic cost estimation is enabled by default if this field is not set + // To turn off cost estimation, set the CostEstimationHints#disabled field to true + // + // Optional + optional CostEstimationHints estimate_traffic_cost = 16; + + // The hashing scheme version to be used when building the hash. + // Defaults to HASHING_SCHEME_VERSION_V2. + // + // Optional + optional HashingSchemeVersion hashing_scheme_version = 17; + + // The maximum number of passes for the Topology-Aware Package Selection (TAPS). + // Higher values can increase the chance of successful package selection for routing of interpreted transactions. + // If unset, this defaults to the value defined in the participant configuration. + // The provided value must not exceed the limit specified in the participant configuration. + // + // Optional + optional uint32 taps_max_passes = 18; +} + +// [docs-entry-start: HashingSchemeVersion] +// The hashing scheme version used when building the hash of the PreparedTransaction +enum HashingSchemeVersion { + HASHING_SCHEME_VERSION_UNSPECIFIED = 0; + reserved 1; // Hashing Scheme V1 - unsupported + HASHING_SCHEME_VERSION_V2 = 2; + HASHING_SCHEME_VERSION_V3 = 3; +} +// [docs-entry-end: HashingSchemeVersion] + +message PrepareSubmissionResponse { + // The interpreted transaction, it represents the ledger changes necessary to execute the commands specified in the request. + // Clients MUST display the content of the transaction to the user for them to validate before signing the hash if the preparing participant is not trusted. + // + // Required + PreparedTransaction prepared_transaction = 1; + // Hash of the transaction, this is what needs to be signed by the party to authorize the transaction. + // Only provided for convenience, clients MUST recompute the hash from the raw transaction if the preparing participant is not trusted. + // May be removed in future versions + // + // Required: must be non-empty + bytes prepared_transaction_hash = 2; + + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion hashing_scheme_version = 3; + + // Optional additional details on how the transaction was encoded and hashed. Only set if verbose_hashing = true in the request + // Note that there are no guarantees on the stability of the format or content of this field. + // Its content should NOT be parsed and should only be used for troubleshooting purposes. + // + // Optional + optional string hashing_details = 4; + + // Traffic cost estimation of the prepared transaction + // + // Optional + optional CostEstimation cost_estimation = 5; +} + +// Signatures provided by a single party +message SinglePartySignatures { + // Submitting party + // + // Required + string party = 1; + // Signatures + // + // Required: must be non-empty + repeated Signature signatures = 2; +} + +// Additional signatures provided by the submitting parties +message PartySignatures { + // Additional signatures provided by all individual parties + // + // Required: must be non-empty + repeated SinglePartySignatures signatures = 1; +} + +message ExecuteSubmissionRequest { + // the prepared transaction + // Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` + // obtained from calling `prepareSubmission`. + // + // Required + PreparedTransaction prepared_transaction = 1; + + // The party(ies) signatures that authorize the prepared submission to be executed by this node. + // Each party can provide one or more signatures.. + // and one or more parties can sign. + // Note that currently, only single party submissions are supported. + // + // Required + PartySignatures party_signatures = 2; + + // Specifies the deduplication period for the change ID (See PrepareSubmissionRequest). + // If omitted, the participant will assume the configured maximum deduplication time. + // + // Optional + oneof deduplication_period { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + google.protobuf.Duration deduplication_duration = 3; + + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer). + int64 deduplication_offset = 4; + } + + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string submission_id = 5; + + // See [PrepareSubmissionRequest.user_id] + // + // Optional + string user_id = 6; + + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion hashing_scheme_version = 7; + + // If set will influence the chosen ledger effective time but will not result in a submission delay so any override + // should be scheduled to executed within the window allowed by synchronizer. + // + // Optional + MinLedgerTime min_ledger_time = 8; +} + +message ExecuteSubmissionResponse {} + +message ExecuteSubmissionAndWaitRequest { + // the prepared transaction + // Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` + // obtained from calling `prepareSubmission`. + // + // Required + PreparedTransaction prepared_transaction = 1; + + // The party(ies) signatures that authorize the prepared submission to be executed by this node. + // Each party can provide one or more signatures.. + // and one or more parties can sign. + // Note that currently, only single party submissions are supported. + // + // Required + PartySignatures party_signatures = 2; + + // Specifies the deduplication period for the change ID (See PrepareSubmissionRequest). + // If omitted, the participant will assume the configured maximum deduplication time. + // + // Optional + oneof deduplication_period { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + google.protobuf.Duration deduplication_duration = 3; + + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer). + int64 deduplication_offset = 4; + } + + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string submission_id = 5; + + // See [PrepareSubmissionRequest.user_id] + // + // Optional + string user_id = 6; + + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion hashing_scheme_version = 7; + + // If set will influence the chosen ledger effective time but will not result in a submission delay so any override + // should be scheduled to executed within the window allowed by synchronizer. + // + // Optional + MinLedgerTime min_ledger_time = 8; +} + +message ExecuteSubmissionAndWaitResponse { + // The id of the transaction that resulted from the submitted command. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string update_id = 1; + + // The details of the offset field are described in ``community/ledger-api/README.md``. + // + // Required + int64 completion_offset = 2; +} + +message ExecuteSubmissionAndWaitForTransactionRequest { + // the prepared transaction + // Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` + // obtained from calling `prepareSubmission`. + // + // Required + PreparedTransaction prepared_transaction = 1; + + // The party(ies) signatures that authorize the prepared submission to be executed by this node. + // Each party can provide one or more signatures.. + // and one or more parties can sign. + // Note that currently, only single party submissions are supported. + // + // Required + PartySignatures party_signatures = 2; + + // Specifies the deduplication period for the change ID (See PrepareSubmissionRequest). + // If omitted, the participant will assume the configured maximum deduplication time. + // + // Optional + oneof deduplication_period { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + google.protobuf.Duration deduplication_duration = 3; + + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer). + int64 deduplication_offset = 4; + } + + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string submission_id = 5; + + // See [PrepareSubmissionRequest.user_id] + // + // Optional + string user_id = 6; + + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion hashing_scheme_version = 7; + + // If set will influence the chosen ledger effective time but will not result in a submission delay so any override + // should be scheduled to executed within the window allowed by synchronizer. + // + // Optional + MinLedgerTime min_ledger_time = 8; + + // If no ``transaction_format`` is provided, a default will be used where ``transaction_shape`` is set to + // TRANSACTION_SHAPE_ACS_DELTA, ``event_format`` is defined with ``filters_by_party`` containing wildcard-template + // filter for all original ``act_as`` and ``read_as`` parties and the ``verbose`` flag is set. + // When the ``transaction_shape`` TRANSACTION_SHAPE_ACS_DELTA shape is used (explicitly or is defaulted to as explained above), + // events will only be returned if the submitting party is hosted on this node. + // + // Optional + TransactionFormat transaction_format = 9; +} + +message ExecuteSubmissionAndWaitForTransactionResponse { + // The transaction that resulted from the submitted command. + // The transaction might contain no events (request conditions result in filtering out all of them). + // + // Required + Transaction transaction = 1; +} + +message MinLedgerTime { + // Required + oneof time { + // Lower bound for the ledger time assigned to the resulting transaction. + // The ledger time of a transaction is assigned as part of command interpretation. + // Important note: for interactive submissions, if the transaction depends on time, it **must** be signed + // and submitted within a time window around the ledger time assigned to the transaction during the prepare method. + // The time delta around that ledger time is a configuration of the ledger, usually short, around 1 minute. + // If however the transaction does not depend on time, the available time window to sign and submit the transaction is bound + // by the preparation time, which is also assigned in the "prepare" step (this request), + // but can be configured with a much larger skew, allowing for more time to sign the request (in the order of hours). + // Must not be set at the same time as min_ledger_time_rel. + // Optional + google.protobuf.Timestamp min_ledger_time_abs = 1; + + // Same as min_ledger_time_abs, but specified as a duration, starting from the time this request is received by the server. + // Must not be set at the same time as min_ledger_time_abs. + // Optional + google.protobuf.Duration min_ledger_time_rel = 2; + } +} + +/** + * Prepared Transaction Message + */ +message PreparedTransaction { + // Daml Transaction representing the ledger effect if executed. See below + // + // Required + DamlTransaction transaction = 1; + // Metadata context necessary to execute the transaction + // + // Required + Metadata metadata = 2; +} + +// Transaction Metadata +// Refer to the hashing documentation for information on how it should be hashed. +message Metadata { + message SubmitterInfo { + // Required: must be non-empty + repeated string act_as = 1; + // Required + string command_id = 2; + } + + message GlobalKeyMappingEntry { + // Required + interactive.GlobalKey key = 1; + // Optional + optional Value value = 2; + } + + message InputContract { + // Required + oneof contract { + // When new versions will be added, they will show here + interactive.transaction.v1.Create v1 = 1; + } + // Required + uint64 created_at = 1000; + reserved 1001; // Used to contain driver_metadata, now contained in event_blob + // Required: must be non-empty + bytes event_blob = 1002; + } + + /* ************************************************** */ + /* ** Metadata information that needs to be signed ** */ + /* ************************************************** */ + + // this used to contain the ledger effective time + reserved 1; + + // Required + SubmitterInfo submitter_info = 2; + // Required + string synchronizer_id = 3; + // Required + uint32 mediator_group = 4; + // Required + string transaction_uuid = 5; + // Required + uint64 preparation_time = 6; + // Not populated if the transaction has no input contracts + // + // Optional: can be empty + repeated InputContract input_contracts = 7; + + /* + * Where ledger time constraints are imposed during the execution of the contract they will be populated + * in the fields below. These are optional because if the transaction does NOT depend on time, these values + * do not need to be set. + * The final ledger effective time used will be chosen when the command is submitted through the [execute] RPC. + * If the ledger effective time is outside of any populated min/max bounds then a different transaction + * can result, that will cause a confirmation message rejection. + */ + // Optional + optional uint64 min_ledger_effective_time = 9; + // Optional + optional uint64 max_ledger_effective_time = 10; + + /* ********************************************************** */ + /* ** Metadata information that does NOT need to be signed ** */ + /* ********************************************************** */ + + // Contextual information needed to process the transaction but not signed, either because it's already indirectly + // signed by signing the transaction, or because it doesn't impact the ledger state + // + // Optional: can be empty + repeated GlobalKeyMappingEntry global_key_mapping = 8; + + // Maximum timestamp at which the transaction can be recorded onto the ledger via the synchronizer `synchronizer_id`. + // If submitted after it will be rejected even if otherwise valid, in which case it needs to be prepared and signed again + // with a new valid max_record_time. + // Unsigned in 3.3 to avoid a breaking protocol change + // Will be signed in 3.4+ + // Set max_record_time in the PreparedTransactionRequest to get this field set accordingly + // + // Optional + optional uint64 max_record_time = 11; +} + +/* + * Daml Transaction. + * This represents the effect on the ledger if this transaction is successfully committed. + */ +message DamlTransaction { + message NodeSeed { + // Required + int32 node_id = 1; + // Required: must be non-empty + bytes seed = 2; + } + + // A transaction may contain nodes with different versions. + // Each node must be hashed using the hashing algorithm corresponding to its specific version. + // [docs-entry-start: DamlTransaction.Node] + message Node { + // Required + string node_id = 1; + + // Versioned node + // + // Required + oneof versioned_node { + // Start at 1000 so we can add more fields before if necessary + // When new versions will be added, they will show here + // + // Required + interactive.transaction.v1.Node v1 = 1000; + } + } + // [docs-entry-end: DamlTransaction.Node] + + // serialization version, will be >= max(nodes version) + // + // Required + string version = 1; + // Root nodes of the transaction + // + // Required: must be non-empty + repeated string roots = 2; + // List of nodes in the transaction + // + // Required: must be non-empty + repeated Node nodes = 3; + // Node seeds are values associated with certain nodes used for generating cryptographic salts + // + // Required: must be non-empty + repeated NodeSeed node_seeds = 4; +} + +message GetPreferredPackageVersionRequest { + // The parties whose participants' vetting state should be considered when resolving the preferred package. + // + // Required: must be non-empty + repeated string parties = 1; + // The package-name for which the preferred package should be resolved. + // + // Required + string package_name = 2; + + // The synchronizer whose vetting state should be used for resolving this query. + // If not specified, the vetting states of all synchronizers to which the participant is connected are used. + // + // Optional + string synchronizer_id = 3; + + // The timestamp at which the package vetting validity should be computed + // on the latest topology snapshot as seen by the participant. + // If not provided, the participant's current clock time is used. + // + // Optional + google.protobuf.Timestamp vetting_valid_at = 4; +} + +message GetPreferredPackageVersionResponse { + // Not populated when no preferred package is found + // + // Optional + PackagePreference package_preference = 1; +} + +message PackagePreference { + // The package reference of the preferred package. + // + // Required + PackageReference package_reference = 1; + + // The synchronizer for which the preferred package was computed. + // If the synchronizer_id was specified in the request, then it matches the request synchronizer_id. + // + // Required + string synchronizer_id = 2; +} + +// Defines a package-name for which the commonly vetted package with the highest version must be found. +message PackageVettingRequirement { + // The parties whose participants' vetting state should be considered when resolving the preferred package. + // + // Required: must be non-empty + repeated string parties = 1; + + // The package-name for which the preferred package should be resolved. + // + // Required + string package_name = 2; +} + +message GetPreferredPackagesRequest { + // The package-name vetting requirements for which the preferred packages should be resolved. + // + // Generally it is enough to provide the requirements for the intended command's root package-names. + // Additional package-name requirements can be provided when additional Daml transaction informees need to use + // package dependencies of the command's root packages. + // + // Required: must be non-empty + repeated PackageVettingRequirement package_vetting_requirements = 1; + + // The synchronizer whose vetting state should be used for resolving this query. + // If not specified, the vetting states of all synchronizers to which the participant is connected are used. + // + // Optional + string synchronizer_id = 2; + + // The timestamp at which the package vetting validity should be computed + // on the latest topology snapshot as seen by the participant. + // If not provided, the participant's current clock time is used. + // + // Optional + google.protobuf.Timestamp vetting_valid_at = 3; +} + +message GetPreferredPackagesResponse { + // The package references of the preferred packages. + // Must contain one package reference for each requested package-name. + // + // If you build command submissions whose content depends on the returned + // preferred packages, then we recommend submitting the preferred package-ids + // in the ``package_id_selection_preference`` of the command submission to + // avoid race conditions with concurrent changes of the on-ledger package vetting state. + // + // Required: must be non-empty + repeated PackageReference package_references = 1; + + // The synchronizer for which the package preferences are computed. + // If the synchronizer_id was specified in the request, then it matches the request synchronizer_id. + // + // Required + string synchronizer_id = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto b/chain/canton/proto/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto new file mode 100644 index 00000000..9621c447 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto @@ -0,0 +1,116 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.interactive.transaction.v1; + +import "com/daml/ledger/api/v2/value.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Interactive.Transaction.V1"; +option java_outer_classname = "InteractiveSubmissionDataOuterClass"; +option java_package = "com.daml.ledger.api.v2.interactive.transaction.v1"; + +/* + * Transaction Nodes + */ + +// Fetch node +message Fetch { + // Specific LF version of the node + // + // Required + string lf_version = 1; + // Required + string contract_id = 2; + // Required + string package_name = 3; + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 4; + // Required: must be non-empty + repeated string signatories = 5; + // Required: must be non-empty + repeated string stakeholders = 6; + // Required: must be non-empty + repeated string acting_parties = 7; + // Optional + Identifier interface_id = 8; +} + +// Exercise node +message Exercise { + // Specific LF version of the node + // + // Required + string lf_version = 1; + // Required + string contract_id = 2; + // Required + string package_name = 3; + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 4; + // Required: must be non-empty + repeated string signatories = 5; + // Required: must be non-empty + repeated string stakeholders = 6; + // Required: must be non-empty + repeated string acting_parties = 7; + // The identifier uses the package-id reference format. + // + // Optional + Identifier interface_id = 8; + // Required + string choice_id = 9; + // Required + Value chosen_value = 10; + // Required + bool consuming = 11; + // Optional: can be empty + repeated string children = 12; + // Optional + Value exercise_result = 13; + // Optional: can be empty + repeated string choice_observers = 14; +} + +// Create Node +message Create { + // Specific LF version of the node + // + // Required + string lf_version = 1; + // Required + string contract_id = 2; + // Required + string package_name = 3; + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 4; + // Required + Value argument = 5; + // Required: must be non-empty + repeated string signatories = 6; + // Required: must be non-empty + repeated string stakeholders = 7; +} + +// Rollback Node +message Rollback { + // Required: must be non-empty + repeated string children = 1; +} + +message Node { + // Required + oneof node_type { + Create create = 1; + Fetch fetch = 2; + Exercise exercise = 3; + Rollback rollback = 4; + } +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/offset_checkpoint.proto b/chain/canton/proto/com/daml/ledger/api/v2/offset_checkpoint.proto new file mode 100644 index 00000000..6bf4a760 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/offset_checkpoint.proto @@ -0,0 +1,39 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "OffsetCheckpointOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// OffsetCheckpoints may be used to: +// +// - detect time out of commands. +// - provide an offset which can be used to restart consumption. +message OffsetCheckpoint { + // The participant's offset, the details of the offset field are described in ``community/ledger-api/README.md``. + // Must be a valid absolute offset (positive integer). + // + // Required + int64 offset = 1; + // The times associated with each synchronizer at this offset. + // + // Optional: can be empty + repeated SynchronizerTime synchronizer_times = 2; +} + +message SynchronizerTime { + // The id of the synchronizer. + // + // Required + string synchronizer_id = 1; + // All commands with a maximum record time below this value MUST be considered lost if their completion has not arrived before this checkpoint. + // + // Required + google.protobuf.Timestamp record_time = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/package_reference.proto b/chain/canton/proto/com/daml/ledger/api/v2/package_reference.proto new file mode 100644 index 00000000..8576c820 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/package_reference.proto @@ -0,0 +1,96 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "PackageReferenceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +message PackageReference { + // Required + string package_id = 1; + // Required + string package_name = 2; + // Required + string package_version = 3; +} + +// A package that is vetting on a given participant and synchronizer, +// modelled after ``VettedPackage`` in `topology.proto `_, +// enriched with the package name and version. +message VettedPackage { + // Package ID of this package + // + // Required + string package_id = 1; + + // The time from which this package is vetted. Empty if vetting time has no + // lower bound. + // + // Optional + google.protobuf.Timestamp valid_from_inclusive = 2; + + // The time until which this package is vetted. Empty if vetting time has no + // upper bound. + // + // Optional + google.protobuf.Timestamp valid_until_exclusive = 3; + + // Name of this package. + // Only available if the package has been uploaded to the current participant. + // + // Optional + string package_name = 4; + + // Version of this package. + // Only available if the package has been uploaded to the current participant. + // + // Optional + string package_version = 5; +} + +// The list of packages vetted on a given participant and synchronizer, modelled +// after ``VettedPackages`` in `topology.proto `_. +// The list only contains packages that matched a filter in the query that +// originated it. +message VettedPackages { + // Sorted by package_name and package_version where known, and package_id as a + // last resort. + // + // Required: must be non-empty + repeated VettedPackage packages = 1; + + // Participant on which these packages are vetted. + // + // Required + string participant_id = 2; + + // Synchronizer on which these packages are vetted. + // + // Required + string synchronizer_id = 3; + + // Serial of last ``VettedPackages`` topology transaction of this participant + // and on this synchronizer. + // + // Required + uint32 topology_serial = 4; +} + +// The serial of last ``VettedPackages`` topology transaction on a given +// participant and synchronizer. +message PriorTopologySerial { + // Optional + oneof serial { + // Previous transaction's serial. + uint32 prior = 1; + // No previous transaction exists. + google.protobuf.Empty no_prior = 2; + } +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/package_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/package_service.proto new file mode 100644 index 00000000..f015a8a9 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/package_service.proto @@ -0,0 +1,194 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/package_reference.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "PackageServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +message ListPackagesResponse { + // The IDs of all Daml-LF packages supported by the server. + // Each element must be a valid PackageIdString (as described in ``value.proto``). + // + // Required: must be non-empty + repeated string package_ids = 1; +} + +message GetPackageResponse { + // The hash function we use to calculate the hash. + // + // Required + HashFunction hash_function = 1; + + // Contains a ``daml_lf`` ArchivePayload. See further details in ``daml_lf.proto``. + // + // Required: must be non-empty + bytes archive_payload = 2; + + // The hash of the archive payload, can also used as a ``package_id``. + // Must be a valid PackageIdString (as described in ``value.proto``). + // + // Required + string hash = 3; +} + +message GetPackageStatusResponse { + // The status of the package. + // + // Required + PackageStatus package_status = 1; +} + +enum PackageStatus { + // The server is not aware of such a package. + PACKAGE_STATUS_UNSPECIFIED = 0; + + // The server is able to execute Daml commands operating on this package. + PACKAGE_STATUS_REGISTERED = 1; +} + +enum HashFunction { + HASH_FUNCTION_SHA256 = 0; +} + +// Allows clients to query the Daml-LF packages that are supported by the server. +service PackageService { + // Returns the identifiers of all supported packages. + rpc ListPackages(ListPackagesRequest) returns (ListPackagesResponse); + + // Returns the contents of a single package. + rpc GetPackage(GetPackageRequest) returns (GetPackageResponse); + + // Returns the status of a single package. + rpc GetPackageStatus(GetPackageStatusRequest) returns (GetPackageStatusResponse); + + // Lists which participant node vetted what packages on which synchronizer. + // Can be called by any authenticated user. + rpc ListVettedPackages(ListVettedPackagesRequest) returns (ListVettedPackagesResponse); +} + +message ListPackagesRequest {} + +message GetPackageRequest { + // The ID of the requested package. + // Must be a valid PackageIdString (as described in ``value.proto``). + // + // Required + string package_id = 1; +} + +message GetPackageStatusRequest { + // The ID of the requested package. + // Must be a valid PackageIdString (as described in ``value.proto``). + // + // Required + string package_id = 1; +} + +// Filter the VettedPackages by package metadata. +// +// A PackageMetadataFilter without package_ids and without package_name_prefixes +// matches any vetted package. +// +// Non-empty fields specify candidate values of which at least one must match. +// If both fields are set, then a candidate is returned if it matches one of the fields. +message PackageMetadataFilter { + // If this list is non-empty, any vetted package with a package ID in this + // list will match the filter. + // + // Optional: can be empty + repeated string package_ids = 1; + + // If this list is non-empty, any vetted package with a name matching at least + // one prefix in this list will match the filter. + // + // Optional: can be empty + repeated string package_name_prefixes = 2; +} + +// Filter the vetted packages by the participant and synchronizer that they are +// hosted on. +// +// Empty fields are ignored, such that a ``TopologyStateFilter`` without +// participant_ids and without synchronizer_ids matches a vetted package hosted +// on any participant and synchronizer. +// +// Non-empty fields specify candidate values of which at least one must match. +// If both fields are set then at least one candidate value must match from each +// field. +message TopologyStateFilter { + // If this list is non-empty, only vetted packages hosted on participants + // listed in this field match the filter. + // Query the current Ledger API's participant's ID via the public + // ``GetParticipantId`` command in ``PartyManagementService``. + // + // Optional: can be empty + repeated string participant_ids = 1; + + // If this list is non-empty, only vetted packages from the topology state of + // the synchronizers in this list match the filter. + // + // Optional: can be empty + repeated string synchronizer_ids = 2; +} + +message ListVettedPackagesRequest { + // The package metadata filter the returned vetted packages set must satisfy. + // + // Optional + PackageMetadataFilter package_metadata_filter = 1; + + // The topology filter the returned vetted packages set must satisfy. + // + // Optional + TopologyStateFilter topology_state_filter = 2; + + // Pagination token to determine the specific page to fetch. Using the token + // guarantees that ``VettedPackages`` on a subsequent page are all greater + // (``VettedPackages`` are sorted by synchronizer ID then participant ID) than + // the last ``VettedPackages`` on a previous page. + // + // The server does not store intermediate results between calls chained by a + // series of page tokens. As a consequence, if new vetted packages are being + // added and a page is requested twice using the same token, more packages can + // be returned on the second call. + // + // Leave unspecified (i.e. as empty string) to fetch the first page. + // + // Optional + string page_token = 3; + + // Maximum number of ``VettedPackages`` results to return in a single page. + // + // If the page_size is unspecified (i.e. left as 0), the server will decide + // the number of results to be returned. + // + // If the page_size exceeds the maximum supported by the server, an + // error will be returned. + // + // To obtain the server's maximum consult the PackageService descriptor + // available in the VersionService. + // + // Optional + uint32 page_size = 4; +} + +message ListVettedPackagesResponse { + // All ``VettedPackages`` that contain at least one ``VettedPackage`` matching + // both a ``PackageMetadataFilter`` and a ``TopologyStateFilter``. + // Sorted by synchronizer_id then participant_id. + // + // Optional: can be empty + repeated VettedPackages vetted_packages = 1; + + // Pagination token to retrieve the next page. + // Empty string if there are no further results. + // + // Optional + string next_page_token = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/reassignment.proto b/chain/canton/proto/com/daml/ledger/api/v2/reassignment.proto new file mode 100644 index 00000000..ea2fc1a8 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/reassignment.proto @@ -0,0 +1,202 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/event.proto"; +import "com/daml/ledger/api/v2/trace_context.proto"; +import "com/daml/ledger/api/v2/value.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "ReassignmentOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Complete view of an on-ledger reassignment. +message Reassignment { + // Assigned by the server. Useful for correlating logs. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string update_id = 1; + + // The ID of the command which resulted in this reassignment. Missing for everyone except the submitting party on the submitting participant. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string command_id = 2; + + // The workflow ID used in reassignment command submission. Only set if the ``workflow_id`` for the command was set. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string workflow_id = 3; + + // The participant's offset. The details of this field are described in ``community/ledger-api/README.md``. + // Must be a valid absolute offset (positive integer). + // + // Required + int64 offset = 4; + + // The collection of reassignment events. + // + // Required: must be non-empty + repeated ReassignmentEvent events = 5; + + // Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + TraceContext trace_context = 6; + + // The time at which the reassignment was recorded. The record time refers to the source/target + // synchronizer for an unassign/assign event respectively. + // + // Required + google.protobuf.Timestamp record_time = 7; + + // A valid synchronizer id. + // Identifies the synchronizer that synchronized this Reassignment. + // + // Required + string synchronizer_id = 8; +} + +message ReassignmentEvent { + // Required + oneof event { + UnassignedEvent unassigned = 1; + AssignedEvent assigned = 2; + } +} + +// Records that a contract has been unassigned, and it becomes unusable on the source synchronizer +message UnassignedEvent { + // The ID of the unassignment. This needs to be used as an input for a assign ReassignmentCommand. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string reassignment_id = 1; + + // The ID of the reassigned contract. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string contract_id = 2; + + // The template of the reassigned contract. + // The identifier uses the package-id reference format. + // + // Required + Identifier template_id = 3; + + // The ID of the source synchronizer + // Must be a valid synchronizer id + // + // Required + string source = 4; + + // The ID of the target synchronizer + // Must be a valid synchronizer id + // + // Required + string target = 5; + + // Party on whose behalf the unassign command was executed. + // Empty if the unassignment happened offline via the repair service. + // Must be a valid PartyIdString (as described in ``value.proto``). + // + // Optional + string submitter = 6; + + // Each corresponding assigned and unassigned event has the same reassignment_counter. This strictly increases + // with each unassign command for the same contract. Creation of the contract corresponds to reassignment_counter + // equals zero. + // + // Required + uint64 reassignment_counter = 7; + + // Assignment exclusivity + // Before this time (measured on the target synchronizer), only the submitter of the unassignment can initiate the assignment + // Defined for reassigning participants. + // + // Optional + google.protobuf.Timestamp assignment_exclusivity = 8; + + // The parties that are notified of this event. + // + // Required: must be non-empty + repeated string witness_parties = 9; + + // The package name of the contract. + // + // Required + string package_name = 10; + + // The offset of origin. + // Offsets are managed by the participant nodes. + // Reassignments can thus NOT be assumed to have the same offsets on different participant nodes. + // Must be a valid absolute offset (positive integer) + // + // Required + int64 offset = 11; + + // The position of this event in the originating reassignment. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of reassignments. + // Must be valid node ID (non-negative integer) + // + // Required + int32 node_id = 12; +} + +// Records that a contract has been assigned, and it can be used on the target synchronizer. +message AssignedEvent { + // The ID of the source synchronizer. + // Must be a valid synchronizer id. + // + // Required + string source = 1; + + // The ID of the target synchronizer. + // Must be a valid synchronizer id. + // + // Required + string target = 2; + + // The ID from the unassigned event. + // For correlation capabilities. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string reassignment_id = 3; + + // Party on whose behalf the assign command was executed. + // Empty if the assignment happened offline via the repair service. + // Must be a valid PartyIdString (as described in ``value.proto``). + // + // Optional + string submitter = 4; + + // Each corresponding assigned and unassigned event has the same reassignment_counter. This strictly increases + // with each unassign command for the same contract. Creation of the contract corresponds to reassignment_counter + // equals zero. + // + // Required + uint64 reassignment_counter = 5; + + // The offset of this event refers to the offset of the assignment, + // while the node_id is the index of within the batch. + // + // Required + CreatedEvent created_event = 6; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/reassignment_commands.proto b/chain/canton/proto/com/daml/ledger/api/v2/reassignment_commands.proto new file mode 100644 index 00000000..eb01f7ae --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/reassignment_commands.proto @@ -0,0 +1,107 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "ReassignmentCommandOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +message ReassignmentCommands { + // Identifier of the on-ledger workflow that this command is a part of. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string workflow_id = 1; + + // Uniquely identifies the participant user that issued the command. + // Must be a valid UserIdString (as described in ``value.proto``). + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + string user_id = 2; + + // Uniquely identifies the command. + // The triple (user_id, submitter, command_id) constitutes the change ID for the intended ledger change. + // The change ID can be used for matching the intended ledger changes with all their completions. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string command_id = 3; + + // Party on whose behalf the command should be executed. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to act on behalf of the given party. + // Must be a valid PartyIdString (as described in ``value.proto``). + // + // Required + string submitter = 4; + + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // If omitted, the participant or the committer may set a value of their choice. + // + // Optional + string submission_id = 5; + + // Individual elements of this reassignment. Must be non-empty. + // + // Required: must be non-empty + repeated ReassignmentCommand commands = 6; +} + +message ReassignmentCommand { + // Required + oneof command { + UnassignCommand unassign_command = 1; + AssignCommand assign_command = 2; + } +} + +// Unassign a contract +message UnassignCommand { + // The ID of the contract the client wants to unassign. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string contract_id = 1; + + // The ID of the source synchronizer + // Must be a valid synchronizer id + // + // Required + string source = 2; + + // The ID of the target synchronizer + // Must be a valid synchronizer id + // + // Required + string target = 3; +} + +// Assign a contract +message AssignCommand { + // The ID from the unassigned event to be completed by this assignment. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string reassignment_id = 1; + + // The ID of the source synchronizer + // Must be a valid synchronizer id + // + // Required + string source = 2; + + // The ID of the target synchronizer + // Must be a valid synchronizer id + // + // Required + string target = 3; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/state_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/state_service.proto new file mode 100644 index 00000000..16dc3818 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/state_service.proto @@ -0,0 +1,256 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/event.proto"; +import "com/daml/ledger/api/v2/reassignment.proto"; +import "com/daml/ledger/api/v2/transaction_filter.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "StateServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Allows clients to get state from the ledger. +service StateService { + // Returns a stream of the snapshot of the active contracts and incomplete (un)assignments at a ledger offset. + // Once the stream of GetActiveContractsResponses completes, + // the client SHOULD begin streaming updates from the update service, + // starting at the GetActiveContractsRequest.active_at_offset specified in this request. + // Clients SHOULD NOT assume that the set of active contracts they receive reflects the state at the ledger end. + rpc GetActiveContracts(GetActiveContractsRequest) returns (stream GetActiveContractsResponse); + + // Get the list of connected synchronizers at the time of the query. + rpc GetConnectedSynchronizers(GetConnectedSynchronizersRequest) returns (GetConnectedSynchronizersResponse); + + // Get the current ledger end. + // Subscriptions started with the returned offset will serve events after this RPC was called. + rpc GetLedgerEnd(GetLedgerEndRequest) returns (GetLedgerEndResponse); + + // Get the latest successfully pruned ledger offsets + rpc GetLatestPrunedOffsets(GetLatestPrunedOffsetsRequest) returns (GetLatestPrunedOffsetsResponse); +} + +// If the given offset is different than the ledger end, and there are (un)assignments in-flight at the given offset, +// the snapshot may fail with "FAILED_PRECONDITION/PARTICIPANT_PRUNED_DATA_ACCESSED". +// Note that it is ok to request acs snapshots for party migration with offsets other than ledger end, because party +// migration is not concerned with incomplete (un)assignments. +message GetActiveContractsRequest { + reserved 1; + reserved "filter"; + + reserved 2; + reserved "verbose"; + + // The offset at which the snapshot of the active contracts will be computed. + // Must be no greater than the current ledger end offset. + // Must be greater than or equal to the last pruning offset. + // Must be a valid absolute offset (positive integer) or ledger begin offset (zero). + // If zero, the empty set will be returned. + // + // Required + int64 active_at_offset = 3; + + // Format of the contract_entries in the result. In case of CreatedEvent the presentation will be of + // TRANSACTION_SHAPE_ACS_DELTA. + // + // Required + EventFormat event_format = 4; + + // Opaque representation of a continuation token defining a position in the active contracts snapshot. + // The prefix of the active contracts snapshot will be omitted up to and including the element from which + // the continuation token was read. + // To reuse the continuation token from a `GetActiveContractsPageResponse`: + // + // - subsequent request must be executed on the same participant with the same version of canton, + // - subsequent request must have the same active_at_offset, + // - subsequent request must have the same event_format + // - and the participant must not have been pruned after the active_at_offset. + // + // If not specified, the whole active contracts snapshot will be returned. + // + // Optional: can be empty + optional bytes stream_continuation_token = 5; +} + +message GetActiveContractsResponse { + // The workflow ID used in command submission which corresponds to the contract_entry. Only set if + // the ``workflow_id`` for the command was set. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string workflow_id = 1; + + // For a contract there could be multiple contract_entry-s in the entire snapshot. These together define + // the state of one contract in the snapshot. + // A contract_entry is included in the result, if and only if there is at least one stakeholder party of the contract + // that is hosted on the synchronizer at the time of the event and the party satisfies the + // ``TransactionFilter`` in the query. + // + // Required + oneof contract_entry { + // The contract is active on the assigned synchronizer, meaning: there was an activation event on the given synchronizer ( + // created, assigned), which is not followed by a deactivation event (archived, unassigned) on the same + // synchronizer, until the active_at_offset. + // Since activeness is defined as a per synchronizer concept, it is possible, that a contract is active on one + // synchronizer, but already archived on another. + // There will be one such message for each synchronizer the contract is active on. + ActiveContract active_contract = 2; + + // Included iff the unassigned event was before or at the active_at_offset, but there was no corresponding + // assigned event before or at the active_at_offset. + IncompleteUnassigned incomplete_unassigned = 3; + + // Important: this message is not indicating that the contract is active on the target synchronizer! + // Included iff the assigned event was before or at the active_at_offset, but there was no corresponding + // unassigned event before or at the active_at_offset. + IncompleteAssigned incomplete_assigned = 4; + } + + // Opaque representation of a continuation token which can be used in the request to bypass the already processed part + // of the active contracts snapshot. + // Only populated for the streaming ``GetActiveContracts`` rpc call. + // + // Optional: can be empty + bytes stream_continuation_token = 5; +} + +message ActiveContract { + // The event as it appeared in the context of its last update (i.e. daml transaction or + // reassignment). In particular, the last offset, node_id pair is preserved. + // The last update is the most recent update created or assigned this contract on synchronizer_id synchronizer. + // The offset of the CreatedEvent might point to an already pruned update, therefore it cannot necessarily be used + // for lookups. + // + // Required + CreatedEvent created_event = 1; + + // A valid synchronizer id + // + // Required + string synchronizer_id = 2; + + // Each corresponding assigned and unassigned event has the same reassignment_counter. This strictly increases + // with each unassign command for the same contract. Creation of the contract corresponds to reassignment_counter + // equals zero. + // This field will be the reassignment_counter of the latest observable activation event on this synchronizer, which is + // before the active_at_offset. + // + // Required + uint64 reassignment_counter = 3; +} + +message IncompleteUnassigned { + // The event as it appeared in the context of its last activation update (i.e. daml transaction or + // reassignment). In particular, the last activation offset, node_id pair is preserved. + // The last activation update is the most recent update created or assigned this contract on synchronizer_id synchronizer before + // the unassigned_event. + // The offset of the CreatedEvent might point to an already pruned update, therefore it cannot necessarily be used + // for lookups. + // + // Required + CreatedEvent created_event = 1; + + // Required + UnassignedEvent unassigned_event = 2; +} + +message IncompleteAssigned { + // Required + AssignedEvent assigned_event = 1; +} + +message GetConnectedSynchronizersRequest { + // The party of interest + // Must be a valid PartyIdString (as described in ``value.proto``). + // If empty, all synchronizers this node is connected to will be returned + // + // Optional + string party = 1; + + // The id of a participant whose mapping of a party to connected synchronizers is requested. + // Must be a valid participant-id retrieved through a prior call to getParticipantId. + // Defaults to the participant id of the host participant. + // + // Optional + string participant_id = 2; + + // The ID of the identity provider configured by ``Identity Provider Config`` + // If not set, it's assumed the user is managed by the default identity provider. + // + // Optional + string identity_provider_id = 3; +} + +message GetConnectedSynchronizersResponse { + message ConnectedSynchronizer { + // The alias of the synchronizer + // + // Required + string synchronizer_alias = 1; + + // The ID of the synchronizer + // + // Required + string synchronizer_id = 2; + + // The permission on the synchronizer + // Set if a party was used in the request, otherwise unspecified. + // + // Optional + ParticipantPermission permission = 3; + } + // Optional: can be empty + repeated ConnectedSynchronizer connected_synchronizers = 1; +} + +// Enum indicating the permission level that the participant has for the party +// whose connected synchronizers are being listed. +enum ParticipantPermission { + PARTICIPANT_PERMISSION_UNSPECIFIED = 0; + + PARTICIPANT_PERMISSION_SUBMISSION = 1; + + // participant can only confirm transactions + PARTICIPANT_PERMISSION_CONFIRMATION = 2; + + // participant can only observe transactions + PARTICIPANT_PERMISSION_OBSERVATION = 3; +} + +message GetLedgerEndRequest {} + +message GetLedgerEndResponse { + // It will always be a non-negative integer. + // If zero, the participant view of the ledger is empty. + // If positive, the absolute offset of the ledger as viewed by the participant. + // + // Optional + int64 offset = 1; +} + +message GetLatestPrunedOffsetsRequest { + // Empty for now, but may contain fields in the future. +} + +message GetLatestPrunedOffsetsResponse { + // It will always be a non-negative integer. + // If positive, the absolute offset up to which the ledger has been pruned, + // disregarding the state of all divulged contracts pruning. + // If zero, the ledger has not been pruned yet. + // + // Optional + int64 participant_pruned_up_to_inclusive = 1; + + // It will always be a non-negative integer. + // If positive, the absolute offset up to which all divulged events have been pruned on the ledger. + // It can be at or before the ``participant_pruned_up_to_inclusive`` offset. + // For more details about all divulged events pruning, + // see ``PruneRequest.prune_all_divulged_contracts`` in ``participant_pruning_service.proto``. + // If zero, the divulged events have not been pruned yet. + // + // Optional + int64 all_divulged_contracts_pruned_up_to_inclusive = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/testing/time_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/testing/time_service.proto new file mode 100644 index 00000000..dea131cb --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/testing/time_service.proto @@ -0,0 +1,50 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2.testing; + +import "google/protobuf/empty.proto"; +import "google/protobuf/timestamp.proto"; + + +option java_outer_classname = "TimeServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2.testing"; +option csharp_namespace = "Com.Daml.Ledger.Api.V2.Testing"; + +// Optional service, exposed for testing static time scenarios. +service TimeService { + + // Returns the current time according to the ledger server. + rpc GetTime (GetTimeRequest) returns (GetTimeResponse); + + // Allows clients to change the ledger's clock in an atomic get-and-set operation. + rpc SetTime (SetTimeRequest) returns (google.protobuf.Empty); +} + +message GetTimeRequest { + +} + +message GetTimeResponse { + + // The current time according to the ledger server. + // + // Required + google.protobuf.Timestamp current_time = 1; +} + +message SetTimeRequest { + + // MUST precisely match the current time as it's known to the ledger server. + // + // Required + google.protobuf.Timestamp current_time = 1; + + // The time the client wants to set on the ledger. + // MUST be a point int time after ``current_time``. + // + // Required + google.protobuf.Timestamp new_time = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/topology_transaction.proto b/chain/canton/proto/com/daml/ledger/api/v2/topology_transaction.proto new file mode 100644 index 00000000..71bb3b87 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/topology_transaction.proto @@ -0,0 +1,110 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/state_service.proto"; +import "com/daml/ledger/api/v2/trace_context.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "TopologyTransactionOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +message TopologyTransaction { + // Assigned by the server. Useful for correlating logs. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string update_id = 1; + + // The absolute offset. The details of this field are described in ``community/ledger-api/README.md``. + // It is a valid absolute offset (positive integer). + // + // Required + int64 offset = 2; + + // A valid synchronizer id. + // Identifies the synchronizer that synchronized the topology transaction. + // + // Required + string synchronizer_id = 3; + + // The time at which the changes in the topology transaction become effective. There is a small delay between a + // topology transaction being sequenced and the changes it contains becoming effective. Topology transactions appear + // in order relative to a synchronizer based on their effective time rather than their sequencing time. + // + // Required + google.protobuf.Timestamp record_time = 4; + + // A non-empty list of topology events. + // + // Required: must be non-empty + repeated TopologyEvent events = 5; + + // Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + com.daml.ledger.api.v2.TraceContext trace_context = 6; +} + +message TopologyEvent { + // Required + oneof event { + ParticipantAuthorizationChanged participant_authorization_changed = 1; + ParticipantAuthorizationRevoked participant_authorization_revoked = 2; + ParticipantAuthorizationAdded participant_authorization_added = 3; + ParticipantAuthorizationOnboarding participant_authorization_onboarding = 4; + } +} + +message ParticipantAuthorizationAdded { + // Required + string party_id = 1; + + // Required + string participant_id = 2; + + // Required + ParticipantPermission participant_permission = 3; +} + +message ParticipantAuthorizationChanged { + // Required + string party_id = 1; + + // Required + string participant_id = 2; + + // Required + ParticipantPermission participant_permission = 3; +} + +message ParticipantAuthorizationRevoked { + // Required + string party_id = 1; + + // Required + string participant_id = 2; +} + +message ParticipantAuthorizationOnboarding { + // Required + string party_id = 1; + + // Required + string participant_id = 2; + + // Required + ParticipantPermission participant_permission = 3; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/trace_context.proto b/chain/canton/proto/com/daml/ledger/api/v2/trace_context.proto new file mode 100644 index 00000000..a1b6a846 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/trace_context.proto @@ -0,0 +1,20 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "TraceContextOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +message TraceContext { + // https://www.w3.org/TR/trace-context/ + // + // Optional + optional string traceparent = 1; + + // Optional + optional string tracestate = 2; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/transaction.proto b/chain/canton/proto/com/daml/ledger/api/v2/transaction.proto new file mode 100644 index 00000000..13d6f3bf --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/transaction.proto @@ -0,0 +1,86 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/event.proto"; +import "com/daml/ledger/api/v2/trace_context.proto"; +import "google/protobuf/timestamp.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "TransactionOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Filtered view of an on-ledger transaction's create and archive events. +message Transaction { + // Assigned by the server. Useful for correlating logs. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string update_id = 1; + + // The ID of the command which resulted in this transaction. Missing for everyone except the submitting party. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string command_id = 2; + + // The workflow ID used in command submission. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Optional + string workflow_id = 3; + + // Ledger effective time. + // + // Required + google.protobuf.Timestamp effective_at = 4; + + // The collection of events. + // Contains: + // + // - ``CreatedEvent`` or ``ArchivedEvent`` in case of ACS_DELTA transaction shape + // - ``CreatedEvent`` or ``ExercisedEvent`` in case of LEDGER_EFFECTS transaction shape + // + // Required: must be non-empty + repeated Event events = 5; + + // The absolute offset. The details of this field are described in ``community/ledger-api/README.md``. + // It is a valid absolute offset (positive integer). + // + // Required + int64 offset = 6; + + // A valid synchronizer id. + // Identifies the synchronizer that synchronized the transaction. + // + // Required + string synchronizer_id = 7; + + // Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + TraceContext trace_context = 8; + + // The time at which the transaction was recorded. The record time refers to the synchronizer + // which synchronized the transaction. + // + // Required + google.protobuf.Timestamp record_time = 9; + + // For transaction externally signed, contains the external transaction hash + // signed by the external party. Can be used to correlate an external submission with a committed transaction. + // + // Optional: can be empty + optional bytes external_transaction_hash = 10; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/transaction_filter.proto b/chain/canton/proto/com/daml/ledger/api/v2/transaction_filter.proto new file mode 100644 index 00000000..cb794a82 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/transaction_filter.proto @@ -0,0 +1,205 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/value.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "TransactionFilterOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// The union of a set of template filters, interface filters, or a wildcard. +message Filters { + // Every filter in the cumulative list expands the scope of the resulting stream. Each interface, + // template or wildcard filter means additional events that will match the query. + // The impact of include_interface_view and include_created_event_blob fields in the filters will + // also be accumulated. + // A template or an interface SHOULD NOT appear twice in the accumulative field. + // A wildcard filter SHOULD NOT be defined more than once in the accumulative field. + // If no ``CumulativeFilter`` defined, the default of a single ``WildcardFilter`` with + // include_created_event_blob unset is used. + // + // Optional: can be empty + repeated CumulativeFilter cumulative = 1; +} + +// A filter that matches all contracts that are either an instance of one of +// the ``template_filters`` or that match one of the ``interface_filters``. +message CumulativeFilter { + // Required + oneof identifier_filter { + // A wildcard filter that matches all templates + // + // Optional + WildcardFilter wildcard_filter = 1; + + // Include an ``InterfaceView`` for every ``InterfaceFilter`` matching a contract. + // The ``InterfaceFilter`` instances MUST each use a unique ``interface_id``. + // + // Optional + InterfaceFilter interface_filter = 2; + + // A template for which the data will be included in the + // ``create_arguments`` of a matching ``CreatedEvent``. + // If a contract is simultaneously selected by a template filter and one or more interface filters, + // the corresponding ``include_created_event_blob`` are consolidated using an OR operation. + // + // Optional + TemplateFilter template_filter = 3; + } +} + +// This filter matches all templates. +message WildcardFilter { + // Whether to include a ``created_event_blob`` in the returned ``CreatedEvent``. + // Use this to access the contract create event payload in your API client + // for submitting it as a disclosed contract with future commands. + // + // Optional + bool include_created_event_blob = 1; +} + +// This filter matches contracts that implement a specific interface. +message InterfaceFilter { + // The interface that a matching contract must implement. + // The ``interface_id`` needs to be valid: corresponding interface should be defined in + // one of the available packages at the time of the query. + // Both package-name and package-id reference formats for the identifier are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + Identifier interface_id = 1; + + // Whether to include the interface view on the contract in the returned ``CreatedEvent``. + // Use this to access contract data in a uniform manner in your API client. + // + // Optional + bool include_interface_view = 2; + + // Whether to include a ``created_event_blob`` in the returned ``CreatedEvent``. + // Use this to access the contract create event payload in your API client + // for submitting it as a disclosed contract with future commands. + // + // Optional + bool include_created_event_blob = 3; +} + +// This filter matches contracts of a specific template. +message TemplateFilter { + // A template for which the payload should be included in the response. + // The ``template_id`` needs to be valid: corresponding template should be defined in + // one of the available packages at the time of the query. + // Both package-name and package-id reference formats for the identifier are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + Identifier template_id = 1; + + // Whether to include a ``created_event_blob`` in the returned ``CreatedEvent``. + // Use this to access the contract event payload in your API client + // for submitting it as a disclosed contract with future commands. + // + // Optional + bool include_created_event_blob = 2; +} + +// A format for events which defines both which events should be included +// and what data should be computed and included for them. +// +// Note that some of the filtering behavior depends on the `TransactionShape`, +// which is expected to be specified alongside usages of `EventFormat`. +message EventFormat { + // Each key must be a valid PartyIdString (as described in ``value.proto``). + // The interpretation of the filter depends on the transaction-shape being filtered: + // + // 1. For **ledger-effects** create and exercise events are returned, for which the witnesses include at least one of + // the listed parties and match the per-party filter. + // 2. For **transaction and active-contract-set streams** create and archive events are returned for all contracts whose + // stakeholders include at least one of the listed parties and match the per-party filter. + // + // Optional: can be empty + map filters_by_party = 1; + + // Wildcard filters that apply to all the parties existing on the participant. The interpretation of the filters is the same + // with the per-party filter as described above. + // + // Optional + Filters filters_for_any_party = 2; + + // If enabled, values served over the API will contain more information than strictly necessary to interpret the data. + // In particular, setting the verbose flag to true triggers the ledger to include labels for record fields. + // + // Optional + bool verbose = 3; +} + +// Event shape for Transactions. +// Shapes are exclusive and only one of them can be defined in queries. +enum TransactionShape { + // Following official proto3 convention, not intended for actual use. + TRANSACTION_SHAPE_UNSPECIFIED = 0; + // Transaction shape that is sufficient to maintain an accurate ACS view. + // The field witness_parties in events are populated as stakeholders, transaction filter will apply accordingly. + // This translates to create and archive events. + TRANSACTION_SHAPE_ACS_DELTA = 1; + // Transaction shape that allows maintaining an ACS and also conveys detailed information about + // all exercises. + // The field witness_parties in events are populated as cumulative informees, transaction filter will apply accordingly. + // This translates to create, consuming exercise and non-consuming exercise. + TRANSACTION_SHAPE_LEDGER_EFFECTS = 2; +} + +// A format that specifies what events to include in Daml transactions +// and what data to compute and include for them. +message TransactionFormat { + // Required + EventFormat event_format = 1; + + // What transaction shape to use for interpreting the filters of the event format. + // + // Required + TransactionShape transaction_shape = 2; +} + +// A format specifying which topology transactions to include and how to render them. +message TopologyFormat { + // Include participant authorization topology events in streams. + // If unset, no participant authorization topology events are emitted in the stream. + // + // Optional + ParticipantAuthorizationTopologyFormat include_participant_authorization_events = 1; +} + +// A format specifying which participant authorization topology transactions to include and how to render them. +message ParticipantAuthorizationTopologyFormat { + // List of parties for which the topology transactions should be sent. + // Empty means: for all parties. + // + // Optional: can be empty + repeated string parties = 1; +} + +// A format specifying what updates to include and how to render them. +message UpdateFormat { + // Include Daml transactions in streams. + // If unset, no transactions are emitted in the stream. + // + // Optional + TransactionFormat include_transactions = 1; + + // Include (un)assignments in the stream. + // The events in the result take the shape TRANSACTION_SHAPE_ACS_DELTA. + // If unset, no (un)assignments are emitted in the stream. + // + // Optional + EventFormat include_reassignments = 2; + + // Include topology events in streams. + // If unset no topology events are emitted in the stream. + // + // Optional + TopologyFormat include_topology_events = 3; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/update_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/update_service.proto new file mode 100644 index 00000000..d8f26cc6 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/update_service.proto @@ -0,0 +1,131 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/offset_checkpoint.proto"; +import "com/daml/ledger/api/v2/reassignment.proto"; +import "com/daml/ledger/api/v2/topology_transaction.proto"; +import "com/daml/ledger/api/v2/transaction.proto"; +import "com/daml/ledger/api/v2/transaction_filter.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "UpdateServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Allows clients to read updates (transactions, (un)assignments, topology events) from the ledger. +// +// ``GetUpdates`` provides a comprehensive stream of updates/changes +// which happened on the virtual shared ledger. These streams are indexed with ledger +// offsets, which are strictly increasing. +// The virtual shared ledger consist of changes happening on multiple synchronizers which are +// connected to the serving participant. Each update belongs to one synchronizer, this is +// provided in the result (the ``synchronizer_id`` field in ``Transaction`` +// for transactions, the ``source`` field in ``UnassignedEvent`` and the ``target`` field in ``AssignedEvent``). +// Consumers can rely on strong causal guarantees on the virtual shared ledger for a single +// synchronizer: updates which have greater offsets are happened after than updates with smaller +// offsets for the same synchronizer. Across different synchronizers this is not guaranteed. +service UpdateService { + // Read the ledger's filtered update stream for the specified contents and filters. + // It returns the event types in accordance with the stream contents selected. Also the selection criteria + // for individual events depends on the transaction shape chosen. + // + // - ACS delta: a requesting party must be a stakeholder of an event for it to be included. + // - ledger effects: a requesting party must be a witness of an event for it to be included. + rpc GetUpdates(GetUpdatesRequest) returns (stream GetUpdatesResponse); + + // Lookup an update by its offset. + // If there is no update with this offset, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + rpc GetUpdateByOffset(GetUpdateByOffsetRequest) returns (GetUpdateResponse); + + // Lookup an update by its ID. + // If there is no update with this ID, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + rpc GetUpdateById(GetUpdateByIdRequest) returns (GetUpdateResponse); +} + +message GetUpdatesRequest { + // Exclusive lower bound offset of the requested ledger section (non-negative integer). + // The response will only contain transactions whose offset is strictly greater than this. + // If set to zero, the lower bound is set to the beginning of the ledger. + // If the participant has been pruned, this parameter must be greater or equal than the pruning offset. + + // Required + int64 begin_exclusive = 1; + + // Inclusive higher bound offset of the requested ledger section. + // If specified the response will only contain transactions whose offset is less than or equal to this. + // If not specified, + // + // - the descending_order must not be selected, + // - the stream will not terminate. + // + // Optional + optional int64 end_inclusive = 2; + + reserved 3; + reserved "filter"; + + reserved 4; + reserved "verbose"; + + // The update format for this request + // + // Required + UpdateFormat update_format = 5; + + // If set, the stream will populate the elements in descending order. + // + // Optional + bool descending_order = 6; +} + +message GetUpdatesResponse { + // The update that matches the filter in the request. + // + // Required + oneof update { + Transaction transaction = 1; + Reassignment reassignment = 2; + OffsetCheckpoint offset_checkpoint = 3; + TopologyTransaction topology_transaction = 4; + } +} + +message GetUpdateByOffsetRequest { + // The offset of the update being looked up. + // Must be a valid absolute offset (positive integer). + // + // Required + int64 offset = 1; + + // The format for the update. + // + // Required + UpdateFormat update_format = 2; +} + +message GetUpdateByIdRequest { + // The ID of a particular update. + // Must be a valid LedgerString (as described in ``value.proto``). + // + // Required + string update_id = 1; + + // The format for the update. + // + // Required + UpdateFormat update_format = 2; +} + +message GetUpdateResponse { + // The update that matches the filter in the request. + // + // Required + oneof update { + Transaction transaction = 1; + Reassignment reassignment = 2; + TopologyTransaction topology_transaction = 3; + } +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/value.proto b/chain/canton/proto/com/daml/ledger/api/v2/value.proto new file mode 100644 index 00000000..ae592ccf --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/value.proto @@ -0,0 +1,206 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// IMPORTANT: The comments for the messages and fields are used to produce Sphinx documentation in Canton. +// Make sure to check if they're valid and the output is as expected. + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "google/protobuf/empty.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "ValueOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Encodes values that the ledger accepts as command arguments and emits as contract arguments. +// +// The values encoding use different classes of non-empty strings as identifiers. Those classes are +// defined as follows: +// +// - NameStrings are strings with length <= 1000 that match the regexp ``[A-Za-z\$_][A-Za-z0-9\$_]*``. +// - PackageIdStrings are strings with length <= 64 that match the regexp ``[A-Za-z0-9\-_ ]+``. +// - PartyIdStrings are strings with length <= 255 that match the regexp ``[A-Za-z0-9:\-_ ]+``. +// - LedgerStrings are strings with length <= 255 that match the regexp ``[A-Za-z0-9#:\-_/ ]+``. +// - UserIdStrings are strings with length <= 128 that match the regexp ``[a-zA-Z0-9@^$.!`\-#+'~_|:]+``. +// +message Value { + oneof sum { + // This value is used for example for choices that don't take any arguments. + google.protobuf.Empty unit = 1; + + // True or false. + bool bool = 2; + + sint64 int64 = 3 [jstype = JS_STRING]; + + // Days since the unix epoch. Can go backwards. Limited from + // 0001-01-01 to 9999-12-31, also to be compatible with + // https://www.ietf.org/rfc/rfc3339.txt + int32 date = 4; + + // Microseconds since the UNIX epoch. Can go backwards. Fixed + // since the vast majority of values will be greater than + // 2^28, since currently the number of microseconds since the + // epoch is greater than that. Range: 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59.999999Z, so that we can convert to/from + // https://www.ietf.org/rfc/rfc3339.txt + sfixed64 timestamp = 5 [jstype = JS_STRING]; + + // A Numeric, that is a decimal value with precision 38 (at most 38 significant digits) and a + // scale between 0 and 37 (significant digits on the right of the decimal point). + // The field has to match the regex + // + // .. code-block:: none + // + // [+-]?\d{1,38}(.\d{0,37})? + // + // and should be representable by a Numeric without loss of precision. + string numeric = 6; + + // An agent operating on the ledger. + // Must be a valid PartyIdString. + string party = 7; + + // A string. + string text = 8; + + // Identifier of an on-ledger contract. Commands which reference an unknown or already archived contract ID will fail. + // Must be a valid LedgerString. + string contract_id = 9; + + // The Optional type, None or Some + Optional optional = 10; + + // Represents a homogeneous list of values. + List list = 11; + + // The TextMap type + TextMap text_map = 12; + + // The GenMap type + GenMap gen_map = 13; + + Record record = 14; + + Variant variant = 15; + + // The Enum type + Enum enum = 16; + } +} + +// Contains nested values. +message Record { + // Omitted from the transaction stream when verbose streaming is not enabled. + // Optional when submitting commands. + Identifier record_id = 1; + + // The nested values of the record. + // Required + repeated RecordField fields = 2; +} + +// A named nested value within a record. +message RecordField { + // When reading a transaction stream, it's omitted if verbose streaming is not enabled. + // When submitting a command, it's optional: + // + // - if all keys within a single record are present, the order in which fields appear does not matter. however, each key must appear exactly once. + // - if any of the keys within a single record are omitted, the order of fields MUST match the order of declaration in the Daml template. + // + // Must be a valid NameString + string label = 1; + + // A nested value of a record. + // Required + Value value = 2; +} + +// Unique identifier of an entity. +// Throughout this API, the following terminology is being used: +// +// - if a Daml package-id is encoded in the package_id field, it is referred to as using a "package-id reference format" +// - if a Daml package-name is encoded in the package_id field, it is referred to as using a "package-name reference format" +message Identifier { + // Generally, the identifier of the Daml package that contains the entity. + // When encoding a package-id, it must be a valid PackageIdString. + // + // The field is overloaded to also be able to contain the package-name of the Daml package. + // This is supported if the entity referenced is either an interface or template. + // When representing the Daml package-name, the encoding is of form `#` + // where `#` (not a valid package-id character) + // is used as a discriminator for signalling a package-name encoding. + // + // Required + string package_id = 1; + + // The dot-separated module name of the identifier. + // Required + string module_name = 2; + + // The dot-separated name of the entity (e.g. record, template, ...) within the module. + // Required + string entity_name = 3; +} + +// A value with alternative representations. +message Variant { + // Omitted from the transaction stream when verbose streaming is not enabled. + // Optional when submitting commands. + Identifier variant_id = 1; + + // Determines which of the Variant's alternatives is encoded in this message. + // Must be a valid NameString. + // Required + string constructor = 2; + + // The value encoded within the Variant. + // Required + Value value = 3; +} + +// A value with finite set of alternative representations. +message Enum { + // Omitted from the transaction stream when verbose streaming is not enabled. + // Optional when submitting commands. + Identifier enum_id = 1; + + // Determines which of the Variant's alternatives is encoded in this message. + // Must be a valid NameString. + // Required + string constructor = 2; +} + +// A homogenous collection of values. +message List { + // The elements must all be of the same concrete value type. + // Optional + repeated Value elements = 1; +} + +// Corresponds to Java's Optional type, Scala's Option, and Haskell's Maybe. +// The reason why we need to wrap this in an additional ``message`` is that we +// need to be able to encode the ``None`` case in the ``Value`` oneof. +message Optional { + Value value = 1; // optional +} + +message TextMap { + message Entry { + string key = 1; + Value value = 2; + } + + repeated Entry entries = 1; +} + +message GenMap { + message Entry { + Value key = 1; + Value value = 2; + } + + repeated Entry entries = 1; +} diff --git a/chain/canton/proto/com/daml/ledger/api/v2/version_service.proto b/chain/canton/proto/com/daml/ledger/api/v2/version_service.proto new file mode 100644 index 00000000..3d736272 --- /dev/null +++ b/chain/canton/proto/com/daml/ledger/api/v2/version_service.proto @@ -0,0 +1,120 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +package com.daml.ledger.api.v2; + +import "com/daml/ledger/api/v2/experimental_features.proto"; +import "google/protobuf/duration.proto"; + +option csharp_namespace = "Com.Daml.Ledger.Api.V2"; +option java_outer_classname = "VersionServiceOuterClass"; +option java_package = "com.daml.ledger.api.v2"; + +// Allows clients to retrieve information about the ledger API version +service VersionService { + // Read the Ledger API version + rpc GetLedgerApiVersion(GetLedgerApiVersionRequest) returns (GetLedgerApiVersionResponse); +} + +message GetLedgerApiVersionRequest {} + +message GetLedgerApiVersionResponse { + // The version of the ledger API. + // + // Required + string version = 1; + + // The features supported by this Ledger API endpoint. + // + // Daml applications CAN use the feature descriptor on top of + // version constraints on the Ledger API version to determine + // whether a given Ledger API endpoint supports the features + // required to run the application. + // + // See the feature descriptions themselves for the relation between + // Ledger API versions and feature presence. + // + // Required + FeaturesDescriptor features = 2; +} + +message FeaturesDescriptor { + // Features under development or features that are used + // for ledger implementation testing purposes only. + // + // Daml applications SHOULD not depend on these in production. + // + // Required + ExperimentalFeatures experimental = 1; + + // If set, then the Ledger API server supports user management. + // It is recommended that clients query this field to gracefully adjust their behavior for + // ledgers that do not support user management. + // + // Required + UserManagementFeature user_management = 2; + + // If set, then the Ledger API server supports party management configurability. + // It is recommended that clients query this field to gracefully adjust their behavior to + // maximum party page size. + // + // Required + PartyManagementFeature party_management = 3; + + // It contains the timeouts related to the periodic offset checkpoint emission + // + // Required + OffsetCheckpointFeature offset_checkpoint = 4; + + // If set, then the Ledger API server supports package listing + // configurability. It is recommended that clients query this field to + // gracefully adjust their behavior to maximum package listing page size. + // + // Required + PackageFeature package_feature = 5; +} + +message UserManagementFeature { + // Whether the Ledger API server provides the user management service. + // + // Required + bool supported = 1; + + // The maximum number of rights that can be assigned to a single user. + // Servers MUST support at least 100 rights per user. + // A value of 0 means that the server enforces no rights per user limit. + // + // Required + int32 max_rights_per_user = 2; + + // The maximum number of users the server can return in a single response (page). + // Servers MUST support at least a 100 users per page. + // A value of 0 means that the server enforces no page size limit. + // + // Required + int32 max_users_page_size = 3; +} + +message PartyManagementFeature { + // The maximum number of parties the server can return in a single response (page). + // + // Required + int32 max_parties_page_size = 1; +} + +message PackageFeature { + // The maximum number of vetted packages the server can return in a single + // response (page) when listing them. + // + // Required + int32 max_vetted_packages_page_size = 1; +} + +message OffsetCheckpointFeature { + // The maximum delay to emmit a new OffsetCheckpoint if it exists + // + // Required + google.protobuf.Duration max_offset_checkpoint_emission_delay = 1; +} diff --git a/chain/canton/tx/create_account_tx_test.go b/chain/canton/tx/create_account_tx_test.go index afc6d90c..bda9f14e 100644 --- a/chain/canton/tx/create_account_tx_test.go +++ b/chain/canton/tx/create_account_tx_test.go @@ -9,7 +9,7 @@ import ( xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" "github.com/cordialsys/crosschain/chain/canton/tx_input" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" ) diff --git a/chain/canton/tx/metadata.go b/chain/canton/tx/metadata.go index 90d30898..f3602c58 100644 --- a/chain/canton/tx/metadata.go +++ b/chain/canton/tx/metadata.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/cordialsys/crosschain/chain/canton/tx_input" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" ) const ( diff --git a/chain/canton/tx/tx.go b/chain/canton/tx/tx.go index 94826158..ba6b09e9 100644 --- a/chain/canton/tx/tx.go +++ b/chain/canton/tx/tx.go @@ -7,11 +7,11 @@ import ( xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" - cantonproto "github.com/cordialsys/crosschain/chain/canton/proto" "github.com/cordialsys/crosschain/chain/canton/tx_input" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" - v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" + cantonproto "github.com/cordialsys/crosschain/chain/canton/types" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" + v1 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1" "google.golang.org/protobuf/proto" ) diff --git a/chain/canton/tx/tx_test.go b/chain/canton/tx/tx_test.go index b442be93..165b2a61 100644 --- a/chain/canton/tx/tx_test.go +++ b/chain/canton/tx/tx_test.go @@ -8,9 +8,9 @@ import ( xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" "github.com/cordialsys/crosschain/chain/canton/tx_input" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" - v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" + v1 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1" "github.com/stretchr/testify/require" ) diff --git a/chain/canton/tx_input/create_account_input.go b/chain/canton/tx_input/create_account_input.go index b87688fd..315c54a1 100644 --- a/chain/canton/tx_input/create_account_input.go +++ b/chain/canton/tx_input/create_account_input.go @@ -6,8 +6,8 @@ import ( "fmt" xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" "github.com/cordialsys/crosschain/factory/drivers/registry" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" "google.golang.org/protobuf/proto" ) diff --git a/chain/canton/tx_input/hash_validation.go b/chain/canton/tx_input/hash_validation.go index 1342d4e3..fdb71d63 100644 --- a/chain/canton/tx_input/hash_validation.go +++ b/chain/canton/tx_input/hash_validation.go @@ -9,9 +9,9 @@ import ( "strconv" "strings" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" - v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" + v1 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1" ) var preparedTransactionHashPurpose = []byte{0x00, 0x00, 0x00, 0x30} diff --git a/chain/canton/tx_input/hash_validation_test.go b/chain/canton/tx_input/hash_validation_test.go index 3301cc50..8be5d13d 100644 --- a/chain/canton/tx_input/hash_validation_test.go +++ b/chain/canton/tx_input/hash_validation_test.go @@ -8,9 +8,9 @@ import ( "strconv" "testing" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" - v1 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive/transaction/v1" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" + v1 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" ) diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index b6567138..2e3d9cff 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -4,8 +4,8 @@ import ( "time" xc "github.com/cordialsys/crosschain" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" "github.com/cordialsys/crosschain/factory/drivers/registry" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" ) // TxInput for Canton holds the result of the prepare step in the diff --git a/chain/canton/types/README.md b/chain/canton/types/README.md new file mode 100644 index 00000000..a3157712 --- /dev/null +++ b/chain/canton/types/README.md @@ -0,0 +1,17 @@ +This directory contains generated Go protobuf/grpc types used by the Canton integration. + +From [`chain/canton`](/Users/conorpatrick/crosschain/chain/canton), regenerate them from checked-in proto source with: + +``` +just pb +``` + +Proto sources live in: + +- [`chain/canton/proto`](/Users/conorpatrick/crosschain/chain/canton/proto) + +Upstream source provenance: + +- `digital-asset/canton` +- `community/ledger-api-proto/src/main/protobuf/com/daml/ledger/api/v2` +- `community/daml-lf/ledger-api-value/src/main/protobuf/com/daml/ledger/api/v2/value.proto` diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service.pb.go new file mode 100644 index 00000000..992365b5 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service.pb.go @@ -0,0 +1,732 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/admin/command_inspection_service.proto + +package admin + +import ( + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CommandState int32 + +const ( + CommandState_COMMAND_STATE_UNSPECIFIED CommandState = 0 // This value acts as wildcard in the queries + CommandState_COMMAND_STATE_PENDING CommandState = 1 + CommandState_COMMAND_STATE_SUCCEEDED CommandState = 2 + CommandState_COMMAND_STATE_FAILED CommandState = 3 +) + +// Enum value maps for CommandState. +var ( + CommandState_name = map[int32]string{ + 0: "COMMAND_STATE_UNSPECIFIED", + 1: "COMMAND_STATE_PENDING", + 2: "COMMAND_STATE_SUCCEEDED", + 3: "COMMAND_STATE_FAILED", + } + CommandState_value = map[string]int32{ + "COMMAND_STATE_UNSPECIFIED": 0, + "COMMAND_STATE_PENDING": 1, + "COMMAND_STATE_SUCCEEDED": 2, + "COMMAND_STATE_FAILED": 3, + } +) + +func (x CommandState) Enum() *CommandState { + p := new(CommandState) + *p = x + return p +} + +func (x CommandState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CommandState) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_enumTypes[0].Descriptor() +} + +func (CommandState) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_enumTypes[0] +} + +func (x CommandState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CommandState.Descriptor instead. +func (CommandState) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{0} +} + +type GetCommandStatusRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Filter by command id + // + // Optional + CommandIdPrefix string `protobuf:"bytes,1,opt,name=command_id_prefix,json=commandIdPrefix,proto3" json:"command_id_prefix,omitempty"` + // Filter by state + // + // Optional + State CommandState `protobuf:"varint,2,opt,name=state,proto3,enum=com.daml.ledger.api.v2.admin.CommandState" json:"state,omitempty"` + // Limit the number of returned statuses + // Defaults to 100 if not set + // + // Optional + Limit uint32 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetCommandStatusRequest) Reset() { + *x = GetCommandStatusRequest{} + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCommandStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCommandStatusRequest) ProtoMessage() {} + +func (x *GetCommandStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCommandStatusRequest.ProtoReflect.Descriptor instead. +func (*GetCommandStatusRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetCommandStatusRequest) GetCommandIdPrefix() string { + if x != nil { + return x.CommandIdPrefix + } + return "" +} + +func (x *GetCommandStatusRequest) GetState() CommandState { + if x != nil { + return x.State + } + return CommandState_COMMAND_STATE_UNSPECIFIED +} + +func (x *GetCommandStatusRequest) GetLimit() uint32 { + if x != nil { + return x.Limit + } + return 0 +} + +type GetCommandStatusResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional: can be empty + CommandStatus []*CommandStatus `protobuf:"bytes,1,rep,name=command_status,json=commandStatus,proto3" json:"command_status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetCommandStatusResponse) Reset() { + *x = GetCommandStatusResponse{} + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetCommandStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetCommandStatusResponse) ProtoMessage() {} + +func (x *GetCommandStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetCommandStatusResponse.ProtoReflect.Descriptor instead. +func (*GetCommandStatusResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetCommandStatusResponse) GetCommandStatus() []*CommandStatus { + if x != nil { + return x.CommandStatus + } + return nil +} + +type Timing struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Description of the timing stage (may be subject to change) + // + // Required + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // Required + DurationMs uint32 `protobuf:"varint,2,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Timing) Reset() { + *x = Timing{} + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Timing) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Timing) ProtoMessage() {} + +func (x *Timing) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Timing.ProtoReflect.Descriptor instead. +func (*Timing) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{2} +} + +func (x *Timing) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Timing) GetDurationMs() uint32 { + if x != nil { + return x.DurationMs + } + return 0 +} + +type CommandStatus struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Time at which the command was received for interpretation by the participant. + // + // Required + Started *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=started,proto3" json:"started,omitempty"` + // Time at which the command was completed. + // + // Optional + Completed *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=completed,proto3" json:"completed,omitempty"` + // The completion associated with the command + // Contains only default values if the command is still pending + // + // Optional + Completion *v2.Completion `protobuf:"bytes,3,opt,name=completion,proto3" json:"completion,omitempty"` + // The state of the command + // + // Required + State CommandState `protobuf:"varint,4,opt,name=state,proto3,enum=com.daml.ledger.api.v2.admin.CommandState" json:"state,omitempty"` + // The individual submitted commands + // + // Required: must be non-empty + Commands []*v2.Command `protobuf:"bytes,5,rep,name=commands,proto3" json:"commands,omitempty"` + // Statistics about the command request + // + // Optional + RequestStatistics *RequestStatistics `protobuf:"bytes,6,opt,name=request_statistics,json=requestStatistics,proto3" json:"request_statistics,omitempty"` + // The ledger updates effected by the command + // + // Optional + Updates *CommandUpdates `protobuf:"bytes,7,opt,name=updates,proto3" json:"updates,omitempty"` + // Synchronizer-ID. May be optional if the transaction was not yet routed. + // + // Optional + SynchronizerId string `protobuf:"bytes,8,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // Timings for the individual stages + // + // Optional: can be empty + Timings []*Timing `protobuf:"bytes,9,rep,name=timings,proto3" json:"timings,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CommandStatus) Reset() { + *x = CommandStatus{} + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommandStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandStatus) ProtoMessage() {} + +func (x *CommandStatus) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandStatus.ProtoReflect.Descriptor instead. +func (*CommandStatus) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{3} +} + +func (x *CommandStatus) GetStarted() *timestamppb.Timestamp { + if x != nil { + return x.Started + } + return nil +} + +func (x *CommandStatus) GetCompleted() *timestamppb.Timestamp { + if x != nil { + return x.Completed + } + return nil +} + +func (x *CommandStatus) GetCompletion() *v2.Completion { + if x != nil { + return x.Completion + } + return nil +} + +func (x *CommandStatus) GetState() CommandState { + if x != nil { + return x.State + } + return CommandState_COMMAND_STATE_UNSPECIFIED +} + +func (x *CommandStatus) GetCommands() []*v2.Command { + if x != nil { + return x.Commands + } + return nil +} + +func (x *CommandStatus) GetRequestStatistics() *RequestStatistics { + if x != nil { + return x.RequestStatistics + } + return nil +} + +func (x *CommandStatus) GetUpdates() *CommandUpdates { + if x != nil { + return x.Updates + } + return nil +} + +func (x *CommandStatus) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *CommandStatus) GetTimings() []*Timing { + if x != nil { + return x.Timings + } + return nil +} + +type RequestStatistics struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional + Envelopes uint32 `protobuf:"varint,1,opt,name=envelopes,proto3" json:"envelopes,omitempty"` + // Optional + RequestSize uint32 `protobuf:"varint,2,opt,name=request_size,json=requestSize,proto3" json:"request_size,omitempty"` + // Optional + Recipients uint32 `protobuf:"varint,3,opt,name=recipients,proto3" json:"recipients,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RequestStatistics) Reset() { + *x = RequestStatistics{} + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RequestStatistics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestStatistics) ProtoMessage() {} + +func (x *RequestStatistics) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestStatistics.ProtoReflect.Descriptor instead. +func (*RequestStatistics) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{4} +} + +func (x *RequestStatistics) GetEnvelopes() uint32 { + if x != nil { + return x.Envelopes + } + return 0 +} + +func (x *RequestStatistics) GetRequestSize() uint32 { + if x != nil { + return x.RequestSize + } + return 0 +} + +func (x *RequestStatistics) GetRecipients() uint32 { + if x != nil { + return x.Recipients + } + return 0 +} + +type CommandUpdates struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional: can be empty + Created []*Contract `protobuf:"bytes,1,rep,name=created,proto3" json:"created,omitempty"` + // Optional: can be empty + Archived []*Contract `protobuf:"bytes,2,rep,name=archived,proto3" json:"archived,omitempty"` + // Required + Exercised uint32 `protobuf:"varint,3,opt,name=exercised,proto3" json:"exercised,omitempty"` + // Required + Fetched uint32 `protobuf:"varint,4,opt,name=fetched,proto3" json:"fetched,omitempty"` + // Required + LookedUpByKey uint32 `protobuf:"varint,5,opt,name=looked_up_by_key,json=lookedUpByKey,proto3" json:"looked_up_by_key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CommandUpdates) Reset() { + *x = CommandUpdates{} + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommandUpdates) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandUpdates) ProtoMessage() {} + +func (x *CommandUpdates) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandUpdates.ProtoReflect.Descriptor instead. +func (*CommandUpdates) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{5} +} + +func (x *CommandUpdates) GetCreated() []*Contract { + if x != nil { + return x.Created + } + return nil +} + +func (x *CommandUpdates) GetArchived() []*Contract { + if x != nil { + return x.Archived + } + return nil +} + +func (x *CommandUpdates) GetExercised() uint32 { + if x != nil { + return x.Exercised + } + return 0 +} + +func (x *CommandUpdates) GetFetched() uint32 { + if x != nil { + return x.Fetched + } + return 0 +} + +func (x *CommandUpdates) GetLookedUpByKey() uint32 { + if x != nil { + return x.LookedUpByKey + } + return 0 +} + +type Contract struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The identifier of the template used to create the contract. + // The identifier uses the package-id reference format. + // + // Required + TemplateId *v2.Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The contract's ID + // + // Required + ContractId string `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // The contract key, if defined + // + // Optional + ContractKey *v2.Value `protobuf:"bytes,3,opt,name=contract_key,json=contractKey,proto3" json:"contract_key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Contract) Reset() { + *x = Contract{} + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Contract) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Contract) ProtoMessage() {} + +func (x *Contract) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Contract.ProtoReflect.Descriptor instead. +func (*Contract) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP(), []int{6} +} + +func (x *Contract) GetTemplateId() *v2.Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *Contract) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *Contract) GetContractKey() *v2.Value { + if x != nil { + return x.ContractKey + } + return nil +} + +var File_com_daml_ledger_api_v2_admin_command_inspection_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDesc = "" + + "\n" + + "=com/daml/ledger/api/v2/admin/command_inspection_service.proto\x12\x1ccom.daml.ledger.api.v2.admin\x1a%com/daml/ledger/api/v2/commands.proto\x1a'com/daml/ledger/api/v2/completion.proto\x1a\"com/daml/ledger/api/v2/value.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x9d\x01\n" + + "\x17GetCommandStatusRequest\x12*\n" + + "\x11command_id_prefix\x18\x01 \x01(\tR\x0fcommandIdPrefix\x12@\n" + + "\x05state\x18\x02 \x01(\x0e2*.com.daml.ledger.api.v2.admin.CommandStateR\x05state\x12\x14\n" + + "\x05limit\x18\x03 \x01(\rR\x05limit\"n\n" + + "\x18GetCommandStatusResponse\x12R\n" + + "\x0ecommand_status\x18\x01 \x03(\v2+.com.daml.ledger.api.v2.admin.CommandStatusR\rcommandStatus\"K\n" + + "\x06Timing\x12 \n" + + "\vdescription\x18\x01 \x01(\tR\vdescription\x12\x1f\n" + + "\vduration_ms\x18\x02 \x01(\rR\n" + + "durationMs\"\xd3\x04\n" + + "\rCommandStatus\x124\n" + + "\astarted\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\astarted\x128\n" + + "\tcompleted\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\tcompleted\x12B\n" + + "\n" + + "completion\x18\x03 \x01(\v2\".com.daml.ledger.api.v2.CompletionR\n" + + "completion\x12@\n" + + "\x05state\x18\x04 \x01(\x0e2*.com.daml.ledger.api.v2.admin.CommandStateR\x05state\x12;\n" + + "\bcommands\x18\x05 \x03(\v2\x1f.com.daml.ledger.api.v2.CommandR\bcommands\x12^\n" + + "\x12request_statistics\x18\x06 \x01(\v2/.com.daml.ledger.api.v2.admin.RequestStatisticsR\x11requestStatistics\x12F\n" + + "\aupdates\x18\a \x01(\v2,.com.daml.ledger.api.v2.admin.CommandUpdatesR\aupdates\x12'\n" + + "\x0fsynchronizer_id\x18\b \x01(\tR\x0esynchronizerId\x12>\n" + + "\atimings\x18\t \x03(\v2$.com.daml.ledger.api.v2.admin.TimingR\atimings\"t\n" + + "\x11RequestStatistics\x12\x1c\n" + + "\tenvelopes\x18\x01 \x01(\rR\tenvelopes\x12!\n" + + "\frequest_size\x18\x02 \x01(\rR\vrequestSize\x12\x1e\n" + + "\n" + + "recipients\x18\x03 \x01(\rR\n" + + "recipients\"\xf7\x01\n" + + "\x0eCommandUpdates\x12@\n" + + "\acreated\x18\x01 \x03(\v2&.com.daml.ledger.api.v2.admin.ContractR\acreated\x12B\n" + + "\barchived\x18\x02 \x03(\v2&.com.daml.ledger.api.v2.admin.ContractR\barchived\x12\x1c\n" + + "\texercised\x18\x03 \x01(\rR\texercised\x12\x18\n" + + "\afetched\x18\x04 \x01(\rR\afetched\x12'\n" + + "\x10looked_up_by_key\x18\x05 \x01(\rR\rlookedUpByKey\"\xb2\x01\n" + + "\bContract\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12\x1f\n" + + "\vcontract_id\x18\x02 \x01(\tR\n" + + "contractId\x12@\n" + + "\fcontract_key\x18\x03 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\vcontractKey*\x7f\n" + + "\fCommandState\x12\x1d\n" + + "\x19COMMAND_STATE_UNSPECIFIED\x10\x00\x12\x19\n" + + "\x15COMMAND_STATE_PENDING\x10\x01\x12\x1b\n" + + "\x17COMMAND_STATE_SUCCEEDED\x10\x02\x12\x18\n" + + "\x14COMMAND_STATE_FAILED\x10\x032\x9e\x01\n" + + "\x18CommandInspectionService\x12\x81\x01\n" + + "\x10GetCommandStatus\x125.com.daml.ledger.api.v2.admin.GetCommandStatusRequest\x1a6.com.daml.ledger.api.v2.admin.GetCommandStatusResponseB\xab\x02\n" + + " com.com.daml.ledger.api.v2.adminB\x1dCommandInspectionServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin\xa2\x02\x06CDLAVA\xaa\x02\x1cCom.Daml.Ledger.Api.V2.Admin\xca\x02\x1cCom\\Daml\\Ledger\\Api\\V2\\Admin\xe2\x02(Com\\Daml\\Ledger\\Api\\V2\\Admin\\GPBMetadata\xea\x02!Com::Daml::Ledger::Api::V2::Adminb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_goTypes = []any{ + (CommandState)(0), // 0: com.daml.ledger.api.v2.admin.CommandState + (*GetCommandStatusRequest)(nil), // 1: com.daml.ledger.api.v2.admin.GetCommandStatusRequest + (*GetCommandStatusResponse)(nil), // 2: com.daml.ledger.api.v2.admin.GetCommandStatusResponse + (*Timing)(nil), // 3: com.daml.ledger.api.v2.admin.Timing + (*CommandStatus)(nil), // 4: com.daml.ledger.api.v2.admin.CommandStatus + (*RequestStatistics)(nil), // 5: com.daml.ledger.api.v2.admin.RequestStatistics + (*CommandUpdates)(nil), // 6: com.daml.ledger.api.v2.admin.CommandUpdates + (*Contract)(nil), // 7: com.daml.ledger.api.v2.admin.Contract + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*v2.Completion)(nil), // 9: com.daml.ledger.api.v2.Completion + (*v2.Command)(nil), // 10: com.daml.ledger.api.v2.Command + (*v2.Identifier)(nil), // 11: com.daml.ledger.api.v2.Identifier + (*v2.Value)(nil), // 12: com.daml.ledger.api.v2.Value +} +var file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_depIdxs = []int32{ + 0, // 0: com.daml.ledger.api.v2.admin.GetCommandStatusRequest.state:type_name -> com.daml.ledger.api.v2.admin.CommandState + 4, // 1: com.daml.ledger.api.v2.admin.GetCommandStatusResponse.command_status:type_name -> com.daml.ledger.api.v2.admin.CommandStatus + 8, // 2: com.daml.ledger.api.v2.admin.CommandStatus.started:type_name -> google.protobuf.Timestamp + 8, // 3: com.daml.ledger.api.v2.admin.CommandStatus.completed:type_name -> google.protobuf.Timestamp + 9, // 4: com.daml.ledger.api.v2.admin.CommandStatus.completion:type_name -> com.daml.ledger.api.v2.Completion + 0, // 5: com.daml.ledger.api.v2.admin.CommandStatus.state:type_name -> com.daml.ledger.api.v2.admin.CommandState + 10, // 6: com.daml.ledger.api.v2.admin.CommandStatus.commands:type_name -> com.daml.ledger.api.v2.Command + 5, // 7: com.daml.ledger.api.v2.admin.CommandStatus.request_statistics:type_name -> com.daml.ledger.api.v2.admin.RequestStatistics + 6, // 8: com.daml.ledger.api.v2.admin.CommandStatus.updates:type_name -> com.daml.ledger.api.v2.admin.CommandUpdates + 3, // 9: com.daml.ledger.api.v2.admin.CommandStatus.timings:type_name -> com.daml.ledger.api.v2.admin.Timing + 7, // 10: com.daml.ledger.api.v2.admin.CommandUpdates.created:type_name -> com.daml.ledger.api.v2.admin.Contract + 7, // 11: com.daml.ledger.api.v2.admin.CommandUpdates.archived:type_name -> com.daml.ledger.api.v2.admin.Contract + 11, // 12: com.daml.ledger.api.v2.admin.Contract.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 12, // 13: com.daml.ledger.api.v2.admin.Contract.contract_key:type_name -> com.daml.ledger.api.v2.Value + 1, // 14: com.daml.ledger.api.v2.admin.CommandInspectionService.GetCommandStatus:input_type -> com.daml.ledger.api.v2.admin.GetCommandStatusRequest + 2, // 15: com.daml.ledger.api.v2.admin.CommandInspectionService.GetCommandStatus:output_type -> com.daml.ledger.api.v2.admin.GetCommandStatusResponse + 15, // [15:16] is the sub-list for method output_type + 14, // [14:15] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_init() } +func file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_init() { + if File_com_daml_ledger_api_v2_admin_command_inspection_service_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_rawDesc)), + NumEnums: 1, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_depIdxs, + EnumInfos: file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_enumTypes, + MessageInfos: file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_admin_command_inspection_service_proto = out.File + file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_admin_command_inspection_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service_grpc.pb.go new file mode 100644 index 00000000..7b10b9da --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/command_inspection_service_grpc.pb.go @@ -0,0 +1,149 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/admin/command_inspection_service.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + CommandInspectionService_GetCommandStatus_FullMethodName = "/com.daml.ledger.api.v2.admin.CommandInspectionService/GetCommandStatus" +) + +// CommandInspectionServiceClient is the client API for CommandInspectionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Status: experimental interface, will change before it is deemed production +// ready +// +// The inspection service provides methods for the ledger administrator +// to look under the hood of a running system. +// In V2 Ledger API this service is not available. +type CommandInspectionServiceClient interface { + // Inquire about the status of a command. + // This service is used for debugging only. The command status is only tracked in memory and is not persisted. + // The service can be used to understand the failure status and the structure of a command. + // Requires admin privileges + // The service is alpha without backward compatibility guarantees. + GetCommandStatus(ctx context.Context, in *GetCommandStatusRequest, opts ...grpc.CallOption) (*GetCommandStatusResponse, error) +} + +type commandInspectionServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewCommandInspectionServiceClient(cc grpc.ClientConnInterface) CommandInspectionServiceClient { + return &commandInspectionServiceClient{cc} +} + +func (c *commandInspectionServiceClient) GetCommandStatus(ctx context.Context, in *GetCommandStatusRequest, opts ...grpc.CallOption) (*GetCommandStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetCommandStatusResponse) + err := c.cc.Invoke(ctx, CommandInspectionService_GetCommandStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CommandInspectionServiceServer is the server API for CommandInspectionService service. +// All implementations must embed UnimplementedCommandInspectionServiceServer +// for forward compatibility. +// +// Status: experimental interface, will change before it is deemed production +// ready +// +// The inspection service provides methods for the ledger administrator +// to look under the hood of a running system. +// In V2 Ledger API this service is not available. +type CommandInspectionServiceServer interface { + // Inquire about the status of a command. + // This service is used for debugging only. The command status is only tracked in memory and is not persisted. + // The service can be used to understand the failure status and the structure of a command. + // Requires admin privileges + // The service is alpha without backward compatibility guarantees. + GetCommandStatus(context.Context, *GetCommandStatusRequest) (*GetCommandStatusResponse, error) + mustEmbedUnimplementedCommandInspectionServiceServer() +} + +// UnimplementedCommandInspectionServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCommandInspectionServiceServer struct{} + +func (UnimplementedCommandInspectionServiceServer) GetCommandStatus(context.Context, *GetCommandStatusRequest) (*GetCommandStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCommandStatus not implemented") +} +func (UnimplementedCommandInspectionServiceServer) mustEmbedUnimplementedCommandInspectionServiceServer() { +} +func (UnimplementedCommandInspectionServiceServer) testEmbeddedByValue() {} + +// UnsafeCommandInspectionServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CommandInspectionServiceServer will +// result in compilation errors. +type UnsafeCommandInspectionServiceServer interface { + mustEmbedUnimplementedCommandInspectionServiceServer() +} + +func RegisterCommandInspectionServiceServer(s grpc.ServiceRegistrar, srv CommandInspectionServiceServer) { + // If the following call pancis, it indicates UnimplementedCommandInspectionServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&CommandInspectionService_ServiceDesc, srv) +} + +func _CommandInspectionService_GetCommandStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetCommandStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandInspectionServiceServer).GetCommandStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandInspectionService_GetCommandStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandInspectionServiceServer).GetCommandStatus(ctx, req.(*GetCommandStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// CommandInspectionService_ServiceDesc is the grpc.ServiceDesc for CommandInspectionService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var CommandInspectionService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.admin.CommandInspectionService", + HandlerType: (*CommandInspectionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetCommandStatus", + Handler: _CommandInspectionService_GetCommandStatus_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/admin/command_inspection_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service.pb.go new file mode 100644 index 00000000..59f96cd8 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service.pb.go @@ -0,0 +1,708 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/admin/identity_provider_config_service.proto + +package admin + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type IdentityProviderConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The identity provider identifier + // Must be a valid LedgerString (as describe in “value.proto“). + // + // Required + IdentityProviderId string `protobuf:"bytes,1,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + // When set, the callers using JWT tokens issued by this identity provider are denied all access + // to the Ledger API. + // Modifiable + // + // Optional + IsDeactivated bool `protobuf:"varint,2,opt,name=is_deactivated,json=isDeactivated,proto3" json:"is_deactivated,omitempty"` + // Specifies the issuer of the JWT token. + // The issuer value is a case sensitive URL using the https scheme that contains scheme, host, + // and optionally, port number and path components and no query or fragment components. + // Modifiable + // + // Can be left empty when used in `UpdateIdentityProviderConfigRequest` if the issuer is not being updated. + // + // Required + Issuer string `protobuf:"bytes,3,opt,name=issuer,proto3" json:"issuer,omitempty"` + // The JWKS (JSON Web Key Set) URL. + // The Ledger API uses JWKs (JSON Web Keys) from the provided URL to verify that the JWT has been + // signed with the loaded JWK. Only RS256 (RSA Signature with SHA-256) signing algorithm is supported. + // Modifiable + // + // Required + JwksUrl string `protobuf:"bytes,4,opt,name=jwks_url,json=jwksUrl,proto3" json:"jwks_url,omitempty"` + // Specifies the audience of the JWT token. + // When set, the callers using JWT tokens issued by this identity provider are allowed to get an access + // only if the "aud" claim includes the string specified here + // Modifiable + // + // Optional + Audience string `protobuf:"bytes,5,opt,name=audience,proto3" json:"audience,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IdentityProviderConfig) Reset() { + *x = IdentityProviderConfig{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IdentityProviderConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IdentityProviderConfig) ProtoMessage() {} + +func (x *IdentityProviderConfig) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IdentityProviderConfig.ProtoReflect.Descriptor instead. +func (*IdentityProviderConfig) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{0} +} + +func (x *IdentityProviderConfig) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +func (x *IdentityProviderConfig) GetIsDeactivated() bool { + if x != nil { + return x.IsDeactivated + } + return false +} + +func (x *IdentityProviderConfig) GetIssuer() string { + if x != nil { + return x.Issuer + } + return "" +} + +func (x *IdentityProviderConfig) GetJwksUrl() string { + if x != nil { + return x.JwksUrl + } + return "" +} + +func (x *IdentityProviderConfig) GetAudience() string { + if x != nil { + return x.Audience + } + return "" +} + +type CreateIdentityProviderConfigRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + IdentityProviderConfig *IdentityProviderConfig `protobuf:"bytes,1,opt,name=identity_provider_config,json=identityProviderConfig,proto3" json:"identity_provider_config,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateIdentityProviderConfigRequest) Reset() { + *x = CreateIdentityProviderConfigRequest{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateIdentityProviderConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateIdentityProviderConfigRequest) ProtoMessage() {} + +func (x *CreateIdentityProviderConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateIdentityProviderConfigRequest.ProtoReflect.Descriptor instead. +func (*CreateIdentityProviderConfigRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateIdentityProviderConfigRequest) GetIdentityProviderConfig() *IdentityProviderConfig { + if x != nil { + return x.IdentityProviderConfig + } + return nil +} + +type CreateIdentityProviderConfigResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + IdentityProviderConfig *IdentityProviderConfig `protobuf:"bytes,1,opt,name=identity_provider_config,json=identityProviderConfig,proto3" json:"identity_provider_config,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateIdentityProviderConfigResponse) Reset() { + *x = CreateIdentityProviderConfigResponse{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateIdentityProviderConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateIdentityProviderConfigResponse) ProtoMessage() {} + +func (x *CreateIdentityProviderConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateIdentityProviderConfigResponse.ProtoReflect.Descriptor instead. +func (*CreateIdentityProviderConfigResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateIdentityProviderConfigResponse) GetIdentityProviderConfig() *IdentityProviderConfig { + if x != nil { + return x.IdentityProviderConfig + } + return nil +} + +type GetIdentityProviderConfigRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + IdentityProviderId string `protobuf:"bytes,1,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetIdentityProviderConfigRequest) Reset() { + *x = GetIdentityProviderConfigRequest{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetIdentityProviderConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetIdentityProviderConfigRequest) ProtoMessage() {} + +func (x *GetIdentityProviderConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetIdentityProviderConfigRequest.ProtoReflect.Descriptor instead. +func (*GetIdentityProviderConfigRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{3} +} + +func (x *GetIdentityProviderConfigRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type GetIdentityProviderConfigResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + IdentityProviderConfig *IdentityProviderConfig `protobuf:"bytes,1,opt,name=identity_provider_config,json=identityProviderConfig,proto3" json:"identity_provider_config,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetIdentityProviderConfigResponse) Reset() { + *x = GetIdentityProviderConfigResponse{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetIdentityProviderConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetIdentityProviderConfigResponse) ProtoMessage() {} + +func (x *GetIdentityProviderConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetIdentityProviderConfigResponse.ProtoReflect.Descriptor instead. +func (*GetIdentityProviderConfigResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{4} +} + +func (x *GetIdentityProviderConfigResponse) GetIdentityProviderConfig() *IdentityProviderConfig { + if x != nil { + return x.IdentityProviderConfig + } + return nil +} + +type ListIdentityProviderConfigsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListIdentityProviderConfigsRequest) Reset() { + *x = ListIdentityProviderConfigsRequest{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListIdentityProviderConfigsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListIdentityProviderConfigsRequest) ProtoMessage() {} + +func (x *ListIdentityProviderConfigsRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListIdentityProviderConfigsRequest.ProtoReflect.Descriptor instead. +func (*ListIdentityProviderConfigsRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{5} +} + +type ListIdentityProviderConfigsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The list of identity provider configs + // + // Required: must be non-empty + IdentityProviderConfigs []*IdentityProviderConfig `protobuf:"bytes,1,rep,name=identity_provider_configs,json=identityProviderConfigs,proto3" json:"identity_provider_configs,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListIdentityProviderConfigsResponse) Reset() { + *x = ListIdentityProviderConfigsResponse{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListIdentityProviderConfigsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListIdentityProviderConfigsResponse) ProtoMessage() {} + +func (x *ListIdentityProviderConfigsResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListIdentityProviderConfigsResponse.ProtoReflect.Descriptor instead. +func (*ListIdentityProviderConfigsResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{6} +} + +func (x *ListIdentityProviderConfigsResponse) GetIdentityProviderConfigs() []*IdentityProviderConfig { + if x != nil { + return x.IdentityProviderConfigs + } + return nil +} + +type UpdateIdentityProviderConfigRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The identity provider config to update. + // Modifiable + // + // Required + IdentityProviderConfig *IdentityProviderConfig `protobuf:"bytes,1,opt,name=identity_provider_config,json=identityProviderConfig,proto3" json:"identity_provider_config,omitempty"` + // An update mask specifies how and which properties of the “IdentityProviderConfig“ message are to be updated. + // An update mask consists of a set of update paths. + // A valid update path points to a field or a subfield relative to the “IdentityProviderConfig“ message. + // A valid update mask must: + // + // 1. contain at least one update path, + // 2. contain only valid update paths. + // + // Fields that can be updated are marked as “Modifiable“. + // For additional information see the documentation for standard protobuf3's “google.protobuf.FieldMask“. + // + // Required + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateIdentityProviderConfigRequest) Reset() { + *x = UpdateIdentityProviderConfigRequest{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateIdentityProviderConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateIdentityProviderConfigRequest) ProtoMessage() {} + +func (x *UpdateIdentityProviderConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateIdentityProviderConfigRequest.ProtoReflect.Descriptor instead. +func (*UpdateIdentityProviderConfigRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateIdentityProviderConfigRequest) GetIdentityProviderConfig() *IdentityProviderConfig { + if x != nil { + return x.IdentityProviderConfig + } + return nil +} + +func (x *UpdateIdentityProviderConfigRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +type UpdateIdentityProviderConfigResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Updated identity provider config + // + // Required + IdentityProviderConfig *IdentityProviderConfig `protobuf:"bytes,1,opt,name=identity_provider_config,json=identityProviderConfig,proto3" json:"identity_provider_config,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateIdentityProviderConfigResponse) Reset() { + *x = UpdateIdentityProviderConfigResponse{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateIdentityProviderConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateIdentityProviderConfigResponse) ProtoMessage() {} + +func (x *UpdateIdentityProviderConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateIdentityProviderConfigResponse.ProtoReflect.Descriptor instead. +func (*UpdateIdentityProviderConfigResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{8} +} + +func (x *UpdateIdentityProviderConfigResponse) GetIdentityProviderConfig() *IdentityProviderConfig { + if x != nil { + return x.IdentityProviderConfig + } + return nil +} + +type DeleteIdentityProviderConfigRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The identity provider config to delete. + // + // Required + IdentityProviderId string `protobuf:"bytes,1,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteIdentityProviderConfigRequest) Reset() { + *x = DeleteIdentityProviderConfigRequest{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteIdentityProviderConfigRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteIdentityProviderConfigRequest) ProtoMessage() {} + +func (x *DeleteIdentityProviderConfigRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteIdentityProviderConfigRequest.ProtoReflect.Descriptor instead. +func (*DeleteIdentityProviderConfigRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{9} +} + +func (x *DeleteIdentityProviderConfigRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +// Does not (yet) contain any data. +type DeleteIdentityProviderConfigResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteIdentityProviderConfigResponse) Reset() { + *x = DeleteIdentityProviderConfigResponse{} + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteIdentityProviderConfigResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteIdentityProviderConfigResponse) ProtoMessage() {} + +func (x *DeleteIdentityProviderConfigResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteIdentityProviderConfigResponse.ProtoReflect.Descriptor instead. +func (*DeleteIdentityProviderConfigResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP(), []int{10} +} + +var File_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDesc = "" + + "\n" + + "Ccom/daml/ledger/api/v2/admin/identity_provider_config_service.proto\x12\x1ccom.daml.ledger.api.v2.admin\x1a google/protobuf/field_mask.proto\"\xc0\x01\n" + + "\x16IdentityProviderConfig\x120\n" + + "\x14identity_provider_id\x18\x01 \x01(\tR\x12identityProviderId\x12%\n" + + "\x0eis_deactivated\x18\x02 \x01(\bR\risDeactivated\x12\x16\n" + + "\x06issuer\x18\x03 \x01(\tR\x06issuer\x12\x19\n" + + "\bjwks_url\x18\x04 \x01(\tR\ajwksUrl\x12\x1a\n" + + "\baudience\x18\x05 \x01(\tR\baudience\"\x95\x01\n" + + "#CreateIdentityProviderConfigRequest\x12n\n" + + "\x18identity_provider_config\x18\x01 \x01(\v24.com.daml.ledger.api.v2.admin.IdentityProviderConfigR\x16identityProviderConfig\"\x96\x01\n" + + "$CreateIdentityProviderConfigResponse\x12n\n" + + "\x18identity_provider_config\x18\x01 \x01(\v24.com.daml.ledger.api.v2.admin.IdentityProviderConfigR\x16identityProviderConfig\"T\n" + + " GetIdentityProviderConfigRequest\x120\n" + + "\x14identity_provider_id\x18\x01 \x01(\tR\x12identityProviderId\"\x93\x01\n" + + "!GetIdentityProviderConfigResponse\x12n\n" + + "\x18identity_provider_config\x18\x01 \x01(\v24.com.daml.ledger.api.v2.admin.IdentityProviderConfigR\x16identityProviderConfig\"$\n" + + "\"ListIdentityProviderConfigsRequest\"\x97\x01\n" + + "#ListIdentityProviderConfigsResponse\x12p\n" + + "\x19identity_provider_configs\x18\x01 \x03(\v24.com.daml.ledger.api.v2.admin.IdentityProviderConfigR\x17identityProviderConfigs\"\xd2\x01\n" + + "#UpdateIdentityProviderConfigRequest\x12n\n" + + "\x18identity_provider_config\x18\x01 \x01(\v24.com.daml.ledger.api.v2.admin.IdentityProviderConfigR\x16identityProviderConfig\x12;\n" + + "\vupdate_mask\x18\x02 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" + + "updateMask\"\x96\x01\n" + + "$UpdateIdentityProviderConfigResponse\x12n\n" + + "\x18identity_provider_config\x18\x01 \x01(\v24.com.daml.ledger.api.v2.admin.IdentityProviderConfigR\x16identityProviderConfig\"W\n" + + "#DeleteIdentityProviderConfigRequest\x120\n" + + "\x14identity_provider_id\x18\x01 \x01(\tR\x12identityProviderId\"&\n" + + "$DeleteIdentityProviderConfigResponse2\xdb\x06\n" + + "\x1dIdentityProviderConfigService\x12\xa5\x01\n" + + "\x1cCreateIdentityProviderConfig\x12A.com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigRequest\x1aB.com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigResponse\x12\x9c\x01\n" + + "\x19GetIdentityProviderConfig\x12>.com.daml.ledger.api.v2.admin.GetIdentityProviderConfigRequest\x1a?.com.daml.ledger.api.v2.admin.GetIdentityProviderConfigResponse\x12\xa5\x01\n" + + "\x1cUpdateIdentityProviderConfig\x12A.com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigRequest\x1aB.com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigResponse\x12\xa2\x01\n" + + "\x1bListIdentityProviderConfigs\x12@.com.daml.ledger.api.v2.admin.ListIdentityProviderConfigsRequest\x1aA.com.daml.ledger.api.v2.admin.ListIdentityProviderConfigsResponse\x12\xa5\x01\n" + + "\x1cDeleteIdentityProviderConfig\x12A.com.daml.ledger.api.v2.admin.DeleteIdentityProviderConfigRequest\x1aB.com.daml.ledger.api.v2.admin.DeleteIdentityProviderConfigResponseB\xb0\x02\n" + + " com.com.daml.ledger.api.v2.adminB\"IdentityProviderConfigServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin\xa2\x02\x06CDLAVA\xaa\x02\x1cCom.Daml.Ledger.Api.V2.Admin\xca\x02\x1cCom\\Daml\\Ledger\\Api\\V2\\Admin\xe2\x02(Com\\Daml\\Ledger\\Api\\V2\\Admin\\GPBMetadata\xea\x02!Com::Daml::Ledger::Api::V2::Adminb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_goTypes = []any{ + (*IdentityProviderConfig)(nil), // 0: com.daml.ledger.api.v2.admin.IdentityProviderConfig + (*CreateIdentityProviderConfigRequest)(nil), // 1: com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigRequest + (*CreateIdentityProviderConfigResponse)(nil), // 2: com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigResponse + (*GetIdentityProviderConfigRequest)(nil), // 3: com.daml.ledger.api.v2.admin.GetIdentityProviderConfigRequest + (*GetIdentityProviderConfigResponse)(nil), // 4: com.daml.ledger.api.v2.admin.GetIdentityProviderConfigResponse + (*ListIdentityProviderConfigsRequest)(nil), // 5: com.daml.ledger.api.v2.admin.ListIdentityProviderConfigsRequest + (*ListIdentityProviderConfigsResponse)(nil), // 6: com.daml.ledger.api.v2.admin.ListIdentityProviderConfigsResponse + (*UpdateIdentityProviderConfigRequest)(nil), // 7: com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigRequest + (*UpdateIdentityProviderConfigResponse)(nil), // 8: com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigResponse + (*DeleteIdentityProviderConfigRequest)(nil), // 9: com.daml.ledger.api.v2.admin.DeleteIdentityProviderConfigRequest + (*DeleteIdentityProviderConfigResponse)(nil), // 10: com.daml.ledger.api.v2.admin.DeleteIdentityProviderConfigResponse + (*fieldmaskpb.FieldMask)(nil), // 11: google.protobuf.FieldMask +} +var file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_depIdxs = []int32{ + 0, // 0: com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigRequest.identity_provider_config:type_name -> com.daml.ledger.api.v2.admin.IdentityProviderConfig + 0, // 1: com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigResponse.identity_provider_config:type_name -> com.daml.ledger.api.v2.admin.IdentityProviderConfig + 0, // 2: com.daml.ledger.api.v2.admin.GetIdentityProviderConfigResponse.identity_provider_config:type_name -> com.daml.ledger.api.v2.admin.IdentityProviderConfig + 0, // 3: com.daml.ledger.api.v2.admin.ListIdentityProviderConfigsResponse.identity_provider_configs:type_name -> com.daml.ledger.api.v2.admin.IdentityProviderConfig + 0, // 4: com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigRequest.identity_provider_config:type_name -> com.daml.ledger.api.v2.admin.IdentityProviderConfig + 11, // 5: com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigRequest.update_mask:type_name -> google.protobuf.FieldMask + 0, // 6: com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigResponse.identity_provider_config:type_name -> com.daml.ledger.api.v2.admin.IdentityProviderConfig + 1, // 7: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.CreateIdentityProviderConfig:input_type -> com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigRequest + 3, // 8: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.GetIdentityProviderConfig:input_type -> com.daml.ledger.api.v2.admin.GetIdentityProviderConfigRequest + 7, // 9: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.UpdateIdentityProviderConfig:input_type -> com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigRequest + 5, // 10: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.ListIdentityProviderConfigs:input_type -> com.daml.ledger.api.v2.admin.ListIdentityProviderConfigsRequest + 9, // 11: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.DeleteIdentityProviderConfig:input_type -> com.daml.ledger.api.v2.admin.DeleteIdentityProviderConfigRequest + 2, // 12: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.CreateIdentityProviderConfig:output_type -> com.daml.ledger.api.v2.admin.CreateIdentityProviderConfigResponse + 4, // 13: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.GetIdentityProviderConfig:output_type -> com.daml.ledger.api.v2.admin.GetIdentityProviderConfigResponse + 8, // 14: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.UpdateIdentityProviderConfig:output_type -> com.daml.ledger.api.v2.admin.UpdateIdentityProviderConfigResponse + 6, // 15: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.ListIdentityProviderConfigs:output_type -> com.daml.ledger.api.v2.admin.ListIdentityProviderConfigsResponse + 10, // 16: com.daml.ledger.api.v2.admin.IdentityProviderConfigService.DeleteIdentityProviderConfig:output_type -> com.daml.ledger.api.v2.admin.DeleteIdentityProviderConfigResponse + 12, // [12:17] is the sub-list for method output_type + 7, // [7:12] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_init() } +func file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_init() { + if File_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 11, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto = out.File + file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_admin_identity_provider_config_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service_grpc.pb.go new file mode 100644 index 00000000..9ff96b15 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/identity_provider_config_service_grpc.pb.go @@ -0,0 +1,339 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/admin/identity_provider_config_service.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + IdentityProviderConfigService_CreateIdentityProviderConfig_FullMethodName = "/com.daml.ledger.api.v2.admin.IdentityProviderConfigService/CreateIdentityProviderConfig" + IdentityProviderConfigService_GetIdentityProviderConfig_FullMethodName = "/com.daml.ledger.api.v2.admin.IdentityProviderConfigService/GetIdentityProviderConfig" + IdentityProviderConfigService_UpdateIdentityProviderConfig_FullMethodName = "/com.daml.ledger.api.v2.admin.IdentityProviderConfigService/UpdateIdentityProviderConfig" + IdentityProviderConfigService_ListIdentityProviderConfigs_FullMethodName = "/com.daml.ledger.api.v2.admin.IdentityProviderConfigService/ListIdentityProviderConfigs" + IdentityProviderConfigService_DeleteIdentityProviderConfig_FullMethodName = "/com.daml.ledger.api.v2.admin.IdentityProviderConfigService/DeleteIdentityProviderConfig" +) + +// IdentityProviderConfigServiceClient is the client API for IdentityProviderConfigService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Identity Provider Config Service makes it possible for participant node administrators +// to setup and manage additional identity providers at runtime. +// +// This allows using access tokens from identity providers unknown at deployment time. When an identity +// provider is configured, independent IDP administrators can manage their own set of parties and users. +// Such parties and users have a matching `identity_provider_id` defined and are inaccessible to +// administrators from other identity providers. A user will only be authenticated if the corresponding JWT +// token is issued by the appropriate identity provider. +// Users and parties without `identity_provider_id` defined are assumed to be using the default identity provider, +// which is configured statically at the participant node's deployment time. +// +// The Ledger API uses the "iss" claim of a JWT token to match the token to a specific IDP. If there is no match, +// the default IDP is assumed. +// +// The fields of request messages (and sub-messages) are marked either as “Optional“ or “Required“: +// +// 1. “Optional“ denoting the client may leave the field unset when sending a request. +// 2. “Required“ denoting the client must set the field to a non-default value when sending a request. +// +// An identity provider config resource is described by the “IdentityProviderConfig“ message, +// An identity provider config resource, once it has been created, can be modified. +// In order to update the properties represented by the “IdentityProviderConfig“ message use the “UpdateIdentityProviderConfig“ RPC. +// The only fields that can be modified are those marked as “Modifiable“. +type IdentityProviderConfigServiceClient interface { + // Create a new identity provider configuration. + // The request will fail if the maximum allowed number of separate configurations is reached. + CreateIdentityProviderConfig(ctx context.Context, in *CreateIdentityProviderConfigRequest, opts ...grpc.CallOption) (*CreateIdentityProviderConfigResponse, error) + // Get the identity provider configuration data by id. + GetIdentityProviderConfig(ctx context.Context, in *GetIdentityProviderConfigRequest, opts ...grpc.CallOption) (*GetIdentityProviderConfigResponse, error) + // Update selected modifiable attribute of an identity provider config resource described + // by the “IdentityProviderConfig“ message. + UpdateIdentityProviderConfig(ctx context.Context, in *UpdateIdentityProviderConfigRequest, opts ...grpc.CallOption) (*UpdateIdentityProviderConfigResponse, error) + // List all existing identity provider configurations. + ListIdentityProviderConfigs(ctx context.Context, in *ListIdentityProviderConfigsRequest, opts ...grpc.CallOption) (*ListIdentityProviderConfigsResponse, error) + // Delete an existing identity provider configuration. + DeleteIdentityProviderConfig(ctx context.Context, in *DeleteIdentityProviderConfigRequest, opts ...grpc.CallOption) (*DeleteIdentityProviderConfigResponse, error) +} + +type identityProviderConfigServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewIdentityProviderConfigServiceClient(cc grpc.ClientConnInterface) IdentityProviderConfigServiceClient { + return &identityProviderConfigServiceClient{cc} +} + +func (c *identityProviderConfigServiceClient) CreateIdentityProviderConfig(ctx context.Context, in *CreateIdentityProviderConfigRequest, opts ...grpc.CallOption) (*CreateIdentityProviderConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateIdentityProviderConfigResponse) + err := c.cc.Invoke(ctx, IdentityProviderConfigService_CreateIdentityProviderConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *identityProviderConfigServiceClient) GetIdentityProviderConfig(ctx context.Context, in *GetIdentityProviderConfigRequest, opts ...grpc.CallOption) (*GetIdentityProviderConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetIdentityProviderConfigResponse) + err := c.cc.Invoke(ctx, IdentityProviderConfigService_GetIdentityProviderConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *identityProviderConfigServiceClient) UpdateIdentityProviderConfig(ctx context.Context, in *UpdateIdentityProviderConfigRequest, opts ...grpc.CallOption) (*UpdateIdentityProviderConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateIdentityProviderConfigResponse) + err := c.cc.Invoke(ctx, IdentityProviderConfigService_UpdateIdentityProviderConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *identityProviderConfigServiceClient) ListIdentityProviderConfigs(ctx context.Context, in *ListIdentityProviderConfigsRequest, opts ...grpc.CallOption) (*ListIdentityProviderConfigsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListIdentityProviderConfigsResponse) + err := c.cc.Invoke(ctx, IdentityProviderConfigService_ListIdentityProviderConfigs_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *identityProviderConfigServiceClient) DeleteIdentityProviderConfig(ctx context.Context, in *DeleteIdentityProviderConfigRequest, opts ...grpc.CallOption) (*DeleteIdentityProviderConfigResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteIdentityProviderConfigResponse) + err := c.cc.Invoke(ctx, IdentityProviderConfigService_DeleteIdentityProviderConfig_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// IdentityProviderConfigServiceServer is the server API for IdentityProviderConfigService service. +// All implementations must embed UnimplementedIdentityProviderConfigServiceServer +// for forward compatibility. +// +// Identity Provider Config Service makes it possible for participant node administrators +// to setup and manage additional identity providers at runtime. +// +// This allows using access tokens from identity providers unknown at deployment time. When an identity +// provider is configured, independent IDP administrators can manage their own set of parties and users. +// Such parties and users have a matching `identity_provider_id` defined and are inaccessible to +// administrators from other identity providers. A user will only be authenticated if the corresponding JWT +// token is issued by the appropriate identity provider. +// Users and parties without `identity_provider_id` defined are assumed to be using the default identity provider, +// which is configured statically at the participant node's deployment time. +// +// The Ledger API uses the "iss" claim of a JWT token to match the token to a specific IDP. If there is no match, +// the default IDP is assumed. +// +// The fields of request messages (and sub-messages) are marked either as “Optional“ or “Required“: +// +// 1. “Optional“ denoting the client may leave the field unset when sending a request. +// 2. “Required“ denoting the client must set the field to a non-default value when sending a request. +// +// An identity provider config resource is described by the “IdentityProviderConfig“ message, +// An identity provider config resource, once it has been created, can be modified. +// In order to update the properties represented by the “IdentityProviderConfig“ message use the “UpdateIdentityProviderConfig“ RPC. +// The only fields that can be modified are those marked as “Modifiable“. +type IdentityProviderConfigServiceServer interface { + // Create a new identity provider configuration. + // The request will fail if the maximum allowed number of separate configurations is reached. + CreateIdentityProviderConfig(context.Context, *CreateIdentityProviderConfigRequest) (*CreateIdentityProviderConfigResponse, error) + // Get the identity provider configuration data by id. + GetIdentityProviderConfig(context.Context, *GetIdentityProviderConfigRequest) (*GetIdentityProviderConfigResponse, error) + // Update selected modifiable attribute of an identity provider config resource described + // by the “IdentityProviderConfig“ message. + UpdateIdentityProviderConfig(context.Context, *UpdateIdentityProviderConfigRequest) (*UpdateIdentityProviderConfigResponse, error) + // List all existing identity provider configurations. + ListIdentityProviderConfigs(context.Context, *ListIdentityProviderConfigsRequest) (*ListIdentityProviderConfigsResponse, error) + // Delete an existing identity provider configuration. + DeleteIdentityProviderConfig(context.Context, *DeleteIdentityProviderConfigRequest) (*DeleteIdentityProviderConfigResponse, error) + mustEmbedUnimplementedIdentityProviderConfigServiceServer() +} + +// UnimplementedIdentityProviderConfigServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedIdentityProviderConfigServiceServer struct{} + +func (UnimplementedIdentityProviderConfigServiceServer) CreateIdentityProviderConfig(context.Context, *CreateIdentityProviderConfigRequest) (*CreateIdentityProviderConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateIdentityProviderConfig not implemented") +} +func (UnimplementedIdentityProviderConfigServiceServer) GetIdentityProviderConfig(context.Context, *GetIdentityProviderConfigRequest) (*GetIdentityProviderConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetIdentityProviderConfig not implemented") +} +func (UnimplementedIdentityProviderConfigServiceServer) UpdateIdentityProviderConfig(context.Context, *UpdateIdentityProviderConfigRequest) (*UpdateIdentityProviderConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateIdentityProviderConfig not implemented") +} +func (UnimplementedIdentityProviderConfigServiceServer) ListIdentityProviderConfigs(context.Context, *ListIdentityProviderConfigsRequest) (*ListIdentityProviderConfigsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListIdentityProviderConfigs not implemented") +} +func (UnimplementedIdentityProviderConfigServiceServer) DeleteIdentityProviderConfig(context.Context, *DeleteIdentityProviderConfigRequest) (*DeleteIdentityProviderConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteIdentityProviderConfig not implemented") +} +func (UnimplementedIdentityProviderConfigServiceServer) mustEmbedUnimplementedIdentityProviderConfigServiceServer() { +} +func (UnimplementedIdentityProviderConfigServiceServer) testEmbeddedByValue() {} + +// UnsafeIdentityProviderConfigServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to IdentityProviderConfigServiceServer will +// result in compilation errors. +type UnsafeIdentityProviderConfigServiceServer interface { + mustEmbedUnimplementedIdentityProviderConfigServiceServer() +} + +func RegisterIdentityProviderConfigServiceServer(s grpc.ServiceRegistrar, srv IdentityProviderConfigServiceServer) { + // If the following call pancis, it indicates UnimplementedIdentityProviderConfigServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&IdentityProviderConfigService_ServiceDesc, srv) +} + +func _IdentityProviderConfigService_CreateIdentityProviderConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateIdentityProviderConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IdentityProviderConfigServiceServer).CreateIdentityProviderConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: IdentityProviderConfigService_CreateIdentityProviderConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IdentityProviderConfigServiceServer).CreateIdentityProviderConfig(ctx, req.(*CreateIdentityProviderConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _IdentityProviderConfigService_GetIdentityProviderConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetIdentityProviderConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IdentityProviderConfigServiceServer).GetIdentityProviderConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: IdentityProviderConfigService_GetIdentityProviderConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IdentityProviderConfigServiceServer).GetIdentityProviderConfig(ctx, req.(*GetIdentityProviderConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _IdentityProviderConfigService_UpdateIdentityProviderConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateIdentityProviderConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IdentityProviderConfigServiceServer).UpdateIdentityProviderConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: IdentityProviderConfigService_UpdateIdentityProviderConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IdentityProviderConfigServiceServer).UpdateIdentityProviderConfig(ctx, req.(*UpdateIdentityProviderConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _IdentityProviderConfigService_ListIdentityProviderConfigs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListIdentityProviderConfigsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IdentityProviderConfigServiceServer).ListIdentityProviderConfigs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: IdentityProviderConfigService_ListIdentityProviderConfigs_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IdentityProviderConfigServiceServer).ListIdentityProviderConfigs(ctx, req.(*ListIdentityProviderConfigsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _IdentityProviderConfigService_DeleteIdentityProviderConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteIdentityProviderConfigRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IdentityProviderConfigServiceServer).DeleteIdentityProviderConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: IdentityProviderConfigService_DeleteIdentityProviderConfig_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IdentityProviderConfigServiceServer).DeleteIdentityProviderConfig(ctx, req.(*DeleteIdentityProviderConfigRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// IdentityProviderConfigService_ServiceDesc is the grpc.ServiceDesc for IdentityProviderConfigService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var IdentityProviderConfigService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.admin.IdentityProviderConfigService", + HandlerType: (*IdentityProviderConfigServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateIdentityProviderConfig", + Handler: _IdentityProviderConfigService_CreateIdentityProviderConfig_Handler, + }, + { + MethodName: "GetIdentityProviderConfig", + Handler: _IdentityProviderConfigService_GetIdentityProviderConfig_Handler, + }, + { + MethodName: "UpdateIdentityProviderConfig", + Handler: _IdentityProviderConfigService_UpdateIdentityProviderConfig_Handler, + }, + { + MethodName: "ListIdentityProviderConfigs", + Handler: _IdentityProviderConfigService_ListIdentityProviderConfigs_Handler, + }, + { + MethodName: "DeleteIdentityProviderConfig", + Handler: _IdentityProviderConfigService_DeleteIdentityProviderConfig_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/admin/identity_provider_config_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/object_meta.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/object_meta.pb.go new file mode 100644 index 00000000..0d36fbc9 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/object_meta.pb.go @@ -0,0 +1,182 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/admin/object_meta.proto + +package admin + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// 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 +type ObjectMeta struct { + state protoimpl.MessageState `protogen:"open.v1"` + // An opaque, non-empty 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 + ResourceVersion string `protobuf:"bytes,6,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` + // 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. + // + // 3. 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. + // Modifiable + // + // Optional: can be empty + Annotations map[string]string `protobuf:"bytes,12,rep,name=annotations,proto3" json:"annotations,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ObjectMeta) Reset() { + *x = ObjectMeta{} + mi := &file_com_daml_ledger_api_v2_admin_object_meta_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ObjectMeta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectMeta) ProtoMessage() {} + +func (x *ObjectMeta) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_object_meta_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectMeta.ProtoReflect.Descriptor instead. +func (*ObjectMeta) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDescGZIP(), []int{0} +} + +func (x *ObjectMeta) GetResourceVersion() string { + if x != nil { + return x.ResourceVersion + } + return "" +} + +func (x *ObjectMeta) GetAnnotations() map[string]string { + if x != nil { + return x.Annotations + } + return nil +} + +var File_com_daml_ledger_api_v2_admin_object_meta_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDesc = "" + + "\n" + + ".com/daml/ledger/api/v2/admin/object_meta.proto\x12\x1ccom.daml.ledger.api.v2.admin\"\xd4\x01\n" + + "\n" + + "ObjectMeta\x12)\n" + + "\x10resource_version\x18\x06 \x01(\tR\x0fresourceVersion\x12[\n" + + "\vannotations\x18\f \x03(\v29.com.daml.ledger.api.v2.admin.ObjectMeta.AnnotationsEntryR\vannotations\x1a>\n" + + "\x10AnnotationsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x9d\x02\n" + + " com.com.daml.ledger.api.v2.adminB\x0fObjectMetaProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin\xa2\x02\x06CDLAVA\xaa\x02\x1cCom.Daml.Ledger.Api.V2.Admin\xca\x02\x1cCom\\Daml\\Ledger\\Api\\V2\\Admin\xe2\x02(Com\\Daml\\Ledger\\Api\\V2\\Admin\\GPBMetadata\xea\x02!Com::Daml::Ledger::Api::V2::Adminb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_admin_object_meta_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_com_daml_ledger_api_v2_admin_object_meta_proto_goTypes = []any{ + (*ObjectMeta)(nil), // 0: com.daml.ledger.api.v2.admin.ObjectMeta + nil, // 1: com.daml.ledger.api.v2.admin.ObjectMeta.AnnotationsEntry +} +var file_com_daml_ledger_api_v2_admin_object_meta_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.admin.ObjectMeta.annotations:type_name -> com.daml.ledger.api.v2.admin.ObjectMeta.AnnotationsEntry + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_admin_object_meta_proto_init() } +func file_com_daml_ledger_api_v2_admin_object_meta_proto_init() { + if File_com_daml_ledger_api_v2_admin_object_meta_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_object_meta_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_admin_object_meta_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_admin_object_meta_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_admin_object_meta_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_admin_object_meta_proto = out.File + file_com_daml_ledger_api_v2_admin_object_meta_proto_goTypes = nil + file_com_daml_ledger_api_v2_admin_object_meta_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service.pb.go new file mode 100644 index 00000000..764a8d74 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service.pb.go @@ -0,0 +1,1171 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/admin/package_management_service.proto + +package admin + +import ( + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UpdateVettedPackagesForceFlag int32 + +const ( + // Force flag left unspecified, defaults to no force flag used in the backend. + UpdateVettedPackagesForceFlag_UPDATE_VETTED_PACKAGES_FORCE_FLAG_UNSPECIFIED UpdateVettedPackagesForceFlag = 0 + // * Allow vetting a package that is upgrade-incompatible with other vetted packages + UpdateVettedPackagesForceFlag_UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_VET_INCOMPATIBLE_UPGRADES UpdateVettedPackagesForceFlag = 2 + // * Allow vetting a package without vetting one or more of its dependencies + UpdateVettedPackagesForceFlag_UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_UNVETTED_DEPENDENCIES UpdateVettedPackagesForceFlag = 3 +) + +// Enum value maps for UpdateVettedPackagesForceFlag. +var ( + UpdateVettedPackagesForceFlag_name = map[int32]string{ + 0: "UPDATE_VETTED_PACKAGES_FORCE_FLAG_UNSPECIFIED", + 2: "UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_VET_INCOMPATIBLE_UPGRADES", + 3: "UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_UNVETTED_DEPENDENCIES", + } + UpdateVettedPackagesForceFlag_value = map[string]int32{ + "UPDATE_VETTED_PACKAGES_FORCE_FLAG_UNSPECIFIED": 0, + "UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_VET_INCOMPATIBLE_UPGRADES": 2, + "UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_UNVETTED_DEPENDENCIES": 3, + } +) + +func (x UpdateVettedPackagesForceFlag) Enum() *UpdateVettedPackagesForceFlag { + p := new(UpdateVettedPackagesForceFlag) + *p = x + return p +} + +func (x UpdateVettedPackagesForceFlag) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (UpdateVettedPackagesForceFlag) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_enumTypes[0].Descriptor() +} + +func (UpdateVettedPackagesForceFlag) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_admin_package_management_service_proto_enumTypes[0] +} + +func (x UpdateVettedPackagesForceFlag) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UpdateVettedPackagesForceFlag.Descriptor instead. +func (UpdateVettedPackagesForceFlag) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{0} +} + +type UploadDarFileRequest_VettingChange int32 + +const ( + // Vetting change field left unspecified, defaults to vetting all the + // packages in the DAR. + UploadDarFileRequest_VETTING_CHANGE_UNSPECIFIED UploadDarFileRequest_VettingChange = 0 + // Vet all the packages in the DAR. + UploadDarFileRequest_VETTING_CHANGE_VET_ALL_PACKAGES UploadDarFileRequest_VettingChange = 1 + // Do not vet any packages in the DAR. + UploadDarFileRequest_VETTING_CHANGE_DONT_VET_ANY_PACKAGES UploadDarFileRequest_VettingChange = 2 +) + +// Enum value maps for UploadDarFileRequest_VettingChange. +var ( + UploadDarFileRequest_VettingChange_name = map[int32]string{ + 0: "VETTING_CHANGE_UNSPECIFIED", + 1: "VETTING_CHANGE_VET_ALL_PACKAGES", + 2: "VETTING_CHANGE_DONT_VET_ANY_PACKAGES", + } + UploadDarFileRequest_VettingChange_value = map[string]int32{ + "VETTING_CHANGE_UNSPECIFIED": 0, + "VETTING_CHANGE_VET_ALL_PACKAGES": 1, + "VETTING_CHANGE_DONT_VET_ANY_PACKAGES": 2, + } +) + +func (x UploadDarFileRequest_VettingChange) Enum() *UploadDarFileRequest_VettingChange { + p := new(UploadDarFileRequest_VettingChange) + *p = x + return p +} + +func (x UploadDarFileRequest_VettingChange) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (UploadDarFileRequest_VettingChange) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_enumTypes[1].Descriptor() +} + +func (UploadDarFileRequest_VettingChange) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_admin_package_management_service_proto_enumTypes[1] +} + +func (x UploadDarFileRequest_VettingChange) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UploadDarFileRequest_VettingChange.Descriptor instead. +func (UploadDarFileRequest_VettingChange) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{3, 0} +} + +type ListKnownPackagesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListKnownPackagesRequest) Reset() { + *x = ListKnownPackagesRequest{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListKnownPackagesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListKnownPackagesRequest) ProtoMessage() {} + +func (x *ListKnownPackagesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListKnownPackagesRequest.ProtoReflect.Descriptor instead. +func (*ListKnownPackagesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{0} +} + +type ListKnownPackagesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The details of all Daml-LF packages known to backing participant. + // + // Required: must be non-empty + PackageDetails []*PackageDetails `protobuf:"bytes,1,rep,name=package_details,json=packageDetails,proto3" json:"package_details,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListKnownPackagesResponse) Reset() { + *x = ListKnownPackagesResponse{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListKnownPackagesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListKnownPackagesResponse) ProtoMessage() {} + +func (x *ListKnownPackagesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListKnownPackagesResponse.ProtoReflect.Descriptor instead. +func (*ListKnownPackagesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{1} +} + +func (x *ListKnownPackagesResponse) GetPackageDetails() []*PackageDetails { + if x != nil { + return x.PackageDetails + } + return nil +} + +type PackageDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The identity of the Daml-LF package. + // Must be a valid PackageIdString (as describe in “value.proto“). + // + // Required + PackageId string `protobuf:"bytes,1,opt,name=package_id,json=packageId,proto3" json:"package_id,omitempty"` + // Size of the package in bytes. + // The size of the package is given by the size of the “daml_lf“ + // ArchivePayload. See further details in “daml_lf.proto“. + // + // Required + PackageSize uint64 `protobuf:"varint,2,opt,name=package_size,json=packageSize,proto3" json:"package_size,omitempty"` + // Indicates since when the package is known to the backing participant. + // Required + KnownSince *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=known_since,json=knownSince,proto3" json:"known_since,omitempty"` + // Name of the package as defined by the package metadata + // + // Required + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + // Version of the package as defined by the package metadata + // + // Required + Version string `protobuf:"bytes,5,opt,name=version,proto3" json:"version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PackageDetails) Reset() { + *x = PackageDetails{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PackageDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PackageDetails) ProtoMessage() {} + +func (x *PackageDetails) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PackageDetails.ProtoReflect.Descriptor instead. +func (*PackageDetails) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{2} +} + +func (x *PackageDetails) GetPackageId() string { + if x != nil { + return x.PackageId + } + return "" +} + +func (x *PackageDetails) GetPackageSize() uint64 { + if x != nil { + return x.PackageSize + } + return 0 +} + +func (x *PackageDetails) GetKnownSince() *timestamppb.Timestamp { + if x != nil { + return x.KnownSince + } + return nil +} + +func (x *PackageDetails) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *PackageDetails) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +type UploadDarFileRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Contains a Daml archive DAR file, which in turn is a jar like zipped + // container for “daml_lf“ archives. See further details in + // “daml_lf.proto“. + // + // Required: must be non-empty + DarFile []byte `protobuf:"bytes,1,opt,name=dar_file,json=darFile,proto3" json:"dar_file,omitempty"` + // Unique submission identifier. + // If not populated, a random identifier will be generated. + // + // Optional + SubmissionId string `protobuf:"bytes,2,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // How to vet packages in the DAR being uploaded + // + // Optional + VettingChange UploadDarFileRequest_VettingChange `protobuf:"varint,3,opt,name=vetting_change,json=vettingChange,proto3,enum=com.daml.ledger.api.v2.admin.UploadDarFileRequest_VettingChange" json:"vetting_change,omitempty"` + // Only used if VettingChange is set to VETTING_CHANGE_VET_ALL_PACKAGES, in + // order to specify which synchronizer to vet on. + // + // If synchronizer_id is set, the synchronizer with this ID will be used. If + // synchronizer_id is unset and the participant is only connected to a single + // synchronizer, that synchronizer will be used by default. If synchronizer_id + // is unset and the participant is connected to multiple synchronizers, the + // request will error out with PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. + // + // Optional + SynchronizerId string `protobuf:"bytes,4,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadDarFileRequest) Reset() { + *x = UploadDarFileRequest{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadDarFileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadDarFileRequest) ProtoMessage() {} + +func (x *UploadDarFileRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadDarFileRequest.ProtoReflect.Descriptor instead. +func (*UploadDarFileRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{3} +} + +func (x *UploadDarFileRequest) GetDarFile() []byte { + if x != nil { + return x.DarFile + } + return nil +} + +func (x *UploadDarFileRequest) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *UploadDarFileRequest) GetVettingChange() UploadDarFileRequest_VettingChange { + if x != nil { + return x.VettingChange + } + return UploadDarFileRequest_VETTING_CHANGE_UNSPECIFIED +} + +func (x *UploadDarFileRequest) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +// A message that is received when the upload operation succeeded. +type UploadDarFileResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UploadDarFileResponse) Reset() { + *x = UploadDarFileResponse{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UploadDarFileResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UploadDarFileResponse) ProtoMessage() {} + +func (x *UploadDarFileResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UploadDarFileResponse.ProtoReflect.Descriptor instead. +func (*UploadDarFileResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{4} +} + +// Performs the same checks that UploadDarFileRequest would perform, but doesn't +// upload the DAR. +type ValidateDarFileRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Contains a Daml archive DAR file, which in turn is a jar like zipped + // container for “daml_lf“ archives. See further details in + // “daml_lf.proto“. + // + // Required: must be non-empty + DarFile []byte `protobuf:"bytes,1,opt,name=dar_file,json=darFile,proto3" json:"dar_file,omitempty"` + // Unique submission identifier. If not defined, defaults to a random identifier. + // + // Optional + SubmissionId string `protobuf:"bytes,2,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // If synchronizer_id is set, the synchronizer with this ID will be used. If + // synchronizer_id is unset and the participant is only connected to a single + // synchronizer, that synchronizer will be used by default. If synchronizer_id + // is unset and the participant is connected to multiple synchronizers, the + // request will error out with PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. + // + // Optional + SynchronizerId string `protobuf:"bytes,4,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidateDarFileRequest) Reset() { + *x = ValidateDarFileRequest{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidateDarFileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateDarFileRequest) ProtoMessage() {} + +func (x *ValidateDarFileRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateDarFileRequest.ProtoReflect.Descriptor instead. +func (*ValidateDarFileRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{5} +} + +func (x *ValidateDarFileRequest) GetDarFile() []byte { + if x != nil { + return x.DarFile + } + return nil +} + +func (x *ValidateDarFileRequest) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *ValidateDarFileRequest) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +type ValidateDarFileResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ValidateDarFileResponse) Reset() { + *x = ValidateDarFileResponse{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ValidateDarFileResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ValidateDarFileResponse) ProtoMessage() {} + +func (x *ValidateDarFileResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ValidateDarFileResponse.ProtoReflect.Descriptor instead. +func (*ValidateDarFileResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{6} +} + +// A change to the set of vetted packages. +type VettedPackagesChange struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Operation: + // + // *VettedPackagesChange_Vet_ + // *VettedPackagesChange_Unvet_ + Operation isVettedPackagesChange_Operation `protobuf_oneof:"operation"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VettedPackagesChange) Reset() { + *x = VettedPackagesChange{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VettedPackagesChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VettedPackagesChange) ProtoMessage() {} + +func (x *VettedPackagesChange) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VettedPackagesChange.ProtoReflect.Descriptor instead. +func (*VettedPackagesChange) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{7} +} + +func (x *VettedPackagesChange) GetOperation() isVettedPackagesChange_Operation { + if x != nil { + return x.Operation + } + return nil +} + +func (x *VettedPackagesChange) GetVet() *VettedPackagesChange_Vet { + if x != nil { + if x, ok := x.Operation.(*VettedPackagesChange_Vet_); ok { + return x.Vet + } + } + return nil +} + +func (x *VettedPackagesChange) GetUnvet() *VettedPackagesChange_Unvet { + if x != nil { + if x, ok := x.Operation.(*VettedPackagesChange_Unvet_); ok { + return x.Unvet + } + } + return nil +} + +type isVettedPackagesChange_Operation interface { + isVettedPackagesChange_Operation() +} + +type VettedPackagesChange_Vet_ struct { + // Add packages to or update packages in the set of vetted packages. + Vet *VettedPackagesChange_Vet `protobuf:"bytes,1,opt,name=vet,proto3,oneof"` +} + +type VettedPackagesChange_Unvet_ struct { + // Remove packages from the set of vetted packages. + Unvet *VettedPackagesChange_Unvet `protobuf:"bytes,2,opt,name=unvet,proto3,oneof"` +} + +func (*VettedPackagesChange_Vet_) isVettedPackagesChange_Operation() {} + +func (*VettedPackagesChange_Unvet_) isVettedPackagesChange_Operation() {} + +// A reference to identify one or more packages. +// +// A reference matches a package if its “package_id“ matches the package's ID, +// its “package_name“ matches the package's name, and its “package_version“ +// matches the package's version. If an attribute in the reference is left +// unspecified (i.e. as an empty string), that attribute is treated as a +// wildcard. At a minimum, “package_id“ or the “package_name“ must be +// specified. +// +// If a reference does not match any package, the reference is considered +// unresolved and the entire update request is rejected. +type VettedPackagesRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Package's package id must be the same as this field. + // + // Optional + PackageId string `protobuf:"bytes,1,opt,name=package_id,json=packageId,proto3" json:"package_id,omitempty"` + // Package's name must be the same as this field. + // + // Optional + PackageName string `protobuf:"bytes,2,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // Package's version must be the same as this field. + // + // Optional + PackageVersion string `protobuf:"bytes,3,opt,name=package_version,json=packageVersion,proto3" json:"package_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VettedPackagesRef) Reset() { + *x = VettedPackagesRef{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VettedPackagesRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VettedPackagesRef) ProtoMessage() {} + +func (x *VettedPackagesRef) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VettedPackagesRef.ProtoReflect.Descriptor instead. +func (*VettedPackagesRef) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{8} +} + +func (x *VettedPackagesRef) GetPackageId() string { + if x != nil { + return x.PackageId + } + return "" +} + +func (x *VettedPackagesRef) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *VettedPackagesRef) GetPackageVersion() string { + if x != nil { + return x.PackageVersion + } + return "" +} + +type UpdateVettedPackagesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Changes to apply to the current vetting state of the participant on the + // specified synchronizer. The changes are applied in order. + // Any package not changed will keep their previous vetting state. + // + // Required: must be non-empty + Changes []*VettedPackagesChange `protobuf:"bytes,1,rep,name=changes,proto3" json:"changes,omitempty"` + // If dry_run is true, then the changes are only prepared, but not applied. If + // a request would trigger an error when run (e.g. TOPOLOGY_DEPENDENCIES_NOT_VETTED), + // it will also trigger an error when dry_run. + // + // Use this flag to preview a change before applying it. + // Defaults to false. + // + // Optional + DryRun bool `protobuf:"varint,2,opt,name=dry_run,json=dryRun,proto3" json:"dry_run,omitempty"` + // If set, the requested changes will take place on the specified + // synchronizer. If synchronizer_id is unset and the participant is only + // connected to a single synchronizer, that synchronizer will be used by + // default. If synchronizer_id is unset and the participant is connected to + // multiple synchronizers, the request will error out with + // PACKAGE_SERVICE_CANNOT_AUTODETECT_SYNCHRONIZER. + // + // Optional + SynchronizerId string `protobuf:"bytes,3,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The serial of the last “VettedPackages“ topology transaction of this + // participant and on this synchronizer. + // + // Execution of the request fails if this is not correct. Use this to guard + // against concurrent changes. + // + // If left unspecified, no validation is done against the last transaction's + // serial. + // + // Optional + ExpectedTopologySerial *v2.PriorTopologySerial `protobuf:"bytes,4,opt,name=expected_topology_serial,json=expectedTopologySerial,proto3" json:"expected_topology_serial,omitempty"` + // Controls whether potentially unsafe vetting updates are allowed. + // + // Optional: can be empty + UpdateVettedPackagesForceFlags []UpdateVettedPackagesForceFlag `protobuf:"varint,5,rep,packed,name=update_vetted_packages_force_flags,json=updateVettedPackagesForceFlags,proto3,enum=com.daml.ledger.api.v2.admin.UpdateVettedPackagesForceFlag" json:"update_vetted_packages_force_flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateVettedPackagesRequest) Reset() { + *x = UpdateVettedPackagesRequest{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateVettedPackagesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateVettedPackagesRequest) ProtoMessage() {} + +func (x *UpdateVettedPackagesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateVettedPackagesRequest.ProtoReflect.Descriptor instead. +func (*UpdateVettedPackagesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{9} +} + +func (x *UpdateVettedPackagesRequest) GetChanges() []*VettedPackagesChange { + if x != nil { + return x.Changes + } + return nil +} + +func (x *UpdateVettedPackagesRequest) GetDryRun() bool { + if x != nil { + return x.DryRun + } + return false +} + +func (x *UpdateVettedPackagesRequest) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *UpdateVettedPackagesRequest) GetExpectedTopologySerial() *v2.PriorTopologySerial { + if x != nil { + return x.ExpectedTopologySerial + } + return nil +} + +func (x *UpdateVettedPackagesRequest) GetUpdateVettedPackagesForceFlags() []UpdateVettedPackagesForceFlag { + if x != nil { + return x.UpdateVettedPackagesForceFlags + } + return nil +} + +type UpdateVettedPackagesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // All vetted packages on this participant and synchronizer, before the + // specified changes. Empty if no vetting state existed beforehand. + // + // Not populated if no vetted topology state exists prior to the update. + // + // Optional + PastVettedPackages *v2.VettedPackages `protobuf:"bytes,1,opt,name=past_vetted_packages,json=pastVettedPackages,proto3" json:"past_vetted_packages,omitempty"` + // All vetted packages on this participant and synchronizer, after the specified changes. + // + // Required + NewVettedPackages *v2.VettedPackages `protobuf:"bytes,2,opt,name=new_vetted_packages,json=newVettedPackages,proto3" json:"new_vetted_packages,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateVettedPackagesResponse) Reset() { + *x = UpdateVettedPackagesResponse{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateVettedPackagesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateVettedPackagesResponse) ProtoMessage() {} + +func (x *UpdateVettedPackagesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateVettedPackagesResponse.ProtoReflect.Descriptor instead. +func (*UpdateVettedPackagesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{10} +} + +func (x *UpdateVettedPackagesResponse) GetPastVettedPackages() *v2.VettedPackages { + if x != nil { + return x.PastVettedPackages + } + return nil +} + +func (x *UpdateVettedPackagesResponse) GetNewVettedPackages() *v2.VettedPackages { + if x != nil { + return x.NewVettedPackages + } + return nil +} + +// Remove packages from the set of vetted packages +type VettedPackagesChange_Unvet struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Packages to be unvetted. + // + // If a reference in this list matches multiple packages, they are all + // unvetted. + // + // Required: must be non-empty + Packages []*VettedPackagesRef `protobuf:"bytes,1,rep,name=packages,proto3" json:"packages,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VettedPackagesChange_Unvet) Reset() { + *x = VettedPackagesChange_Unvet{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VettedPackagesChange_Unvet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VettedPackagesChange_Unvet) ProtoMessage() {} + +func (x *VettedPackagesChange_Unvet) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VettedPackagesChange_Unvet.ProtoReflect.Descriptor instead. +func (*VettedPackagesChange_Unvet) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{7, 0} +} + +func (x *VettedPackagesChange_Unvet) GetPackages() []*VettedPackagesRef { + if x != nil { + return x.Packages + } + return nil +} + +// Set vetting bounds of a list of packages. Packages that were not previously +// vetted have their bounds added, previous vetting bounds are overwritten. +type VettedPackagesChange_Vet struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Packages to be vetted. + // + // If a reference in this list matches more than one package, the change is + // considered ambiguous and the entire update request is rejected. In other + // words, every reference must match exactly one package. + // + // Required: must be non-empty + Packages []*VettedPackagesRef `protobuf:"bytes,1,rep,name=packages,proto3" json:"packages,omitempty"` + // The time from which these packages should be vetted, prior lower bounds + // are overwritten. + // Optional + NewValidFromInclusive *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=new_valid_from_inclusive,json=newValidFromInclusive,proto3" json:"new_valid_from_inclusive,omitempty"` + // The time until which these packages should be vetted, prior upper bounds + // are overwritten. + // Optional + NewValidUntilExclusive *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=new_valid_until_exclusive,json=newValidUntilExclusive,proto3" json:"new_valid_until_exclusive,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VettedPackagesChange_Vet) Reset() { + *x = VettedPackagesChange_Vet{} + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VettedPackagesChange_Vet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VettedPackagesChange_Vet) ProtoMessage() {} + +func (x *VettedPackagesChange_Vet) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VettedPackagesChange_Vet.ProtoReflect.Descriptor instead. +func (*VettedPackagesChange_Vet) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP(), []int{7, 1} +} + +func (x *VettedPackagesChange_Vet) GetPackages() []*VettedPackagesRef { + if x != nil { + return x.Packages + } + return nil +} + +func (x *VettedPackagesChange_Vet) GetNewValidFromInclusive() *timestamppb.Timestamp { + if x != nil { + return x.NewValidFromInclusive + } + return nil +} + +func (x *VettedPackagesChange_Vet) GetNewValidUntilExclusive() *timestamppb.Timestamp { + if x != nil { + return x.NewValidUntilExclusive + } + return nil +} + +var File_com_daml_ledger_api_v2_admin_package_management_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDesc = "" + + "\n" + + "=com/daml/ledger/api/v2/admin/package_management_service.proto\x12\x1ccom.daml.ledger.api.v2.admin\x1a.com/daml/ledger/api/v2/package_reference.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x1a\n" + + "\x18ListKnownPackagesRequest\"r\n" + + "\x19ListKnownPackagesResponse\x12U\n" + + "\x0fpackage_details\x18\x01 \x03(\v2,.com.daml.ledger.api.v2.admin.PackageDetailsR\x0epackageDetails\"\xbd\x01\n" + + "\x0ePackageDetails\x12\x1d\n" + + "\n" + + "package_id\x18\x01 \x01(\tR\tpackageId\x12!\n" + + "\fpackage_size\x18\x02 \x01(\x04R\vpackageSize\x12;\n" + + "\vknown_since\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "knownSince\x12\x12\n" + + "\x04name\x18\x04 \x01(\tR\x04name\x12\x18\n" + + "\aversion\x18\x05 \x01(\tR\aversion\"\xe8\x02\n" + + "\x14UploadDarFileRequest\x12\x19\n" + + "\bdar_file\x18\x01 \x01(\fR\adarFile\x12#\n" + + "\rsubmission_id\x18\x02 \x01(\tR\fsubmissionId\x12g\n" + + "\x0evetting_change\x18\x03 \x01(\x0e2@.com.daml.ledger.api.v2.admin.UploadDarFileRequest.VettingChangeR\rvettingChange\x12'\n" + + "\x0fsynchronizer_id\x18\x04 \x01(\tR\x0esynchronizerId\"~\n" + + "\rVettingChange\x12\x1e\n" + + "\x1aVETTING_CHANGE_UNSPECIFIED\x10\x00\x12#\n" + + "\x1fVETTING_CHANGE_VET_ALL_PACKAGES\x10\x01\x12(\n" + + "$VETTING_CHANGE_DONT_VET_ANY_PACKAGES\x10\x02\"\x17\n" + + "\x15UploadDarFileResponse\"\x81\x01\n" + + "\x16ValidateDarFileRequest\x12\x19\n" + + "\bdar_file\x18\x01 \x01(\fR\adarFile\x12#\n" + + "\rsubmission_id\x18\x02 \x01(\tR\fsubmissionId\x12'\n" + + "\x0fsynchronizer_id\x18\x04 \x01(\tR\x0esynchronizerId\"\x19\n" + + "\x17ValidateDarFileResponse\"\x98\x04\n" + + "\x14VettedPackagesChange\x12J\n" + + "\x03vet\x18\x01 \x01(\v26.com.daml.ledger.api.v2.admin.VettedPackagesChange.VetH\x00R\x03vet\x12P\n" + + "\x05unvet\x18\x02 \x01(\v28.com.daml.ledger.api.v2.admin.VettedPackagesChange.UnvetH\x00R\x05unvet\x1aT\n" + + "\x05Unvet\x12K\n" + + "\bpackages\x18\x01 \x03(\v2/.com.daml.ledger.api.v2.admin.VettedPackagesRefR\bpackages\x1a\xfe\x01\n" + + "\x03Vet\x12K\n" + + "\bpackages\x18\x01 \x03(\v2/.com.daml.ledger.api.v2.admin.VettedPackagesRefR\bpackages\x12S\n" + + "\x18new_valid_from_inclusive\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x15newValidFromInclusive\x12U\n" + + "\x19new_valid_until_exclusive\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x16newValidUntilExclusiveB\v\n" + + "\toperation\"~\n" + + "\x11VettedPackagesRef\x12\x1d\n" + + "\n" + + "package_id\x18\x01 \x01(\tR\tpackageId\x12!\n" + + "\fpackage_name\x18\x02 \x01(\tR\vpackageName\x12'\n" + + "\x0fpackage_version\x18\x03 \x01(\tR\x0epackageVersion\"\x9e\x03\n" + + "\x1bUpdateVettedPackagesRequest\x12L\n" + + "\achanges\x18\x01 \x03(\v22.com.daml.ledger.api.v2.admin.VettedPackagesChangeR\achanges\x12\x17\n" + + "\adry_run\x18\x02 \x01(\bR\x06dryRun\x12'\n" + + "\x0fsynchronizer_id\x18\x03 \x01(\tR\x0esynchronizerId\x12e\n" + + "\x18expected_topology_serial\x18\x04 \x01(\v2+.com.daml.ledger.api.v2.PriorTopologySerialR\x16expectedTopologySerial\x12\x87\x01\n" + + "\"update_vetted_packages_force_flags\x18\x05 \x03(\x0e2;.com.daml.ledger.api.v2.admin.UpdateVettedPackagesForceFlagR\x1eupdateVettedPackagesForceFlags\"\xd0\x01\n" + + "\x1cUpdateVettedPackagesResponse\x12X\n" + + "\x14past_vetted_packages\x18\x01 \x01(\v2&.com.daml.ledger.api.v2.VettedPackagesR\x12pastVettedPackages\x12V\n" + + "\x13new_vetted_packages\x18\x02 \x01(\v2&.com.daml.ledger.api.v2.VettedPackagesR\x11newVettedPackages*\xe2\x01\n" + + "\x1dUpdateVettedPackagesForceFlag\x121\n" + + "-UPDATE_VETTED_PACKAGES_FORCE_FLAG_UNSPECIFIED\x10\x00\x12E\n" + + "AUPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_VET_INCOMPATIBLE_UPGRADES\x10\x02\x12A\n" + + "=UPDATE_VETTED_PACKAGES_FORCE_FLAG_ALLOW_UNVETTED_DEPENDENCIES\x10\x03\"\x04\b\x01\x10\x012\xab\x04\n" + + "\x18PackageManagementService\x12\x84\x01\n" + + "\x11ListKnownPackages\x126.com.daml.ledger.api.v2.admin.ListKnownPackagesRequest\x1a7.com.daml.ledger.api.v2.admin.ListKnownPackagesResponse\x12x\n" + + "\rUploadDarFile\x122.com.daml.ledger.api.v2.admin.UploadDarFileRequest\x1a3.com.daml.ledger.api.v2.admin.UploadDarFileResponse\x12~\n" + + "\x0fValidateDarFile\x124.com.daml.ledger.api.v2.admin.ValidateDarFileRequest\x1a5.com.daml.ledger.api.v2.admin.ValidateDarFileResponse\x12\x8d\x01\n" + + "\x14UpdateVettedPackages\x129.com.daml.ledger.api.v2.admin.UpdateVettedPackagesRequest\x1a:.com.daml.ledger.api.v2.admin.UpdateVettedPackagesResponseB\xab\x02\n" + + " com.com.daml.ledger.api.v2.adminB\x1dPackageManagementServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin\xa2\x02\x06CDLAVA\xaa\x02\x1cCom.Daml.Ledger.Api.V2.Admin\xca\x02\x1cCom\\Daml\\Ledger\\Api\\V2\\Admin\xe2\x02(Com\\Daml\\Ledger\\Api\\V2\\Admin\\GPBMetadata\xea\x02!Com::Daml::Ledger::Api::V2::Adminb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_admin_package_management_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes = make([]protoimpl.MessageInfo, 13) +var file_com_daml_ledger_api_v2_admin_package_management_service_proto_goTypes = []any{ + (UpdateVettedPackagesForceFlag)(0), // 0: com.daml.ledger.api.v2.admin.UpdateVettedPackagesForceFlag + (UploadDarFileRequest_VettingChange)(0), // 1: com.daml.ledger.api.v2.admin.UploadDarFileRequest.VettingChange + (*ListKnownPackagesRequest)(nil), // 2: com.daml.ledger.api.v2.admin.ListKnownPackagesRequest + (*ListKnownPackagesResponse)(nil), // 3: com.daml.ledger.api.v2.admin.ListKnownPackagesResponse + (*PackageDetails)(nil), // 4: com.daml.ledger.api.v2.admin.PackageDetails + (*UploadDarFileRequest)(nil), // 5: com.daml.ledger.api.v2.admin.UploadDarFileRequest + (*UploadDarFileResponse)(nil), // 6: com.daml.ledger.api.v2.admin.UploadDarFileResponse + (*ValidateDarFileRequest)(nil), // 7: com.daml.ledger.api.v2.admin.ValidateDarFileRequest + (*ValidateDarFileResponse)(nil), // 8: com.daml.ledger.api.v2.admin.ValidateDarFileResponse + (*VettedPackagesChange)(nil), // 9: com.daml.ledger.api.v2.admin.VettedPackagesChange + (*VettedPackagesRef)(nil), // 10: com.daml.ledger.api.v2.admin.VettedPackagesRef + (*UpdateVettedPackagesRequest)(nil), // 11: com.daml.ledger.api.v2.admin.UpdateVettedPackagesRequest + (*UpdateVettedPackagesResponse)(nil), // 12: com.daml.ledger.api.v2.admin.UpdateVettedPackagesResponse + (*VettedPackagesChange_Unvet)(nil), // 13: com.daml.ledger.api.v2.admin.VettedPackagesChange.Unvet + (*VettedPackagesChange_Vet)(nil), // 14: com.daml.ledger.api.v2.admin.VettedPackagesChange.Vet + (*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp + (*v2.PriorTopologySerial)(nil), // 16: com.daml.ledger.api.v2.PriorTopologySerial + (*v2.VettedPackages)(nil), // 17: com.daml.ledger.api.v2.VettedPackages +} +var file_com_daml_ledger_api_v2_admin_package_management_service_proto_depIdxs = []int32{ + 4, // 0: com.daml.ledger.api.v2.admin.ListKnownPackagesResponse.package_details:type_name -> com.daml.ledger.api.v2.admin.PackageDetails + 15, // 1: com.daml.ledger.api.v2.admin.PackageDetails.known_since:type_name -> google.protobuf.Timestamp + 1, // 2: com.daml.ledger.api.v2.admin.UploadDarFileRequest.vetting_change:type_name -> com.daml.ledger.api.v2.admin.UploadDarFileRequest.VettingChange + 14, // 3: com.daml.ledger.api.v2.admin.VettedPackagesChange.vet:type_name -> com.daml.ledger.api.v2.admin.VettedPackagesChange.Vet + 13, // 4: com.daml.ledger.api.v2.admin.VettedPackagesChange.unvet:type_name -> com.daml.ledger.api.v2.admin.VettedPackagesChange.Unvet + 9, // 5: com.daml.ledger.api.v2.admin.UpdateVettedPackagesRequest.changes:type_name -> com.daml.ledger.api.v2.admin.VettedPackagesChange + 16, // 6: com.daml.ledger.api.v2.admin.UpdateVettedPackagesRequest.expected_topology_serial:type_name -> com.daml.ledger.api.v2.PriorTopologySerial + 0, // 7: com.daml.ledger.api.v2.admin.UpdateVettedPackagesRequest.update_vetted_packages_force_flags:type_name -> com.daml.ledger.api.v2.admin.UpdateVettedPackagesForceFlag + 17, // 8: com.daml.ledger.api.v2.admin.UpdateVettedPackagesResponse.past_vetted_packages:type_name -> com.daml.ledger.api.v2.VettedPackages + 17, // 9: com.daml.ledger.api.v2.admin.UpdateVettedPackagesResponse.new_vetted_packages:type_name -> com.daml.ledger.api.v2.VettedPackages + 10, // 10: com.daml.ledger.api.v2.admin.VettedPackagesChange.Unvet.packages:type_name -> com.daml.ledger.api.v2.admin.VettedPackagesRef + 10, // 11: com.daml.ledger.api.v2.admin.VettedPackagesChange.Vet.packages:type_name -> com.daml.ledger.api.v2.admin.VettedPackagesRef + 15, // 12: com.daml.ledger.api.v2.admin.VettedPackagesChange.Vet.new_valid_from_inclusive:type_name -> google.protobuf.Timestamp + 15, // 13: com.daml.ledger.api.v2.admin.VettedPackagesChange.Vet.new_valid_until_exclusive:type_name -> google.protobuf.Timestamp + 2, // 14: com.daml.ledger.api.v2.admin.PackageManagementService.ListKnownPackages:input_type -> com.daml.ledger.api.v2.admin.ListKnownPackagesRequest + 5, // 15: com.daml.ledger.api.v2.admin.PackageManagementService.UploadDarFile:input_type -> com.daml.ledger.api.v2.admin.UploadDarFileRequest + 7, // 16: com.daml.ledger.api.v2.admin.PackageManagementService.ValidateDarFile:input_type -> com.daml.ledger.api.v2.admin.ValidateDarFileRequest + 11, // 17: com.daml.ledger.api.v2.admin.PackageManagementService.UpdateVettedPackages:input_type -> com.daml.ledger.api.v2.admin.UpdateVettedPackagesRequest + 3, // 18: com.daml.ledger.api.v2.admin.PackageManagementService.ListKnownPackages:output_type -> com.daml.ledger.api.v2.admin.ListKnownPackagesResponse + 6, // 19: com.daml.ledger.api.v2.admin.PackageManagementService.UploadDarFile:output_type -> com.daml.ledger.api.v2.admin.UploadDarFileResponse + 8, // 20: com.daml.ledger.api.v2.admin.PackageManagementService.ValidateDarFile:output_type -> com.daml.ledger.api.v2.admin.ValidateDarFileResponse + 12, // 21: com.daml.ledger.api.v2.admin.PackageManagementService.UpdateVettedPackages:output_type -> com.daml.ledger.api.v2.admin.UpdateVettedPackagesResponse + 18, // [18:22] is the sub-list for method output_type + 14, // [14:18] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_admin_package_management_service_proto_init() } +func file_com_daml_ledger_api_v2_admin_package_management_service_proto_init() { + if File_com_daml_ledger_api_v2_admin_package_management_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes[7].OneofWrappers = []any{ + (*VettedPackagesChange_Vet_)(nil), + (*VettedPackagesChange_Unvet_)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_package_management_service_proto_rawDesc)), + NumEnums: 2, + NumMessages: 13, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_admin_package_management_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_admin_package_management_service_proto_depIdxs, + EnumInfos: file_com_daml_ledger_api_v2_admin_package_management_service_proto_enumTypes, + MessageInfos: file_com_daml_ledger_api_v2_admin_package_management_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_admin_package_management_service_proto = out.File + file_com_daml_ledger_api_v2_admin_package_management_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_admin_package_management_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service_grpc.pb.go new file mode 100644 index 00000000..cfccd48f --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/package_management_service_grpc.pb.go @@ -0,0 +1,279 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/admin/package_management_service.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + PackageManagementService_ListKnownPackages_FullMethodName = "/com.daml.ledger.api.v2.admin.PackageManagementService/ListKnownPackages" + PackageManagementService_UploadDarFile_FullMethodName = "/com.daml.ledger.api.v2.admin.PackageManagementService/UploadDarFile" + PackageManagementService_ValidateDarFile_FullMethodName = "/com.daml.ledger.api.v2.admin.PackageManagementService/ValidateDarFile" + PackageManagementService_UpdateVettedPackages_FullMethodName = "/com.daml.ledger.api.v2.admin.PackageManagementService/UpdateVettedPackages" +) + +// PackageManagementServiceClient is the client API for PackageManagementService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Status: experimental interface, will change before it is deemed production +// ready +// +// Query the Daml-LF packages supported by the ledger participant and upload +// DAR files. We use 'backing participant' to refer to this specific participant +// in the methods of this API. +type PackageManagementServiceClient interface { + // Returns the details of all Daml-LF packages known to the backing participant. + ListKnownPackages(ctx context.Context, in *ListKnownPackagesRequest, opts ...grpc.CallOption) (*ListKnownPackagesResponse, error) + // Upload a DAR file to the participant. + // + // If vetting is enabled in the request, the DAR is checked for upgrade compatibility + // with the set of the already vetted packages on the target vetting synchronizer + // See UploadDarFileRequest for details regarding vetting and the target vetting synchronizer. + UploadDarFile(ctx context.Context, in *UploadDarFileRequest, opts ...grpc.CallOption) (*UploadDarFileResponse, error) + // Validates the DAR and checks the upgrade compatibility of the DAR's packages + // with the set of the already vetted packages on the target vetting synchronizer. + // See ValidateDarFileRequest for details regarding the target vetting synchronizer. + // + // The operation has no effect on the state of the participant or the Canton ledger: + // the DAR payload and its packages are not persisted neither are the packages vetted. + ValidateDarFile(ctx context.Context, in *ValidateDarFileRequest, opts ...grpc.CallOption) (*ValidateDarFileResponse, error) + // Update the vetted packages of this participant + UpdateVettedPackages(ctx context.Context, in *UpdateVettedPackagesRequest, opts ...grpc.CallOption) (*UpdateVettedPackagesResponse, error) +} + +type packageManagementServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewPackageManagementServiceClient(cc grpc.ClientConnInterface) PackageManagementServiceClient { + return &packageManagementServiceClient{cc} +} + +func (c *packageManagementServiceClient) ListKnownPackages(ctx context.Context, in *ListKnownPackagesRequest, opts ...grpc.CallOption) (*ListKnownPackagesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListKnownPackagesResponse) + err := c.cc.Invoke(ctx, PackageManagementService_ListKnownPackages_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *packageManagementServiceClient) UploadDarFile(ctx context.Context, in *UploadDarFileRequest, opts ...grpc.CallOption) (*UploadDarFileResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UploadDarFileResponse) + err := c.cc.Invoke(ctx, PackageManagementService_UploadDarFile_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *packageManagementServiceClient) ValidateDarFile(ctx context.Context, in *ValidateDarFileRequest, opts ...grpc.CallOption) (*ValidateDarFileResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ValidateDarFileResponse) + err := c.cc.Invoke(ctx, PackageManagementService_ValidateDarFile_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *packageManagementServiceClient) UpdateVettedPackages(ctx context.Context, in *UpdateVettedPackagesRequest, opts ...grpc.CallOption) (*UpdateVettedPackagesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateVettedPackagesResponse) + err := c.cc.Invoke(ctx, PackageManagementService_UpdateVettedPackages_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PackageManagementServiceServer is the server API for PackageManagementService service. +// All implementations must embed UnimplementedPackageManagementServiceServer +// for forward compatibility. +// +// Status: experimental interface, will change before it is deemed production +// ready +// +// Query the Daml-LF packages supported by the ledger participant and upload +// DAR files. We use 'backing participant' to refer to this specific participant +// in the methods of this API. +type PackageManagementServiceServer interface { + // Returns the details of all Daml-LF packages known to the backing participant. + ListKnownPackages(context.Context, *ListKnownPackagesRequest) (*ListKnownPackagesResponse, error) + // Upload a DAR file to the participant. + // + // If vetting is enabled in the request, the DAR is checked for upgrade compatibility + // with the set of the already vetted packages on the target vetting synchronizer + // See UploadDarFileRequest for details regarding vetting and the target vetting synchronizer. + UploadDarFile(context.Context, *UploadDarFileRequest) (*UploadDarFileResponse, error) + // Validates the DAR and checks the upgrade compatibility of the DAR's packages + // with the set of the already vetted packages on the target vetting synchronizer. + // See ValidateDarFileRequest for details regarding the target vetting synchronizer. + // + // The operation has no effect on the state of the participant or the Canton ledger: + // the DAR payload and its packages are not persisted neither are the packages vetted. + ValidateDarFile(context.Context, *ValidateDarFileRequest) (*ValidateDarFileResponse, error) + // Update the vetted packages of this participant + UpdateVettedPackages(context.Context, *UpdateVettedPackagesRequest) (*UpdateVettedPackagesResponse, error) + mustEmbedUnimplementedPackageManagementServiceServer() +} + +// UnimplementedPackageManagementServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedPackageManagementServiceServer struct{} + +func (UnimplementedPackageManagementServiceServer) ListKnownPackages(context.Context, *ListKnownPackagesRequest) (*ListKnownPackagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListKnownPackages not implemented") +} +func (UnimplementedPackageManagementServiceServer) UploadDarFile(context.Context, *UploadDarFileRequest) (*UploadDarFileResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UploadDarFile not implemented") +} +func (UnimplementedPackageManagementServiceServer) ValidateDarFile(context.Context, *ValidateDarFileRequest) (*ValidateDarFileResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidateDarFile not implemented") +} +func (UnimplementedPackageManagementServiceServer) UpdateVettedPackages(context.Context, *UpdateVettedPackagesRequest) (*UpdateVettedPackagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateVettedPackages not implemented") +} +func (UnimplementedPackageManagementServiceServer) mustEmbedUnimplementedPackageManagementServiceServer() { +} +func (UnimplementedPackageManagementServiceServer) testEmbeddedByValue() {} + +// UnsafePackageManagementServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PackageManagementServiceServer will +// result in compilation errors. +type UnsafePackageManagementServiceServer interface { + mustEmbedUnimplementedPackageManagementServiceServer() +} + +func RegisterPackageManagementServiceServer(s grpc.ServiceRegistrar, srv PackageManagementServiceServer) { + // If the following call pancis, it indicates UnimplementedPackageManagementServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&PackageManagementService_ServiceDesc, srv) +} + +func _PackageManagementService_ListKnownPackages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListKnownPackagesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageManagementServiceServer).ListKnownPackages(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageManagementService_ListKnownPackages_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageManagementServiceServer).ListKnownPackages(ctx, req.(*ListKnownPackagesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PackageManagementService_UploadDarFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UploadDarFileRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageManagementServiceServer).UploadDarFile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageManagementService_UploadDarFile_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageManagementServiceServer).UploadDarFile(ctx, req.(*UploadDarFileRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PackageManagementService_ValidateDarFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ValidateDarFileRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageManagementServiceServer).ValidateDarFile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageManagementService_ValidateDarFile_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageManagementServiceServer).ValidateDarFile(ctx, req.(*ValidateDarFileRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PackageManagementService_UpdateVettedPackages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateVettedPackagesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageManagementServiceServer).UpdateVettedPackages(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageManagementService_UpdateVettedPackages_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageManagementServiceServer).UpdateVettedPackages(ctx, req.(*UpdateVettedPackagesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// PackageManagementService_ServiceDesc is the grpc.ServiceDesc for PackageManagementService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PackageManagementService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.admin.PackageManagementService", + HandlerType: (*PackageManagementServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListKnownPackages", + Handler: _PackageManagementService_ListKnownPackages_Handler, + }, + { + MethodName: "UploadDarFile", + Handler: _PackageManagementService_UploadDarFile_Handler, + }, + { + MethodName: "ValidateDarFile", + Handler: _PackageManagementService_ValidateDarFile_Handler, + }, + { + MethodName: "UpdateVettedPackages", + Handler: _PackageManagementService_UpdateVettedPackages_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/admin/package_management_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service.pb.go new file mode 100644 index 00000000..f8a1d8a9 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service.pb.go @@ -0,0 +1,204 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/admin/participant_pruning_service.proto + +package admin + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PruneRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Inclusive valid absolute offset (positive integer) up to which the ledger is to be pruned. + // By default the following data is pruned: + // + // 1. All normal and divulged contracts that have been archived before + // `prune_up_to`. + // 2. All transaction events and completions before `prune_up_to` + // 3. All immediately divulged contracts created before `prune_up_to` independent of whether + // they were archived before `prune_up_to`. + // + // Required + PruneUpTo int64 `protobuf:"varint,1,opt,name=prune_up_to,json=pruneUpTo,proto3" json:"prune_up_to,omitempty"` + // Unique submission identifier. + // If not populated, defaults to a random identifier, used for logging. + // + // Optional + SubmissionId string `protobuf:"bytes,2,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // Deprecated flag used to prune all immediately and retroactively divulged contracts. + // It is a no-op since the divulged contracts are pruned along with the deactivated contracts. + // + // Optional + PruneAllDivulgedContracts bool `protobuf:"varint,3,opt,name=prune_all_divulged_contracts,json=pruneAllDivulgedContracts,proto3" json:"prune_all_divulged_contracts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PruneRequest) Reset() { + *x = PruneRequest{} + mi := &file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PruneRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PruneRequest) ProtoMessage() {} + +func (x *PruneRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PruneRequest.ProtoReflect.Descriptor instead. +func (*PruneRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescGZIP(), []int{0} +} + +func (x *PruneRequest) GetPruneUpTo() int64 { + if x != nil { + return x.PruneUpTo + } + return 0 +} + +func (x *PruneRequest) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *PruneRequest) GetPruneAllDivulgedContracts() bool { + if x != nil { + return x.PruneAllDivulgedContracts + } + return false +} + +type PruneResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PruneResponse) Reset() { + *x = PruneResponse{} + mi := &file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PruneResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PruneResponse) ProtoMessage() {} + +func (x *PruneResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PruneResponse.ProtoReflect.Descriptor instead. +func (*PruneResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescGZIP(), []int{1} +} + +var File_com_daml_ledger_api_v2_admin_participant_pruning_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDesc = "" + + "\n" + + ">com/daml/ledger/api/v2/admin/participant_pruning_service.proto\x12\x1ccom.daml.ledger.api.v2.admin\"\x94\x01\n" + + "\fPruneRequest\x12\x1e\n" + + "\vprune_up_to\x18\x01 \x01(\x03R\tpruneUpTo\x12#\n" + + "\rsubmission_id\x18\x02 \x01(\tR\fsubmissionId\x12?\n" + + "\x1cprune_all_divulged_contracts\x18\x03 \x01(\bR\x19pruneAllDivulgedContracts\"\x0f\n" + + "\rPruneResponse2}\n" + + "\x19ParticipantPruningService\x12`\n" + + "\x05Prune\x12*.com.daml.ledger.api.v2.admin.PruneRequest\x1a+.com.daml.ledger.api.v2.admin.PruneResponseB\xac\x02\n" + + " com.com.daml.ledger.api.v2.adminB\x1eParticipantPruningServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin\xa2\x02\x06CDLAVA\xaa\x02\x1cCom.Daml.Ledger.Api.V2.Admin\xca\x02\x1cCom\\Daml\\Ledger\\Api\\V2\\Admin\xe2\x02(Com\\Daml\\Ledger\\Api\\V2\\Admin\\GPBMetadata\xea\x02!Com::Daml::Ledger::Api::V2::Adminb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_goTypes = []any{ + (*PruneRequest)(nil), // 0: com.daml.ledger.api.v2.admin.PruneRequest + (*PruneResponse)(nil), // 1: com.daml.ledger.api.v2.admin.PruneResponse +} +var file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_depIdxs = []int32{ + 0, // 0: com.daml.ledger.api.v2.admin.ParticipantPruningService.Prune:input_type -> com.daml.ledger.api.v2.admin.PruneRequest + 1, // 1: com.daml.ledger.api.v2.admin.ParticipantPruningService.Prune:output_type -> com.daml.ledger.api.v2.admin.PruneResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_init() } +func file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_init() { + if File_com_daml_ledger_api_v2_admin_participant_pruning_service_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_admin_participant_pruning_service_proto = out.File + file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_admin_participant_pruning_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service_grpc.pb.go new file mode 100644 index 00000000..0ebf38ab --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/participant_pruning_service_grpc.pb.go @@ -0,0 +1,147 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/admin/participant_pruning_service.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + ParticipantPruningService_Prune_FullMethodName = "/com.daml.ledger.api.v2.admin.ParticipantPruningService/Prune" +) + +// ParticipantPruningServiceClient is the client API for ParticipantPruningService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Prunes/truncates the "oldest" transactions from the participant (the participant Ledger Api Server plus any other +// participant-local state) by removing a portion of the ledger in such a way that the set of future, allowed +// commands are not affected. +// +// This enables: +// +// 1. keeping the "inactive" portion of the ledger to a manageable size and +// 2. removing inactive state to honor the right to be forgotten. +type ParticipantPruningServiceClient interface { + // Prune the ledger specifying the offset before and at which ledger transactions should be removed. Only returns when + // the potentially long-running prune request ends successfully or with an error. + Prune(ctx context.Context, in *PruneRequest, opts ...grpc.CallOption) (*PruneResponse, error) +} + +type participantPruningServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewParticipantPruningServiceClient(cc grpc.ClientConnInterface) ParticipantPruningServiceClient { + return &participantPruningServiceClient{cc} +} + +func (c *participantPruningServiceClient) Prune(ctx context.Context, in *PruneRequest, opts ...grpc.CallOption) (*PruneResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PruneResponse) + err := c.cc.Invoke(ctx, ParticipantPruningService_Prune_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ParticipantPruningServiceServer is the server API for ParticipantPruningService service. +// All implementations must embed UnimplementedParticipantPruningServiceServer +// for forward compatibility. +// +// Prunes/truncates the "oldest" transactions from the participant (the participant Ledger Api Server plus any other +// participant-local state) by removing a portion of the ledger in such a way that the set of future, allowed +// commands are not affected. +// +// This enables: +// +// 1. keeping the "inactive" portion of the ledger to a manageable size and +// 2. removing inactive state to honor the right to be forgotten. +type ParticipantPruningServiceServer interface { + // Prune the ledger specifying the offset before and at which ledger transactions should be removed. Only returns when + // the potentially long-running prune request ends successfully or with an error. + Prune(context.Context, *PruneRequest) (*PruneResponse, error) + mustEmbedUnimplementedParticipantPruningServiceServer() +} + +// UnimplementedParticipantPruningServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedParticipantPruningServiceServer struct{} + +func (UnimplementedParticipantPruningServiceServer) Prune(context.Context, *PruneRequest) (*PruneResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Prune not implemented") +} +func (UnimplementedParticipantPruningServiceServer) mustEmbedUnimplementedParticipantPruningServiceServer() { +} +func (UnimplementedParticipantPruningServiceServer) testEmbeddedByValue() {} + +// UnsafeParticipantPruningServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ParticipantPruningServiceServer will +// result in compilation errors. +type UnsafeParticipantPruningServiceServer interface { + mustEmbedUnimplementedParticipantPruningServiceServer() +} + +func RegisterParticipantPruningServiceServer(s grpc.ServiceRegistrar, srv ParticipantPruningServiceServer) { + // If the following call pancis, it indicates UnimplementedParticipantPruningServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&ParticipantPruningService_ServiceDesc, srv) +} + +func _ParticipantPruningService_Prune_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PruneRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ParticipantPruningServiceServer).Prune(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ParticipantPruningService_Prune_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ParticipantPruningServiceServer).Prune(ctx, req.(*PruneRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ParticipantPruningService_ServiceDesc is the grpc.ServiceDesc for ParticipantPruningService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ParticipantPruningService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.admin.ParticipantPruningService", + HandlerType: (*ParticipantPruningServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Prune", + Handler: _ParticipantPruningService_Prune_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/admin/participant_pruning_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service.pb.go new file mode 100644 index 00000000..ecc53c8f --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service.pb.go @@ -0,0 +1,1450 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/admin/party_management_service.proto + +package admin + +import ( + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Required authorization: “HasRight(ParticipantAdmin)“ +type GetParticipantIdRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetParticipantIdRequest) Reset() { + *x = GetParticipantIdRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetParticipantIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetParticipantIdRequest) ProtoMessage() {} + +func (x *GetParticipantIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetParticipantIdRequest.ProtoReflect.Descriptor instead. +func (*GetParticipantIdRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{0} +} + +type GetParticipantIdResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Identifier of the participant, which SHOULD be globally unique. + // Must be a valid LedgerString (as describe in “value.proto“). + // + // Required + ParticipantId string `protobuf:"bytes,1,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetParticipantIdResponse) Reset() { + *x = GetParticipantIdResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetParticipantIdResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetParticipantIdResponse) ProtoMessage() {} + +func (x *GetParticipantIdResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetParticipantIdResponse.ProtoReflect.Descriptor instead. +func (*GetParticipantIdResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetParticipantIdResponse) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)“ +type GetPartiesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The stable, unique identifier of the Daml parties. + // Must be valid PartyIdStrings (as described in “value.proto“). + // + // Required: must be non-empty + Parties []string `protobuf:"bytes,1,rep,name=parties,proto3" json:"parties,omitempty"` + // The id of the “Identity Provider“ whose parties should be retrieved. + // If not set, assume the party is managed by the default identity provider or party is not hosted by the participant. + // + // Optional + IdentityProviderId string `protobuf:"bytes,2,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPartiesRequest) Reset() { + *x = GetPartiesRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPartiesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPartiesRequest) ProtoMessage() {} + +func (x *GetPartiesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPartiesRequest.ProtoReflect.Descriptor instead. +func (*GetPartiesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{2} +} + +func (x *GetPartiesRequest) GetParties() []string { + if x != nil { + return x.Parties + } + return nil +} + +func (x *GetPartiesRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type GetPartiesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The details of the requested Daml parties by the participant, if known. + // The party details may not be in the same order as requested. + // + // Required: must be non-empty + PartyDetails []*PartyDetails `protobuf:"bytes,1,rep,name=party_details,json=partyDetails,proto3" json:"party_details,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPartiesResponse) Reset() { + *x = GetPartiesResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPartiesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPartiesResponse) ProtoMessage() {} + +func (x *GetPartiesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPartiesResponse.ProtoReflect.Descriptor instead. +func (*GetPartiesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{3} +} + +func (x *GetPartiesResponse) GetPartyDetails() []*PartyDetails { + if x != nil { + return x.PartyDetails + } + return nil +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)“ +type ListKnownPartiesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Pagination token to determine the specific page to fetch. Using the token guarantees that parties on a subsequent + // page are all lexically greater than the last party on a previous page. Server does not store intermediate results + // between calls chained by a series of page tokens. As a consequence, if new parties are being added and a page is + // requested twice using the same token, more parties can be returned on the second call. + // Leave empty to fetch the first page. + // + // Optional + PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // Maximum number of results to be returned by the server. The server will return no more than that many results, + // but it might return fewer. If the page_size is 0, the server will decide the number of results to be returned. + // If the page_size exceeds the maximum supported by the server, an error will be returned. To obtain the server's + // maximum consult the PartyManagementFeature descriptor available in the VersionService. + // + // Optional + PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // The id of the “Identity Provider“ whose parties should be retrieved. + // If not set, assume the party is managed by the default identity provider or party is not hosted by the participant. + // + // Optional + IdentityProviderId string `protobuf:"bytes,1,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + // An optional filter for the party name, searching for all party names known to this node + // starting with the given prefix. This can either be just a string or extend up to the full + // identifier. + // + // Optional + FilterParty string `protobuf:"bytes,4,opt,name=filter_party,json=filterParty,proto3" json:"filter_party,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListKnownPartiesRequest) Reset() { + *x = ListKnownPartiesRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListKnownPartiesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListKnownPartiesRequest) ProtoMessage() {} + +func (x *ListKnownPartiesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListKnownPartiesRequest.ProtoReflect.Descriptor instead. +func (*ListKnownPartiesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{4} +} + +func (x *ListKnownPartiesRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListKnownPartiesRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListKnownPartiesRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +func (x *ListKnownPartiesRequest) GetFilterParty() string { + if x != nil { + return x.FilterParty + } + return "" +} + +type ListKnownPartiesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The details of all Daml parties known by the participant. + // + // Required: must be non-empty + PartyDetails []*PartyDetails `protobuf:"bytes,1,rep,name=party_details,json=partyDetails,proto3" json:"party_details,omitempty"` + // Pagination token to retrieve the next page. + // Empty, if there are no further results. + // + // Optional + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListKnownPartiesResponse) Reset() { + *x = ListKnownPartiesResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListKnownPartiesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListKnownPartiesResponse) ProtoMessage() {} + +func (x *ListKnownPartiesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListKnownPartiesResponse.ProtoReflect.Descriptor instead. +func (*ListKnownPartiesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{5} +} + +func (x *ListKnownPartiesResponse) GetPartyDetails() []*PartyDetails { + if x != nil { + return x.PartyDetails + } + return nil +} + +func (x *ListKnownPartiesResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Required authorization: +// +// ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)`` +type AllocatePartyRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // A hint to the participant which party ID to allocate. It can be + // ignored. + // Must be a valid PartyIdString (as described in “value.proto“). + // + // Optional + PartyIdHint string `protobuf:"bytes,1,opt,name=party_id_hint,json=partyIdHint,proto3" json:"party_id_hint,omitempty"` + // Participant-local metadata to be stored in the “PartyDetails“ of this newly allocated party. + // + // Optional + LocalMetadata *ObjectMeta `protobuf:"bytes,3,opt,name=local_metadata,json=localMetadata,proto3" json:"local_metadata,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the party is managed by the default identity provider or party is not hosted by the participant. + // + // Optional + IdentityProviderId string `protobuf:"bytes,4,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + // The synchronizer, on which the party should be allocated. + // For backwards compatibility, this field may be omitted, if the participant is connected to only one synchronizer. + // Otherwise a synchronizer must be specified. + // + // Optional + SynchronizerId string `protobuf:"bytes,5,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The user who will get the act_as rights to the newly allocated party. + // If set to an empty string (the default), no user will get rights to the party. + // + // Optional + UserId string `protobuf:"bytes,6,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AllocatePartyRequest) Reset() { + *x = AllocatePartyRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AllocatePartyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllocatePartyRequest) ProtoMessage() {} + +func (x *AllocatePartyRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AllocatePartyRequest.ProtoReflect.Descriptor instead. +func (*AllocatePartyRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{6} +} + +func (x *AllocatePartyRequest) GetPartyIdHint() string { + if x != nil { + return x.PartyIdHint + } + return "" +} + +func (x *AllocatePartyRequest) GetLocalMetadata() *ObjectMeta { + if x != nil { + return x.LocalMetadata + } + return nil +} + +func (x *AllocatePartyRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +func (x *AllocatePartyRequest) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *AllocatePartyRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +type AllocatePartyResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The allocated party details + // + // Required + PartyDetails *PartyDetails `protobuf:"bytes,1,opt,name=party_details,json=partyDetails,proto3" json:"party_details,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AllocatePartyResponse) Reset() { + *x = AllocatePartyResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AllocatePartyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllocatePartyResponse) ProtoMessage() {} + +func (x *AllocatePartyResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AllocatePartyResponse.ProtoReflect.Descriptor instead. +func (*AllocatePartyResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{7} +} + +func (x *AllocatePartyResponse) GetPartyDetails() *PartyDetails { + if x != nil { + return x.PartyDetails + } + return nil +} + +// Required authorization: +// +// ``HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)`` +type AllocateExternalPartyRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // TODO(#27670) support synchronizer aliases + // Synchronizer ID on which to onboard the party + // + // Required + Synchronizer string `protobuf:"bytes,1,opt,name=synchronizer,proto3" json:"synchronizer,omitempty"` + // TopologyTransactions to onboard the external party + // Can contain: + // - A namespace for the party. + // This can be either a single NamespaceDelegation, + // or DecentralizedNamespaceDefinition along with its authorized namespace owners in the form of NamespaceDelegations. + // May be provided, if so it must be fully authorized by the signatures in this request combined with the existing topology state. + // - A PartyToParticipant to register the hosting relationship of the party, and the party's signing keys and threshold. + // Must be provided. + // + // Required: must be non-empty + OnboardingTransactions []*AllocateExternalPartyRequest_SignedTransaction `protobuf:"bytes,2,rep,name=onboarding_transactions,json=onboardingTransactions,proto3" json:"onboarding_transactions,omitempty"` + // Optional signatures of the combined hash of all onboarding_transactions + // This may be used instead of providing signatures on each individual transaction + // + // Optional: can be empty + MultiHashSignatures []*v2.Signature `protobuf:"bytes,3,rep,name=multi_hash_signatures,json=multiHashSignatures,proto3" json:"multi_hash_signatures,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the party is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,4,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + // When true, this RPC will attempt to wait for the party to be allocated on the synchronizer before returning. + // When false, the allocation will happen asynchronously. + // This is a best effort only as this synchronization is only possible for non decentralized parties (single hosting node). + // For decentralized parties, this flag is ignored. + // Defaults to true. + // + // Optional + WaitForAllocation *bool `protobuf:"varint,5,opt,name=wait_for_allocation,json=waitForAllocation,proto3,oneof" json:"wait_for_allocation,omitempty"` + // The user who will get the act_as rights to the newly allocated party. + // If set to an empty string (the default), no user will get rights to the party. + // + // Optional + UserId string `protobuf:"bytes,6,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AllocateExternalPartyRequest) Reset() { + *x = AllocateExternalPartyRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AllocateExternalPartyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllocateExternalPartyRequest) ProtoMessage() {} + +func (x *AllocateExternalPartyRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AllocateExternalPartyRequest.ProtoReflect.Descriptor instead. +func (*AllocateExternalPartyRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{8} +} + +func (x *AllocateExternalPartyRequest) GetSynchronizer() string { + if x != nil { + return x.Synchronizer + } + return "" +} + +func (x *AllocateExternalPartyRequest) GetOnboardingTransactions() []*AllocateExternalPartyRequest_SignedTransaction { + if x != nil { + return x.OnboardingTransactions + } + return nil +} + +func (x *AllocateExternalPartyRequest) GetMultiHashSignatures() []*v2.Signature { + if x != nil { + return x.MultiHashSignatures + } + return nil +} + +func (x *AllocateExternalPartyRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +func (x *AllocateExternalPartyRequest) GetWaitForAllocation() bool { + if x != nil && x.WaitForAllocation != nil { + return *x.WaitForAllocation + } + return false +} + +func (x *AllocateExternalPartyRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +type AllocateExternalPartyResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The allocated party id + // + // Required + PartyId string `protobuf:"bytes,1,opt,name=party_id,json=partyId,proto3" json:"party_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AllocateExternalPartyResponse) Reset() { + *x = AllocateExternalPartyResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AllocateExternalPartyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllocateExternalPartyResponse) ProtoMessage() {} + +func (x *AllocateExternalPartyResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AllocateExternalPartyResponse.ProtoReflect.Descriptor instead. +func (*AllocateExternalPartyResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{9} +} + +func (x *AllocateExternalPartyResponse) GetPartyId() string { + if x != nil { + return x.PartyId + } + return "" +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(party_details.identity_provider_id)“ +type UpdatePartyDetailsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Party to be updated + // Modifiable + // + // Required + PartyDetails *PartyDetails `protobuf:"bytes,1,opt,name=party_details,json=partyDetails,proto3" json:"party_details,omitempty"` + // An update mask specifies how and which properties of the “PartyDetails“ message are to be updated. + // An update mask consists of a set of update paths. + // A valid update path points to a field or a subfield relative to the “PartyDetails“ message. + // A valid update mask must: + // + // 1. contain at least one update path, + // 2. contain only valid update paths. + // + // Fields that can be updated are marked as “Modifiable“. + // An update path can also point to non-“Modifiable“ fields such as 'party' and 'local_metadata.resource_version' + // because they are used: + // + // 1. to identify the party details resource subject to the update, + // 2. for concurrent change control. + // + // An update path can also point to non-“Modifiable“ fields such as 'is_local' + // as long as the values provided in the update request match the server values. + // Examples of update paths: 'local_metadata.annotations', 'local_metadata'. + // For additional information see the documentation for standard protobuf3's “google.protobuf.FieldMask“. + // For similar Ledger API see “com.daml.ledger.api.v2.admin.UpdateUserRequest“. + // + // Required + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdatePartyDetailsRequest) Reset() { + *x = UpdatePartyDetailsRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdatePartyDetailsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePartyDetailsRequest) ProtoMessage() {} + +func (x *UpdatePartyDetailsRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePartyDetailsRequest.ProtoReflect.Descriptor instead. +func (*UpdatePartyDetailsRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{10} +} + +func (x *UpdatePartyDetailsRequest) GetPartyDetails() *PartyDetails { + if x != nil { + return x.PartyDetails + } + return nil +} + +func (x *UpdatePartyDetailsRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +type UpdatePartyDetailsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Updated party details + // + // Required + PartyDetails *PartyDetails `protobuf:"bytes,1,opt,name=party_details,json=partyDetails,proto3" json:"party_details,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdatePartyDetailsResponse) Reset() { + *x = UpdatePartyDetailsResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdatePartyDetailsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePartyDetailsResponse) ProtoMessage() {} + +func (x *UpdatePartyDetailsResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePartyDetailsResponse.ProtoReflect.Descriptor instead. +func (*UpdatePartyDetailsResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{11} +} + +func (x *UpdatePartyDetailsResponse) GetPartyDetails() *PartyDetails { + if x != nil { + return x.PartyDetails + } + return nil +} + +type PartyDetails struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The stable unique identifier of a Daml party. + // Must be a valid PartyIdString (as described in “value.proto“). + // + // Required + Party string `protobuf:"bytes,1,opt,name=party,proto3" json:"party,omitempty"` + // true if party is hosted by the participant and the party shares the same identity provider as the user issuing the request. + // + // Optional + IsLocal bool `protobuf:"varint,3,opt,name=is_local,json=isLocal,proto3" json:"is_local,omitempty"` + // Participant-local metadata of this party. + // Modifiable + // + // Optional + LocalMetadata *ObjectMeta `protobuf:"bytes,4,opt,name=local_metadata,json=localMetadata,proto3" json:"local_metadata,omitempty"` + // The id of the “Identity Provider“ + // Optional, if not set, there could be 3 options: + // + // 1. the party is managed by the default identity provider. + // 2. party is not hosted by the participant. + // 3. party is hosted by the participant, but is outside of the user's identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,5,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PartyDetails) Reset() { + *x = PartyDetails{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PartyDetails) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PartyDetails) ProtoMessage() {} + +func (x *PartyDetails) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PartyDetails.ProtoReflect.Descriptor instead. +func (*PartyDetails) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{12} +} + +func (x *PartyDetails) GetParty() string { + if x != nil { + return x.Party + } + return "" +} + +func (x *PartyDetails) GetIsLocal() bool { + if x != nil { + return x.IsLocal + } + return false +} + +func (x *PartyDetails) GetLocalMetadata() *ObjectMeta { + if x != nil { + return x.LocalMetadata + } + return nil +} + +func (x *PartyDetails) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +// Required authorization: “HasRight(ParticipantAdmin)“ +type UpdatePartyIdentityProviderIdRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Party to update + // + // Required + Party string `protobuf:"bytes,1,opt,name=party,proto3" json:"party,omitempty"` + // Current identity provider id of the party + // + // Optional + SourceIdentityProviderId string `protobuf:"bytes,2,opt,name=source_identity_provider_id,json=sourceIdentityProviderId,proto3" json:"source_identity_provider_id,omitempty"` + // Target identity provider id of the party + // + // Optional + TargetIdentityProviderId string `protobuf:"bytes,3,opt,name=target_identity_provider_id,json=targetIdentityProviderId,proto3" json:"target_identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdatePartyIdentityProviderIdRequest) Reset() { + *x = UpdatePartyIdentityProviderIdRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdatePartyIdentityProviderIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePartyIdentityProviderIdRequest) ProtoMessage() {} + +func (x *UpdatePartyIdentityProviderIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePartyIdentityProviderIdRequest.ProtoReflect.Descriptor instead. +func (*UpdatePartyIdentityProviderIdRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{13} +} + +func (x *UpdatePartyIdentityProviderIdRequest) GetParty() string { + if x != nil { + return x.Party + } + return "" +} + +func (x *UpdatePartyIdentityProviderIdRequest) GetSourceIdentityProviderId() string { + if x != nil { + return x.SourceIdentityProviderId + } + return "" +} + +func (x *UpdatePartyIdentityProviderIdRequest) GetTargetIdentityProviderId() string { + if x != nil { + return x.TargetIdentityProviderId + } + return "" +} + +type UpdatePartyIdentityProviderIdResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdatePartyIdentityProviderIdResponse) Reset() { + *x = UpdatePartyIdentityProviderIdResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdatePartyIdentityProviderIdResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdatePartyIdentityProviderIdResponse) ProtoMessage() {} + +func (x *UpdatePartyIdentityProviderIdResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdatePartyIdentityProviderIdResponse.ProtoReflect.Descriptor instead. +func (*UpdatePartyIdentityProviderIdResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{14} +} + +type GenerateExternalPartyTopologyRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Synchronizer-id for which we are building this request. + // TODO(#27670) support synchronizer aliases + // + // Required + Synchronizer string `protobuf:"bytes,1,opt,name=synchronizer,proto3" json:"synchronizer,omitempty"` + // The actual party id will be constructed from this hint and a fingerprint of the public key + // + // Required + PartyHint string `protobuf:"bytes,2,opt,name=party_hint,json=partyHint,proto3" json:"party_hint,omitempty"` + // Public key + // + // Required + PublicKey *v2.SigningPublicKey `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + // If true, then the local participant will only be observing, not confirming. Default false. + // + // Optional + LocalParticipantObservationOnly bool `protobuf:"varint,4,opt,name=local_participant_observation_only,json=localParticipantObservationOnly,proto3" json:"local_participant_observation_only,omitempty"` + // Other participant ids which should be confirming for this party + // + // Optional: can be empty + OtherConfirmingParticipantUids []string `protobuf:"bytes,5,rep,name=other_confirming_participant_uids,json=otherConfirmingParticipantUids,proto3" json:"other_confirming_participant_uids,omitempty"` + // Confirmation threshold >= 1 for the party. Defaults to all available confirmers (or if set to 0). + // + // Optional + ConfirmationThreshold uint32 `protobuf:"varint,6,opt,name=confirmation_threshold,json=confirmationThreshold,proto3" json:"confirmation_threshold,omitempty"` + // Other observing participant ids for this party + // + // Optional: can be empty + ObservingParticipantUids []string `protobuf:"bytes,7,rep,name=observing_participant_uids,json=observingParticipantUids,proto3" json:"observing_participant_uids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GenerateExternalPartyTopologyRequest) Reset() { + *x = GenerateExternalPartyTopologyRequest{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenerateExternalPartyTopologyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateExternalPartyTopologyRequest) ProtoMessage() {} + +func (x *GenerateExternalPartyTopologyRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateExternalPartyTopologyRequest.ProtoReflect.Descriptor instead. +func (*GenerateExternalPartyTopologyRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{15} +} + +func (x *GenerateExternalPartyTopologyRequest) GetSynchronizer() string { + if x != nil { + return x.Synchronizer + } + return "" +} + +func (x *GenerateExternalPartyTopologyRequest) GetPartyHint() string { + if x != nil { + return x.PartyHint + } + return "" +} + +func (x *GenerateExternalPartyTopologyRequest) GetPublicKey() *v2.SigningPublicKey { + if x != nil { + return x.PublicKey + } + return nil +} + +func (x *GenerateExternalPartyTopologyRequest) GetLocalParticipantObservationOnly() bool { + if x != nil { + return x.LocalParticipantObservationOnly + } + return false +} + +func (x *GenerateExternalPartyTopologyRequest) GetOtherConfirmingParticipantUids() []string { + if x != nil { + return x.OtherConfirmingParticipantUids + } + return nil +} + +func (x *GenerateExternalPartyTopologyRequest) GetConfirmationThreshold() uint32 { + if x != nil { + return x.ConfirmationThreshold + } + return 0 +} + +func (x *GenerateExternalPartyTopologyRequest) GetObservingParticipantUids() []string { + if x != nil { + return x.ObservingParticipantUids + } + return nil +} + +// Response message with topology transactions and the multi-hash to be signed. +type GenerateExternalPartyTopologyResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The generated party id + // + // Required + PartyId string `protobuf:"bytes,1,opt,name=party_id,json=partyId,proto3" json:"party_id,omitempty"` + // The fingerprint of the supplied public key + // + // Required + PublicKeyFingerprint string `protobuf:"bytes,2,opt,name=public_key_fingerprint,json=publicKeyFingerprint,proto3" json:"public_key_fingerprint,omitempty"` + // The serialized topology transactions which need to be signed and submitted as part of the allocate party process + // Note that the serialization includes the versioning information. Therefore, the transaction here is serialized + // as an `UntypedVersionedMessage` which in turn contains the serialized `TopologyTransaction` in the version + // supported by the synchronizer. + // + // Required: must be non-empty + TopologyTransactions [][]byte `protobuf:"bytes,3,rep,name=topology_transactions,json=topologyTransactions,proto3" json:"topology_transactions,omitempty"` + // the multi-hash which may be signed instead of each individual transaction + // + // Required: must be non-empty + MultiHash []byte `protobuf:"bytes,4,opt,name=multi_hash,json=multiHash,proto3" json:"multi_hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GenerateExternalPartyTopologyResponse) Reset() { + *x = GenerateExternalPartyTopologyResponse{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenerateExternalPartyTopologyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateExternalPartyTopologyResponse) ProtoMessage() {} + +func (x *GenerateExternalPartyTopologyResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateExternalPartyTopologyResponse.ProtoReflect.Descriptor instead. +func (*GenerateExternalPartyTopologyResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{16} +} + +func (x *GenerateExternalPartyTopologyResponse) GetPartyId() string { + if x != nil { + return x.PartyId + } + return "" +} + +func (x *GenerateExternalPartyTopologyResponse) GetPublicKeyFingerprint() string { + if x != nil { + return x.PublicKeyFingerprint + } + return "" +} + +func (x *GenerateExternalPartyTopologyResponse) GetTopologyTransactions() [][]byte { + if x != nil { + return x.TopologyTransactions + } + return nil +} + +func (x *GenerateExternalPartyTopologyResponse) GetMultiHash() []byte { + if x != nil { + return x.MultiHash + } + return nil +} + +type AllocateExternalPartyRequest_SignedTransaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The serialized TopologyTransaction + // + // Required: must be non-empty + Transaction []byte `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` + // Additional signatures for this transaction specifically + // Use for transactions that require additional signatures beyond the namespace key signatures + // e.g: PartyToParticipant must be signed by all registered keys + // + // Optional: can be empty + Signatures []*v2.Signature `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AllocateExternalPartyRequest_SignedTransaction) Reset() { + *x = AllocateExternalPartyRequest_SignedTransaction{} + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AllocateExternalPartyRequest_SignedTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllocateExternalPartyRequest_SignedTransaction) ProtoMessage() {} + +func (x *AllocateExternalPartyRequest_SignedTransaction) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AllocateExternalPartyRequest_SignedTransaction.ProtoReflect.Descriptor instead. +func (*AllocateExternalPartyRequest_SignedTransaction) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP(), []int{8, 0} +} + +func (x *AllocateExternalPartyRequest_SignedTransaction) GetTransaction() []byte { + if x != nil { + return x.Transaction + } + return nil +} + +func (x *AllocateExternalPartyRequest_SignedTransaction) GetSignatures() []*v2.Signature { + if x != nil { + return x.Signatures + } + return nil +} + +var File_com_daml_ledger_api_v2_admin_party_management_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDesc = "" + + "\n" + + ";com/daml/ledger/api/v2/admin/party_management_service.proto\x12\x1ccom.daml.ledger.api.v2.admin\x1a.com/daml/ledger/api/v2/admin/object_meta.proto\x1a#com/daml/ledger/api/v2/crypto.proto\x1a google/protobuf/field_mask.proto\"\x19\n" + + "\x17GetParticipantIdRequest\"A\n" + + "\x18GetParticipantIdResponse\x12%\n" + + "\x0eparticipant_id\x18\x01 \x01(\tR\rparticipantId\"_\n" + + "\x11GetPartiesRequest\x12\x18\n" + + "\aparties\x18\x01 \x03(\tR\aparties\x120\n" + + "\x14identity_provider_id\x18\x02 \x01(\tR\x12identityProviderId\"e\n" + + "\x12GetPartiesResponse\x12O\n" + + "\rparty_details\x18\x01 \x03(\v2*.com.daml.ledger.api.v2.admin.PartyDetailsR\fpartyDetails\"\xaa\x01\n" + + "\x17ListKnownPartiesRequest\x12\x1d\n" + + "\n" + + "page_token\x18\x02 \x01(\tR\tpageToken\x12\x1b\n" + + "\tpage_size\x18\x03 \x01(\x05R\bpageSize\x120\n" + + "\x14identity_provider_id\x18\x01 \x01(\tR\x12identityProviderId\x12!\n" + + "\ffilter_party\x18\x04 \x01(\tR\vfilterParty\"\x93\x01\n" + + "\x18ListKnownPartiesResponse\x12O\n" + + "\rparty_details\x18\x01 \x03(\v2*.com.daml.ledger.api.v2.admin.PartyDetailsR\fpartyDetails\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"\x85\x02\n" + + "\x14AllocatePartyRequest\x12\"\n" + + "\rparty_id_hint\x18\x01 \x01(\tR\vpartyIdHint\x12O\n" + + "\x0elocal_metadata\x18\x03 \x01(\v2(.com.daml.ledger.api.v2.admin.ObjectMetaR\rlocalMetadata\x120\n" + + "\x14identity_provider_id\x18\x04 \x01(\tR\x12identityProviderId\x12'\n" + + "\x0fsynchronizer_id\x18\x05 \x01(\tR\x0esynchronizerId\x12\x17\n" + + "\auser_id\x18\x06 \x01(\tR\x06userIdJ\x04\b\x02\x10\x03\"h\n" + + "\x15AllocatePartyResponse\x12O\n" + + "\rparty_details\x18\x01 \x01(\v2*.com.daml.ledger.api.v2.admin.PartyDetailsR\fpartyDetails\"\xb3\x04\n" + + "\x1cAllocateExternalPartyRequest\x12\"\n" + + "\fsynchronizer\x18\x01 \x01(\tR\fsynchronizer\x12\x85\x01\n" + + "\x17onboarding_transactions\x18\x02 \x03(\v2L.com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest.SignedTransactionR\x16onboardingTransactions\x12U\n" + + "\x15multi_hash_signatures\x18\x03 \x03(\v2!.com.daml.ledger.api.v2.SignatureR\x13multiHashSignatures\x120\n" + + "\x14identity_provider_id\x18\x04 \x01(\tR\x12identityProviderId\x123\n" + + "\x13wait_for_allocation\x18\x05 \x01(\bH\x00R\x11waitForAllocation\x88\x01\x01\x12\x17\n" + + "\auser_id\x18\x06 \x01(\tR\x06userId\x1ax\n" + + "\x11SignedTransaction\x12 \n" + + "\vtransaction\x18\x01 \x01(\fR\vtransaction\x12A\n" + + "\n" + + "signatures\x18\x02 \x03(\v2!.com.daml.ledger.api.v2.SignatureR\n" + + "signaturesB\x16\n" + + "\x14_wait_for_allocation\":\n" + + "\x1dAllocateExternalPartyResponse\x12\x19\n" + + "\bparty_id\x18\x01 \x01(\tR\apartyId\"\xa9\x01\n" + + "\x19UpdatePartyDetailsRequest\x12O\n" + + "\rparty_details\x18\x01 \x01(\v2*.com.daml.ledger.api.v2.admin.PartyDetailsR\fpartyDetails\x12;\n" + + "\vupdate_mask\x18\x02 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" + + "updateMask\"m\n" + + "\x1aUpdatePartyDetailsResponse\x12O\n" + + "\rparty_details\x18\x01 \x01(\v2*.com.daml.ledger.api.v2.admin.PartyDetailsR\fpartyDetails\"\xc2\x01\n" + + "\fPartyDetails\x12\x14\n" + + "\x05party\x18\x01 \x01(\tR\x05party\x12\x19\n" + + "\bis_local\x18\x03 \x01(\bR\aisLocal\x12O\n" + + "\x0elocal_metadata\x18\x04 \x01(\v2(.com.daml.ledger.api.v2.admin.ObjectMetaR\rlocalMetadata\x120\n" + + "\x14identity_provider_id\x18\x05 \x01(\tR\x12identityProviderId\"\xba\x01\n" + + "$UpdatePartyIdentityProviderIdRequest\x12\x14\n" + + "\x05party\x18\x01 \x01(\tR\x05party\x12=\n" + + "\x1bsource_identity_provider_id\x18\x02 \x01(\tR\x18sourceIdentityProviderId\x12=\n" + + "\x1btarget_identity_provider_id\x18\x03 \x01(\tR\x18targetIdentityProviderId\"'\n" + + "%UpdatePartyIdentityProviderIdResponse\"\xbf\x03\n" + + "$GenerateExternalPartyTopologyRequest\x12\"\n" + + "\fsynchronizer\x18\x01 \x01(\tR\fsynchronizer\x12\x1d\n" + + "\n" + + "party_hint\x18\x02 \x01(\tR\tpartyHint\x12G\n" + + "\n" + + "public_key\x18\x03 \x01(\v2(.com.daml.ledger.api.v2.SigningPublicKeyR\tpublicKey\x12K\n" + + "\"local_participant_observation_only\x18\x04 \x01(\bR\x1flocalParticipantObservationOnly\x12I\n" + + "!other_confirming_participant_uids\x18\x05 \x03(\tR\x1eotherConfirmingParticipantUids\x125\n" + + "\x16confirmation_threshold\x18\x06 \x01(\rR\x15confirmationThreshold\x12<\n" + + "\x1aobserving_participant_uids\x18\a \x03(\tR\x18observingParticipantUids\"\xcc\x01\n" + + "%GenerateExternalPartyTopologyResponse\x12\x19\n" + + "\bparty_id\x18\x01 \x01(\tR\apartyId\x124\n" + + "\x16public_key_fingerprint\x18\x02 \x01(\tR\x14publicKeyFingerprint\x123\n" + + "\x15topology_transactions\x18\x03 \x03(\fR\x14topologyTransactions\x12\x1d\n" + + "\n" + + "multi_hash\x18\x04 \x01(\fR\tmultiHash2\xfe\b\n" + + "\x16PartyManagementService\x12\x81\x01\n" + + "\x10GetParticipantId\x125.com.daml.ledger.api.v2.admin.GetParticipantIdRequest\x1a6.com.daml.ledger.api.v2.admin.GetParticipantIdResponse\x12o\n" + + "\n" + + "GetParties\x12/.com.daml.ledger.api.v2.admin.GetPartiesRequest\x1a0.com.daml.ledger.api.v2.admin.GetPartiesResponse\x12\x81\x01\n" + + "\x10ListKnownParties\x125.com.daml.ledger.api.v2.admin.ListKnownPartiesRequest\x1a6.com.daml.ledger.api.v2.admin.ListKnownPartiesResponse\x12x\n" + + "\rAllocateParty\x122.com.daml.ledger.api.v2.admin.AllocatePartyRequest\x1a3.com.daml.ledger.api.v2.admin.AllocatePartyResponse\x12\x90\x01\n" + + "\x15AllocateExternalParty\x12:.com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest\x1a;.com.daml.ledger.api.v2.admin.AllocateExternalPartyResponse\x12\x87\x01\n" + + "\x12UpdatePartyDetails\x127.com.daml.ledger.api.v2.admin.UpdatePartyDetailsRequest\x1a8.com.daml.ledger.api.v2.admin.UpdatePartyDetailsResponse\x12\xa8\x01\n" + + "\x1dUpdatePartyIdentityProviderId\x12B.com.daml.ledger.api.v2.admin.UpdatePartyIdentityProviderIdRequest\x1aC.com.daml.ledger.api.v2.admin.UpdatePartyIdentityProviderIdResponse\x12\xa8\x01\n" + + "\x1dGenerateExternalPartyTopology\x12B.com.daml.ledger.api.v2.admin.GenerateExternalPartyTopologyRequest\x1aC.com.daml.ledger.api.v2.admin.GenerateExternalPartyTopologyResponseB\xa9\x02\n" + + " com.com.daml.ledger.api.v2.adminB\x1bPartyManagementServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin\xa2\x02\x06CDLAVA\xaa\x02\x1cCom.Daml.Ledger.Api.V2.Admin\xca\x02\x1cCom\\Daml\\Ledger\\Api\\V2\\Admin\xe2\x02(Com\\Daml\\Ledger\\Api\\V2\\Admin\\GPBMetadata\xea\x02!Com::Daml::Ledger::Api::V2::Adminb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes = make([]protoimpl.MessageInfo, 18) +var file_com_daml_ledger_api_v2_admin_party_management_service_proto_goTypes = []any{ + (*GetParticipantIdRequest)(nil), // 0: com.daml.ledger.api.v2.admin.GetParticipantIdRequest + (*GetParticipantIdResponse)(nil), // 1: com.daml.ledger.api.v2.admin.GetParticipantIdResponse + (*GetPartiesRequest)(nil), // 2: com.daml.ledger.api.v2.admin.GetPartiesRequest + (*GetPartiesResponse)(nil), // 3: com.daml.ledger.api.v2.admin.GetPartiesResponse + (*ListKnownPartiesRequest)(nil), // 4: com.daml.ledger.api.v2.admin.ListKnownPartiesRequest + (*ListKnownPartiesResponse)(nil), // 5: com.daml.ledger.api.v2.admin.ListKnownPartiesResponse + (*AllocatePartyRequest)(nil), // 6: com.daml.ledger.api.v2.admin.AllocatePartyRequest + (*AllocatePartyResponse)(nil), // 7: com.daml.ledger.api.v2.admin.AllocatePartyResponse + (*AllocateExternalPartyRequest)(nil), // 8: com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest + (*AllocateExternalPartyResponse)(nil), // 9: com.daml.ledger.api.v2.admin.AllocateExternalPartyResponse + (*UpdatePartyDetailsRequest)(nil), // 10: com.daml.ledger.api.v2.admin.UpdatePartyDetailsRequest + (*UpdatePartyDetailsResponse)(nil), // 11: com.daml.ledger.api.v2.admin.UpdatePartyDetailsResponse + (*PartyDetails)(nil), // 12: com.daml.ledger.api.v2.admin.PartyDetails + (*UpdatePartyIdentityProviderIdRequest)(nil), // 13: com.daml.ledger.api.v2.admin.UpdatePartyIdentityProviderIdRequest + (*UpdatePartyIdentityProviderIdResponse)(nil), // 14: com.daml.ledger.api.v2.admin.UpdatePartyIdentityProviderIdResponse + (*GenerateExternalPartyTopologyRequest)(nil), // 15: com.daml.ledger.api.v2.admin.GenerateExternalPartyTopologyRequest + (*GenerateExternalPartyTopologyResponse)(nil), // 16: com.daml.ledger.api.v2.admin.GenerateExternalPartyTopologyResponse + (*AllocateExternalPartyRequest_SignedTransaction)(nil), // 17: com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest.SignedTransaction + (*ObjectMeta)(nil), // 18: com.daml.ledger.api.v2.admin.ObjectMeta + (*v2.Signature)(nil), // 19: com.daml.ledger.api.v2.Signature + (*fieldmaskpb.FieldMask)(nil), // 20: google.protobuf.FieldMask + (*v2.SigningPublicKey)(nil), // 21: com.daml.ledger.api.v2.SigningPublicKey +} +var file_com_daml_ledger_api_v2_admin_party_management_service_proto_depIdxs = []int32{ + 12, // 0: com.daml.ledger.api.v2.admin.GetPartiesResponse.party_details:type_name -> com.daml.ledger.api.v2.admin.PartyDetails + 12, // 1: com.daml.ledger.api.v2.admin.ListKnownPartiesResponse.party_details:type_name -> com.daml.ledger.api.v2.admin.PartyDetails + 18, // 2: com.daml.ledger.api.v2.admin.AllocatePartyRequest.local_metadata:type_name -> com.daml.ledger.api.v2.admin.ObjectMeta + 12, // 3: com.daml.ledger.api.v2.admin.AllocatePartyResponse.party_details:type_name -> com.daml.ledger.api.v2.admin.PartyDetails + 17, // 4: com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest.onboarding_transactions:type_name -> com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest.SignedTransaction + 19, // 5: com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest.multi_hash_signatures:type_name -> com.daml.ledger.api.v2.Signature + 12, // 6: com.daml.ledger.api.v2.admin.UpdatePartyDetailsRequest.party_details:type_name -> com.daml.ledger.api.v2.admin.PartyDetails + 20, // 7: com.daml.ledger.api.v2.admin.UpdatePartyDetailsRequest.update_mask:type_name -> google.protobuf.FieldMask + 12, // 8: com.daml.ledger.api.v2.admin.UpdatePartyDetailsResponse.party_details:type_name -> com.daml.ledger.api.v2.admin.PartyDetails + 18, // 9: com.daml.ledger.api.v2.admin.PartyDetails.local_metadata:type_name -> com.daml.ledger.api.v2.admin.ObjectMeta + 21, // 10: com.daml.ledger.api.v2.admin.GenerateExternalPartyTopologyRequest.public_key:type_name -> com.daml.ledger.api.v2.SigningPublicKey + 19, // 11: com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest.SignedTransaction.signatures:type_name -> com.daml.ledger.api.v2.Signature + 0, // 12: com.daml.ledger.api.v2.admin.PartyManagementService.GetParticipantId:input_type -> com.daml.ledger.api.v2.admin.GetParticipantIdRequest + 2, // 13: com.daml.ledger.api.v2.admin.PartyManagementService.GetParties:input_type -> com.daml.ledger.api.v2.admin.GetPartiesRequest + 4, // 14: com.daml.ledger.api.v2.admin.PartyManagementService.ListKnownParties:input_type -> com.daml.ledger.api.v2.admin.ListKnownPartiesRequest + 6, // 15: com.daml.ledger.api.v2.admin.PartyManagementService.AllocateParty:input_type -> com.daml.ledger.api.v2.admin.AllocatePartyRequest + 8, // 16: com.daml.ledger.api.v2.admin.PartyManagementService.AllocateExternalParty:input_type -> com.daml.ledger.api.v2.admin.AllocateExternalPartyRequest + 10, // 17: com.daml.ledger.api.v2.admin.PartyManagementService.UpdatePartyDetails:input_type -> com.daml.ledger.api.v2.admin.UpdatePartyDetailsRequest + 13, // 18: com.daml.ledger.api.v2.admin.PartyManagementService.UpdatePartyIdentityProviderId:input_type -> com.daml.ledger.api.v2.admin.UpdatePartyIdentityProviderIdRequest + 15, // 19: com.daml.ledger.api.v2.admin.PartyManagementService.GenerateExternalPartyTopology:input_type -> com.daml.ledger.api.v2.admin.GenerateExternalPartyTopologyRequest + 1, // 20: com.daml.ledger.api.v2.admin.PartyManagementService.GetParticipantId:output_type -> com.daml.ledger.api.v2.admin.GetParticipantIdResponse + 3, // 21: com.daml.ledger.api.v2.admin.PartyManagementService.GetParties:output_type -> com.daml.ledger.api.v2.admin.GetPartiesResponse + 5, // 22: com.daml.ledger.api.v2.admin.PartyManagementService.ListKnownParties:output_type -> com.daml.ledger.api.v2.admin.ListKnownPartiesResponse + 7, // 23: com.daml.ledger.api.v2.admin.PartyManagementService.AllocateParty:output_type -> com.daml.ledger.api.v2.admin.AllocatePartyResponse + 9, // 24: com.daml.ledger.api.v2.admin.PartyManagementService.AllocateExternalParty:output_type -> com.daml.ledger.api.v2.admin.AllocateExternalPartyResponse + 11, // 25: com.daml.ledger.api.v2.admin.PartyManagementService.UpdatePartyDetails:output_type -> com.daml.ledger.api.v2.admin.UpdatePartyDetailsResponse + 14, // 26: com.daml.ledger.api.v2.admin.PartyManagementService.UpdatePartyIdentityProviderId:output_type -> com.daml.ledger.api.v2.admin.UpdatePartyIdentityProviderIdResponse + 16, // 27: com.daml.ledger.api.v2.admin.PartyManagementService.GenerateExternalPartyTopology:output_type -> com.daml.ledger.api.v2.admin.GenerateExternalPartyTopologyResponse + 20, // [20:28] is the sub-list for method output_type + 12, // [12:20] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_admin_party_management_service_proto_init() } +func file_com_daml_ledger_api_v2_admin_party_management_service_proto_init() { + if File_com_daml_ledger_api_v2_admin_party_management_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_admin_object_meta_proto_init() + file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes[8].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_party_management_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 18, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_admin_party_management_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_admin_party_management_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_admin_party_management_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_admin_party_management_service_proto = out.File + file_com_daml_ledger_api_v2_admin_party_management_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_admin_party_management_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service_grpc.pb.go new file mode 100644 index 00000000..4cca453f --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/party_management_service_grpc.pb.go @@ -0,0 +1,539 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/admin/party_management_service.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + PartyManagementService_GetParticipantId_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/GetParticipantId" + PartyManagementService_GetParties_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/GetParties" + PartyManagementService_ListKnownParties_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/ListKnownParties" + PartyManagementService_AllocateParty_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/AllocateParty" + PartyManagementService_AllocateExternalParty_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/AllocateExternalParty" + PartyManagementService_UpdatePartyDetails_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/UpdatePartyDetails" + PartyManagementService_UpdatePartyIdentityProviderId_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/UpdatePartyIdentityProviderId" + PartyManagementService_GenerateExternalPartyTopology_FullMethodName = "/com.daml.ledger.api.v2.admin.PartyManagementService/GenerateExternalPartyTopology" +) + +// PartyManagementServiceClient is the client API for PartyManagementService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// This service allows inspecting the party management state of the ledger known to the participant +// and managing the participant-local party metadata. +// +// The authorization rules for its RPCs are specified on the “Request“ +// messages as boolean expressions over these facts: +// +// 1. “HasRight(r)“ denoting whether the authenticated user has right “r“ and +// 2. “IsAuthenticatedIdentityProviderAdmin(idp)“ denoting whether “idp“ is equal to the “identity_provider_id“ +// of the authenticated user and the user has an IdentityProviderAdmin right. +// +// If `identity_provider_id` is set to an empty string, then it's effectively set to the value of access token's 'iss' field if that is provided. +// If `identity_provider_id` remains an empty string, the default identity provider will be assumed. +// +// The fields of request messages (and sub-messages) are marked either as “Optional“ or “Required“: +// +// 1. “Optional“ denoting the client may leave the field unset when sending a request. +// 2. “Required“ denoting the client must set the field to a non-default value when sending a request. +// +// A party details resource is described by the “PartyDetails“ message, +// A party details resource, once it has been created, can be modified using the “UpdatePartyDetails“ RPC. +// The only fields that can be modified are those marked as “Modifiable“. +type PartyManagementServiceClient interface { + // Return the identifier of the participant. + // All horizontally scaled replicas should return the same id. + // daml-on-kv-ledger: returns an identifier supplied on command line at launch time + // canton: returns globally unique identifier of the participant + GetParticipantId(ctx context.Context, in *GetParticipantIdRequest, opts ...grpc.CallOption) (*GetParticipantIdResponse, error) + // Get the party details of the given parties. Only known parties will be + // returned in the list. + GetParties(ctx context.Context, in *GetPartiesRequest, opts ...grpc.CallOption) (*GetPartiesResponse, error) + // List the parties known by the participant. + // The list returned contains parties whose ledger access is facilitated by + // the participant and the ones maintained elsewhere. + ListKnownParties(ctx context.Context, in *ListKnownPartiesRequest, opts ...grpc.CallOption) (*ListKnownPartiesResponse, error) + // Allocates a new party on a ledger and adds it to the set managed by the participant. + // Caller specifies a party identifier suggestion, the actual identifier + // allocated might be different and is implementation specific. + // Caller can specify party metadata that is stored locally on the participant. + // This call may: + // + // - Succeed, in which case the actual allocated identifier is visible in + // the response. + // - Respond with a gRPC error + // + // daml-on-kv-ledger: suggestion's uniqueness is checked by the validators in + // the consensus layer and call rejected if the identifier is already present. + // canton: completely different globally unique identifier is allocated. + // Behind the scenes calls to an internal protocol are made. As that protocol + // is richer than the surface protocol, the arguments take implicit values + // The party identifier suggestion must be a valid party name. Party names are required to be non-empty US-ASCII strings built from letters, digits, space, + // colon, minus and underscore limited to 255 chars + AllocateParty(ctx context.Context, in *AllocatePartyRequest, opts ...grpc.CallOption) (*AllocatePartyResponse, error) + // Alpha 3.3: Endpoint to allocate a new external party on a synchronizer + // + // # Expected to be stable in 3.5 + // + // The external party must be hosted (at least) on this node with either confirmation or observation permissions + // It can optionally be hosted on other nodes (then called a multi-hosted party). + // If hosted on additional nodes, explicit authorization of the hosting relationship must be performed on those nodes + // before the party can be used. + // Decentralized namespaces are supported but must be provided fully authorized by their owners. + // The individual owner namespace transactions can be submitted in the same call (fully authorized as well). + // In the simple case of a non-multi hosted, non-decentralized party, the RPC will return once the party is + // effectively allocated and ready to use, similarly to the AllocateParty behavior. + // For more complex scenarios applications may need to query the party status explicitly (only through the admin API as of now). + AllocateExternalParty(ctx context.Context, in *AllocateExternalPartyRequest, opts ...grpc.CallOption) (*AllocateExternalPartyResponse, error) + // Update selected modifiable participant-local attributes of a party details resource. + // Can update the participant's local information for local parties. + UpdatePartyDetails(ctx context.Context, in *UpdatePartyDetailsRequest, opts ...grpc.CallOption) (*UpdatePartyDetailsResponse, error) + // Update the assignment of a party from one IDP to another. + UpdatePartyIdentityProviderId(ctx context.Context, in *UpdatePartyIdentityProviderIdRequest, opts ...grpc.CallOption) (*UpdatePartyIdentityProviderIdResponse, error) + // Alpha 3.3: Convenience endpoint to generate topology transactions for external signing + // + // # Expected to be stable in 3.5 + // + // You may use this endpoint to generate the common external topology transactions + // which can be signed externally and uploaded as part of the allocate party process + // + // Note that this request will create a normal namespace using the same key for the + // identity as for signing. More elaborate schemes such as multi-signature + // or decentralized parties require you to construct the topology transactions yourself. + GenerateExternalPartyTopology(ctx context.Context, in *GenerateExternalPartyTopologyRequest, opts ...grpc.CallOption) (*GenerateExternalPartyTopologyResponse, error) +} + +type partyManagementServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewPartyManagementServiceClient(cc grpc.ClientConnInterface) PartyManagementServiceClient { + return &partyManagementServiceClient{cc} +} + +func (c *partyManagementServiceClient) GetParticipantId(ctx context.Context, in *GetParticipantIdRequest, opts ...grpc.CallOption) (*GetParticipantIdResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetParticipantIdResponse) + err := c.cc.Invoke(ctx, PartyManagementService_GetParticipantId_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *partyManagementServiceClient) GetParties(ctx context.Context, in *GetPartiesRequest, opts ...grpc.CallOption) (*GetPartiesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetPartiesResponse) + err := c.cc.Invoke(ctx, PartyManagementService_GetParties_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *partyManagementServiceClient) ListKnownParties(ctx context.Context, in *ListKnownPartiesRequest, opts ...grpc.CallOption) (*ListKnownPartiesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListKnownPartiesResponse) + err := c.cc.Invoke(ctx, PartyManagementService_ListKnownParties_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *partyManagementServiceClient) AllocateParty(ctx context.Context, in *AllocatePartyRequest, opts ...grpc.CallOption) (*AllocatePartyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AllocatePartyResponse) + err := c.cc.Invoke(ctx, PartyManagementService_AllocateParty_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *partyManagementServiceClient) AllocateExternalParty(ctx context.Context, in *AllocateExternalPartyRequest, opts ...grpc.CallOption) (*AllocateExternalPartyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AllocateExternalPartyResponse) + err := c.cc.Invoke(ctx, PartyManagementService_AllocateExternalParty_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *partyManagementServiceClient) UpdatePartyDetails(ctx context.Context, in *UpdatePartyDetailsRequest, opts ...grpc.CallOption) (*UpdatePartyDetailsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdatePartyDetailsResponse) + err := c.cc.Invoke(ctx, PartyManagementService_UpdatePartyDetails_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *partyManagementServiceClient) UpdatePartyIdentityProviderId(ctx context.Context, in *UpdatePartyIdentityProviderIdRequest, opts ...grpc.CallOption) (*UpdatePartyIdentityProviderIdResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdatePartyIdentityProviderIdResponse) + err := c.cc.Invoke(ctx, PartyManagementService_UpdatePartyIdentityProviderId_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *partyManagementServiceClient) GenerateExternalPartyTopology(ctx context.Context, in *GenerateExternalPartyTopologyRequest, opts ...grpc.CallOption) (*GenerateExternalPartyTopologyResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GenerateExternalPartyTopologyResponse) + err := c.cc.Invoke(ctx, PartyManagementService_GenerateExternalPartyTopology_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PartyManagementServiceServer is the server API for PartyManagementService service. +// All implementations must embed UnimplementedPartyManagementServiceServer +// for forward compatibility. +// +// This service allows inspecting the party management state of the ledger known to the participant +// and managing the participant-local party metadata. +// +// The authorization rules for its RPCs are specified on the “Request“ +// messages as boolean expressions over these facts: +// +// 1. “HasRight(r)“ denoting whether the authenticated user has right “r“ and +// 2. “IsAuthenticatedIdentityProviderAdmin(idp)“ denoting whether “idp“ is equal to the “identity_provider_id“ +// of the authenticated user and the user has an IdentityProviderAdmin right. +// +// If `identity_provider_id` is set to an empty string, then it's effectively set to the value of access token's 'iss' field if that is provided. +// If `identity_provider_id` remains an empty string, the default identity provider will be assumed. +// +// The fields of request messages (and sub-messages) are marked either as “Optional“ or “Required“: +// +// 1. “Optional“ denoting the client may leave the field unset when sending a request. +// 2. “Required“ denoting the client must set the field to a non-default value when sending a request. +// +// A party details resource is described by the “PartyDetails“ message, +// A party details resource, once it has been created, can be modified using the “UpdatePartyDetails“ RPC. +// The only fields that can be modified are those marked as “Modifiable“. +type PartyManagementServiceServer interface { + // Return the identifier of the participant. + // All horizontally scaled replicas should return the same id. + // daml-on-kv-ledger: returns an identifier supplied on command line at launch time + // canton: returns globally unique identifier of the participant + GetParticipantId(context.Context, *GetParticipantIdRequest) (*GetParticipantIdResponse, error) + // Get the party details of the given parties. Only known parties will be + // returned in the list. + GetParties(context.Context, *GetPartiesRequest) (*GetPartiesResponse, error) + // List the parties known by the participant. + // The list returned contains parties whose ledger access is facilitated by + // the participant and the ones maintained elsewhere. + ListKnownParties(context.Context, *ListKnownPartiesRequest) (*ListKnownPartiesResponse, error) + // Allocates a new party on a ledger and adds it to the set managed by the participant. + // Caller specifies a party identifier suggestion, the actual identifier + // allocated might be different and is implementation specific. + // Caller can specify party metadata that is stored locally on the participant. + // This call may: + // + // - Succeed, in which case the actual allocated identifier is visible in + // the response. + // - Respond with a gRPC error + // + // daml-on-kv-ledger: suggestion's uniqueness is checked by the validators in + // the consensus layer and call rejected if the identifier is already present. + // canton: completely different globally unique identifier is allocated. + // Behind the scenes calls to an internal protocol are made. As that protocol + // is richer than the surface protocol, the arguments take implicit values + // The party identifier suggestion must be a valid party name. Party names are required to be non-empty US-ASCII strings built from letters, digits, space, + // colon, minus and underscore limited to 255 chars + AllocateParty(context.Context, *AllocatePartyRequest) (*AllocatePartyResponse, error) + // Alpha 3.3: Endpoint to allocate a new external party on a synchronizer + // + // # Expected to be stable in 3.5 + // + // The external party must be hosted (at least) on this node with either confirmation or observation permissions + // It can optionally be hosted on other nodes (then called a multi-hosted party). + // If hosted on additional nodes, explicit authorization of the hosting relationship must be performed on those nodes + // before the party can be used. + // Decentralized namespaces are supported but must be provided fully authorized by their owners. + // The individual owner namespace transactions can be submitted in the same call (fully authorized as well). + // In the simple case of a non-multi hosted, non-decentralized party, the RPC will return once the party is + // effectively allocated and ready to use, similarly to the AllocateParty behavior. + // For more complex scenarios applications may need to query the party status explicitly (only through the admin API as of now). + AllocateExternalParty(context.Context, *AllocateExternalPartyRequest) (*AllocateExternalPartyResponse, error) + // Update selected modifiable participant-local attributes of a party details resource. + // Can update the participant's local information for local parties. + UpdatePartyDetails(context.Context, *UpdatePartyDetailsRequest) (*UpdatePartyDetailsResponse, error) + // Update the assignment of a party from one IDP to another. + UpdatePartyIdentityProviderId(context.Context, *UpdatePartyIdentityProviderIdRequest) (*UpdatePartyIdentityProviderIdResponse, error) + // Alpha 3.3: Convenience endpoint to generate topology transactions for external signing + // + // # Expected to be stable in 3.5 + // + // You may use this endpoint to generate the common external topology transactions + // which can be signed externally and uploaded as part of the allocate party process + // + // Note that this request will create a normal namespace using the same key for the + // identity as for signing. More elaborate schemes such as multi-signature + // or decentralized parties require you to construct the topology transactions yourself. + GenerateExternalPartyTopology(context.Context, *GenerateExternalPartyTopologyRequest) (*GenerateExternalPartyTopologyResponse, error) + mustEmbedUnimplementedPartyManagementServiceServer() +} + +// UnimplementedPartyManagementServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedPartyManagementServiceServer struct{} + +func (UnimplementedPartyManagementServiceServer) GetParticipantId(context.Context, *GetParticipantIdRequest) (*GetParticipantIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetParticipantId not implemented") +} +func (UnimplementedPartyManagementServiceServer) GetParties(context.Context, *GetPartiesRequest) (*GetPartiesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetParties not implemented") +} +func (UnimplementedPartyManagementServiceServer) ListKnownParties(context.Context, *ListKnownPartiesRequest) (*ListKnownPartiesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListKnownParties not implemented") +} +func (UnimplementedPartyManagementServiceServer) AllocateParty(context.Context, *AllocatePartyRequest) (*AllocatePartyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllocateParty not implemented") +} +func (UnimplementedPartyManagementServiceServer) AllocateExternalParty(context.Context, *AllocateExternalPartyRequest) (*AllocateExternalPartyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllocateExternalParty not implemented") +} +func (UnimplementedPartyManagementServiceServer) UpdatePartyDetails(context.Context, *UpdatePartyDetailsRequest) (*UpdatePartyDetailsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdatePartyDetails not implemented") +} +func (UnimplementedPartyManagementServiceServer) UpdatePartyIdentityProviderId(context.Context, *UpdatePartyIdentityProviderIdRequest) (*UpdatePartyIdentityProviderIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdatePartyIdentityProviderId not implemented") +} +func (UnimplementedPartyManagementServiceServer) GenerateExternalPartyTopology(context.Context, *GenerateExternalPartyTopologyRequest) (*GenerateExternalPartyTopologyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateExternalPartyTopology not implemented") +} +func (UnimplementedPartyManagementServiceServer) mustEmbedUnimplementedPartyManagementServiceServer() { +} +func (UnimplementedPartyManagementServiceServer) testEmbeddedByValue() {} + +// UnsafePartyManagementServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PartyManagementServiceServer will +// result in compilation errors. +type UnsafePartyManagementServiceServer interface { + mustEmbedUnimplementedPartyManagementServiceServer() +} + +func RegisterPartyManagementServiceServer(s grpc.ServiceRegistrar, srv PartyManagementServiceServer) { + // If the following call pancis, it indicates UnimplementedPartyManagementServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&PartyManagementService_ServiceDesc, srv) +} + +func _PartyManagementService_GetParticipantId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetParticipantIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).GetParticipantId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_GetParticipantId_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).GetParticipantId(ctx, req.(*GetParticipantIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PartyManagementService_GetParties_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPartiesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).GetParties(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_GetParties_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).GetParties(ctx, req.(*GetPartiesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PartyManagementService_ListKnownParties_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListKnownPartiesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).ListKnownParties(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_ListKnownParties_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).ListKnownParties(ctx, req.(*ListKnownPartiesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PartyManagementService_AllocateParty_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AllocatePartyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).AllocateParty(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_AllocateParty_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).AllocateParty(ctx, req.(*AllocatePartyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PartyManagementService_AllocateExternalParty_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AllocateExternalPartyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).AllocateExternalParty(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_AllocateExternalParty_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).AllocateExternalParty(ctx, req.(*AllocateExternalPartyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PartyManagementService_UpdatePartyDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdatePartyDetailsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).UpdatePartyDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_UpdatePartyDetails_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).UpdatePartyDetails(ctx, req.(*UpdatePartyDetailsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PartyManagementService_UpdatePartyIdentityProviderId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdatePartyIdentityProviderIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).UpdatePartyIdentityProviderId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_UpdatePartyIdentityProviderId_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).UpdatePartyIdentityProviderId(ctx, req.(*UpdatePartyIdentityProviderIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PartyManagementService_GenerateExternalPartyTopology_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenerateExternalPartyTopologyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PartyManagementServiceServer).GenerateExternalPartyTopology(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PartyManagementService_GenerateExternalPartyTopology_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PartyManagementServiceServer).GenerateExternalPartyTopology(ctx, req.(*GenerateExternalPartyTopologyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// PartyManagementService_ServiceDesc is the grpc.ServiceDesc for PartyManagementService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PartyManagementService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.admin.PartyManagementService", + HandlerType: (*PartyManagementServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetParticipantId", + Handler: _PartyManagementService_GetParticipantId_Handler, + }, + { + MethodName: "GetParties", + Handler: _PartyManagementService_GetParties_Handler, + }, + { + MethodName: "ListKnownParties", + Handler: _PartyManagementService_ListKnownParties_Handler, + }, + { + MethodName: "AllocateParty", + Handler: _PartyManagementService_AllocateParty_Handler, + }, + { + MethodName: "AllocateExternalParty", + Handler: _PartyManagementService_AllocateExternalParty_Handler, + }, + { + MethodName: "UpdatePartyDetails", + Handler: _PartyManagementService_UpdatePartyDetails_Handler, + }, + { + MethodName: "UpdatePartyIdentityProviderId", + Handler: _PartyManagementService_UpdatePartyIdentityProviderId_Handler, + }, + { + MethodName: "GenerateExternalPartyTopology", + Handler: _PartyManagementService_GenerateExternalPartyTopology_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/admin/party_management_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service.pb.go new file mode 100644 index 00000000..df87283f --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service.pb.go @@ -0,0 +1,1847 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/admin/user_management_service.proto + +package admin + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Users are used to dynamically manage the rights given to Daml applications. +// They are stored and managed per participant node. +type User struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user identifier, which must be a non-empty string of at most 128 + // characters that are either alphanumeric ASCII characters or one of the symbols "@^$.!`-#+'~_|:()". + // + // Required + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // The primary party as which this user reads and acts by default on the ledger + // *provided* it has the corresponding “CanReadAs(primary_party)“ or + // “CanActAs(primary_party)“ rights. + // Ledger API clients SHOULD set this field to a non-empty value for all users to + // enable the users to act on the ledger using their own Daml party. + // Users for participant administrators MAY have an associated primary party. + // Modifiable + // + // Optional + PrimaryParty string `protobuf:"bytes,2,opt,name=primary_party,json=primaryParty,proto3" json:"primary_party,omitempty"` + // When set, then the user is denied all access to the Ledger API. + // Otherwise, the user has access to the Ledger API as per the user's rights. + // Modifiable + // + // Optional + IsDeactivated bool `protobuf:"varint,3,opt,name=is_deactivated,json=isDeactivated,proto3" json:"is_deactivated,omitempty"` + // The metadata of this user. + // Note that the “metadata.resource_version“ tracks changes to the properties described by the “User“ message and not the user's rights. + // Modifiable + // + // Optional + Metadata *ObjectMeta `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` + // The ID of the identity provider configured by “Identity Provider Config“ + // If not set, assume the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,5,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *User) Reset() { + *x = User{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{0} +} + +func (x *User) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *User) GetPrimaryParty() string { + if x != nil { + return x.PrimaryParty + } + return "" +} + +func (x *User) GetIsDeactivated() bool { + if x != nil { + return x.IsDeactivated + } + return false +} + +func (x *User) GetMetadata() *ObjectMeta { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *User) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +// A right granted to a user. +type Right struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Kind: + // + // *Right_ParticipantAdmin_ + // *Right_CanActAs_ + // *Right_CanReadAs_ + // *Right_IdentityProviderAdmin_ + // *Right_CanReadAsAnyParty_ + // *Right_CanExecuteAs_ + // *Right_CanExecuteAsAnyParty_ + Kind isRight_Kind `protobuf_oneof:"kind"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right) Reset() { + *x = Right{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right) ProtoMessage() {} + +func (x *Right) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right.ProtoReflect.Descriptor instead. +func (*Right) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1} +} + +func (x *Right) GetKind() isRight_Kind { + if x != nil { + return x.Kind + } + return nil +} + +func (x *Right) GetParticipantAdmin() *Right_ParticipantAdmin { + if x != nil { + if x, ok := x.Kind.(*Right_ParticipantAdmin_); ok { + return x.ParticipantAdmin + } + } + return nil +} + +func (x *Right) GetCanActAs() *Right_CanActAs { + if x != nil { + if x, ok := x.Kind.(*Right_CanActAs_); ok { + return x.CanActAs + } + } + return nil +} + +func (x *Right) GetCanReadAs() *Right_CanReadAs { + if x != nil { + if x, ok := x.Kind.(*Right_CanReadAs_); ok { + return x.CanReadAs + } + } + return nil +} + +func (x *Right) GetIdentityProviderAdmin() *Right_IdentityProviderAdmin { + if x != nil { + if x, ok := x.Kind.(*Right_IdentityProviderAdmin_); ok { + return x.IdentityProviderAdmin + } + } + return nil +} + +func (x *Right) GetCanReadAsAnyParty() *Right_CanReadAsAnyParty { + if x != nil { + if x, ok := x.Kind.(*Right_CanReadAsAnyParty_); ok { + return x.CanReadAsAnyParty + } + } + return nil +} + +func (x *Right) GetCanExecuteAs() *Right_CanExecuteAs { + if x != nil { + if x, ok := x.Kind.(*Right_CanExecuteAs_); ok { + return x.CanExecuteAs + } + } + return nil +} + +func (x *Right) GetCanExecuteAsAnyParty() *Right_CanExecuteAsAnyParty { + if x != nil { + if x, ok := x.Kind.(*Right_CanExecuteAsAnyParty_); ok { + return x.CanExecuteAsAnyParty + } + } + return nil +} + +type isRight_Kind interface { + isRight_Kind() +} + +type Right_ParticipantAdmin_ struct { + // The user can administer the participant node. + ParticipantAdmin *Right_ParticipantAdmin `protobuf:"bytes,1,opt,name=participant_admin,json=participantAdmin,proto3,oneof"` +} + +type Right_CanActAs_ struct { + // The user can act as a specific party. + CanActAs *Right_CanActAs `protobuf:"bytes,2,opt,name=can_act_as,json=canActAs,proto3,oneof"` +} + +type Right_CanReadAs_ struct { + // The user can read ledger data visible to a specific party. + CanReadAs *Right_CanReadAs `protobuf:"bytes,3,opt,name=can_read_as,json=canReadAs,proto3,oneof"` +} + +type Right_IdentityProviderAdmin_ struct { + // The user can administer users and parties assigned to the same identity provider as the one of the user. + IdentityProviderAdmin *Right_IdentityProviderAdmin `protobuf:"bytes,4,opt,name=identity_provider_admin,json=identityProviderAdmin,proto3,oneof"` +} + +type Right_CanReadAsAnyParty_ struct { + // The user can read as any party on a participant + CanReadAsAnyParty *Right_CanReadAsAnyParty `protobuf:"bytes,5,opt,name=can_read_as_any_party,json=canReadAsAnyParty,proto3,oneof"` +} + +type Right_CanExecuteAs_ struct { + // The user can prepare and execute submissions as a specific party. + CanExecuteAs *Right_CanExecuteAs `protobuf:"bytes,6,opt,name=can_execute_as,json=canExecuteAs,proto3,oneof"` +} + +type Right_CanExecuteAsAnyParty_ struct { + // The user can prepare and execute submissions as any party on a participant. + CanExecuteAsAnyParty *Right_CanExecuteAsAnyParty `protobuf:"bytes,7,opt,name=can_execute_as_any_party,json=canExecuteAsAnyParty,proto3,oneof"` +} + +func (*Right_ParticipantAdmin_) isRight_Kind() {} + +func (*Right_CanActAs_) isRight_Kind() {} + +func (*Right_CanReadAs_) isRight_Kind() {} + +func (*Right_IdentityProviderAdmin_) isRight_Kind() {} + +func (*Right_CanReadAsAnyParty_) isRight_Kind() {} + +func (*Right_CanExecuteAs_) isRight_Kind() {} + +func (*Right_CanExecuteAsAnyParty_) isRight_Kind() {} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(user.identity_provider_id)“ +type CreateUserRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user to create. + // + // Required + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + // The rights to be assigned to the user upon creation, + // which SHOULD include appropriate rights for the “user.primary_party“. + // + // Optional: can be empty + Rights []*Right `protobuf:"bytes,2,rep,name=rights,proto3" json:"rights,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateUserRequest) Reset() { + *x = CreateUserRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateUserRequest) ProtoMessage() {} + +func (x *CreateUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateUserRequest.ProtoReflect.Descriptor instead. +func (*CreateUserRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateUserRequest) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *CreateUserRequest) GetRights() []*Right { + if x != nil { + return x.Rights + } + return nil +} + +type CreateUserResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Created user. + // + // Required + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateUserResponse) Reset() { + *x = CreateUserResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateUserResponse) ProtoMessage() {} + +func (x *CreateUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateUserResponse.ProtoReflect.Descriptor instead. +func (*CreateUserResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{3} +} + +func (x *CreateUserResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)“ +type GetUserRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user whose data to retrieve. + // If set to empty string (the default), then the data for the authenticated user will be retrieved. + // + // Optional + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,2,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUserRequest) Reset() { + *x = GetUserRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserRequest) ProtoMessage() {} + +func (x *GetUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserRequest.ProtoReflect.Descriptor instead. +func (*GetUserRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{4} +} + +func (x *GetUserRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GetUserRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type GetUserResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Retrieved user. + // + // Required + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUserResponse) Reset() { + *x = GetUserResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserResponse) ProtoMessage() {} + +func (x *GetUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserResponse.ProtoReflect.Descriptor instead. +func (*GetUserResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{5} +} + +func (x *GetUserResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(user.identity_provider_id)“ +type UpdateUserRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user to update. + // Modifiable + // + // Required + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + // An update mask specifies how and which properties of the “User“ message are to be updated. + // An update mask consists of a set of update paths. + // A valid update path points to a field or a subfield relative to the “User“ message. + // A valid update mask must: + // + // 1. contain at least one update path, + // 2. contain only valid update paths. + // + // Fields that can be updated are marked as “Modifiable“. + // An update path can also point to a non-“Modifiable“ fields such as 'id' and 'metadata.resource_version' + // because they are used: + // + // 1. to identify the user resource subject to the update, + // 2. for concurrent change control. + // + // Examples of valid update paths: 'primary_party', 'metadata', 'metadata.annotations'. + // For additional information see the documentation for standard protobuf3's “google.protobuf.FieldMask“. + // For similar Ledger API see “com.daml.ledger.api.v2.admin.UpdatePartyDetailsRequest“. + // + // Required + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateUserRequest) Reset() { + *x = UpdateUserRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserRequest) ProtoMessage() {} + +func (x *UpdateUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserRequest.ProtoReflect.Descriptor instead. +func (*UpdateUserRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateUserRequest) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *UpdateUserRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +type UpdateUserResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Updated user + // + // Required + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateUserResponse) Reset() { + *x = UpdateUserResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserResponse) ProtoMessage() {} + +func (x *UpdateUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserResponse.ProtoReflect.Descriptor instead. +func (*UpdateUserResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateUserResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)“ +type DeleteUserRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user to delete. + // + // Required + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,2,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteUserRequest) Reset() { + *x = DeleteUserRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserRequest) ProtoMessage() {} + +func (x *DeleteUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteUserRequest.ProtoReflect.Descriptor instead. +func (*DeleteUserRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{8} +} + +func (x *DeleteUserRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *DeleteUserRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +// Does not (yet) contain any data. +type DeleteUserResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteUserResponse) Reset() { + *x = DeleteUserResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUserResponse) ProtoMessage() {} + +func (x *DeleteUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteUserResponse.ProtoReflect.Descriptor instead. +func (*DeleteUserResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{9} +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)“ +type ListUsersRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Pagination token to determine the specific page to fetch. + // Leave empty to fetch the first page. + // + // Optional + PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // Maximum number of results to be returned by the server. The server will return no more than that many results, but it might return fewer. + // If 0, the server will decide the number of results to be returned. + // + // Optional + PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,4,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListUsersRequest) Reset() { + *x = ListUsersRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListUsersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUsersRequest) ProtoMessage() {} + +func (x *ListUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUsersRequest.ProtoReflect.Descriptor instead. +func (*ListUsersRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{10} +} + +func (x *ListUsersRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListUsersRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListUsersRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type ListUsersResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // A subset of users of the participant node that fit into this page. + // Can be empty if no more users + // + // Optional: can be empty + Users []*User `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"` + // Pagination token to retrieve the next page. + // Empty, if there are no further results. + // + // Optional + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListUsersResponse) Reset() { + *x = ListUsersResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUsersResponse) ProtoMessage() {} + +func (x *ListUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUsersResponse.ProtoReflect.Descriptor instead. +func (*ListUsersResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{11} +} + +func (x *ListUsersResponse) GetUsers() []*User { + if x != nil { + return x.Users + } + return nil +} + +func (x *ListUsersResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Add the rights to the set of rights granted to the user. +// +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)“ +type GrantUserRightsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user to whom to grant rights. + // + // Required + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The rights to grant. + // + // Optional: can be empty + Rights []*Right `protobuf:"bytes,2,rep,name=rights,proto3" json:"rights,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,3,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GrantUserRightsRequest) Reset() { + *x = GrantUserRightsRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GrantUserRightsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GrantUserRightsRequest) ProtoMessage() {} + +func (x *GrantUserRightsRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GrantUserRightsRequest.ProtoReflect.Descriptor instead. +func (*GrantUserRightsRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{12} +} + +func (x *GrantUserRightsRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *GrantUserRightsRequest) GetRights() []*Right { + if x != nil { + return x.Rights + } + return nil +} + +func (x *GrantUserRightsRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type GrantUserRightsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The rights that were newly granted by the request. + // + // Optional: can be empty + NewlyGrantedRights []*Right `protobuf:"bytes,1,rep,name=newly_granted_rights,json=newlyGrantedRights,proto3" json:"newly_granted_rights,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GrantUserRightsResponse) Reset() { + *x = GrantUserRightsResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GrantUserRightsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GrantUserRightsResponse) ProtoMessage() {} + +func (x *GrantUserRightsResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GrantUserRightsResponse.ProtoReflect.Descriptor instead. +func (*GrantUserRightsResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{13} +} + +func (x *GrantUserRightsResponse) GetNewlyGrantedRights() []*Right { + if x != nil { + return x.NewlyGrantedRights + } + return nil +} + +// Remove the rights from the set of rights granted to the user. +// +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id)“ +type RevokeUserRightsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user from whom to revoke rights. + // + // Required + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The rights to revoke. + // + // Optional: can be empty + Rights []*Right `protobuf:"bytes,2,rep,name=rights,proto3" json:"rights,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,3,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevokeUserRightsRequest) Reset() { + *x = RevokeUserRightsRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevokeUserRightsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevokeUserRightsRequest) ProtoMessage() {} + +func (x *RevokeUserRightsRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevokeUserRightsRequest.ProtoReflect.Descriptor instead. +func (*RevokeUserRightsRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{14} +} + +func (x *RevokeUserRightsRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *RevokeUserRightsRequest) GetRights() []*Right { + if x != nil { + return x.Rights + } + return nil +} + +func (x *RevokeUserRightsRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type RevokeUserRightsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The rights that were actually revoked by the request. + // + // Optional: can be empty + NewlyRevokedRights []*Right `protobuf:"bytes,1,rep,name=newly_revoked_rights,json=newlyRevokedRights,proto3" json:"newly_revoked_rights,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevokeUserRightsResponse) Reset() { + *x = RevokeUserRightsResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevokeUserRightsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevokeUserRightsResponse) ProtoMessage() {} + +func (x *RevokeUserRightsResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevokeUserRightsResponse.ProtoReflect.Descriptor instead. +func (*RevokeUserRightsResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{15} +} + +func (x *RevokeUserRightsResponse) GetNewlyRevokedRights() []*Right { + if x != nil { + return x.NewlyRevokedRights + } + return nil +} + +// Required authorization: “HasRight(ParticipantAdmin) OR IsAuthenticatedIdentityProviderAdmin(identity_provider_id) OR IsAuthenticatedUser(user_id)“ +type ListUserRightsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The user for which to list the rights. + // If set to empty string (the default), then the rights for the authenticated user will be listed. + // + // Required + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The id of the “Identity Provider“ + // If not set, assume the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,2,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListUserRightsRequest) Reset() { + *x = ListUserRightsRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListUserRightsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUserRightsRequest) ProtoMessage() {} + +func (x *ListUserRightsRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUserRightsRequest.ProtoReflect.Descriptor instead. +func (*ListUserRightsRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{16} +} + +func (x *ListUserRightsRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *ListUserRightsRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type ListUserRightsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // All rights of the user. + // + // Optional: can be empty + Rights []*Right `protobuf:"bytes,1,rep,name=rights,proto3" json:"rights,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListUserRightsResponse) Reset() { + *x = ListUserRightsResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListUserRightsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUserRightsResponse) ProtoMessage() {} + +func (x *ListUserRightsResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUserRightsResponse.ProtoReflect.Descriptor instead. +func (*ListUserRightsResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{17} +} + +func (x *ListUserRightsResponse) GetRights() []*Right { + if x != nil { + return x.Rights + } + return nil +} + +// Required authorization: “HasRight(ParticipantAdmin)“ +type UpdateUserIdentityProviderIdRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // User to update + // + // Required + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // Current identity provider ID of the user + // If omitted, the default IDP is assumed + // + // Optional + SourceIdentityProviderId string `protobuf:"bytes,2,opt,name=source_identity_provider_id,json=sourceIdentityProviderId,proto3" json:"source_identity_provider_id,omitempty"` + // Target identity provider ID of the user + // If omitted, the default IDP is assumed + // + // Optional + TargetIdentityProviderId string `protobuf:"bytes,3,opt,name=target_identity_provider_id,json=targetIdentityProviderId,proto3" json:"target_identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateUserIdentityProviderIdRequest) Reset() { + *x = UpdateUserIdentityProviderIdRequest{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateUserIdentityProviderIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserIdentityProviderIdRequest) ProtoMessage() {} + +func (x *UpdateUserIdentityProviderIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserIdentityProviderIdRequest.ProtoReflect.Descriptor instead. +func (*UpdateUserIdentityProviderIdRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{18} +} + +func (x *UpdateUserIdentityProviderIdRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *UpdateUserIdentityProviderIdRequest) GetSourceIdentityProviderId() string { + if x != nil { + return x.SourceIdentityProviderId + } + return "" +} + +func (x *UpdateUserIdentityProviderIdRequest) GetTargetIdentityProviderId() string { + if x != nil { + return x.TargetIdentityProviderId + } + return "" +} + +type UpdateUserIdentityProviderIdResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateUserIdentityProviderIdResponse) Reset() { + *x = UpdateUserIdentityProviderIdResponse{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateUserIdentityProviderIdResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserIdentityProviderIdResponse) ProtoMessage() {} + +func (x *UpdateUserIdentityProviderIdResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserIdentityProviderIdResponse.ProtoReflect.Descriptor instead. +func (*UpdateUserIdentityProviderIdResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{19} +} + +// The right to administer the participant node. +type Right_ParticipantAdmin struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right_ParticipantAdmin) Reset() { + *x = Right_ParticipantAdmin{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right_ParticipantAdmin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right_ParticipantAdmin) ProtoMessage() {} + +func (x *Right_ParticipantAdmin) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right_ParticipantAdmin.ProtoReflect.Descriptor instead. +func (*Right_ParticipantAdmin) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1, 0} +} + +type Right_CanActAs struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The right to authorize commands for this party. + // + // Required + Party string `protobuf:"bytes,1,opt,name=party,proto3" json:"party,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right_CanActAs) Reset() { + *x = Right_CanActAs{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right_CanActAs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right_CanActAs) ProtoMessage() {} + +func (x *Right_CanActAs) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right_CanActAs.ProtoReflect.Descriptor instead. +func (*Right_CanActAs) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1, 1} +} + +func (x *Right_CanActAs) GetParty() string { + if x != nil { + return x.Party + } + return "" +} + +type Right_CanReadAs struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The right to read ledger data visible to this party. + // + // Required + Party string `protobuf:"bytes,1,opt,name=party,proto3" json:"party,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right_CanReadAs) Reset() { + *x = Right_CanReadAs{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right_CanReadAs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right_CanReadAs) ProtoMessage() {} + +func (x *Right_CanReadAs) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right_CanReadAs.ProtoReflect.Descriptor instead. +func (*Right_CanReadAs) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1, 2} +} + +func (x *Right_CanReadAs) GetParty() string { + if x != nil { + return x.Party + } + return "" +} + +type Right_CanExecuteAs struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The right to prepare and execute submissions as this party. + // This right does not entitle the user to perform any reads. + // If reading is required, a separate ReadAs right must be added. + // Right to execute as a party is also implicitly contained in the CanActAs right. + // + // Required + Party string `protobuf:"bytes,1,opt,name=party,proto3" json:"party,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right_CanExecuteAs) Reset() { + *x = Right_CanExecuteAs{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right_CanExecuteAs) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right_CanExecuteAs) ProtoMessage() {} + +func (x *Right_CanExecuteAs) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right_CanExecuteAs.ProtoReflect.Descriptor instead. +func (*Right_CanExecuteAs) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1, 3} +} + +func (x *Right_CanExecuteAs) GetParty() string { + if x != nil { + return x.Party + } + return "" +} + +// The right to administer the identity provider that the user is assigned to. +// It means, being able to manage users and parties that are also assigned +// to the same identity provider. +type Right_IdentityProviderAdmin struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right_IdentityProviderAdmin) Reset() { + *x = Right_IdentityProviderAdmin{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right_IdentityProviderAdmin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right_IdentityProviderAdmin) ProtoMessage() {} + +func (x *Right_IdentityProviderAdmin) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right_IdentityProviderAdmin.ProtoReflect.Descriptor instead. +func (*Right_IdentityProviderAdmin) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1, 4} +} + +// The rights of a participant's super reader. Its utility is predominantly for +// feeding external tools, such as PQS, continually without the need to change subscriptions +// as new parties pop in and out of existence. +type Right_CanReadAsAnyParty struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right_CanReadAsAnyParty) Reset() { + *x = Right_CanReadAsAnyParty{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right_CanReadAsAnyParty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right_CanReadAsAnyParty) ProtoMessage() {} + +func (x *Right_CanReadAsAnyParty) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right_CanReadAsAnyParty.ProtoReflect.Descriptor instead. +func (*Right_CanReadAsAnyParty) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1, 5} +} + +// The rights of a user to prepare and execute transactions as any party. +// Its utility is predominantly for users that perform interactive submissions +// on behalf of many parties. +type Right_CanExecuteAsAnyParty struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Right_CanExecuteAsAnyParty) Reset() { + *x = Right_CanExecuteAsAnyParty{} + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Right_CanExecuteAsAnyParty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Right_CanExecuteAsAnyParty) ProtoMessage() {} + +func (x *Right_CanExecuteAsAnyParty) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Right_CanExecuteAsAnyParty.ProtoReflect.Descriptor instead. +func (*Right_CanExecuteAsAnyParty) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP(), []int{1, 6} +} + +var File_com_daml_ledger_api_v2_admin_user_management_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDesc = "" + + "\n" + + ":com/daml/ledger/api/v2/admin/user_management_service.proto\x12\x1ccom.daml.ledger.api.v2.admin\x1a.com/daml/ledger/api/v2/admin/object_meta.proto\x1a google/protobuf/field_mask.proto\"\xda\x01\n" + + "\x04User\x12\x0e\n" + + "\x02id\x18\x01 \x01(\tR\x02id\x12#\n" + + "\rprimary_party\x18\x02 \x01(\tR\fprimaryParty\x12%\n" + + "\x0eis_deactivated\x18\x03 \x01(\bR\risDeactivated\x12D\n" + + "\bmetadata\x18\x04 \x01(\v2(.com.daml.ledger.api.v2.admin.ObjectMetaR\bmetadata\x120\n" + + "\x14identity_provider_id\x18\x05 \x01(\tR\x12identityProviderId\"\x86\a\n" + + "\x05Right\x12c\n" + + "\x11participant_admin\x18\x01 \x01(\v24.com.daml.ledger.api.v2.admin.Right.ParticipantAdminH\x00R\x10participantAdmin\x12L\n" + + "\n" + + "can_act_as\x18\x02 \x01(\v2,.com.daml.ledger.api.v2.admin.Right.CanActAsH\x00R\bcanActAs\x12O\n" + + "\vcan_read_as\x18\x03 \x01(\v2-.com.daml.ledger.api.v2.admin.Right.CanReadAsH\x00R\tcanReadAs\x12s\n" + + "\x17identity_provider_admin\x18\x04 \x01(\v29.com.daml.ledger.api.v2.admin.Right.IdentityProviderAdminH\x00R\x15identityProviderAdmin\x12i\n" + + "\x15can_read_as_any_party\x18\x05 \x01(\v25.com.daml.ledger.api.v2.admin.Right.CanReadAsAnyPartyH\x00R\x11canReadAsAnyParty\x12X\n" + + "\x0ecan_execute_as\x18\x06 \x01(\v20.com.daml.ledger.api.v2.admin.Right.CanExecuteAsH\x00R\fcanExecuteAs\x12r\n" + + "\x18can_execute_as_any_party\x18\a \x01(\v28.com.daml.ledger.api.v2.admin.Right.CanExecuteAsAnyPartyH\x00R\x14canExecuteAsAnyParty\x1a\x12\n" + + "\x10ParticipantAdmin\x1a \n" + + "\bCanActAs\x12\x14\n" + + "\x05party\x18\x01 \x01(\tR\x05party\x1a!\n" + + "\tCanReadAs\x12\x14\n" + + "\x05party\x18\x01 \x01(\tR\x05party\x1a$\n" + + "\fCanExecuteAs\x12\x14\n" + + "\x05party\x18\x01 \x01(\tR\x05party\x1a\x17\n" + + "\x15IdentityProviderAdmin\x1a\x13\n" + + "\x11CanReadAsAnyParty\x1a\x16\n" + + "\x14CanExecuteAsAnyPartyB\x06\n" + + "\x04kind\"\x88\x01\n" + + "\x11CreateUserRequest\x126\n" + + "\x04user\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.admin.UserR\x04user\x12;\n" + + "\x06rights\x18\x02 \x03(\v2#.com.daml.ledger.api.v2.admin.RightR\x06rights\"L\n" + + "\x12CreateUserResponse\x126\n" + + "\x04user\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.admin.UserR\x04user\"[\n" + + "\x0eGetUserRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x120\n" + + "\x14identity_provider_id\x18\x02 \x01(\tR\x12identityProviderId\"I\n" + + "\x0fGetUserResponse\x126\n" + + "\x04user\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.admin.UserR\x04user\"\x88\x01\n" + + "\x11UpdateUserRequest\x126\n" + + "\x04user\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.admin.UserR\x04user\x12;\n" + + "\vupdate_mask\x18\x02 \x01(\v2\x1a.google.protobuf.FieldMaskR\n" + + "updateMask\"L\n" + + "\x12UpdateUserResponse\x126\n" + + "\x04user\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.admin.UserR\x04user\"^\n" + + "\x11DeleteUserRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x120\n" + + "\x14identity_provider_id\x18\x02 \x01(\tR\x12identityProviderId\"\x14\n" + + "\x12DeleteUserResponse\"\x80\x01\n" + + "\x10ListUsersRequest\x12\x1d\n" + + "\n" + + "page_token\x18\x02 \x01(\tR\tpageToken\x12\x1b\n" + + "\tpage_size\x18\x03 \x01(\x05R\bpageSize\x120\n" + + "\x14identity_provider_id\x18\x04 \x01(\tR\x12identityProviderId\"u\n" + + "\x11ListUsersResponse\x128\n" + + "\x05users\x18\x01 \x03(\v2\".com.daml.ledger.api.v2.admin.UserR\x05users\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"\xa0\x01\n" + + "\x16GrantUserRightsRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x12;\n" + + "\x06rights\x18\x02 \x03(\v2#.com.daml.ledger.api.v2.admin.RightR\x06rights\x120\n" + + "\x14identity_provider_id\x18\x03 \x01(\tR\x12identityProviderId\"p\n" + + "\x17GrantUserRightsResponse\x12U\n" + + "\x14newly_granted_rights\x18\x01 \x03(\v2#.com.daml.ledger.api.v2.admin.RightR\x12newlyGrantedRights\"\xa1\x01\n" + + "\x17RevokeUserRightsRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x12;\n" + + "\x06rights\x18\x02 \x03(\v2#.com.daml.ledger.api.v2.admin.RightR\x06rights\x120\n" + + "\x14identity_provider_id\x18\x03 \x01(\tR\x12identityProviderId\"q\n" + + "\x18RevokeUserRightsResponse\x12U\n" + + "\x14newly_revoked_rights\x18\x01 \x03(\v2#.com.daml.ledger.api.v2.admin.RightR\x12newlyRevokedRights\"b\n" + + "\x15ListUserRightsRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x120\n" + + "\x14identity_provider_id\x18\x02 \x01(\tR\x12identityProviderId\"U\n" + + "\x16ListUserRightsResponse\x12;\n" + + "\x06rights\x18\x01 \x03(\v2#.com.daml.ledger.api.v2.admin.RightR\x06rights\"\xbc\x01\n" + + "#UpdateUserIdentityProviderIdRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x12=\n" + + "\x1bsource_identity_provider_id\x18\x02 \x01(\tR\x18sourceIdentityProviderId\x12=\n" + + "\x1btarget_identity_provider_id\x18\x03 \x01(\tR\x18targetIdentityProviderId\"&\n" + + "$UpdateUserIdentityProviderIdResponse2\xe9\b\n" + + "\x15UserManagementService\x12o\n" + + "\n" + + "CreateUser\x12/.com.daml.ledger.api.v2.admin.CreateUserRequest\x1a0.com.daml.ledger.api.v2.admin.CreateUserResponse\x12f\n" + + "\aGetUser\x12,.com.daml.ledger.api.v2.admin.GetUserRequest\x1a-.com.daml.ledger.api.v2.admin.GetUserResponse\x12o\n" + + "\n" + + "UpdateUser\x12/.com.daml.ledger.api.v2.admin.UpdateUserRequest\x1a0.com.daml.ledger.api.v2.admin.UpdateUserResponse\x12o\n" + + "\n" + + "DeleteUser\x12/.com.daml.ledger.api.v2.admin.DeleteUserRequest\x1a0.com.daml.ledger.api.v2.admin.DeleteUserResponse\x12l\n" + + "\tListUsers\x12..com.daml.ledger.api.v2.admin.ListUsersRequest\x1a/.com.daml.ledger.api.v2.admin.ListUsersResponse\x12~\n" + + "\x0fGrantUserRights\x124.com.daml.ledger.api.v2.admin.GrantUserRightsRequest\x1a5.com.daml.ledger.api.v2.admin.GrantUserRightsResponse\x12\x81\x01\n" + + "\x10RevokeUserRights\x125.com.daml.ledger.api.v2.admin.RevokeUserRightsRequest\x1a6.com.daml.ledger.api.v2.admin.RevokeUserRightsResponse\x12{\n" + + "\x0eListUserRights\x123.com.daml.ledger.api.v2.admin.ListUserRightsRequest\x1a4.com.daml.ledger.api.v2.admin.ListUserRightsResponse\x12\xa5\x01\n" + + "\x1cUpdateUserIdentityProviderId\x12A.com.daml.ledger.api.v2.admin.UpdateUserIdentityProviderIdRequest\x1aB.com.daml.ledger.api.v2.admin.UpdateUserIdentityProviderIdResponseB\xa8\x02\n" + + " com.com.daml.ledger.api.v2.adminB\x1aUserManagementServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin\xa2\x02\x06CDLAVA\xaa\x02\x1cCom.Daml.Ledger.Api.V2.Admin\xca\x02\x1cCom\\Daml\\Ledger\\Api\\V2\\Admin\xe2\x02(Com\\Daml\\Ledger\\Api\\V2\\Admin\\GPBMetadata\xea\x02!Com::Daml::Ledger::Api::V2::Adminb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_com_daml_ledger_api_v2_admin_user_management_service_proto_goTypes = []any{ + (*User)(nil), // 0: com.daml.ledger.api.v2.admin.User + (*Right)(nil), // 1: com.daml.ledger.api.v2.admin.Right + (*CreateUserRequest)(nil), // 2: com.daml.ledger.api.v2.admin.CreateUserRequest + (*CreateUserResponse)(nil), // 3: com.daml.ledger.api.v2.admin.CreateUserResponse + (*GetUserRequest)(nil), // 4: com.daml.ledger.api.v2.admin.GetUserRequest + (*GetUserResponse)(nil), // 5: com.daml.ledger.api.v2.admin.GetUserResponse + (*UpdateUserRequest)(nil), // 6: com.daml.ledger.api.v2.admin.UpdateUserRequest + (*UpdateUserResponse)(nil), // 7: com.daml.ledger.api.v2.admin.UpdateUserResponse + (*DeleteUserRequest)(nil), // 8: com.daml.ledger.api.v2.admin.DeleteUserRequest + (*DeleteUserResponse)(nil), // 9: com.daml.ledger.api.v2.admin.DeleteUserResponse + (*ListUsersRequest)(nil), // 10: com.daml.ledger.api.v2.admin.ListUsersRequest + (*ListUsersResponse)(nil), // 11: com.daml.ledger.api.v2.admin.ListUsersResponse + (*GrantUserRightsRequest)(nil), // 12: com.daml.ledger.api.v2.admin.GrantUserRightsRequest + (*GrantUserRightsResponse)(nil), // 13: com.daml.ledger.api.v2.admin.GrantUserRightsResponse + (*RevokeUserRightsRequest)(nil), // 14: com.daml.ledger.api.v2.admin.RevokeUserRightsRequest + (*RevokeUserRightsResponse)(nil), // 15: com.daml.ledger.api.v2.admin.RevokeUserRightsResponse + (*ListUserRightsRequest)(nil), // 16: com.daml.ledger.api.v2.admin.ListUserRightsRequest + (*ListUserRightsResponse)(nil), // 17: com.daml.ledger.api.v2.admin.ListUserRightsResponse + (*UpdateUserIdentityProviderIdRequest)(nil), // 18: com.daml.ledger.api.v2.admin.UpdateUserIdentityProviderIdRequest + (*UpdateUserIdentityProviderIdResponse)(nil), // 19: com.daml.ledger.api.v2.admin.UpdateUserIdentityProviderIdResponse + (*Right_ParticipantAdmin)(nil), // 20: com.daml.ledger.api.v2.admin.Right.ParticipantAdmin + (*Right_CanActAs)(nil), // 21: com.daml.ledger.api.v2.admin.Right.CanActAs + (*Right_CanReadAs)(nil), // 22: com.daml.ledger.api.v2.admin.Right.CanReadAs + (*Right_CanExecuteAs)(nil), // 23: com.daml.ledger.api.v2.admin.Right.CanExecuteAs + (*Right_IdentityProviderAdmin)(nil), // 24: com.daml.ledger.api.v2.admin.Right.IdentityProviderAdmin + (*Right_CanReadAsAnyParty)(nil), // 25: com.daml.ledger.api.v2.admin.Right.CanReadAsAnyParty + (*Right_CanExecuteAsAnyParty)(nil), // 26: com.daml.ledger.api.v2.admin.Right.CanExecuteAsAnyParty + (*ObjectMeta)(nil), // 27: com.daml.ledger.api.v2.admin.ObjectMeta + (*fieldmaskpb.FieldMask)(nil), // 28: google.protobuf.FieldMask +} +var file_com_daml_ledger_api_v2_admin_user_management_service_proto_depIdxs = []int32{ + 27, // 0: com.daml.ledger.api.v2.admin.User.metadata:type_name -> com.daml.ledger.api.v2.admin.ObjectMeta + 20, // 1: com.daml.ledger.api.v2.admin.Right.participant_admin:type_name -> com.daml.ledger.api.v2.admin.Right.ParticipantAdmin + 21, // 2: com.daml.ledger.api.v2.admin.Right.can_act_as:type_name -> com.daml.ledger.api.v2.admin.Right.CanActAs + 22, // 3: com.daml.ledger.api.v2.admin.Right.can_read_as:type_name -> com.daml.ledger.api.v2.admin.Right.CanReadAs + 24, // 4: com.daml.ledger.api.v2.admin.Right.identity_provider_admin:type_name -> com.daml.ledger.api.v2.admin.Right.IdentityProviderAdmin + 25, // 5: com.daml.ledger.api.v2.admin.Right.can_read_as_any_party:type_name -> com.daml.ledger.api.v2.admin.Right.CanReadAsAnyParty + 23, // 6: com.daml.ledger.api.v2.admin.Right.can_execute_as:type_name -> com.daml.ledger.api.v2.admin.Right.CanExecuteAs + 26, // 7: com.daml.ledger.api.v2.admin.Right.can_execute_as_any_party:type_name -> com.daml.ledger.api.v2.admin.Right.CanExecuteAsAnyParty + 0, // 8: com.daml.ledger.api.v2.admin.CreateUserRequest.user:type_name -> com.daml.ledger.api.v2.admin.User + 1, // 9: com.daml.ledger.api.v2.admin.CreateUserRequest.rights:type_name -> com.daml.ledger.api.v2.admin.Right + 0, // 10: com.daml.ledger.api.v2.admin.CreateUserResponse.user:type_name -> com.daml.ledger.api.v2.admin.User + 0, // 11: com.daml.ledger.api.v2.admin.GetUserResponse.user:type_name -> com.daml.ledger.api.v2.admin.User + 0, // 12: com.daml.ledger.api.v2.admin.UpdateUserRequest.user:type_name -> com.daml.ledger.api.v2.admin.User + 28, // 13: com.daml.ledger.api.v2.admin.UpdateUserRequest.update_mask:type_name -> google.protobuf.FieldMask + 0, // 14: com.daml.ledger.api.v2.admin.UpdateUserResponse.user:type_name -> com.daml.ledger.api.v2.admin.User + 0, // 15: com.daml.ledger.api.v2.admin.ListUsersResponse.users:type_name -> com.daml.ledger.api.v2.admin.User + 1, // 16: com.daml.ledger.api.v2.admin.GrantUserRightsRequest.rights:type_name -> com.daml.ledger.api.v2.admin.Right + 1, // 17: com.daml.ledger.api.v2.admin.GrantUserRightsResponse.newly_granted_rights:type_name -> com.daml.ledger.api.v2.admin.Right + 1, // 18: com.daml.ledger.api.v2.admin.RevokeUserRightsRequest.rights:type_name -> com.daml.ledger.api.v2.admin.Right + 1, // 19: com.daml.ledger.api.v2.admin.RevokeUserRightsResponse.newly_revoked_rights:type_name -> com.daml.ledger.api.v2.admin.Right + 1, // 20: com.daml.ledger.api.v2.admin.ListUserRightsResponse.rights:type_name -> com.daml.ledger.api.v2.admin.Right + 2, // 21: com.daml.ledger.api.v2.admin.UserManagementService.CreateUser:input_type -> com.daml.ledger.api.v2.admin.CreateUserRequest + 4, // 22: com.daml.ledger.api.v2.admin.UserManagementService.GetUser:input_type -> com.daml.ledger.api.v2.admin.GetUserRequest + 6, // 23: com.daml.ledger.api.v2.admin.UserManagementService.UpdateUser:input_type -> com.daml.ledger.api.v2.admin.UpdateUserRequest + 8, // 24: com.daml.ledger.api.v2.admin.UserManagementService.DeleteUser:input_type -> com.daml.ledger.api.v2.admin.DeleteUserRequest + 10, // 25: com.daml.ledger.api.v2.admin.UserManagementService.ListUsers:input_type -> com.daml.ledger.api.v2.admin.ListUsersRequest + 12, // 26: com.daml.ledger.api.v2.admin.UserManagementService.GrantUserRights:input_type -> com.daml.ledger.api.v2.admin.GrantUserRightsRequest + 14, // 27: com.daml.ledger.api.v2.admin.UserManagementService.RevokeUserRights:input_type -> com.daml.ledger.api.v2.admin.RevokeUserRightsRequest + 16, // 28: com.daml.ledger.api.v2.admin.UserManagementService.ListUserRights:input_type -> com.daml.ledger.api.v2.admin.ListUserRightsRequest + 18, // 29: com.daml.ledger.api.v2.admin.UserManagementService.UpdateUserIdentityProviderId:input_type -> com.daml.ledger.api.v2.admin.UpdateUserIdentityProviderIdRequest + 3, // 30: com.daml.ledger.api.v2.admin.UserManagementService.CreateUser:output_type -> com.daml.ledger.api.v2.admin.CreateUserResponse + 5, // 31: com.daml.ledger.api.v2.admin.UserManagementService.GetUser:output_type -> com.daml.ledger.api.v2.admin.GetUserResponse + 7, // 32: com.daml.ledger.api.v2.admin.UserManagementService.UpdateUser:output_type -> com.daml.ledger.api.v2.admin.UpdateUserResponse + 9, // 33: com.daml.ledger.api.v2.admin.UserManagementService.DeleteUser:output_type -> com.daml.ledger.api.v2.admin.DeleteUserResponse + 11, // 34: com.daml.ledger.api.v2.admin.UserManagementService.ListUsers:output_type -> com.daml.ledger.api.v2.admin.ListUsersResponse + 13, // 35: com.daml.ledger.api.v2.admin.UserManagementService.GrantUserRights:output_type -> com.daml.ledger.api.v2.admin.GrantUserRightsResponse + 15, // 36: com.daml.ledger.api.v2.admin.UserManagementService.RevokeUserRights:output_type -> com.daml.ledger.api.v2.admin.RevokeUserRightsResponse + 17, // 37: com.daml.ledger.api.v2.admin.UserManagementService.ListUserRights:output_type -> com.daml.ledger.api.v2.admin.ListUserRightsResponse + 19, // 38: com.daml.ledger.api.v2.admin.UserManagementService.UpdateUserIdentityProviderId:output_type -> com.daml.ledger.api.v2.admin.UpdateUserIdentityProviderIdResponse + 30, // [30:39] is the sub-list for method output_type + 21, // [21:30] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_admin_user_management_service_proto_init() } +func file_com_daml_ledger_api_v2_admin_user_management_service_proto_init() { + if File_com_daml_ledger_api_v2_admin_user_management_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_admin_object_meta_proto_init() + file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes[1].OneofWrappers = []any{ + (*Right_ParticipantAdmin_)(nil), + (*Right_CanActAs_)(nil), + (*Right_CanReadAs_)(nil), + (*Right_IdentityProviderAdmin_)(nil), + (*Right_CanReadAsAnyParty_)(nil), + (*Right_CanExecuteAs_)(nil), + (*Right_CanExecuteAsAnyParty_)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_admin_user_management_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 27, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_admin_user_management_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_admin_user_management_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_admin_user_management_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_admin_user_management_service_proto = out.File + file_com_daml_ledger_api_v2_admin_user_management_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_admin_user_management_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service_grpc.pb.go new file mode 100644 index 00000000..519cafd8 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/admin/user_management_service_grpc.pb.go @@ -0,0 +1,508 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/admin/user_management_service.proto + +package admin + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + UserManagementService_CreateUser_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/CreateUser" + UserManagementService_GetUser_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/GetUser" + UserManagementService_UpdateUser_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/UpdateUser" + UserManagementService_DeleteUser_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/DeleteUser" + UserManagementService_ListUsers_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/ListUsers" + UserManagementService_GrantUserRights_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/GrantUserRights" + UserManagementService_RevokeUserRights_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/RevokeUserRights" + UserManagementService_ListUserRights_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/ListUserRights" + UserManagementService_UpdateUserIdentityProviderId_FullMethodName = "/com.daml.ledger.api.v2.admin.UserManagementService/UpdateUserIdentityProviderId" +) + +// UserManagementServiceClient is the client API for UserManagementService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Service to manage users and their rights for interacting with the Ledger API +// served by a participant node. +// +// The authorization rules for its RPCs are specified on the “Request“ +// messages as boolean expressions over these facts: +// +// 1. “HasRight(r)“ denoting whether the authenticated user has right “r“ and +// 2. “IsAuthenticatedUser(uid)“ denoting whether “uid“ is the empty string or equal to the id of the authenticated user. +// 3. “IsAuthenticatedIdentityProviderAdmin(idp)“ denoting whether “idp“ is equal to the “identity_provider_id“ +// of the authenticated user and the user has an IdentityProviderAdmin right. +// +// If `user_id` is set to the empty string (the default), then the data for the authenticated user will be retrieved. +// If `identity_provider_id` is set to an empty string, then it's effectively set to the value of access token's 'iss' field if that is provided. +// If `identity_provider_id` remains an empty string, the default identity provider will be assumed. +// +// The fields of request messages (and sub-messages) are marked either as “Optional“ or “Required“: +// +// 1. “Optional“ denoting the client may leave the field unset when sending a request. +// 2. “Required“ denoting the client must set the field to a non-default value when sending a request. +// +// A user resource consists of: +// +// 1. a set of properties represented by the “User“ message, +// 2. a set of user rights, where each right is represented by the “Right“ message. +// +// A user resource, once it has been created, can be modified. +// In order to update the properties represented by the “User“ message use the “UpdateUser“ RPC. The only fields that can be modified are those marked as “Modifiable“. +// In order to grant or revoke user rights use “GrantRights' and “RevokeRights“ RPCs. +type UserManagementServiceClient interface { + // Create a new user. + CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) + // Get the user data of a specific user or the authenticated user. + GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) + // Update selected modifiable attribute of a user resource described by the “User“ message. + UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*UpdateUserResponse, error) + // Delete an existing user and all its rights. + DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error) + // List all existing users. + ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) + // Grant rights to a user. + // Granting rights does not affect the resource version of the corresponding user. + GrantUserRights(ctx context.Context, in *GrantUserRightsRequest, opts ...grpc.CallOption) (*GrantUserRightsResponse, error) + // Revoke rights from a user. + // Revoking rights does not affect the resource version of the corresponding user. + RevokeUserRights(ctx context.Context, in *RevokeUserRightsRequest, opts ...grpc.CallOption) (*RevokeUserRightsResponse, error) + // List the set of all rights granted to a user. + ListUserRights(ctx context.Context, in *ListUserRightsRequest, opts ...grpc.CallOption) (*ListUserRightsResponse, error) + // Update the assignment of a user from one IDP to another. + UpdateUserIdentityProviderId(ctx context.Context, in *UpdateUserIdentityProviderIdRequest, opts ...grpc.CallOption) (*UpdateUserIdentityProviderIdResponse, error) +} + +type userManagementServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUserManagementServiceClient(cc grpc.ClientConnInterface) UserManagementServiceClient { + return &userManagementServiceClient{cc} +} + +func (c *userManagementServiceClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CreateUserResponse) + err := c.cc.Invoke(ctx, UserManagementService_CreateUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUserResponse) + err := c.cc.Invoke(ctx, UserManagementService_GetUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*UpdateUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateUserResponse) + err := c.cc.Invoke(ctx, UserManagementService_UpdateUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*DeleteUserResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(DeleteUserResponse) + err := c.cc.Invoke(ctx, UserManagementService_DeleteUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListUsersResponse) + err := c.cc.Invoke(ctx, UserManagementService_ListUsers_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) GrantUserRights(ctx context.Context, in *GrantUserRightsRequest, opts ...grpc.CallOption) (*GrantUserRightsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GrantUserRightsResponse) + err := c.cc.Invoke(ctx, UserManagementService_GrantUserRights_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) RevokeUserRights(ctx context.Context, in *RevokeUserRightsRequest, opts ...grpc.CallOption) (*RevokeUserRightsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RevokeUserRightsResponse) + err := c.cc.Invoke(ctx, UserManagementService_RevokeUserRights_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) ListUserRights(ctx context.Context, in *ListUserRightsRequest, opts ...grpc.CallOption) (*ListUserRightsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListUserRightsResponse) + err := c.cc.Invoke(ctx, UserManagementService_ListUserRights_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userManagementServiceClient) UpdateUserIdentityProviderId(ctx context.Context, in *UpdateUserIdentityProviderIdRequest, opts ...grpc.CallOption) (*UpdateUserIdentityProviderIdResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateUserIdentityProviderIdResponse) + err := c.cc.Invoke(ctx, UserManagementService_UpdateUserIdentityProviderId_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserManagementServiceServer is the server API for UserManagementService service. +// All implementations must embed UnimplementedUserManagementServiceServer +// for forward compatibility. +// +// Service to manage users and their rights for interacting with the Ledger API +// served by a participant node. +// +// The authorization rules for its RPCs are specified on the “Request“ +// messages as boolean expressions over these facts: +// +// 1. “HasRight(r)“ denoting whether the authenticated user has right “r“ and +// 2. “IsAuthenticatedUser(uid)“ denoting whether “uid“ is the empty string or equal to the id of the authenticated user. +// 3. “IsAuthenticatedIdentityProviderAdmin(idp)“ denoting whether “idp“ is equal to the “identity_provider_id“ +// of the authenticated user and the user has an IdentityProviderAdmin right. +// +// If `user_id` is set to the empty string (the default), then the data for the authenticated user will be retrieved. +// If `identity_provider_id` is set to an empty string, then it's effectively set to the value of access token's 'iss' field if that is provided. +// If `identity_provider_id` remains an empty string, the default identity provider will be assumed. +// +// The fields of request messages (and sub-messages) are marked either as “Optional“ or “Required“: +// +// 1. “Optional“ denoting the client may leave the field unset when sending a request. +// 2. “Required“ denoting the client must set the field to a non-default value when sending a request. +// +// A user resource consists of: +// +// 1. a set of properties represented by the “User“ message, +// 2. a set of user rights, where each right is represented by the “Right“ message. +// +// A user resource, once it has been created, can be modified. +// In order to update the properties represented by the “User“ message use the “UpdateUser“ RPC. The only fields that can be modified are those marked as “Modifiable“. +// In order to grant or revoke user rights use “GrantRights' and “RevokeRights“ RPCs. +type UserManagementServiceServer interface { + // Create a new user. + CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) + // Get the user data of a specific user or the authenticated user. + GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) + // Update selected modifiable attribute of a user resource described by the “User“ message. + UpdateUser(context.Context, *UpdateUserRequest) (*UpdateUserResponse, error) + // Delete an existing user and all its rights. + DeleteUser(context.Context, *DeleteUserRequest) (*DeleteUserResponse, error) + // List all existing users. + ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) + // Grant rights to a user. + // Granting rights does not affect the resource version of the corresponding user. + GrantUserRights(context.Context, *GrantUserRightsRequest) (*GrantUserRightsResponse, error) + // Revoke rights from a user. + // Revoking rights does not affect the resource version of the corresponding user. + RevokeUserRights(context.Context, *RevokeUserRightsRequest) (*RevokeUserRightsResponse, error) + // List the set of all rights granted to a user. + ListUserRights(context.Context, *ListUserRightsRequest) (*ListUserRightsResponse, error) + // Update the assignment of a user from one IDP to another. + UpdateUserIdentityProviderId(context.Context, *UpdateUserIdentityProviderIdRequest) (*UpdateUserIdentityProviderIdResponse, error) + mustEmbedUnimplementedUserManagementServiceServer() +} + +// UnimplementedUserManagementServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedUserManagementServiceServer struct{} + +func (UnimplementedUserManagementServiceServer) CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateUser not implemented") +} +func (UnimplementedUserManagementServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") +} +func (UnimplementedUserManagementServiceServer) UpdateUser(context.Context, *UpdateUserRequest) (*UpdateUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUser not implemented") +} +func (UnimplementedUserManagementServiceServer) DeleteUser(context.Context, *DeleteUserRequest) (*DeleteUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteUser not implemented") +} +func (UnimplementedUserManagementServiceServer) ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListUsers not implemented") +} +func (UnimplementedUserManagementServiceServer) GrantUserRights(context.Context, *GrantUserRightsRequest) (*GrantUserRightsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GrantUserRights not implemented") +} +func (UnimplementedUserManagementServiceServer) RevokeUserRights(context.Context, *RevokeUserRightsRequest) (*RevokeUserRightsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RevokeUserRights not implemented") +} +func (UnimplementedUserManagementServiceServer) ListUserRights(context.Context, *ListUserRightsRequest) (*ListUserRightsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListUserRights not implemented") +} +func (UnimplementedUserManagementServiceServer) UpdateUserIdentityProviderId(context.Context, *UpdateUserIdentityProviderIdRequest) (*UpdateUserIdentityProviderIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateUserIdentityProviderId not implemented") +} +func (UnimplementedUserManagementServiceServer) mustEmbedUnimplementedUserManagementServiceServer() {} +func (UnimplementedUserManagementServiceServer) testEmbeddedByValue() {} + +// UnsafeUserManagementServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserManagementServiceServer will +// result in compilation errors. +type UnsafeUserManagementServiceServer interface { + mustEmbedUnimplementedUserManagementServiceServer() +} + +func RegisterUserManagementServiceServer(s grpc.ServiceRegistrar, srv UserManagementServiceServer) { + // If the following call pancis, it indicates UnimplementedUserManagementServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&UserManagementService_ServiceDesc, srv) +} + +func _UserManagementService_CreateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).CreateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_CreateUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).CreateUser(ctx, req.(*CreateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).GetUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_GetUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).GetUser(ctx, req.(*GetUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_UpdateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).UpdateUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_UpdateUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).UpdateUser(ctx, req.(*UpdateUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_DeleteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).DeleteUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_DeleteUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).DeleteUser(ctx, req.(*DeleteUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_ListUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListUsersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).ListUsers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_ListUsers_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).ListUsers(ctx, req.(*ListUsersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_GrantUserRights_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GrantUserRightsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).GrantUserRights(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_GrantUserRights_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).GrantUserRights(ctx, req.(*GrantUserRightsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_RevokeUserRights_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RevokeUserRightsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).RevokeUserRights(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_RevokeUserRights_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).RevokeUserRights(ctx, req.(*RevokeUserRightsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_ListUserRights_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListUserRightsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).ListUserRights(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_ListUserRights_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).ListUserRights(ctx, req.(*ListUserRightsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UserManagementService_UpdateUserIdentityProviderId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateUserIdentityProviderIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserManagementServiceServer).UpdateUserIdentityProviderId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UserManagementService_UpdateUserIdentityProviderId_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserManagementServiceServer).UpdateUserIdentityProviderId(ctx, req.(*UpdateUserIdentityProviderIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// UserManagementService_ServiceDesc is the grpc.ServiceDesc for UserManagementService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var UserManagementService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.admin.UserManagementService", + HandlerType: (*UserManagementServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateUser", + Handler: _UserManagementService_CreateUser_Handler, + }, + { + MethodName: "GetUser", + Handler: _UserManagementService_GetUser_Handler, + }, + { + MethodName: "UpdateUser", + Handler: _UserManagementService_UpdateUser_Handler, + }, + { + MethodName: "DeleteUser", + Handler: _UserManagementService_DeleteUser_Handler, + }, + { + MethodName: "ListUsers", + Handler: _UserManagementService_ListUsers_Handler, + }, + { + MethodName: "GrantUserRights", + Handler: _UserManagementService_GrantUserRights_Handler, + }, + { + MethodName: "RevokeUserRights", + Handler: _UserManagementService_RevokeUserRights_Handler, + }, + { + MethodName: "ListUserRights", + Handler: _UserManagementService_ListUserRights_Handler, + }, + { + MethodName: "UpdateUserIdentityProviderId", + Handler: _UserManagementService_UpdateUserIdentityProviderId_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/admin/user_management_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/command_completion_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/command_completion_service.pb.go new file mode 100644 index 00000000..a244c488 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/command_completion_service.pb.go @@ -0,0 +1,267 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/command_completion_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CompletionStreamRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Only completions of commands submitted with the same user_id will be visible in the stream. + // Must be a valid UserIdString (as described in “value.proto“). + // + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // Non-empty list of parties whose data should be included. + // The stream shows only completions of commands for which at least one of the “act_as“ parties is in the given set of parties. + // Must be a valid PartyIdString (as described in “value.proto“). + // + // Required: must be non-empty + Parties []string `protobuf:"bytes,2,rep,name=parties,proto3" json:"parties,omitempty"` + // This optional field indicates the minimum offset for completions. This can be used to resume an earlier completion stream. + // If not set the ledger uses the ledger begin offset instead. + // If specified, it must be a valid absolute offset (positive integer) or zero (ledger begin offset). + // If the ledger has been pruned, this parameter must be specified and greater than the pruning offset. + // + // Optional + BeginExclusive int64 `protobuf:"varint,3,opt,name=begin_exclusive,json=beginExclusive,proto3" json:"begin_exclusive,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompletionStreamRequest) Reset() { + *x = CompletionStreamRequest{} + mi := &file_com_daml_ledger_api_v2_command_completion_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompletionStreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompletionStreamRequest) ProtoMessage() {} + +func (x *CompletionStreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_completion_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompletionStreamRequest.ProtoReflect.Descriptor instead. +func (*CompletionStreamRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescGZIP(), []int{0} +} + +func (x *CompletionStreamRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *CompletionStreamRequest) GetParties() []string { + if x != nil { + return x.Parties + } + return nil +} + +func (x *CompletionStreamRequest) GetBeginExclusive() int64 { + if x != nil { + return x.BeginExclusive + } + return 0 +} + +type CompletionStreamResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to CompletionResponse: + // + // *CompletionStreamResponse_Completion + // *CompletionStreamResponse_OffsetCheckpoint + CompletionResponse isCompletionStreamResponse_CompletionResponse `protobuf_oneof:"completion_response"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompletionStreamResponse) Reset() { + *x = CompletionStreamResponse{} + mi := &file_com_daml_ledger_api_v2_command_completion_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompletionStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompletionStreamResponse) ProtoMessage() {} + +func (x *CompletionStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_completion_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompletionStreamResponse.ProtoReflect.Descriptor instead. +func (*CompletionStreamResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescGZIP(), []int{1} +} + +func (x *CompletionStreamResponse) GetCompletionResponse() isCompletionStreamResponse_CompletionResponse { + if x != nil { + return x.CompletionResponse + } + return nil +} + +func (x *CompletionStreamResponse) GetCompletion() *Completion { + if x != nil { + if x, ok := x.CompletionResponse.(*CompletionStreamResponse_Completion); ok { + return x.Completion + } + } + return nil +} + +func (x *CompletionStreamResponse) GetOffsetCheckpoint() *OffsetCheckpoint { + if x != nil { + if x, ok := x.CompletionResponse.(*CompletionStreamResponse_OffsetCheckpoint); ok { + return x.OffsetCheckpoint + } + } + return nil +} + +type isCompletionStreamResponse_CompletionResponse interface { + isCompletionStreamResponse_CompletionResponse() +} + +type CompletionStreamResponse_Completion struct { + Completion *Completion `protobuf:"bytes,1,opt,name=completion,proto3,oneof"` +} + +type CompletionStreamResponse_OffsetCheckpoint struct { + OffsetCheckpoint *OffsetCheckpoint `protobuf:"bytes,2,opt,name=offset_checkpoint,json=offsetCheckpoint,proto3,oneof"` +} + +func (*CompletionStreamResponse_Completion) isCompletionStreamResponse_CompletionResponse() {} + +func (*CompletionStreamResponse_OffsetCheckpoint) isCompletionStreamResponse_CompletionResponse() {} + +var File_com_daml_ledger_api_v2_command_completion_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_command_completion_service_proto_rawDesc = "" + + "\n" + + "7com/daml/ledger/api/v2/command_completion_service.proto\x12\x16com.daml.ledger.api.v2\x1a'com/daml/ledger/api/v2/completion.proto\x1a.com/daml/ledger/api/v2/offset_checkpoint.proto\"u\n" + + "\x17CompletionStreamRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x12\x18\n" + + "\aparties\x18\x02 \x03(\tR\aparties\x12'\n" + + "\x0fbegin_exclusive\x18\x03 \x01(\x03R\x0ebeginExclusive\"\xd0\x01\n" + + "\x18CompletionStreamResponse\x12D\n" + + "\n" + + "completion\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.CompletionH\x00R\n" + + "completion\x12W\n" + + "\x11offset_checkpoint\x18\x02 \x01(\v2(.com.daml.ledger.api.v2.OffsetCheckpointH\x00R\x10offsetCheckpointB\x15\n" + + "\x13completion_response2\x93\x01\n" + + "\x18CommandCompletionService\x12w\n" + + "\x10CompletionStream\x12/.com.daml.ledger.api.v2.CompletionStreamRequest\x1a0.com.daml.ledger.api.v2.CompletionStreamResponse0\x01B\x8a\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x1dCommandCompletionServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_command_completion_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_command_completion_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_command_completion_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_command_completion_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_com_daml_ledger_api_v2_command_completion_service_proto_goTypes = []any{ + (*CompletionStreamRequest)(nil), // 0: com.daml.ledger.api.v2.CompletionStreamRequest + (*CompletionStreamResponse)(nil), // 1: com.daml.ledger.api.v2.CompletionStreamResponse + (*Completion)(nil), // 2: com.daml.ledger.api.v2.Completion + (*OffsetCheckpoint)(nil), // 3: com.daml.ledger.api.v2.OffsetCheckpoint +} +var file_com_daml_ledger_api_v2_command_completion_service_proto_depIdxs = []int32{ + 2, // 0: com.daml.ledger.api.v2.CompletionStreamResponse.completion:type_name -> com.daml.ledger.api.v2.Completion + 3, // 1: com.daml.ledger.api.v2.CompletionStreamResponse.offset_checkpoint:type_name -> com.daml.ledger.api.v2.OffsetCheckpoint + 0, // 2: com.daml.ledger.api.v2.CommandCompletionService.CompletionStream:input_type -> com.daml.ledger.api.v2.CompletionStreamRequest + 1, // 3: com.daml.ledger.api.v2.CommandCompletionService.CompletionStream:output_type -> com.daml.ledger.api.v2.CompletionStreamResponse + 3, // [3:4] is the sub-list for method output_type + 2, // [2:3] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_command_completion_service_proto_init() } +func file_com_daml_ledger_api_v2_command_completion_service_proto_init() { + if File_com_daml_ledger_api_v2_command_completion_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_completion_proto_init() + file_com_daml_ledger_api_v2_offset_checkpoint_proto_init() + file_com_daml_ledger_api_v2_command_completion_service_proto_msgTypes[1].OneofWrappers = []any{ + (*CompletionStreamResponse_Completion)(nil), + (*CompletionStreamResponse_OffsetCheckpoint)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_command_completion_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_command_completion_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_command_completion_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_command_completion_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_command_completion_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_command_completion_service_proto = out.File + file_com_daml_ledger_api_v2_command_completion_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_command_completion_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/command_completion_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/command_completion_service_grpc.pb.go new file mode 100644 index 00000000..e111e973 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/command_completion_service_grpc.pb.go @@ -0,0 +1,160 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/command_completion_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + CommandCompletionService_CompletionStream_FullMethodName = "/com.daml.ledger.api.v2.CommandCompletionService/CompletionStream" +) + +// CommandCompletionServiceClient is the client API for CommandCompletionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Allows clients to observe the status of their submissions. +// Commands may be submitted via the Command Submission Service. +// The on-ledger effects of their submissions are disclosed by the Update Service. +// +// Commands may fail in 2 distinct manners: +// +// 1. Failure communicated synchronously in the gRPC error of the submission. +// 2. Failure communicated asynchronously in a Completion, see “completion.proto“. +// +// Note that not only successfully submitted commands MAY produce a completion event. For example, the participant MAY +// choose to produce a completion event for a rejection of a duplicate command. +// +// Clients that do not receive a successful completion about their submission MUST NOT assume that it was successful. +// Clients SHOULD subscribe to the CompletionStream before starting to submit commands to prevent race conditions. +type CommandCompletionServiceClient interface { + // Subscribe to command completion events. + CompletionStream(ctx context.Context, in *CompletionStreamRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[CompletionStreamResponse], error) +} + +type commandCompletionServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewCommandCompletionServiceClient(cc grpc.ClientConnInterface) CommandCompletionServiceClient { + return &commandCompletionServiceClient{cc} +} + +func (c *commandCompletionServiceClient) CompletionStream(ctx context.Context, in *CompletionStreamRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[CompletionStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &CommandCompletionService_ServiceDesc.Streams[0], CommandCompletionService_CompletionStream_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[CompletionStreamRequest, CompletionStreamResponse]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type CommandCompletionService_CompletionStreamClient = grpc.ServerStreamingClient[CompletionStreamResponse] + +// CommandCompletionServiceServer is the server API for CommandCompletionService service. +// All implementations must embed UnimplementedCommandCompletionServiceServer +// for forward compatibility. +// +// Allows clients to observe the status of their submissions. +// Commands may be submitted via the Command Submission Service. +// The on-ledger effects of their submissions are disclosed by the Update Service. +// +// Commands may fail in 2 distinct manners: +// +// 1. Failure communicated synchronously in the gRPC error of the submission. +// 2. Failure communicated asynchronously in a Completion, see “completion.proto“. +// +// Note that not only successfully submitted commands MAY produce a completion event. For example, the participant MAY +// choose to produce a completion event for a rejection of a duplicate command. +// +// Clients that do not receive a successful completion about their submission MUST NOT assume that it was successful. +// Clients SHOULD subscribe to the CompletionStream before starting to submit commands to prevent race conditions. +type CommandCompletionServiceServer interface { + // Subscribe to command completion events. + CompletionStream(*CompletionStreamRequest, grpc.ServerStreamingServer[CompletionStreamResponse]) error + mustEmbedUnimplementedCommandCompletionServiceServer() +} + +// UnimplementedCommandCompletionServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCommandCompletionServiceServer struct{} + +func (UnimplementedCommandCompletionServiceServer) CompletionStream(*CompletionStreamRequest, grpc.ServerStreamingServer[CompletionStreamResponse]) error { + return status.Errorf(codes.Unimplemented, "method CompletionStream not implemented") +} +func (UnimplementedCommandCompletionServiceServer) mustEmbedUnimplementedCommandCompletionServiceServer() { +} +func (UnimplementedCommandCompletionServiceServer) testEmbeddedByValue() {} + +// UnsafeCommandCompletionServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CommandCompletionServiceServer will +// result in compilation errors. +type UnsafeCommandCompletionServiceServer interface { + mustEmbedUnimplementedCommandCompletionServiceServer() +} + +func RegisterCommandCompletionServiceServer(s grpc.ServiceRegistrar, srv CommandCompletionServiceServer) { + // If the following call pancis, it indicates UnimplementedCommandCompletionServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&CommandCompletionService_ServiceDesc, srv) +} + +func _CommandCompletionService_CompletionStream_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(CompletionStreamRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(CommandCompletionServiceServer).CompletionStream(m, &grpc.GenericServerStream[CompletionStreamRequest, CompletionStreamResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type CommandCompletionService_CompletionStreamServer = grpc.ServerStreamingServer[CompletionStreamResponse] + +// CommandCompletionService_ServiceDesc is the grpc.ServiceDesc for CommandCompletionService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var CommandCompletionService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.CommandCompletionService", + HandlerType: (*CommandCompletionServiceServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "CompletionStream", + Handler: _CommandCompletionService_CompletionStream_Handler, + ServerStreams: true, + }, + }, + Metadata: "com/daml/ledger/api/v2/command_completion_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/command_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/command_service.pb.go new file mode 100644 index 00000000..9d804175 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/command_service.pb.go @@ -0,0 +1,452 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/command_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// These commands are executed as a single atomic transaction. +type SubmitAndWaitRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The commands to be submitted. + // + // Required + Commands *Commands `protobuf:"bytes,1,opt,name=commands,proto3" json:"commands,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitAndWaitRequest) Reset() { + *x = SubmitAndWaitRequest{} + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitAndWaitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitAndWaitRequest) ProtoMessage() {} + +func (x *SubmitAndWaitRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitAndWaitRequest.ProtoReflect.Descriptor instead. +func (*SubmitAndWaitRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_service_proto_rawDescGZIP(), []int{0} +} + +func (x *SubmitAndWaitRequest) GetCommands() *Commands { + if x != nil { + return x.Commands + } + return nil +} + +// These commands are executed as a single atomic transaction. +type SubmitAndWaitForTransactionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The commands to be submitted. + // + // Required + Commands *Commands `protobuf:"bytes,1,opt,name=commands,proto3" json:"commands,omitempty"` + // If no “transaction_format“ is provided, a default will be used where “transaction_shape“ is set to + // TRANSACTION_SHAPE_ACS_DELTA, “event_format“ is defined with “filters_by_party“ containing wildcard-template + // filter for all original “act_as“ and “read_as“ parties and the “verbose“ flag is set. + // + // Optional + TransactionFormat *TransactionFormat `protobuf:"bytes,2,opt,name=transaction_format,json=transactionFormat,proto3" json:"transaction_format,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitAndWaitForTransactionRequest) Reset() { + *x = SubmitAndWaitForTransactionRequest{} + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitAndWaitForTransactionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitAndWaitForTransactionRequest) ProtoMessage() {} + +func (x *SubmitAndWaitForTransactionRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitAndWaitForTransactionRequest.ProtoReflect.Descriptor instead. +func (*SubmitAndWaitForTransactionRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_service_proto_rawDescGZIP(), []int{1} +} + +func (x *SubmitAndWaitForTransactionRequest) GetCommands() *Commands { + if x != nil { + return x.Commands + } + return nil +} + +func (x *SubmitAndWaitForTransactionRequest) GetTransactionFormat() *TransactionFormat { + if x != nil { + return x.TransactionFormat + } + return nil +} + +type SubmitAndWaitResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The id of the transaction that resulted from the submitted command. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // The details of the offset field are described in “community/ledger-api/README.md“. + // + // Required + CompletionOffset int64 `protobuf:"varint,2,opt,name=completion_offset,json=completionOffset,proto3" json:"completion_offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitAndWaitResponse) Reset() { + *x = SubmitAndWaitResponse{} + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitAndWaitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitAndWaitResponse) ProtoMessage() {} + +func (x *SubmitAndWaitResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitAndWaitResponse.ProtoReflect.Descriptor instead. +func (*SubmitAndWaitResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_service_proto_rawDescGZIP(), []int{2} +} + +func (x *SubmitAndWaitResponse) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *SubmitAndWaitResponse) GetCompletionOffset() int64 { + if x != nil { + return x.CompletionOffset + } + return 0 +} + +type SubmitAndWaitForTransactionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The transaction that resulted from the submitted command. + // The transaction might contain no events (request conditions result in filtering out all of them). + // + // Required + Transaction *Transaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitAndWaitForTransactionResponse) Reset() { + *x = SubmitAndWaitForTransactionResponse{} + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitAndWaitForTransactionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitAndWaitForTransactionResponse) ProtoMessage() {} + +func (x *SubmitAndWaitForTransactionResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitAndWaitForTransactionResponse.ProtoReflect.Descriptor instead. +func (*SubmitAndWaitForTransactionResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_service_proto_rawDescGZIP(), []int{3} +} + +func (x *SubmitAndWaitForTransactionResponse) GetTransaction() *Transaction { + if x != nil { + return x.Transaction + } + return nil +} + +// This reassignment is executed as a single atomic update. +type SubmitAndWaitForReassignmentRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The reassignment commands to be submitted. + // + // Required + ReassignmentCommands *ReassignmentCommands `protobuf:"bytes,1,opt,name=reassignment_commands,json=reassignmentCommands,proto3" json:"reassignment_commands,omitempty"` + // If no event_format provided, the result will contain no events. + // The events in the result, will take shape TRANSACTION_SHAPE_ACS_DELTA. + // + // Optional + EventFormat *EventFormat `protobuf:"bytes,2,opt,name=event_format,json=eventFormat,proto3" json:"event_format,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitAndWaitForReassignmentRequest) Reset() { + *x = SubmitAndWaitForReassignmentRequest{} + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitAndWaitForReassignmentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitAndWaitForReassignmentRequest) ProtoMessage() {} + +func (x *SubmitAndWaitForReassignmentRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitAndWaitForReassignmentRequest.ProtoReflect.Descriptor instead. +func (*SubmitAndWaitForReassignmentRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_service_proto_rawDescGZIP(), []int{4} +} + +func (x *SubmitAndWaitForReassignmentRequest) GetReassignmentCommands() *ReassignmentCommands { + if x != nil { + return x.ReassignmentCommands + } + return nil +} + +func (x *SubmitAndWaitForReassignmentRequest) GetEventFormat() *EventFormat { + if x != nil { + return x.EventFormat + } + return nil +} + +type SubmitAndWaitForReassignmentResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The reassignment that resulted from the submitted reassignment command. + // The reassignment might contain no events (request conditions result in filtering out all of them). + // + // Required + Reassignment *Reassignment `protobuf:"bytes,1,opt,name=reassignment,proto3" json:"reassignment,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitAndWaitForReassignmentResponse) Reset() { + *x = SubmitAndWaitForReassignmentResponse{} + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitAndWaitForReassignmentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitAndWaitForReassignmentResponse) ProtoMessage() {} + +func (x *SubmitAndWaitForReassignmentResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitAndWaitForReassignmentResponse.ProtoReflect.Descriptor instead. +func (*SubmitAndWaitForReassignmentResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_service_proto_rawDescGZIP(), []int{5} +} + +func (x *SubmitAndWaitForReassignmentResponse) GetReassignment() *Reassignment { + if x != nil { + return x.Reassignment + } + return nil +} + +var File_com_daml_ledger_api_v2_command_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_command_service_proto_rawDesc = "" + + "\n" + + ",com/daml/ledger/api/v2/command_service.proto\x12\x16com.daml.ledger.api.v2\x1a%com/daml/ledger/api/v2/commands.proto\x1a)com/daml/ledger/api/v2/reassignment.proto\x1a2com/daml/ledger/api/v2/reassignment_commands.proto\x1a(com/daml/ledger/api/v2/transaction.proto\x1a/com/daml/ledger/api/v2/transaction_filter.proto\"T\n" + + "\x14SubmitAndWaitRequest\x12<\n" + + "\bcommands\x18\x01 \x01(\v2 .com.daml.ledger.api.v2.CommandsR\bcommands\"\xbc\x01\n" + + "\"SubmitAndWaitForTransactionRequest\x12<\n" + + "\bcommands\x18\x01 \x01(\v2 .com.daml.ledger.api.v2.CommandsR\bcommands\x12X\n" + + "\x12transaction_format\x18\x02 \x01(\v2).com.daml.ledger.api.v2.TransactionFormatR\x11transactionFormat\"a\n" + + "\x15SubmitAndWaitResponse\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12+\n" + + "\x11completion_offset\x18\x02 \x01(\x03R\x10completionOffset\"l\n" + + "#SubmitAndWaitForTransactionResponse\x12E\n" + + "\vtransaction\x18\x01 \x01(\v2#.com.daml.ledger.api.v2.TransactionR\vtransaction\"\xd0\x01\n" + + "#SubmitAndWaitForReassignmentRequest\x12a\n" + + "\x15reassignment_commands\x18\x01 \x01(\v2,.com.daml.ledger.api.v2.ReassignmentCommandsR\x14reassignmentCommands\x12F\n" + + "\fevent_format\x18\x02 \x01(\v2#.com.daml.ledger.api.v2.EventFormatR\veventFormat\"p\n" + + "$SubmitAndWaitForReassignmentResponse\x12H\n" + + "\freassignment\x18\x01 \x01(\v2$.com.daml.ledger.api.v2.ReassignmentR\freassignment2\xb3\x03\n" + + "\x0eCommandService\x12l\n" + + "\rSubmitAndWait\x12,.com.daml.ledger.api.v2.SubmitAndWaitRequest\x1a-.com.daml.ledger.api.v2.SubmitAndWaitResponse\x12\x96\x01\n" + + "\x1bSubmitAndWaitForTransaction\x12:.com.daml.ledger.api.v2.SubmitAndWaitForTransactionRequest\x1a;.com.daml.ledger.api.v2.SubmitAndWaitForTransactionResponse\x12\x99\x01\n" + + "\x1cSubmitAndWaitForReassignment\x12;.com.daml.ledger.api.v2.SubmitAndWaitForReassignmentRequest\x1a<.com.daml.ledger.api.v2.SubmitAndWaitForReassignmentResponseB\x80\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x13CommandServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_command_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_command_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_command_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_command_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_command_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_command_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_command_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_command_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_command_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_com_daml_ledger_api_v2_command_service_proto_goTypes = []any{ + (*SubmitAndWaitRequest)(nil), // 0: com.daml.ledger.api.v2.SubmitAndWaitRequest + (*SubmitAndWaitForTransactionRequest)(nil), // 1: com.daml.ledger.api.v2.SubmitAndWaitForTransactionRequest + (*SubmitAndWaitResponse)(nil), // 2: com.daml.ledger.api.v2.SubmitAndWaitResponse + (*SubmitAndWaitForTransactionResponse)(nil), // 3: com.daml.ledger.api.v2.SubmitAndWaitForTransactionResponse + (*SubmitAndWaitForReassignmentRequest)(nil), // 4: com.daml.ledger.api.v2.SubmitAndWaitForReassignmentRequest + (*SubmitAndWaitForReassignmentResponse)(nil), // 5: com.daml.ledger.api.v2.SubmitAndWaitForReassignmentResponse + (*Commands)(nil), // 6: com.daml.ledger.api.v2.Commands + (*TransactionFormat)(nil), // 7: com.daml.ledger.api.v2.TransactionFormat + (*Transaction)(nil), // 8: com.daml.ledger.api.v2.Transaction + (*ReassignmentCommands)(nil), // 9: com.daml.ledger.api.v2.ReassignmentCommands + (*EventFormat)(nil), // 10: com.daml.ledger.api.v2.EventFormat + (*Reassignment)(nil), // 11: com.daml.ledger.api.v2.Reassignment +} +var file_com_daml_ledger_api_v2_command_service_proto_depIdxs = []int32{ + 6, // 0: com.daml.ledger.api.v2.SubmitAndWaitRequest.commands:type_name -> com.daml.ledger.api.v2.Commands + 6, // 1: com.daml.ledger.api.v2.SubmitAndWaitForTransactionRequest.commands:type_name -> com.daml.ledger.api.v2.Commands + 7, // 2: com.daml.ledger.api.v2.SubmitAndWaitForTransactionRequest.transaction_format:type_name -> com.daml.ledger.api.v2.TransactionFormat + 8, // 3: com.daml.ledger.api.v2.SubmitAndWaitForTransactionResponse.transaction:type_name -> com.daml.ledger.api.v2.Transaction + 9, // 4: com.daml.ledger.api.v2.SubmitAndWaitForReassignmentRequest.reassignment_commands:type_name -> com.daml.ledger.api.v2.ReassignmentCommands + 10, // 5: com.daml.ledger.api.v2.SubmitAndWaitForReassignmentRequest.event_format:type_name -> com.daml.ledger.api.v2.EventFormat + 11, // 6: com.daml.ledger.api.v2.SubmitAndWaitForReassignmentResponse.reassignment:type_name -> com.daml.ledger.api.v2.Reassignment + 0, // 7: com.daml.ledger.api.v2.CommandService.SubmitAndWait:input_type -> com.daml.ledger.api.v2.SubmitAndWaitRequest + 1, // 8: com.daml.ledger.api.v2.CommandService.SubmitAndWaitForTransaction:input_type -> com.daml.ledger.api.v2.SubmitAndWaitForTransactionRequest + 4, // 9: com.daml.ledger.api.v2.CommandService.SubmitAndWaitForReassignment:input_type -> com.daml.ledger.api.v2.SubmitAndWaitForReassignmentRequest + 2, // 10: com.daml.ledger.api.v2.CommandService.SubmitAndWait:output_type -> com.daml.ledger.api.v2.SubmitAndWaitResponse + 3, // 11: com.daml.ledger.api.v2.CommandService.SubmitAndWaitForTransaction:output_type -> com.daml.ledger.api.v2.SubmitAndWaitForTransactionResponse + 5, // 12: com.daml.ledger.api.v2.CommandService.SubmitAndWaitForReassignment:output_type -> com.daml.ledger.api.v2.SubmitAndWaitForReassignmentResponse + 10, // [10:13] is the sub-list for method output_type + 7, // [7:10] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_command_service_proto_init() } +func file_com_daml_ledger_api_v2_command_service_proto_init() { + if File_com_daml_ledger_api_v2_command_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_commands_proto_init() + file_com_daml_ledger_api_v2_reassignment_proto_init() + file_com_daml_ledger_api_v2_reassignment_commands_proto_init() + file_com_daml_ledger_api_v2_transaction_proto_init() + file_com_daml_ledger_api_v2_transaction_filter_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_command_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_command_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_command_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_command_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_command_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_command_service_proto = out.File + file_com_daml_ledger_api_v2_command_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_command_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/command_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/command_service_grpc.pb.go new file mode 100644 index 00000000..53858226 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/command_service_grpc.pb.go @@ -0,0 +1,224 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/command_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + CommandService_SubmitAndWait_FullMethodName = "/com.daml.ledger.api.v2.CommandService/SubmitAndWait" + CommandService_SubmitAndWaitForTransaction_FullMethodName = "/com.daml.ledger.api.v2.CommandService/SubmitAndWaitForTransaction" + CommandService_SubmitAndWaitForReassignment_FullMethodName = "/com.daml.ledger.api.v2.CommandService/SubmitAndWaitForReassignment" +) + +// CommandServiceClient is the client API for CommandService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Command Service is able to correlate submitted commands with completion data, identify timeouts, and return contextual +// information with each tracking result. This supports the implementation of stateless clients. +// +// Note that submitted commands generally produce completion events as well, even in case a command gets rejected. +// For example, the participant SHOULD produce a completion event for a rejection of a duplicate command. +type CommandServiceClient interface { + // Submits a single composite command and waits for its result. + // Propagates the gRPC error of failed submissions including Daml interpretation errors. + SubmitAndWait(ctx context.Context, in *SubmitAndWaitRequest, opts ...grpc.CallOption) (*SubmitAndWaitResponse, error) + // Submits a single composite command, waits for its result, and returns the transaction. + // Propagates the gRPC error of failed submissions including Daml interpretation errors. + SubmitAndWaitForTransaction(ctx context.Context, in *SubmitAndWaitForTransactionRequest, opts ...grpc.CallOption) (*SubmitAndWaitForTransactionResponse, error) + // Submits a single composite reassignment command, waits for its result, and returns the reassignment. + // Propagates the gRPC error of failed submission. + SubmitAndWaitForReassignment(ctx context.Context, in *SubmitAndWaitForReassignmentRequest, opts ...grpc.CallOption) (*SubmitAndWaitForReassignmentResponse, error) +} + +type commandServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewCommandServiceClient(cc grpc.ClientConnInterface) CommandServiceClient { + return &commandServiceClient{cc} +} + +func (c *commandServiceClient) SubmitAndWait(ctx context.Context, in *SubmitAndWaitRequest, opts ...grpc.CallOption) (*SubmitAndWaitResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SubmitAndWaitResponse) + err := c.cc.Invoke(ctx, CommandService_SubmitAndWait_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *commandServiceClient) SubmitAndWaitForTransaction(ctx context.Context, in *SubmitAndWaitForTransactionRequest, opts ...grpc.CallOption) (*SubmitAndWaitForTransactionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SubmitAndWaitForTransactionResponse) + err := c.cc.Invoke(ctx, CommandService_SubmitAndWaitForTransaction_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *commandServiceClient) SubmitAndWaitForReassignment(ctx context.Context, in *SubmitAndWaitForReassignmentRequest, opts ...grpc.CallOption) (*SubmitAndWaitForReassignmentResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SubmitAndWaitForReassignmentResponse) + err := c.cc.Invoke(ctx, CommandService_SubmitAndWaitForReassignment_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CommandServiceServer is the server API for CommandService service. +// All implementations must embed UnimplementedCommandServiceServer +// for forward compatibility. +// +// Command Service is able to correlate submitted commands with completion data, identify timeouts, and return contextual +// information with each tracking result. This supports the implementation of stateless clients. +// +// Note that submitted commands generally produce completion events as well, even in case a command gets rejected. +// For example, the participant SHOULD produce a completion event for a rejection of a duplicate command. +type CommandServiceServer interface { + // Submits a single composite command and waits for its result. + // Propagates the gRPC error of failed submissions including Daml interpretation errors. + SubmitAndWait(context.Context, *SubmitAndWaitRequest) (*SubmitAndWaitResponse, error) + // Submits a single composite command, waits for its result, and returns the transaction. + // Propagates the gRPC error of failed submissions including Daml interpretation errors. + SubmitAndWaitForTransaction(context.Context, *SubmitAndWaitForTransactionRequest) (*SubmitAndWaitForTransactionResponse, error) + // Submits a single composite reassignment command, waits for its result, and returns the reassignment. + // Propagates the gRPC error of failed submission. + SubmitAndWaitForReassignment(context.Context, *SubmitAndWaitForReassignmentRequest) (*SubmitAndWaitForReassignmentResponse, error) + mustEmbedUnimplementedCommandServiceServer() +} + +// UnimplementedCommandServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCommandServiceServer struct{} + +func (UnimplementedCommandServiceServer) SubmitAndWait(context.Context, *SubmitAndWaitRequest) (*SubmitAndWaitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitAndWait not implemented") +} +func (UnimplementedCommandServiceServer) SubmitAndWaitForTransaction(context.Context, *SubmitAndWaitForTransactionRequest) (*SubmitAndWaitForTransactionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitAndWaitForTransaction not implemented") +} +func (UnimplementedCommandServiceServer) SubmitAndWaitForReassignment(context.Context, *SubmitAndWaitForReassignmentRequest) (*SubmitAndWaitForReassignmentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitAndWaitForReassignment not implemented") +} +func (UnimplementedCommandServiceServer) mustEmbedUnimplementedCommandServiceServer() {} +func (UnimplementedCommandServiceServer) testEmbeddedByValue() {} + +// UnsafeCommandServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CommandServiceServer will +// result in compilation errors. +type UnsafeCommandServiceServer interface { + mustEmbedUnimplementedCommandServiceServer() +} + +func RegisterCommandServiceServer(s grpc.ServiceRegistrar, srv CommandServiceServer) { + // If the following call pancis, it indicates UnimplementedCommandServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&CommandService_ServiceDesc, srv) +} + +func _CommandService_SubmitAndWait_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitAndWaitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandServiceServer).SubmitAndWait(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandService_SubmitAndWait_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandServiceServer).SubmitAndWait(ctx, req.(*SubmitAndWaitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _CommandService_SubmitAndWaitForTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitAndWaitForTransactionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandServiceServer).SubmitAndWaitForTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandService_SubmitAndWaitForTransaction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandServiceServer).SubmitAndWaitForTransaction(ctx, req.(*SubmitAndWaitForTransactionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _CommandService_SubmitAndWaitForReassignment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitAndWaitForReassignmentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandServiceServer).SubmitAndWaitForReassignment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandService_SubmitAndWaitForReassignment_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandServiceServer).SubmitAndWaitForReassignment(ctx, req.(*SubmitAndWaitForReassignmentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// CommandService_ServiceDesc is the grpc.ServiceDesc for CommandService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var CommandService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.CommandService", + HandlerType: (*CommandServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SubmitAndWait", + Handler: _CommandService_SubmitAndWait_Handler, + }, + { + MethodName: "SubmitAndWaitForTransaction", + Handler: _CommandService_SubmitAndWaitForTransaction_Handler, + }, + { + MethodName: "SubmitAndWaitForReassignment", + Handler: _CommandService_SubmitAndWaitForReassignment_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/command_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/command_submission_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/command_submission_service.pb.go new file mode 100644 index 00000000..83df2005 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/command_submission_service.pb.go @@ -0,0 +1,269 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/command_submission_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// The submitted commands will be processed atomically in a single transaction. Moreover, each “Command“ in “commands“ will be executed in the order specified by the request. +type SubmitRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The commands to be submitted in a single transaction. + // + // Required + Commands *Commands `protobuf:"bytes,1,opt,name=commands,proto3" json:"commands,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitRequest) Reset() { + *x = SubmitRequest{} + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitRequest) ProtoMessage() {} + +func (x *SubmitRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitRequest.ProtoReflect.Descriptor instead. +func (*SubmitRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescGZIP(), []int{0} +} + +func (x *SubmitRequest) GetCommands() *Commands { + if x != nil { + return x.Commands + } + return nil +} + +type SubmitResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitResponse) Reset() { + *x = SubmitResponse{} + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitResponse) ProtoMessage() {} + +func (x *SubmitResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitResponse.ProtoReflect.Descriptor instead. +func (*SubmitResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescGZIP(), []int{1} +} + +type SubmitReassignmentRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The reassignment command to be submitted. + // + // Required + ReassignmentCommands *ReassignmentCommands `protobuf:"bytes,1,opt,name=reassignment_commands,json=reassignmentCommands,proto3" json:"reassignment_commands,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitReassignmentRequest) Reset() { + *x = SubmitReassignmentRequest{} + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitReassignmentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitReassignmentRequest) ProtoMessage() {} + +func (x *SubmitReassignmentRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitReassignmentRequest.ProtoReflect.Descriptor instead. +func (*SubmitReassignmentRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescGZIP(), []int{2} +} + +func (x *SubmitReassignmentRequest) GetReassignmentCommands() *ReassignmentCommands { + if x != nil { + return x.ReassignmentCommands + } + return nil +} + +type SubmitReassignmentResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SubmitReassignmentResponse) Reset() { + *x = SubmitReassignmentResponse{} + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SubmitReassignmentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitReassignmentResponse) ProtoMessage() {} + +func (x *SubmitReassignmentResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitReassignmentResponse.ProtoReflect.Descriptor instead. +func (*SubmitReassignmentResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescGZIP(), []int{3} +} + +var File_com_daml_ledger_api_v2_command_submission_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_command_submission_service_proto_rawDesc = "" + + "\n" + + "7com/daml/ledger/api/v2/command_submission_service.proto\x12\x16com.daml.ledger.api.v2\x1a%com/daml/ledger/api/v2/commands.proto\x1a2com/daml/ledger/api/v2/reassignment_commands.proto\"M\n" + + "\rSubmitRequest\x12<\n" + + "\bcommands\x18\x01 \x01(\v2 .com.daml.ledger.api.v2.CommandsR\bcommands\"\x10\n" + + "\x0eSubmitResponse\"~\n" + + "\x19SubmitReassignmentRequest\x12a\n" + + "\x15reassignment_commands\x18\x01 \x01(\v2,.com.daml.ledger.api.v2.ReassignmentCommandsR\x14reassignmentCommands\"\x1c\n" + + "\x1aSubmitReassignmentResponse2\xf0\x01\n" + + "\x18CommandSubmissionService\x12W\n" + + "\x06Submit\x12%.com.daml.ledger.api.v2.SubmitRequest\x1a&.com.daml.ledger.api.v2.SubmitResponse\x12{\n" + + "\x12SubmitReassignment\x121.com.daml.ledger.api.v2.SubmitReassignmentRequest\x1a2.com.daml.ledger.api.v2.SubmitReassignmentResponseB\x8a\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x1dCommandSubmissionServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_command_submission_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_command_submission_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_command_submission_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_com_daml_ledger_api_v2_command_submission_service_proto_goTypes = []any{ + (*SubmitRequest)(nil), // 0: com.daml.ledger.api.v2.SubmitRequest + (*SubmitResponse)(nil), // 1: com.daml.ledger.api.v2.SubmitResponse + (*SubmitReassignmentRequest)(nil), // 2: com.daml.ledger.api.v2.SubmitReassignmentRequest + (*SubmitReassignmentResponse)(nil), // 3: com.daml.ledger.api.v2.SubmitReassignmentResponse + (*Commands)(nil), // 4: com.daml.ledger.api.v2.Commands + (*ReassignmentCommands)(nil), // 5: com.daml.ledger.api.v2.ReassignmentCommands +} +var file_com_daml_ledger_api_v2_command_submission_service_proto_depIdxs = []int32{ + 4, // 0: com.daml.ledger.api.v2.SubmitRequest.commands:type_name -> com.daml.ledger.api.v2.Commands + 5, // 1: com.daml.ledger.api.v2.SubmitReassignmentRequest.reassignment_commands:type_name -> com.daml.ledger.api.v2.ReassignmentCommands + 0, // 2: com.daml.ledger.api.v2.CommandSubmissionService.Submit:input_type -> com.daml.ledger.api.v2.SubmitRequest + 2, // 3: com.daml.ledger.api.v2.CommandSubmissionService.SubmitReassignment:input_type -> com.daml.ledger.api.v2.SubmitReassignmentRequest + 1, // 4: com.daml.ledger.api.v2.CommandSubmissionService.Submit:output_type -> com.daml.ledger.api.v2.SubmitResponse + 3, // 5: com.daml.ledger.api.v2.CommandSubmissionService.SubmitReassignment:output_type -> com.daml.ledger.api.v2.SubmitReassignmentResponse + 4, // [4:6] is the sub-list for method output_type + 2, // [2:4] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_command_submission_service_proto_init() } +func file_com_daml_ledger_api_v2_command_submission_service_proto_init() { + if File_com_daml_ledger_api_v2_command_submission_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_commands_proto_init() + file_com_daml_ledger_api_v2_reassignment_commands_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_command_submission_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_command_submission_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_command_submission_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_command_submission_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_command_submission_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_command_submission_service_proto = out.File + file_com_daml_ledger_api_v2_command_submission_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_command_submission_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/command_submission_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/command_submission_service_grpc.pb.go new file mode 100644 index 00000000..3d46200e --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/command_submission_service_grpc.pb.go @@ -0,0 +1,197 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/command_submission_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + CommandSubmissionService_Submit_FullMethodName = "/com.daml.ledger.api.v2.CommandSubmissionService/Submit" + CommandSubmissionService_SubmitReassignment_FullMethodName = "/com.daml.ledger.api.v2.CommandSubmissionService/SubmitReassignment" +) + +// CommandSubmissionServiceClient is the client API for CommandSubmissionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Allows clients to attempt advancing the ledger's state by submitting commands. +// The final states of their submissions are disclosed by the Command Completion Service. +// The on-ledger effects of their submissions are disclosed by the Update Service. +// +// Commands may fail in 2 distinct manners: +// +// 1. Failure communicated synchronously in the gRPC error of the submission. +// 2. Failure communicated asynchronously in a Completion, see “completion.proto“. +// +// Note that not only successfully submitted commands MAY produce a completion event. For example, the participant MAY +// choose to produce a completion event for a rejection of a duplicate command. +// +// Clients that do not receive a successful completion about their submission MUST NOT assume that it was successful. +// Clients SHOULD subscribe to the CompletionStream before starting to submit commands to prevent race conditions. +type CommandSubmissionServiceClient interface { + // Submit a single composite command. + Submit(ctx context.Context, in *SubmitRequest, opts ...grpc.CallOption) (*SubmitResponse, error) + // Submit a single reassignment. + SubmitReassignment(ctx context.Context, in *SubmitReassignmentRequest, opts ...grpc.CallOption) (*SubmitReassignmentResponse, error) +} + +type commandSubmissionServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewCommandSubmissionServiceClient(cc grpc.ClientConnInterface) CommandSubmissionServiceClient { + return &commandSubmissionServiceClient{cc} +} + +func (c *commandSubmissionServiceClient) Submit(ctx context.Context, in *SubmitRequest, opts ...grpc.CallOption) (*SubmitResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SubmitResponse) + err := c.cc.Invoke(ctx, CommandSubmissionService_Submit_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *commandSubmissionServiceClient) SubmitReassignment(ctx context.Context, in *SubmitReassignmentRequest, opts ...grpc.CallOption) (*SubmitReassignmentResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SubmitReassignmentResponse) + err := c.cc.Invoke(ctx, CommandSubmissionService_SubmitReassignment_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CommandSubmissionServiceServer is the server API for CommandSubmissionService service. +// All implementations must embed UnimplementedCommandSubmissionServiceServer +// for forward compatibility. +// +// Allows clients to attempt advancing the ledger's state by submitting commands. +// The final states of their submissions are disclosed by the Command Completion Service. +// The on-ledger effects of their submissions are disclosed by the Update Service. +// +// Commands may fail in 2 distinct manners: +// +// 1. Failure communicated synchronously in the gRPC error of the submission. +// 2. Failure communicated asynchronously in a Completion, see “completion.proto“. +// +// Note that not only successfully submitted commands MAY produce a completion event. For example, the participant MAY +// choose to produce a completion event for a rejection of a duplicate command. +// +// Clients that do not receive a successful completion about their submission MUST NOT assume that it was successful. +// Clients SHOULD subscribe to the CompletionStream before starting to submit commands to prevent race conditions. +type CommandSubmissionServiceServer interface { + // Submit a single composite command. + Submit(context.Context, *SubmitRequest) (*SubmitResponse, error) + // Submit a single reassignment. + SubmitReassignment(context.Context, *SubmitReassignmentRequest) (*SubmitReassignmentResponse, error) + mustEmbedUnimplementedCommandSubmissionServiceServer() +} + +// UnimplementedCommandSubmissionServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCommandSubmissionServiceServer struct{} + +func (UnimplementedCommandSubmissionServiceServer) Submit(context.Context, *SubmitRequest) (*SubmitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Submit not implemented") +} +func (UnimplementedCommandSubmissionServiceServer) SubmitReassignment(context.Context, *SubmitReassignmentRequest) (*SubmitReassignmentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitReassignment not implemented") +} +func (UnimplementedCommandSubmissionServiceServer) mustEmbedUnimplementedCommandSubmissionServiceServer() { +} +func (UnimplementedCommandSubmissionServiceServer) testEmbeddedByValue() {} + +// UnsafeCommandSubmissionServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CommandSubmissionServiceServer will +// result in compilation errors. +type UnsafeCommandSubmissionServiceServer interface { + mustEmbedUnimplementedCommandSubmissionServiceServer() +} + +func RegisterCommandSubmissionServiceServer(s grpc.ServiceRegistrar, srv CommandSubmissionServiceServer) { + // If the following call pancis, it indicates UnimplementedCommandSubmissionServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&CommandSubmissionService_ServiceDesc, srv) +} + +func _CommandSubmissionService_Submit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandSubmissionServiceServer).Submit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandSubmissionService_Submit_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandSubmissionServiceServer).Submit(ctx, req.(*SubmitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _CommandSubmissionService_SubmitReassignment_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SubmitReassignmentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandSubmissionServiceServer).SubmitReassignment(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandSubmissionService_SubmitReassignment_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandSubmissionServiceServer).SubmitReassignment(ctx, req.(*SubmitReassignmentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// CommandSubmissionService_ServiceDesc is the grpc.ServiceDesc for CommandSubmissionService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var CommandSubmissionService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.CommandSubmissionService", + HandlerType: (*CommandSubmissionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Submit", + Handler: _CommandSubmissionService_Submit_Handler, + }, + { + MethodName: "SubmitReassignment", + Handler: _CommandSubmissionService_SubmitReassignment_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/command_submission_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/commands.pb.go b/chain/canton/types/com/daml/ledger/api/v2/commands.pb.go new file mode 100644 index 00000000..d88f07fd --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/commands.pb.go @@ -0,0 +1,1052 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/commands.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// A command can either create a new contract or exercise a choice on an existing contract. +type Command struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Command: + // + // *Command_Create + // *Command_Exercise + // *Command_ExerciseByKey + // *Command_CreateAndExercise + Command isCommand_Command `protobuf_oneof:"command"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Command) Reset() { + *x = Command{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Command) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Command) ProtoMessage() {} + +func (x *Command) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Command.ProtoReflect.Descriptor instead. +func (*Command) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{0} +} + +func (x *Command) GetCommand() isCommand_Command { + if x != nil { + return x.Command + } + return nil +} + +func (x *Command) GetCreate() *CreateCommand { + if x != nil { + if x, ok := x.Command.(*Command_Create); ok { + return x.Create + } + } + return nil +} + +func (x *Command) GetExercise() *ExerciseCommand { + if x != nil { + if x, ok := x.Command.(*Command_Exercise); ok { + return x.Exercise + } + } + return nil +} + +func (x *Command) GetExerciseByKey() *ExerciseByKeyCommand { + if x != nil { + if x, ok := x.Command.(*Command_ExerciseByKey); ok { + return x.ExerciseByKey + } + } + return nil +} + +func (x *Command) GetCreateAndExercise() *CreateAndExerciseCommand { + if x != nil { + if x, ok := x.Command.(*Command_CreateAndExercise); ok { + return x.CreateAndExercise + } + } + return nil +} + +type isCommand_Command interface { + isCommand_Command() +} + +type Command_Create struct { + Create *CreateCommand `protobuf:"bytes,1,opt,name=create,proto3,oneof"` +} + +type Command_Exercise struct { + Exercise *ExerciseCommand `protobuf:"bytes,2,opt,name=exercise,proto3,oneof"` +} + +type Command_ExerciseByKey struct { + ExerciseByKey *ExerciseByKeyCommand `protobuf:"bytes,4,opt,name=exercise_by_key,json=exerciseByKey,proto3,oneof"` +} + +type Command_CreateAndExercise struct { + CreateAndExercise *CreateAndExerciseCommand `protobuf:"bytes,3,opt,name=create_and_exercise,json=createAndExercise,proto3,oneof"` +} + +func (*Command_Create) isCommand_Command() {} + +func (*Command_Exercise) isCommand_Command() {} + +func (*Command_ExerciseByKey) isCommand_Command() {} + +func (*Command_CreateAndExercise) isCommand_Command() {} + +// Create a new contract instance based on a template. +type CreateCommand struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The template of contract the client wants to create. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + TemplateId *Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The arguments required for creating a contract from this template. + // + // Required + CreateArguments *Record `protobuf:"bytes,2,opt,name=create_arguments,json=createArguments,proto3" json:"create_arguments,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateCommand) Reset() { + *x = CreateCommand{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateCommand) ProtoMessage() {} + +func (x *CreateCommand) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateCommand.ProtoReflect.Descriptor instead. +func (*CreateCommand) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateCommand) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *CreateCommand) GetCreateArguments() *Record { + if x != nil { + return x.CreateArguments + } + return nil +} + +// Exercise a choice on an existing contract. +type ExerciseCommand struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The template or interface of the contract the client wants to exercise. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // To exercise a choice on an interface, specify the interface identifier in the template_id field. + // + // Required + TemplateId *Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The ID of the contract the client wants to exercise upon. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ContractId string `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // The name of the choice the client wants to exercise. + // Must be a valid NameString (as described in “value.proto“) + // + // Required + Choice string `protobuf:"bytes,3,opt,name=choice,proto3" json:"choice,omitempty"` + // The argument for this choice. + // + // Required + ChoiceArgument *Value `protobuf:"bytes,4,opt,name=choice_argument,json=choiceArgument,proto3" json:"choice_argument,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExerciseCommand) Reset() { + *x = ExerciseCommand{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExerciseCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExerciseCommand) ProtoMessage() {} + +func (x *ExerciseCommand) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExerciseCommand.ProtoReflect.Descriptor instead. +func (*ExerciseCommand) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{2} +} + +func (x *ExerciseCommand) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *ExerciseCommand) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *ExerciseCommand) GetChoice() string { + if x != nil { + return x.Choice + } + return "" +} + +func (x *ExerciseCommand) GetChoiceArgument() *Value { + if x != nil { + return x.ChoiceArgument + } + return nil +} + +// Exercise a choice on an existing contract specified by its key. +type ExerciseByKeyCommand struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The template of contract the client wants to exercise. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + TemplateId *Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The key of the contract the client wants to exercise upon. + // + // Required + ContractKey *Value `protobuf:"bytes,2,opt,name=contract_key,json=contractKey,proto3" json:"contract_key,omitempty"` + // The name of the choice the client wants to exercise. + // Must be a valid NameString (as described in “value.proto“) + // + // Required + Choice string `protobuf:"bytes,3,opt,name=choice,proto3" json:"choice,omitempty"` + // The argument for this choice. + // + // Required + ChoiceArgument *Value `protobuf:"bytes,4,opt,name=choice_argument,json=choiceArgument,proto3" json:"choice_argument,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExerciseByKeyCommand) Reset() { + *x = ExerciseByKeyCommand{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExerciseByKeyCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExerciseByKeyCommand) ProtoMessage() {} + +func (x *ExerciseByKeyCommand) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExerciseByKeyCommand.ProtoReflect.Descriptor instead. +func (*ExerciseByKeyCommand) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{3} +} + +func (x *ExerciseByKeyCommand) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *ExerciseByKeyCommand) GetContractKey() *Value { + if x != nil { + return x.ContractKey + } + return nil +} + +func (x *ExerciseByKeyCommand) GetChoice() string { + if x != nil { + return x.Choice + } + return "" +} + +func (x *ExerciseByKeyCommand) GetChoiceArgument() *Value { + if x != nil { + return x.ChoiceArgument + } + return nil +} + +// Create a contract and exercise a choice on it in the same transaction. +type CreateAndExerciseCommand struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The template of the contract the client wants to create. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + TemplateId *Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The arguments required for creating a contract from this template. + // + // Required + CreateArguments *Record `protobuf:"bytes,2,opt,name=create_arguments,json=createArguments,proto3" json:"create_arguments,omitempty"` + // The name of the choice the client wants to exercise. + // Must be a valid NameString (as described in “value.proto“). + // + // Required + Choice string `protobuf:"bytes,3,opt,name=choice,proto3" json:"choice,omitempty"` + // The argument for this choice. + // + // Required + ChoiceArgument *Value `protobuf:"bytes,4,opt,name=choice_argument,json=choiceArgument,proto3" json:"choice_argument,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateAndExerciseCommand) Reset() { + *x = CreateAndExerciseCommand{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateAndExerciseCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAndExerciseCommand) ProtoMessage() {} + +func (x *CreateAndExerciseCommand) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAndExerciseCommand.ProtoReflect.Descriptor instead. +func (*CreateAndExerciseCommand) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{4} +} + +func (x *CreateAndExerciseCommand) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *CreateAndExerciseCommand) GetCreateArguments() *Record { + if x != nil { + return x.CreateArguments + } + return nil +} + +func (x *CreateAndExerciseCommand) GetChoice() string { + if x != nil { + return x.Choice + } + return "" +} + +func (x *CreateAndExerciseCommand) GetChoiceArgument() *Value { + if x != nil { + return x.ChoiceArgument + } + return nil +} + +// An additional contract that is used to resolve +// contract & contract key lookups. +type DisclosedContract struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The template id of the contract. + // The identifier uses the package-id reference format. + // + // If provided, used to validate the template id of the contract serialized in the created_event_blob. + // + // Optional + TemplateId *Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The contract id + // + // If provided, used to validate the contract id of the contract serialized in the created_event_blob. + // + // Optional + ContractId string `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // Opaque byte string containing the complete payload required by the Daml engine + // to reconstruct a contract not known to the receiving participant. + // + // Required: must be non-empty + CreatedEventBlob []byte `protobuf:"bytes,3,opt,name=created_event_blob,json=createdEventBlob,proto3" json:"created_event_blob,omitempty"` + // The ID of the synchronizer where the contract is currently assigned + // + // Optional + SynchronizerId string `protobuf:"bytes,4,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DisclosedContract) Reset() { + *x = DisclosedContract{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DisclosedContract) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DisclosedContract) ProtoMessage() {} + +func (x *DisclosedContract) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DisclosedContract.ProtoReflect.Descriptor instead. +func (*DisclosedContract) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{5} +} + +func (x *DisclosedContract) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *DisclosedContract) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *DisclosedContract) GetCreatedEventBlob() []byte { + if x != nil { + return x.CreatedEventBlob + } + return nil +} + +func (x *DisclosedContract) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +// A composite command that groups multiple commands together. +type Commands struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Identifier of the on-ledger workflow that this command is a part of. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + WorkflowId string `protobuf:"bytes,1,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"` + // Uniquely identifies the participant user that issued the command. + // Must be a valid UserIdString (as described in “value.proto“). + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // Uniquely identifies the command. + // The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, + // where act_as is interpreted as a set of party names. + // The change ID can be used for matching the intended ledger changes with all their completions. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + CommandId string `protobuf:"bytes,3,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + // Individual elements of this atomic command. Must be non-empty. + // + // Required: must be non-empty + Commands []*Command `protobuf:"bytes,4,rep,name=commands,proto3" json:"commands,omitempty"` + // Specifies the deduplication period for the change ID. + // If omitted, the participant will assume the configured maximum deduplication time. + // + // # Optional + // + // Types that are valid to be assigned to DeduplicationPeriod: + // + // *Commands_DeduplicationDuration + // *Commands_DeduplicationOffset + DeduplicationPeriod isCommands_DeduplicationPeriod `protobuf_oneof:"deduplication_period"` + // Lower bound for the ledger time assigned to the resulting transaction. + // Note: The ledger time of a transaction is assigned as part of command interpretation. + // Use this property if you expect that command interpretation will take a considerate amount of time, such that by + // the time the resulting transaction is sequenced, its assigned ledger time is not valid anymore. + // Must not be set at the same time as min_ledger_time_rel. + // + // Optional + MinLedgerTimeAbs *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=min_ledger_time_abs,json=minLedgerTimeAbs,proto3" json:"min_ledger_time_abs,omitempty"` + // Same as min_ledger_time_abs, but specified as a duration, starting from the time the command is received by the server. + // Must not be set at the same time as min_ledger_time_abs. + // + // Optional + MinLedgerTimeRel *durationpb.Duration `protobuf:"bytes,8,opt,name=min_ledger_time_rel,json=minLedgerTimeRel,proto3" json:"min_ledger_time_rel,omitempty"` + // Set of parties on whose behalf the command should be executed. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to act on behalf of each of the given parties. + // Each element must be a valid PartyIdString (as described in “value.proto“). + // + // Required: must be non-empty + ActAs []string `protobuf:"bytes,9,rep,name=act_as,json=actAs,proto3" json:"act_as,omitempty"` + // Set of parties on whose behalf (in addition to all parties listed in “act_as“) contracts can be retrieved. + // This affects Daml operations such as “fetch“, “fetchByKey“, “lookupByKey“, “exercise“, and “exerciseByKey“. + // Note: A participant node of a Daml network can host multiple parties. Each contract present on the participant + // node is only visible to a subset of these parties. A command can only use contracts that are visible to at least + // one of the parties in “act_as“ or “read_as“. This visibility check is independent from the Daml authorization + // rules for fetch operations. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to read contract data on behalf of each of the given parties. + // + // Optional: can be empty + ReadAs []string `protobuf:"bytes,10,rep,name=read_as,json=readAs,proto3" json:"read_as,omitempty"` + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in “value.proto“). + // + // If omitted, the participant or the committer may set a value of their choice. + // + // Optional + SubmissionId string `protobuf:"bytes,11,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // Additional contracts used to resolve contract & contract key lookups. + // + // Optional: can be empty + DisclosedContracts []*DisclosedContract `protobuf:"bytes,12,rep,name=disclosed_contracts,json=disclosedContracts,proto3" json:"disclosed_contracts,omitempty"` + // Must be a valid synchronizer id + // + // Optional + SynchronizerId string `protobuf:"bytes,13,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The package-id selection preference of the client for resolving + // package names and interface instances in command submission and interpretation + // + // Optional: can be empty + PackageIdSelectionPreference []string `protobuf:"bytes,14,rep,name=package_id_selection_preference,json=packageIdSelectionPreference,proto3" json:"package_id_selection_preference,omitempty"` + // Fetches the contract keys into the caches to speed up the command processing. + // Should only contain contract keys that are expected to be resolved during interpretation of the commands. + // Keys of disclosed contracts do not need prefetching. + // + // Optional: can be empty + PrefetchContractKeys []*PrefetchContractKey `protobuf:"bytes,15,rep,name=prefetch_contract_keys,json=prefetchContractKeys,proto3" json:"prefetch_contract_keys,omitempty"` + // The maximum number of passes for the Topology-Aware Package Selection (TAPS). + // Higher values can increase the chance of successful package selection for routing of interpreted transactions. + // If unset, this defaults to the value defined in the participant configuration. + // The provided value must not exceed the limit specified in the participant configuration. + // + // Optional + TapsMaxPasses *uint32 `protobuf:"varint,16,opt,name=taps_max_passes,json=tapsMaxPasses,proto3,oneof" json:"taps_max_passes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Commands) Reset() { + *x = Commands{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Commands) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Commands) ProtoMessage() {} + +func (x *Commands) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Commands.ProtoReflect.Descriptor instead. +func (*Commands) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{6} +} + +func (x *Commands) GetWorkflowId() string { + if x != nil { + return x.WorkflowId + } + return "" +} + +func (x *Commands) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *Commands) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *Commands) GetCommands() []*Command { + if x != nil { + return x.Commands + } + return nil +} + +func (x *Commands) GetDeduplicationPeriod() isCommands_DeduplicationPeriod { + if x != nil { + return x.DeduplicationPeriod + } + return nil +} + +func (x *Commands) GetDeduplicationDuration() *durationpb.Duration { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*Commands_DeduplicationDuration); ok { + return x.DeduplicationDuration + } + } + return nil +} + +func (x *Commands) GetDeduplicationOffset() int64 { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*Commands_DeduplicationOffset); ok { + return x.DeduplicationOffset + } + } + return 0 +} + +func (x *Commands) GetMinLedgerTimeAbs() *timestamppb.Timestamp { + if x != nil { + return x.MinLedgerTimeAbs + } + return nil +} + +func (x *Commands) GetMinLedgerTimeRel() *durationpb.Duration { + if x != nil { + return x.MinLedgerTimeRel + } + return nil +} + +func (x *Commands) GetActAs() []string { + if x != nil { + return x.ActAs + } + return nil +} + +func (x *Commands) GetReadAs() []string { + if x != nil { + return x.ReadAs + } + return nil +} + +func (x *Commands) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *Commands) GetDisclosedContracts() []*DisclosedContract { + if x != nil { + return x.DisclosedContracts + } + return nil +} + +func (x *Commands) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *Commands) GetPackageIdSelectionPreference() []string { + if x != nil { + return x.PackageIdSelectionPreference + } + return nil +} + +func (x *Commands) GetPrefetchContractKeys() []*PrefetchContractKey { + if x != nil { + return x.PrefetchContractKeys + } + return nil +} + +func (x *Commands) GetTapsMaxPasses() uint32 { + if x != nil && x.TapsMaxPasses != nil { + return *x.TapsMaxPasses + } + return 0 +} + +type isCommands_DeduplicationPeriod interface { + isCommands_DeduplicationPeriod() +} + +type Commands_DeduplicationDuration struct { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + DeduplicationDuration *durationpb.Duration `protobuf:"bytes,5,opt,name=deduplication_duration,json=deduplicationDuration,proto3,oneof"` +} + +type Commands_DeduplicationOffset struct { + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer) or participant begin (zero). + DeduplicationOffset int64 `protobuf:"varint,6,opt,name=deduplication_offset,json=deduplicationOffset,proto3,oneof"` +} + +func (*Commands_DeduplicationDuration) isCommands_DeduplicationPeriod() {} + +func (*Commands_DeduplicationOffset) isCommands_DeduplicationPeriod() {} + +// Preload contracts +type PrefetchContractKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The template of contract the client wants to prefetch. + // Both package-name and package-id reference identifier formats for the template-id are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + TemplateId *Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The key of the contract the client wants to prefetch. + // + // Required + ContractKey *Value `protobuf:"bytes,2,opt,name=contract_key,json=contractKey,proto3" json:"contract_key,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PrefetchContractKey) Reset() { + *x = PrefetchContractKey{} + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PrefetchContractKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrefetchContractKey) ProtoMessage() {} + +func (x *PrefetchContractKey) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_commands_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrefetchContractKey.ProtoReflect.Descriptor instead. +func (*PrefetchContractKey) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP(), []int{7} +} + +func (x *PrefetchContractKey) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *PrefetchContractKey) GetContractKey() *Value { + if x != nil { + return x.ContractKey + } + return nil +} + +var File_com_daml_ledger_api_v2_commands_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_commands_proto_rawDesc = "" + + "\n" + + "%com/daml/ledger/api/v2/commands.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/value.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xd8\x02\n" + + "\aCommand\x12?\n" + + "\x06create\x18\x01 \x01(\v2%.com.daml.ledger.api.v2.CreateCommandH\x00R\x06create\x12E\n" + + "\bexercise\x18\x02 \x01(\v2'.com.daml.ledger.api.v2.ExerciseCommandH\x00R\bexercise\x12V\n" + + "\x0fexercise_by_key\x18\x04 \x01(\v2,.com.daml.ledger.api.v2.ExerciseByKeyCommandH\x00R\rexerciseByKey\x12b\n" + + "\x13create_and_exercise\x18\x03 \x01(\v20.com.daml.ledger.api.v2.CreateAndExerciseCommandH\x00R\x11createAndExerciseB\t\n" + + "\acommand\"\x9f\x01\n" + + "\rCreateCommand\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12I\n" + + "\x10create_arguments\x18\x02 \x01(\v2\x1e.com.daml.ledger.api.v2.RecordR\x0fcreateArguments\"\xd7\x01\n" + + "\x0fExerciseCommand\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12\x1f\n" + + "\vcontract_id\x18\x02 \x01(\tR\n" + + "contractId\x12\x16\n" + + "\x06choice\x18\x03 \x01(\tR\x06choice\x12F\n" + + "\x0fchoice_argument\x18\x04 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x0echoiceArgument\"\xfd\x01\n" + + "\x14ExerciseByKeyCommand\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12@\n" + + "\fcontract_key\x18\x02 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\vcontractKey\x12\x16\n" + + "\x06choice\x18\x03 \x01(\tR\x06choice\x12F\n" + + "\x0fchoice_argument\x18\x04 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x0echoiceArgument\"\x8a\x02\n" + + "\x18CreateAndExerciseCommand\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12I\n" + + "\x10create_arguments\x18\x02 \x01(\v2\x1e.com.daml.ledger.api.v2.RecordR\x0fcreateArguments\x12\x16\n" + + "\x06choice\x18\x03 \x01(\tR\x06choice\x12F\n" + + "\x0fchoice_argument\x18\x04 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x0echoiceArgument\"\xd0\x01\n" + + "\x11DisclosedContract\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12\x1f\n" + + "\vcontract_id\x18\x02 \x01(\tR\n" + + "contractId\x12,\n" + + "\x12created_event_blob\x18\x03 \x01(\fR\x10createdEventBlob\x12'\n" + + "\x0fsynchronizer_id\x18\x04 \x01(\tR\x0esynchronizerId\"\x9b\a\n" + + "\bCommands\x12\x1f\n" + + "\vworkflow_id\x18\x01 \x01(\tR\n" + + "workflowId\x12\x17\n" + + "\auser_id\x18\x02 \x01(\tR\x06userId\x12\x1d\n" + + "\n" + + "command_id\x18\x03 \x01(\tR\tcommandId\x12;\n" + + "\bcommands\x18\x04 \x03(\v2\x1f.com.daml.ledger.api.v2.CommandR\bcommands\x12R\n" + + "\x16deduplication_duration\x18\x05 \x01(\v2\x19.google.protobuf.DurationH\x00R\x15deduplicationDuration\x123\n" + + "\x14deduplication_offset\x18\x06 \x01(\x03H\x00R\x13deduplicationOffset\x12I\n" + + "\x13min_ledger_time_abs\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\x10minLedgerTimeAbs\x12H\n" + + "\x13min_ledger_time_rel\x18\b \x01(\v2\x19.google.protobuf.DurationR\x10minLedgerTimeRel\x12\x15\n" + + "\x06act_as\x18\t \x03(\tR\x05actAs\x12\x17\n" + + "\aread_as\x18\n" + + " \x03(\tR\x06readAs\x12#\n" + + "\rsubmission_id\x18\v \x01(\tR\fsubmissionId\x12Z\n" + + "\x13disclosed_contracts\x18\f \x03(\v2).com.daml.ledger.api.v2.DisclosedContractR\x12disclosedContracts\x12'\n" + + "\x0fsynchronizer_id\x18\r \x01(\tR\x0esynchronizerId\x12E\n" + + "\x1fpackage_id_selection_preference\x18\x0e \x03(\tR\x1cpackageIdSelectionPreference\x12a\n" + + "\x16prefetch_contract_keys\x18\x0f \x03(\v2+.com.daml.ledger.api.v2.PrefetchContractKeyR\x14prefetchContractKeys\x12+\n" + + "\x0ftaps_max_passes\x18\x10 \x01(\rH\x01R\rtapsMaxPasses\x88\x01\x01B\x16\n" + + "\x14deduplication_periodB\x12\n" + + "\x10_taps_max_passes\"\x9c\x01\n" + + "\x13PrefetchContractKey\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12@\n" + + "\fcontract_key\x18\x02 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\vcontractKeyB\xfa\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\rCommandsProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_commands_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_commands_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_commands_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_commands_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_commands_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_commands_proto_rawDesc), len(file_com_daml_ledger_api_v2_commands_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_commands_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_commands_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_com_daml_ledger_api_v2_commands_proto_goTypes = []any{ + (*Command)(nil), // 0: com.daml.ledger.api.v2.Command + (*CreateCommand)(nil), // 1: com.daml.ledger.api.v2.CreateCommand + (*ExerciseCommand)(nil), // 2: com.daml.ledger.api.v2.ExerciseCommand + (*ExerciseByKeyCommand)(nil), // 3: com.daml.ledger.api.v2.ExerciseByKeyCommand + (*CreateAndExerciseCommand)(nil), // 4: com.daml.ledger.api.v2.CreateAndExerciseCommand + (*DisclosedContract)(nil), // 5: com.daml.ledger.api.v2.DisclosedContract + (*Commands)(nil), // 6: com.daml.ledger.api.v2.Commands + (*PrefetchContractKey)(nil), // 7: com.daml.ledger.api.v2.PrefetchContractKey + (*Identifier)(nil), // 8: com.daml.ledger.api.v2.Identifier + (*Record)(nil), // 9: com.daml.ledger.api.v2.Record + (*Value)(nil), // 10: com.daml.ledger.api.v2.Value + (*durationpb.Duration)(nil), // 11: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 12: google.protobuf.Timestamp +} +var file_com_daml_ledger_api_v2_commands_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.Command.create:type_name -> com.daml.ledger.api.v2.CreateCommand + 2, // 1: com.daml.ledger.api.v2.Command.exercise:type_name -> com.daml.ledger.api.v2.ExerciseCommand + 3, // 2: com.daml.ledger.api.v2.Command.exercise_by_key:type_name -> com.daml.ledger.api.v2.ExerciseByKeyCommand + 4, // 3: com.daml.ledger.api.v2.Command.create_and_exercise:type_name -> com.daml.ledger.api.v2.CreateAndExerciseCommand + 8, // 4: com.daml.ledger.api.v2.CreateCommand.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 9, // 5: com.daml.ledger.api.v2.CreateCommand.create_arguments:type_name -> com.daml.ledger.api.v2.Record + 8, // 6: com.daml.ledger.api.v2.ExerciseCommand.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 10, // 7: com.daml.ledger.api.v2.ExerciseCommand.choice_argument:type_name -> com.daml.ledger.api.v2.Value + 8, // 8: com.daml.ledger.api.v2.ExerciseByKeyCommand.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 10, // 9: com.daml.ledger.api.v2.ExerciseByKeyCommand.contract_key:type_name -> com.daml.ledger.api.v2.Value + 10, // 10: com.daml.ledger.api.v2.ExerciseByKeyCommand.choice_argument:type_name -> com.daml.ledger.api.v2.Value + 8, // 11: com.daml.ledger.api.v2.CreateAndExerciseCommand.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 9, // 12: com.daml.ledger.api.v2.CreateAndExerciseCommand.create_arguments:type_name -> com.daml.ledger.api.v2.Record + 10, // 13: com.daml.ledger.api.v2.CreateAndExerciseCommand.choice_argument:type_name -> com.daml.ledger.api.v2.Value + 8, // 14: com.daml.ledger.api.v2.DisclosedContract.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 0, // 15: com.daml.ledger.api.v2.Commands.commands:type_name -> com.daml.ledger.api.v2.Command + 11, // 16: com.daml.ledger.api.v2.Commands.deduplication_duration:type_name -> google.protobuf.Duration + 12, // 17: com.daml.ledger.api.v2.Commands.min_ledger_time_abs:type_name -> google.protobuf.Timestamp + 11, // 18: com.daml.ledger.api.v2.Commands.min_ledger_time_rel:type_name -> google.protobuf.Duration + 5, // 19: com.daml.ledger.api.v2.Commands.disclosed_contracts:type_name -> com.daml.ledger.api.v2.DisclosedContract + 7, // 20: com.daml.ledger.api.v2.Commands.prefetch_contract_keys:type_name -> com.daml.ledger.api.v2.PrefetchContractKey + 8, // 21: com.daml.ledger.api.v2.PrefetchContractKey.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 10, // 22: com.daml.ledger.api.v2.PrefetchContractKey.contract_key:type_name -> com.daml.ledger.api.v2.Value + 23, // [23:23] is the sub-list for method output_type + 23, // [23:23] is the sub-list for method input_type + 23, // [23:23] is the sub-list for extension type_name + 23, // [23:23] is the sub-list for extension extendee + 0, // [0:23] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_commands_proto_init() } +func file_com_daml_ledger_api_v2_commands_proto_init() { + if File_com_daml_ledger_api_v2_commands_proto != nil { + return + } + file_com_daml_ledger_api_v2_value_proto_init() + file_com_daml_ledger_api_v2_commands_proto_msgTypes[0].OneofWrappers = []any{ + (*Command_Create)(nil), + (*Command_Exercise)(nil), + (*Command_ExerciseByKey)(nil), + (*Command_CreateAndExercise)(nil), + } + file_com_daml_ledger_api_v2_commands_proto_msgTypes[6].OneofWrappers = []any{ + (*Commands_DeduplicationDuration)(nil), + (*Commands_DeduplicationOffset)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_commands_proto_rawDesc), len(file_com_daml_ledger_api_v2_commands_proto_rawDesc)), + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_commands_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_commands_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_commands_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_commands_proto = out.File + file_com_daml_ledger_api_v2_commands_proto_goTypes = nil + file_com_daml_ledger_api_v2_commands_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/completion.pb.go b/chain/canton/types/com/daml/ledger/api/v2/completion.pb.go new file mode 100644 index 00000000..2655a51f --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/completion.pb.go @@ -0,0 +1,369 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/completion.proto + +package apiv2 + +import ( + rpc "google.golang.org/genproto/googleapis/rpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// A completion represents the status of a submitted command on the ledger: it can be successful or failed. +type Completion struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the succeeded or failed command. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + // Identifies the exact type of the error. + // It uses the same format of conveying error details as it is used for the RPC responses of the APIs. + // + // Optional + Status *rpc.Status `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` + // The update_id of the transaction or reassignment that resulted from the command with command_id. + // + // Only set for successfully executed commands. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + UpdateId string `protobuf:"bytes,3,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // The user-id that was used for the submission, as described in “commands.proto“. + // Must be a valid UserIdString (as described in “value.proto“). + // + // Required + UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The set of parties on whose behalf the commands were executed. + // Contains the “act_as“ parties from “commands.proto“ + // filtered to the requesting parties in CompletionStreamRequest. + // The order of the parties need not be the same as in the submission. + // Each element must be a valid PartyIdString (as described in “value.proto“). + // + // Required: must be non-empty + ActAs []string `protobuf:"bytes,5,rep,name=act_as,json=actAs,proto3" json:"act_as,omitempty"` + // The submission ID this completion refers to, as described in “commands.proto“. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + SubmissionId string `protobuf:"bytes,6,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // The actual deduplication window used for the submission, which is derived from + // “Commands.deduplication_period“. The ledger may convert the deduplication period into other + // descriptions and extend the period in implementation-specified ways. + // + // Used to audit the deduplication guarantee described in “commands.proto“. + // + // The deduplication guarantee applies even if the completion omits this field. + // + // # Optional + // + // Types that are valid to be assigned to DeduplicationPeriod: + // + // *Completion_DeduplicationOffset + // *Completion_DeduplicationDuration + DeduplicationPeriod isCompletion_DeduplicationPeriod `protobuf_oneof:"deduplication_period"` + // The Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + TraceContext *TraceContext `protobuf:"bytes,9,opt,name=trace_context,json=traceContext,proto3" json:"trace_context,omitempty"` + // May be used in a subsequent CompletionStreamRequest to resume the consumption of this stream at a later time. + // Must be a valid absolute offset (positive integer). + // + // Required + Offset int64 `protobuf:"varint,10,opt,name=offset,proto3" json:"offset,omitempty"` + // The synchronizer along with its record time. + // The synchronizer id provided, in case of + // + // - successful/failed transactions: identifies the synchronizer of the transaction + // - for successful/failed unassign commands: identifies the source synchronizer + // - for successful/failed assign commands: identifies the target synchronizer + // + // Required + SynchronizerTime *SynchronizerTime `protobuf:"bytes,11,opt,name=synchronizer_time,json=synchronizerTime,proto3" json:"synchronizer_time,omitempty"` + // The traffic cost paid by this participant node for the confirmation request + // for the submitted command. + // + // Commands whose execution is rejected before their corresponding + // confirmation request is ordered by the synchronizer will report a paid + // traffic cost of zero. + // If a confirmation request is ordered for a command, but the request fails + // (e.g., due to contention with a concurrent contract archival), the traffic + // cost is paid and reported on the failed completion for the request. + // + // If you want to correlate the traffic cost of a successful completion + // with the transaction that resulted from the command, you can use the + // “offset“ field to retrieve the transaction using + // “UpdateService.GetUpdateByOffset“ on the same participant node; or alternatively use the “update_id“ + // field to retrieve the transaction using “UpdateService.GetUpdateById“ on any participant node + // that sees the transaction. + // + // Note: for completions processed before the participant started serving + // traffic cost on the Ledger API, this field will be set to zero. + // Additionally, the total cost incurred by the submitting node for the submission of the transaction may be greater + // than the reported cost, for example if retries were issued due to failed submissions to the synchronizer. + // The cost reported here is the one paid for ordering the confirmation request. + // + // Optional + PaidTrafficCost int64 `protobuf:"varint,12,opt,name=paid_traffic_cost,json=paidTrafficCost,proto3" json:"paid_traffic_cost,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Completion) Reset() { + *x = Completion{} + mi := &file_com_daml_ledger_api_v2_completion_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Completion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Completion) ProtoMessage() {} + +func (x *Completion) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_completion_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Completion.ProtoReflect.Descriptor instead. +func (*Completion) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_completion_proto_rawDescGZIP(), []int{0} +} + +func (x *Completion) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *Completion) GetStatus() *rpc.Status { + if x != nil { + return x.Status + } + return nil +} + +func (x *Completion) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *Completion) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *Completion) GetActAs() []string { + if x != nil { + return x.ActAs + } + return nil +} + +func (x *Completion) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *Completion) GetDeduplicationPeriod() isCompletion_DeduplicationPeriod { + if x != nil { + return x.DeduplicationPeriod + } + return nil +} + +func (x *Completion) GetDeduplicationOffset() int64 { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*Completion_DeduplicationOffset); ok { + return x.DeduplicationOffset + } + } + return 0 +} + +func (x *Completion) GetDeduplicationDuration() *durationpb.Duration { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*Completion_DeduplicationDuration); ok { + return x.DeduplicationDuration + } + } + return nil +} + +func (x *Completion) GetTraceContext() *TraceContext { + if x != nil { + return x.TraceContext + } + return nil +} + +func (x *Completion) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *Completion) GetSynchronizerTime() *SynchronizerTime { + if x != nil { + return x.SynchronizerTime + } + return nil +} + +func (x *Completion) GetPaidTrafficCost() int64 { + if x != nil { + return x.PaidTrafficCost + } + return 0 +} + +type isCompletion_DeduplicationPeriod interface { + isCompletion_DeduplicationPeriod() +} + +type Completion_DeduplicationOffset struct { + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // + // Must be a valid absolute offset (positive integer) or participant begin (zero). + DeduplicationOffset int64 `protobuf:"varint,7,opt,name=deduplication_offset,json=deduplicationOffset,proto3,oneof"` +} + +type Completion_DeduplicationDuration struct { + // Specifies the length of the deduplication period. + // It is measured in record time of completions. + // + // Must be non-negative. + DeduplicationDuration *durationpb.Duration `protobuf:"bytes,8,opt,name=deduplication_duration,json=deduplicationDuration,proto3,oneof"` +} + +func (*Completion_DeduplicationOffset) isCompletion_DeduplicationPeriod() {} + +func (*Completion_DeduplicationDuration) isCompletion_DeduplicationPeriod() {} + +var File_com_daml_ledger_api_v2_completion_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_completion_proto_rawDesc = "" + + "\n" + + "'com/daml/ledger/api/v2/completion.proto\x12\x16com.daml.ledger.api.v2\x1a.com/daml/ledger/api/v2/offset_checkpoint.proto\x1a*com/daml/ledger/api/v2/trace_context.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x17google/rpc/status.proto\"\xd0\x04\n" + + "\n" + + "Completion\x12\x1d\n" + + "\n" + + "command_id\x18\x01 \x01(\tR\tcommandId\x12*\n" + + "\x06status\x18\x02 \x01(\v2\x12.google.rpc.StatusR\x06status\x12\x1b\n" + + "\tupdate_id\x18\x03 \x01(\tR\bupdateId\x12\x17\n" + + "\auser_id\x18\x04 \x01(\tR\x06userId\x12\x15\n" + + "\x06act_as\x18\x05 \x03(\tR\x05actAs\x12#\n" + + "\rsubmission_id\x18\x06 \x01(\tR\fsubmissionId\x123\n" + + "\x14deduplication_offset\x18\a \x01(\x03H\x00R\x13deduplicationOffset\x12R\n" + + "\x16deduplication_duration\x18\b \x01(\v2\x19.google.protobuf.DurationH\x00R\x15deduplicationDuration\x12I\n" + + "\rtrace_context\x18\t \x01(\v2$.com.daml.ledger.api.v2.TraceContextR\ftraceContext\x12\x16\n" + + "\x06offset\x18\n" + + " \x01(\x03R\x06offset\x12U\n" + + "\x11synchronizer_time\x18\v \x01(\v2(.com.daml.ledger.api.v2.SynchronizerTimeR\x10synchronizerTime\x12*\n" + + "\x11paid_traffic_cost\x18\f \x01(\x03R\x0fpaidTrafficCostB\x16\n" + + "\x14deduplication_periodB\xfc\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\x0fCompletionProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_completion_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_completion_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_completion_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_completion_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_completion_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_completion_proto_rawDesc), len(file_com_daml_ledger_api_v2_completion_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_completion_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_completion_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_com_daml_ledger_api_v2_completion_proto_goTypes = []any{ + (*Completion)(nil), // 0: com.daml.ledger.api.v2.Completion + (*rpc.Status)(nil), // 1: google.rpc.Status + (*durationpb.Duration)(nil), // 2: google.protobuf.Duration + (*TraceContext)(nil), // 3: com.daml.ledger.api.v2.TraceContext + (*SynchronizerTime)(nil), // 4: com.daml.ledger.api.v2.SynchronizerTime +} +var file_com_daml_ledger_api_v2_completion_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.Completion.status:type_name -> google.rpc.Status + 2, // 1: com.daml.ledger.api.v2.Completion.deduplication_duration:type_name -> google.protobuf.Duration + 3, // 2: com.daml.ledger.api.v2.Completion.trace_context:type_name -> com.daml.ledger.api.v2.TraceContext + 4, // 3: com.daml.ledger.api.v2.Completion.synchronizer_time:type_name -> com.daml.ledger.api.v2.SynchronizerTime + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_completion_proto_init() } +func file_com_daml_ledger_api_v2_completion_proto_init() { + if File_com_daml_ledger_api_v2_completion_proto != nil { + return + } + file_com_daml_ledger_api_v2_offset_checkpoint_proto_init() + file_com_daml_ledger_api_v2_trace_context_proto_init() + file_com_daml_ledger_api_v2_completion_proto_msgTypes[0].OneofWrappers = []any{ + (*Completion_DeduplicationOffset)(nil), + (*Completion_DeduplicationDuration)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_completion_proto_rawDesc), len(file_com_daml_ledger_api_v2_completion_proto_rawDesc)), + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_completion_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_completion_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_completion_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_completion_proto = out.File + file_com_daml_ledger_api_v2_completion_proto_goTypes = nil + file_com_daml_ledger_api_v2_completion_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/contract_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/contract_service.pb.go new file mode 100644 index 00000000..2053ce71 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/contract_service.pb.go @@ -0,0 +1,212 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/contract_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetContractRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the contract. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ContractId string `protobuf:"bytes,1,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // The list of querying parties + // The stakeholders of the referenced contract must have an intersection with any of these parties + // to return the result. + // If no querying_parties specified, all possible contracts could be returned. + // + // Optional: can be empty + QueryingParties []string `protobuf:"bytes,2,rep,name=querying_parties,json=queryingParties,proto3" json:"querying_parties,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetContractRequest) Reset() { + *x = GetContractRequest{} + mi := &file_com_daml_ledger_api_v2_contract_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetContractRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContractRequest) ProtoMessage() {} + +func (x *GetContractRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_contract_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContractRequest.ProtoReflect.Descriptor instead. +func (*GetContractRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_contract_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetContractRequest) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *GetContractRequest) GetQueryingParties() []string { + if x != nil { + return x.QueryingParties + } + return nil +} + +type GetContractResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The representative_package_id will be always set to the contract package ID, therefore this endpoint should + // not be used to lookup contract which entered the participant via party replication or repair service. + // The witnesses field will contain only the querying_parties which are also stakeholders of the contract as well. + // The following fields of the created event cannot be populated, so those should not be used / parsed: + // + // - offset + // - node_id + // - created_event_blob + // - interface_views + // - acs_delta + // + // Required + CreatedEvent *CreatedEvent `protobuf:"bytes,1,opt,name=created_event,json=createdEvent,proto3" json:"created_event,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetContractResponse) Reset() { + *x = GetContractResponse{} + mi := &file_com_daml_ledger_api_v2_contract_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetContractResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetContractResponse) ProtoMessage() {} + +func (x *GetContractResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_contract_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetContractResponse.ProtoReflect.Descriptor instead. +func (*GetContractResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_contract_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetContractResponse) GetCreatedEvent() *CreatedEvent { + if x != nil { + return x.CreatedEvent + } + return nil +} + +var File_com_daml_ledger_api_v2_contract_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_contract_service_proto_rawDesc = "" + + "\n" + + "-com/daml/ledger/api/v2/contract_service.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/event.proto\"`\n" + + "\x12GetContractRequest\x12\x1f\n" + + "\vcontract_id\x18\x01 \x01(\tR\n" + + "contractId\x12)\n" + + "\x10querying_parties\x18\x02 \x03(\tR\x0fqueryingParties\"`\n" + + "\x13GetContractResponse\x12I\n" + + "\rcreated_event\x18\x01 \x01(\v2$.com.daml.ledger.api.v2.CreatedEventR\fcreatedEvent2y\n" + + "\x0fContractService\x12f\n" + + "\vGetContract\x12*.com.daml.ledger.api.v2.GetContractRequest\x1a+.com.daml.ledger.api.v2.GetContractResponseB\x81\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x14ContractServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_contract_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_contract_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_contract_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_contract_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_contract_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_contract_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_contract_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_contract_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_contract_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_com_daml_ledger_api_v2_contract_service_proto_goTypes = []any{ + (*GetContractRequest)(nil), // 0: com.daml.ledger.api.v2.GetContractRequest + (*GetContractResponse)(nil), // 1: com.daml.ledger.api.v2.GetContractResponse + (*CreatedEvent)(nil), // 2: com.daml.ledger.api.v2.CreatedEvent +} +var file_com_daml_ledger_api_v2_contract_service_proto_depIdxs = []int32{ + 2, // 0: com.daml.ledger.api.v2.GetContractResponse.created_event:type_name -> com.daml.ledger.api.v2.CreatedEvent + 0, // 1: com.daml.ledger.api.v2.ContractService.GetContract:input_type -> com.daml.ledger.api.v2.GetContractRequest + 1, // 2: com.daml.ledger.api.v2.ContractService.GetContract:output_type -> com.daml.ledger.api.v2.GetContractResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_contract_service_proto_init() } +func file_com_daml_ledger_api_v2_contract_service_proto_init() { + if File_com_daml_ledger_api_v2_contract_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_event_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_contract_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_contract_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_contract_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_contract_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_contract_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_contract_service_proto = out.File + file_com_daml_ledger_api_v2_contract_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_contract_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/contract_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/contract_service_grpc.pb.go new file mode 100644 index 00000000..7c3ef920 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/contract_service_grpc.pb.go @@ -0,0 +1,140 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/contract_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + ContractService_GetContract_FullMethodName = "/com.daml.ledger.api.v2.ContractService/GetContract" +) + +// ContractServiceClient is the client API for ContractService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// This service is experimental / alpha, therefore no backwards compatibility is guaranteed. +type ContractServiceClient interface { + // Looking up contract data by contract ID. + // This endpoint is experimental / alpha, therefore no backwards compatibility is guaranteed. + // This endpoint must not be used to look up contracts which entered the participant via party replication + // or repair service. + // If there is no contract exist with the contract ID, or there is no intersection with the querying_parties, + // an CONTRACT_PAYLOAD_NOT_FOUND error will be raised. + GetContract(ctx context.Context, in *GetContractRequest, opts ...grpc.CallOption) (*GetContractResponse, error) +} + +type contractServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewContractServiceClient(cc grpc.ClientConnInterface) ContractServiceClient { + return &contractServiceClient{cc} +} + +func (c *contractServiceClient) GetContract(ctx context.Context, in *GetContractRequest, opts ...grpc.CallOption) (*GetContractResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetContractResponse) + err := c.cc.Invoke(ctx, ContractService_GetContract_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ContractServiceServer is the server API for ContractService service. +// All implementations must embed UnimplementedContractServiceServer +// for forward compatibility. +// +// This service is experimental / alpha, therefore no backwards compatibility is guaranteed. +type ContractServiceServer interface { + // Looking up contract data by contract ID. + // This endpoint is experimental / alpha, therefore no backwards compatibility is guaranteed. + // This endpoint must not be used to look up contracts which entered the participant via party replication + // or repair service. + // If there is no contract exist with the contract ID, or there is no intersection with the querying_parties, + // an CONTRACT_PAYLOAD_NOT_FOUND error will be raised. + GetContract(context.Context, *GetContractRequest) (*GetContractResponse, error) + mustEmbedUnimplementedContractServiceServer() +} + +// UnimplementedContractServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedContractServiceServer struct{} + +func (UnimplementedContractServiceServer) GetContract(context.Context, *GetContractRequest) (*GetContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetContract not implemented") +} +func (UnimplementedContractServiceServer) mustEmbedUnimplementedContractServiceServer() {} +func (UnimplementedContractServiceServer) testEmbeddedByValue() {} + +// UnsafeContractServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ContractServiceServer will +// result in compilation errors. +type UnsafeContractServiceServer interface { + mustEmbedUnimplementedContractServiceServer() +} + +func RegisterContractServiceServer(s grpc.ServiceRegistrar, srv ContractServiceServer) { + // If the following call pancis, it indicates UnimplementedContractServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&ContractService_ServiceDesc, srv) +} + +func _ContractService_GetContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetContractRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ContractServiceServer).GetContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: ContractService_GetContract_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ContractServiceServer).GetContract(ctx, req.(*GetContractRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ContractService_ServiceDesc is the grpc.ServiceDesc for ContractService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ContractService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.ContractService", + HandlerType: (*ContractServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetContract", + Handler: _ContractService_GetContract_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/contract_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/crypto.pb.go b/chain/canton/types/com/daml/ledger/api/v2/crypto.pb.go new file mode 100644 index 00000000..2d2695d8 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/crypto.pb.go @@ -0,0 +1,507 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/crypto.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SigningKeySpec int32 + +const ( + SigningKeySpec_SIGNING_KEY_SPEC_UNSPECIFIED SigningKeySpec = 0 + // Elliptic Curve Key from Curve25519 + // as defined in http://ed25519.cr.yp.to/ + SigningKeySpec_SIGNING_KEY_SPEC_EC_CURVE25519 SigningKeySpec = 1 + // Elliptic Curve Key from the NIST P-256 curve (aka secp256r1) + // as defined in https://doi.org/10.6028/NIST.FIPS.186-4 + SigningKeySpec_SIGNING_KEY_SPEC_EC_P256 SigningKeySpec = 2 + // Elliptic Curve Key from the NIST P-384 curve (aka secp384r1) + // as defined in https://doi.org/10.6028/NIST.FIPS.186-4 + SigningKeySpec_SIGNING_KEY_SPEC_EC_P384 SigningKeySpec = 3 + // Elliptic Curve Key from SECG P256k1 curve (aka secp256k1) + // commonly used in bitcoin and ethereum + // as defined in https://www.secg.org/sec2-v2.pdf + SigningKeySpec_SIGNING_KEY_SPEC_EC_SECP256K1 SigningKeySpec = 4 +) + +// Enum value maps for SigningKeySpec. +var ( + SigningKeySpec_name = map[int32]string{ + 0: "SIGNING_KEY_SPEC_UNSPECIFIED", + 1: "SIGNING_KEY_SPEC_EC_CURVE25519", + 2: "SIGNING_KEY_SPEC_EC_P256", + 3: "SIGNING_KEY_SPEC_EC_P384", + 4: "SIGNING_KEY_SPEC_EC_SECP256K1", + } + SigningKeySpec_value = map[string]int32{ + "SIGNING_KEY_SPEC_UNSPECIFIED": 0, + "SIGNING_KEY_SPEC_EC_CURVE25519": 1, + "SIGNING_KEY_SPEC_EC_P256": 2, + "SIGNING_KEY_SPEC_EC_P384": 3, + "SIGNING_KEY_SPEC_EC_SECP256K1": 4, + } +) + +func (x SigningKeySpec) Enum() *SigningKeySpec { + p := new(SigningKeySpec) + *p = x + return p +} + +func (x SigningKeySpec) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SigningKeySpec) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_crypto_proto_enumTypes[0].Descriptor() +} + +func (SigningKeySpec) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_crypto_proto_enumTypes[0] +} + +func (x SigningKeySpec) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SigningKeySpec.Descriptor instead. +func (SigningKeySpec) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_crypto_proto_rawDescGZIP(), []int{0} +} + +// Serialization format for crypto keys and signatures +type CryptoKeyFormat int32 + +const ( + CryptoKeyFormat_CRYPTO_KEY_FORMAT_UNSPECIFIED CryptoKeyFormat = 0 + // ASN.1 + DER encoding + // Legacy format no longer used, except for migrations + CryptoKeyFormat_CRYPTO_KEY_FORMAT_DER CryptoKeyFormat = 1 + // Raw encoding of a key + CryptoKeyFormat_CRYPTO_KEY_FORMAT_RAW CryptoKeyFormat = 2 + // ASN.1 + DER-encoding of X.509 SubjectPublicKeyInfo structure: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 + CryptoKeyFormat_CRYPTO_KEY_FORMAT_DER_X509_SUBJECT_PUBLIC_KEY_INFO CryptoKeyFormat = 3 +) + +// Enum value maps for CryptoKeyFormat. +var ( + CryptoKeyFormat_name = map[int32]string{ + 0: "CRYPTO_KEY_FORMAT_UNSPECIFIED", + 1: "CRYPTO_KEY_FORMAT_DER", + 2: "CRYPTO_KEY_FORMAT_RAW", + 3: "CRYPTO_KEY_FORMAT_DER_X509_SUBJECT_PUBLIC_KEY_INFO", + } + CryptoKeyFormat_value = map[string]int32{ + "CRYPTO_KEY_FORMAT_UNSPECIFIED": 0, + "CRYPTO_KEY_FORMAT_DER": 1, + "CRYPTO_KEY_FORMAT_RAW": 2, + "CRYPTO_KEY_FORMAT_DER_X509_SUBJECT_PUBLIC_KEY_INFO": 3, + } +) + +func (x CryptoKeyFormat) Enum() *CryptoKeyFormat { + p := new(CryptoKeyFormat) + *p = x + return p +} + +func (x CryptoKeyFormat) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CryptoKeyFormat) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_crypto_proto_enumTypes[1].Descriptor() +} + +func (CryptoKeyFormat) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_crypto_proto_enumTypes[1] +} + +func (x CryptoKeyFormat) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CryptoKeyFormat.Descriptor instead. +func (CryptoKeyFormat) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_crypto_proto_rawDescGZIP(), []int{1} +} + +type SigningAlgorithmSpec int32 + +const ( + SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_UNSPECIFIED SigningAlgorithmSpec = 0 + // EdDSA Signature based on Curve25519 with SHA-512 + // http://ed25519.cr.yp.to/ + SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_ED25519 SigningAlgorithmSpec = 1 + // Elliptic Curve Digital Signature Algorithm with SHA256 + SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_256 SigningAlgorithmSpec = 2 + // Elliptic Curve Digital Signature Algorithm with SHA384 + SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_384 SigningAlgorithmSpec = 3 +) + +// Enum value maps for SigningAlgorithmSpec. +var ( + SigningAlgorithmSpec_name = map[int32]string{ + 0: "SIGNING_ALGORITHM_SPEC_UNSPECIFIED", + 1: "SIGNING_ALGORITHM_SPEC_ED25519", + 2: "SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_256", + 3: "SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_384", + } + SigningAlgorithmSpec_value = map[string]int32{ + "SIGNING_ALGORITHM_SPEC_UNSPECIFIED": 0, + "SIGNING_ALGORITHM_SPEC_ED25519": 1, + "SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_256": 2, + "SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_384": 3, + } +) + +func (x SigningAlgorithmSpec) Enum() *SigningAlgorithmSpec { + p := new(SigningAlgorithmSpec) + *p = x + return p +} + +func (x SigningAlgorithmSpec) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SigningAlgorithmSpec) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_crypto_proto_enumTypes[2].Descriptor() +} + +func (SigningAlgorithmSpec) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_crypto_proto_enumTypes[2] +} + +func (x SigningAlgorithmSpec) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SigningAlgorithmSpec.Descriptor instead. +func (SigningAlgorithmSpec) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_crypto_proto_rawDescGZIP(), []int{2} +} + +type SignatureFormat int32 + +const ( + SignatureFormat_SIGNATURE_FORMAT_UNSPECIFIED SignatureFormat = 0 + // Signature scheme specific signature format + // Legacy format no longer used, except for migrations + SignatureFormat_SIGNATURE_FORMAT_RAW SignatureFormat = 1 + // ASN.1 + DER-encoding of the `r` and `s` integers, as defined in https://datatracker.ietf.org/doc/html/rfc3279#section-2.2.3 + // Used for ECDSA signatures + SignatureFormat_SIGNATURE_FORMAT_DER SignatureFormat = 2 + // Concatenation of the integers `r || s` in little-endian form, as defined in https://datatracker.ietf.org/doc/html/rfc8032#section-3.3 + // Note that this is different from the format defined in IEEE P1363, which uses concatenation in big-endian form. + // Used for EdDSA signatures + SignatureFormat_SIGNATURE_FORMAT_CONCAT SignatureFormat = 3 + // Symbolic crypto, must only be used for testing + SignatureFormat_SIGNATURE_FORMAT_SYMBOLIC SignatureFormat = 10000 +) + +// Enum value maps for SignatureFormat. +var ( + SignatureFormat_name = map[int32]string{ + 0: "SIGNATURE_FORMAT_UNSPECIFIED", + 1: "SIGNATURE_FORMAT_RAW", + 2: "SIGNATURE_FORMAT_DER", + 3: "SIGNATURE_FORMAT_CONCAT", + 10000: "SIGNATURE_FORMAT_SYMBOLIC", + } + SignatureFormat_value = map[string]int32{ + "SIGNATURE_FORMAT_UNSPECIFIED": 0, + "SIGNATURE_FORMAT_RAW": 1, + "SIGNATURE_FORMAT_DER": 2, + "SIGNATURE_FORMAT_CONCAT": 3, + "SIGNATURE_FORMAT_SYMBOLIC": 10000, + } +) + +func (x SignatureFormat) Enum() *SignatureFormat { + p := new(SignatureFormat) + *p = x + return p +} + +func (x SignatureFormat) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SignatureFormat) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_crypto_proto_enumTypes[3].Descriptor() +} + +func (SignatureFormat) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_crypto_proto_enumTypes[3] +} + +func (x SignatureFormat) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SignatureFormat.Descriptor instead. +func (SignatureFormat) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_crypto_proto_rawDescGZIP(), []int{3} +} + +type SigningPublicKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The serialization format of the public key + // + // Required + Format CryptoKeyFormat `protobuf:"varint,1,opt,name=format,proto3,enum=com.daml.ledger.api.v2.CryptoKeyFormat" json:"format,omitempty"` + // Serialized public key in the format specified above + // + // Required: must be non-empty + KeyData []byte `protobuf:"bytes,2,opt,name=key_data,json=keyData,proto3" json:"key_data,omitempty"` + // The key specification + // + // Required + KeySpec SigningKeySpec `protobuf:"varint,3,opt,name=key_spec,json=keySpec,proto3,enum=com.daml.ledger.api.v2.SigningKeySpec" json:"key_spec,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SigningPublicKey) Reset() { + *x = SigningPublicKey{} + mi := &file_com_daml_ledger_api_v2_crypto_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SigningPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SigningPublicKey) ProtoMessage() {} + +func (x *SigningPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_crypto_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SigningPublicKey.ProtoReflect.Descriptor instead. +func (*SigningPublicKey) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_crypto_proto_rawDescGZIP(), []int{0} +} + +func (x *SigningPublicKey) GetFormat() CryptoKeyFormat { + if x != nil { + return x.Format + } + return CryptoKeyFormat_CRYPTO_KEY_FORMAT_UNSPECIFIED +} + +func (x *SigningPublicKey) GetKeyData() []byte { + if x != nil { + return x.KeyData + } + return nil +} + +func (x *SigningPublicKey) GetKeySpec() SigningKeySpec { + if x != nil { + return x.KeySpec + } + return SigningKeySpec_SIGNING_KEY_SPEC_UNSPECIFIED +} + +type Signature struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + Format SignatureFormat `protobuf:"varint,1,opt,name=format,proto3,enum=com.daml.ledger.api.v2.SignatureFormat" json:"format,omitempty"` + // Required: must be non-empty + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + // The fingerprint/id of the keypair used to create this signature and needed to verify. + // + // Required + SignedBy string `protobuf:"bytes,3,opt,name=signed_by,json=signedBy,proto3" json:"signed_by,omitempty"` + // The signing algorithm specification used to produce this signature + // + // Required + SigningAlgorithmSpec SigningAlgorithmSpec `protobuf:"varint,4,opt,name=signing_algorithm_spec,json=signingAlgorithmSpec,proto3,enum=com.daml.ledger.api.v2.SigningAlgorithmSpec" json:"signing_algorithm_spec,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Signature) Reset() { + *x = Signature{} + mi := &file_com_daml_ledger_api_v2_crypto_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Signature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Signature) ProtoMessage() {} + +func (x *Signature) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_crypto_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Signature.ProtoReflect.Descriptor instead. +func (*Signature) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_crypto_proto_rawDescGZIP(), []int{1} +} + +func (x *Signature) GetFormat() SignatureFormat { + if x != nil { + return x.Format + } + return SignatureFormat_SIGNATURE_FORMAT_UNSPECIFIED +} + +func (x *Signature) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *Signature) GetSignedBy() string { + if x != nil { + return x.SignedBy + } + return "" +} + +func (x *Signature) GetSigningAlgorithmSpec() SigningAlgorithmSpec { + if x != nil { + return x.SigningAlgorithmSpec + } + return SigningAlgorithmSpec_SIGNING_ALGORITHM_SPEC_UNSPECIFIED +} + +var File_com_daml_ledger_api_v2_crypto_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_crypto_proto_rawDesc = "" + + "\n" + + "#com/daml/ledger/api/v2/crypto.proto\x12\x16com.daml.ledger.api.v2\"\xb1\x01\n" + + "\x10SigningPublicKey\x12?\n" + + "\x06format\x18\x01 \x01(\x0e2'.com.daml.ledger.api.v2.CryptoKeyFormatR\x06format\x12\x19\n" + + "\bkey_data\x18\x02 \x01(\fR\akeyData\x12A\n" + + "\bkey_spec\x18\x03 \x01(\x0e2&.com.daml.ledger.api.v2.SigningKeySpecR\akeySpec\"\xeb\x01\n" + + "\tSignature\x12?\n" + + "\x06format\x18\x01 \x01(\x0e2'.com.daml.ledger.api.v2.SignatureFormatR\x06format\x12\x1c\n" + + "\tsignature\x18\x02 \x01(\fR\tsignature\x12\x1b\n" + + "\tsigned_by\x18\x03 \x01(\tR\bsignedBy\x12b\n" + + "\x16signing_algorithm_spec\x18\x04 \x01(\x0e2,.com.daml.ledger.api.v2.SigningAlgorithmSpecR\x14signingAlgorithmSpec*\xb5\x01\n" + + "\x0eSigningKeySpec\x12 \n" + + "\x1cSIGNING_KEY_SPEC_UNSPECIFIED\x10\x00\x12\"\n" + + "\x1eSIGNING_KEY_SPEC_EC_CURVE25519\x10\x01\x12\x1c\n" + + "\x18SIGNING_KEY_SPEC_EC_P256\x10\x02\x12\x1c\n" + + "\x18SIGNING_KEY_SPEC_EC_P384\x10\x03\x12!\n" + + "\x1dSIGNING_KEY_SPEC_EC_SECP256K1\x10\x04*\xaa\x01\n" + + "\x0fCryptoKeyFormat\x12!\n" + + "\x1dCRYPTO_KEY_FORMAT_UNSPECIFIED\x10\x00\x12\x19\n" + + "\x15CRYPTO_KEY_FORMAT_DER\x10\x01\x12\x19\n" + + "\x15CRYPTO_KEY_FORMAT_RAW\x10\x02\x126\n" + + "2CRYPTO_KEY_FORMAT_DER_X509_SUBJECT_PUBLIC_KEY_INFO\x10\x03\"\x06\b\x90N\x10\x90N*\xb8\x01\n" + + "\x14SigningAlgorithmSpec\x12&\n" + + "\"SIGNING_ALGORITHM_SPEC_UNSPECIFIED\x10\x00\x12\"\n" + + "\x1eSIGNING_ALGORITHM_SPEC_ED25519\x10\x01\x12)\n" + + "%SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_256\x10\x02\x12)\n" + + "%SIGNING_ALGORITHM_SPEC_EC_DSA_SHA_384\x10\x03*\xa4\x01\n" + + "\x0fSignatureFormat\x12 \n" + + "\x1cSIGNATURE_FORMAT_UNSPECIFIED\x10\x00\x12\x18\n" + + "\x14SIGNATURE_FORMAT_RAW\x10\x01\x12\x18\n" + + "\x14SIGNATURE_FORMAT_DER\x10\x02\x12\x1b\n" + + "\x17SIGNATURE_FORMAT_CONCAT\x10\x03\x12\x1e\n" + + "\x19SIGNATURE_FORMAT_SYMBOLIC\x10\x90NB\xf8\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\vCryptoProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_crypto_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_crypto_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_crypto_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_crypto_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_crypto_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_crypto_proto_rawDesc), len(file_com_daml_ledger_api_v2_crypto_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_crypto_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_crypto_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_com_daml_ledger_api_v2_crypto_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_com_daml_ledger_api_v2_crypto_proto_goTypes = []any{ + (SigningKeySpec)(0), // 0: com.daml.ledger.api.v2.SigningKeySpec + (CryptoKeyFormat)(0), // 1: com.daml.ledger.api.v2.CryptoKeyFormat + (SigningAlgorithmSpec)(0), // 2: com.daml.ledger.api.v2.SigningAlgorithmSpec + (SignatureFormat)(0), // 3: com.daml.ledger.api.v2.SignatureFormat + (*SigningPublicKey)(nil), // 4: com.daml.ledger.api.v2.SigningPublicKey + (*Signature)(nil), // 5: com.daml.ledger.api.v2.Signature +} +var file_com_daml_ledger_api_v2_crypto_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.SigningPublicKey.format:type_name -> com.daml.ledger.api.v2.CryptoKeyFormat + 0, // 1: com.daml.ledger.api.v2.SigningPublicKey.key_spec:type_name -> com.daml.ledger.api.v2.SigningKeySpec + 3, // 2: com.daml.ledger.api.v2.Signature.format:type_name -> com.daml.ledger.api.v2.SignatureFormat + 2, // 3: com.daml.ledger.api.v2.Signature.signing_algorithm_spec:type_name -> com.daml.ledger.api.v2.SigningAlgorithmSpec + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_crypto_proto_init() } +func file_com_daml_ledger_api_v2_crypto_proto_init() { + if File_com_daml_ledger_api_v2_crypto_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_crypto_proto_rawDesc), len(file_com_daml_ledger_api_v2_crypto_proto_rawDesc)), + NumEnums: 4, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_crypto_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_crypto_proto_depIdxs, + EnumInfos: file_com_daml_ledger_api_v2_crypto_proto_enumTypes, + MessageInfos: file_com_daml_ledger_api_v2_crypto_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_crypto_proto = out.File + file_com_daml_ledger_api_v2_crypto_proto_goTypes = nil + file_com_daml_ledger_api_v2_crypto_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/event.pb.go b/chain/canton/types/com/daml/ledger/api/v2/event.pb.go new file mode 100644 index 00000000..847d3aef --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/event.pb.go @@ -0,0 +1,1016 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/event.proto + +package apiv2 + +import ( + rpc "google.golang.org/genproto/googleapis/rpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Events in transactions can have two primary shapes: +// +// - ACS delta: events can be CreatedEvent or ArchivedEvent +// - ledger effects: events can be CreatedEvent or ExercisedEvent +// +// In the update service the events are restricted to the events +// visible for the parties specified in the transaction filter. Each +// event message type below contains a “witness_parties“ field which +// indicates the subset of the requested parties that can see the event +// in question. +type Event struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Event: + // + // *Event_Created + // *Event_Archived + // *Event_Exercised + Event isEvent_Event `protobuf_oneof:"event"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Event) Reset() { + *x = Event{} + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Event) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Event) ProtoMessage() {} + +func (x *Event) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Event.ProtoReflect.Descriptor instead. +func (*Event) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_proto_rawDescGZIP(), []int{0} +} + +func (x *Event) GetEvent() isEvent_Event { + if x != nil { + return x.Event + } + return nil +} + +func (x *Event) GetCreated() *CreatedEvent { + if x != nil { + if x, ok := x.Event.(*Event_Created); ok { + return x.Created + } + } + return nil +} + +func (x *Event) GetArchived() *ArchivedEvent { + if x != nil { + if x, ok := x.Event.(*Event_Archived); ok { + return x.Archived + } + } + return nil +} + +func (x *Event) GetExercised() *ExercisedEvent { + if x != nil { + if x, ok := x.Event.(*Event_Exercised); ok { + return x.Exercised + } + } + return nil +} + +type isEvent_Event interface { + isEvent_Event() +} + +type Event_Created struct { + // The event as it appeared in the context of its original daml transaction on this participant node. + // In particular, the offset, node_id pair of the daml transaction are preserved. + Created *CreatedEvent `protobuf:"bytes,1,opt,name=created,proto3,oneof"` +} + +type Event_Archived struct { + Archived *ArchivedEvent `protobuf:"bytes,2,opt,name=archived,proto3,oneof"` +} + +type Event_Exercised struct { + Exercised *ExercisedEvent `protobuf:"bytes,3,opt,name=exercised,proto3,oneof"` +} + +func (*Event_Created) isEvent_Event() {} + +func (*Event_Archived) isEvent_Event() {} + +func (*Event_Exercised) isEvent_Event() {} + +// Records that a contract has been created, and choices may now be exercised on it. +type CreatedEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The offset of origin, which has contextual meaning, please see description at messages that include a CreatedEvent. + // Offsets are managed by the participant nodes. + // Transactions can thus NOT be assumed to have the same offsets on different participant nodes. + // It is a valid absolute offset (positive integer) + // + // Required + Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + // The position of this event in the originating transaction or reassignment. + // The origin has contextual meaning, please see description at messages that include a CreatedEvent. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of transactions. + // Must be valid node ID (non-negative integer) + // + // Required + NodeId int32 `protobuf:"varint,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // The ID of the created contract. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ContractId string `protobuf:"bytes,3,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // The template of the created contract. + // The identifier uses the package-id reference format. + // + // Required + TemplateId *Identifier `protobuf:"bytes,4,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The key of the created contract. + // This will be set if and only if “template_id“ defines a contract key. + // + // Optional + ContractKey *Value `protobuf:"bytes,5,opt,name=contract_key,json=contractKey,proto3" json:"contract_key,omitempty"` + // The hash of contract_key. + // This will be set if and only if “template_id“ defines a contract key. + // + // Optional: can be empty + ContractKeyHash []byte `protobuf:"bytes,16,opt,name=contract_key_hash,json=contractKeyHash,proto3" json:"contract_key_hash,omitempty"` + // The arguments that have been used to create the contract. + // + // Required + CreateArguments *Record `protobuf:"bytes,6,opt,name=create_arguments,json=createArguments,proto3" json:"create_arguments,omitempty"` + // Opaque representation of contract create event payload intended for forwarding + // to an API server as a contract disclosed as part of a command + // submission. + // + // Optional: can be empty + CreatedEventBlob []byte `protobuf:"bytes,7,opt,name=created_event_blob,json=createdEventBlob,proto3" json:"created_event_blob,omitempty"` + // Interface views specified in the transaction filter. + // Includes an “InterfaceView“ for each interface for which there is a “InterfaceFilter“ with + // + // - its party in the “witness_parties“ of this event, + // - and which is implemented by the template of this event, + // - and which has “include_interface_view“ set. + // + // Optional: can be empty + InterfaceViews []*InterfaceView `protobuf:"bytes,8,rep,name=interface_views,json=interfaceViews,proto3" json:"interface_views,omitempty"` + // The parties that are notified of this event. When a “CreatedEvent“ + // is returned as part of a transaction tree or ledger-effects transaction, this will include all + // the parties specified in the “TransactionFilter“ that are witnesses of the event + // (the stakeholders of the contract and all informees of all the ancestors + // of this create action that this participant knows about). + // If served as part of a ACS delta transaction those will + // be limited to all parties specified in the “TransactionFilter“ that + // are stakeholders of the contract (i.e. either signatories or observers). + // If the “CreatedEvent“ is returned as part of an AssignedEvent, + // ActiveContract or IncompleteUnassigned (so the event is related to + // an assignment or unassignment): this will include all parties of the + // “TransactionFilter“ that are stakeholders of the contract. + // + // The behavior of reading create events visible to parties not hosted + // on the participant node serving the Ledger API is undefined. Concretely, + // there is neither a guarantee that the participant node will serve all their + // create events on the ACS stream, nor is there a guarantee that matching archive + // events are delivered for such create events. + // + // For most clients this is not a problem, as they only read events for parties + // that are hosted on the participant node. If you need to read events + // for parties that may not be hosted at all times on the participant node, + // subscribe to the “TopologyEvent“s for that party by setting a corresponding + // “UpdateFormat“. Using these events, query the ACS as-of an offset where the + // party is hosted on the participant node, and ignore create events at offsets + // where the party is not hosted on the participant node. + // + // Required: must be non-empty + WitnessParties []string `protobuf:"bytes,9,rep,name=witness_parties,json=witnessParties,proto3" json:"witness_parties,omitempty"` + // The signatories for this contract as specified by the template. + // + // Required: must be non-empty + Signatories []string `protobuf:"bytes,10,rep,name=signatories,proto3" json:"signatories,omitempty"` + // The observers for this contract as specified explicitly by the template or implicitly as choice controllers. + // This field never contains parties that are signatories. + // + // Optional: can be empty + Observers []string `protobuf:"bytes,11,rep,name=observers,proto3" json:"observers,omitempty"` + // Ledger effective time of the transaction that created the contract. + // + // Required + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + // The package name of the created contract. + // + // Required + PackageName string `protobuf:"bytes,13,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // Whether this event would be part of respective ACS_DELTA shaped stream, + // and should therefore considered when tracking contract activeness on the client-side. + // + // Required + AcsDelta bool `protobuf:"varint,14,opt,name=acs_delta,json=acsDelta,proto3" json:"acs_delta,omitempty"` + // A package-id present in the participant package store that typechecks the contract's argument. + // This may differ from the package-id of the template used to create the contract. + // For contracts created before Canton 3.4, this field matches the contract's creation package-id. + // + // NOTE: Experimental, server internal concept, not for client consumption. Subject to change without notice. + // + // Required + RepresentativePackageId string `protobuf:"bytes,15,opt,name=representative_package_id,json=representativePackageId,proto3" json:"representative_package_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreatedEvent) Reset() { + *x = CreatedEvent{} + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreatedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreatedEvent) ProtoMessage() {} + +func (x *CreatedEvent) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreatedEvent.ProtoReflect.Descriptor instead. +func (*CreatedEvent) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_proto_rawDescGZIP(), []int{1} +} + +func (x *CreatedEvent) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *CreatedEvent) GetNodeId() int32 { + if x != nil { + return x.NodeId + } + return 0 +} + +func (x *CreatedEvent) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *CreatedEvent) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *CreatedEvent) GetContractKey() *Value { + if x != nil { + return x.ContractKey + } + return nil +} + +func (x *CreatedEvent) GetContractKeyHash() []byte { + if x != nil { + return x.ContractKeyHash + } + return nil +} + +func (x *CreatedEvent) GetCreateArguments() *Record { + if x != nil { + return x.CreateArguments + } + return nil +} + +func (x *CreatedEvent) GetCreatedEventBlob() []byte { + if x != nil { + return x.CreatedEventBlob + } + return nil +} + +func (x *CreatedEvent) GetInterfaceViews() []*InterfaceView { + if x != nil { + return x.InterfaceViews + } + return nil +} + +func (x *CreatedEvent) GetWitnessParties() []string { + if x != nil { + return x.WitnessParties + } + return nil +} + +func (x *CreatedEvent) GetSignatories() []string { + if x != nil { + return x.Signatories + } + return nil +} + +func (x *CreatedEvent) GetObservers() []string { + if x != nil { + return x.Observers + } + return nil +} + +func (x *CreatedEvent) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + +func (x *CreatedEvent) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *CreatedEvent) GetAcsDelta() bool { + if x != nil { + return x.AcsDelta + } + return false +} + +func (x *CreatedEvent) GetRepresentativePackageId() string { + if x != nil { + return x.RepresentativePackageId + } + return "" +} + +// View of a create event matched by an interface filter. +type InterfaceView struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The interface implemented by the matched event. + // The identifier uses the package-id reference format. + // + // Required + InterfaceId *Identifier `protobuf:"bytes,1,opt,name=interface_id,json=interfaceId,proto3" json:"interface_id,omitempty"` + // Whether the view was successfully computed, and if not, + // the reason for the error. The error is reported using the same rules + // for error codes and messages as the errors returned for API requests. + // + // Required + ViewStatus *rpc.Status `protobuf:"bytes,2,opt,name=view_status,json=viewStatus,proto3" json:"view_status,omitempty"` + // The value of the interface's view method on this event. + // Set if it was requested in the “InterfaceFilter“ and it could be + // successfully computed. + // + // Optional + ViewValue *Record `protobuf:"bytes,3,opt,name=view_value,json=viewValue,proto3" json:"view_value,omitempty"` + // The package defining the interface implementation used to compute the view. + // Can be different from the package that was used to create the contract itself, + // as the contract arguments can be upgraded or downgraded using smart-contract upgrading + // as part of computing the interface view. + // Populated if the view computation is successful, otherwise empty. + // + // Optional + ImplementationPackageId string `protobuf:"bytes,4,opt,name=implementation_package_id,json=implementationPackageId,proto3" json:"implementation_package_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InterfaceView) Reset() { + *x = InterfaceView{} + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InterfaceView) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InterfaceView) ProtoMessage() {} + +func (x *InterfaceView) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InterfaceView.ProtoReflect.Descriptor instead. +func (*InterfaceView) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_proto_rawDescGZIP(), []int{2} +} + +func (x *InterfaceView) GetInterfaceId() *Identifier { + if x != nil { + return x.InterfaceId + } + return nil +} + +func (x *InterfaceView) GetViewStatus() *rpc.Status { + if x != nil { + return x.ViewStatus + } + return nil +} + +func (x *InterfaceView) GetViewValue() *Record { + if x != nil { + return x.ViewValue + } + return nil +} + +func (x *InterfaceView) GetImplementationPackageId() string { + if x != nil { + return x.ImplementationPackageId + } + return "" +} + +// Records that a contract has been archived, and choices may no longer be exercised on it. +type ArchivedEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The offset of origin. + // Offsets are managed by the participant nodes. + // Transactions can thus NOT be assumed to have the same offsets on different participant nodes. + // It is a valid absolute offset (positive integer) + // + // Required + Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + // The position of this event in the originating transaction or reassignment. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of transactions. + // Must be valid node ID (non-negative integer) + // + // Required + NodeId int32 `protobuf:"varint,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // The ID of the archived contract. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ContractId string `protobuf:"bytes,3,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // Identifies the template that defines the choice that archived the contract. + // This template's package-id may differ from the target contract's package-id + // if the target contract has been upgraded or downgraded. + // + // The identifier uses the package-id reference format. + // + // Required + TemplateId *Identifier `protobuf:"bytes,4,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The parties that are notified of this event. For an “ArchivedEvent“, + // these are the intersection of the stakeholders of the contract in + // question and the parties specified in the “TransactionFilter“. The + // stakeholders are the union of the signatories and the observers of + // the contract. + // Each one of its elements must be a valid PartyIdString (as described + // in “value.proto“). + // + // Required: must be non-empty + WitnessParties []string `protobuf:"bytes,5,rep,name=witness_parties,json=witnessParties,proto3" json:"witness_parties,omitempty"` + // The package name of the contract. + // + // Required + PackageName string `protobuf:"bytes,6,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // The interfaces implemented by the target template that have been + // matched from the interface filter query. + // Populated only in case interface filters with include_interface_view set. + // + // If defined, the identifier uses the package-id reference format. + // + // Optional: can be empty + ImplementedInterfaces []*Identifier `protobuf:"bytes,7,rep,name=implemented_interfaces,json=implementedInterfaces,proto3" json:"implemented_interfaces,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ArchivedEvent) Reset() { + *x = ArchivedEvent{} + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ArchivedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ArchivedEvent) ProtoMessage() {} + +func (x *ArchivedEvent) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ArchivedEvent.ProtoReflect.Descriptor instead. +func (*ArchivedEvent) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_proto_rawDescGZIP(), []int{3} +} + +func (x *ArchivedEvent) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *ArchivedEvent) GetNodeId() int32 { + if x != nil { + return x.NodeId + } + return 0 +} + +func (x *ArchivedEvent) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *ArchivedEvent) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *ArchivedEvent) GetWitnessParties() []string { + if x != nil { + return x.WitnessParties + } + return nil +} + +func (x *ArchivedEvent) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *ArchivedEvent) GetImplementedInterfaces() []*Identifier { + if x != nil { + return x.ImplementedInterfaces + } + return nil +} + +// Records that a choice has been exercised on a target contract. +type ExercisedEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The offset of origin. + // Offsets are managed by the participant nodes. + // Transactions can thus NOT be assumed to have the same offsets on different participant nodes. + // It is a valid absolute offset (positive integer) + // + // Required + Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + // The position of this event in the originating transaction or reassignment. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of transactions. + // Must be valid node ID (non-negative integer) + // + // Required + NodeId int32 `protobuf:"varint,2,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // The ID of the target contract. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ContractId string `protobuf:"bytes,3,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // Identifies the template that defines the executed choice. + // This template's package-id may differ from the target contract's package-id + // if the target contract has been upgraded or downgraded. + // + // The identifier uses the package-id reference format. + // + // Required + TemplateId *Identifier `protobuf:"bytes,4,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The interface where the choice is defined, if inherited. + // If defined, the identifier uses the package-id reference format. + // + // Optional + InterfaceId *Identifier `protobuf:"bytes,5,opt,name=interface_id,json=interfaceId,proto3" json:"interface_id,omitempty"` + // The choice that was exercised on the target contract. + // Must be a valid NameString (as described in “value.proto“). + // + // Required + Choice string `protobuf:"bytes,6,opt,name=choice,proto3" json:"choice,omitempty"` + // The argument of the exercised choice. + // + // Required + ChoiceArgument *Value `protobuf:"bytes,7,opt,name=choice_argument,json=choiceArgument,proto3" json:"choice_argument,omitempty"` + // The parties that exercised the choice. + // Each element must be a valid PartyIdString (as described in “value.proto“). + // + // Required: must be non-empty + ActingParties []string `protobuf:"bytes,8,rep,name=acting_parties,json=actingParties,proto3" json:"acting_parties,omitempty"` + // If true, the target contract may no longer be exercised. + // + // Required + Consuming bool `protobuf:"varint,9,opt,name=consuming,proto3" json:"consuming,omitempty"` + // The parties that are notified of this event. The witnesses of an exercise + // node will depend on whether the exercise was consuming or not. + // If consuming, the witnesses are the union of the stakeholders, + // the actors and all informees of all the ancestors of this event this + // participant knows about. + // If not consuming, the witnesses are the union of the signatories, + // the actors and all informees of all the ancestors of this event this + // participant knows about. + // In both cases the witnesses are limited to the querying parties, or not + // limited in case anyParty filters are used. + // Note that the actors might not necessarily be observers + // and thus stakeholders. This is the case when the controllers of a + // choice are specified using "flexible controllers", using the + // “choice ... controller“ syntax, and said controllers are not + // explicitly marked as observers. + // Each element must be a valid PartyIdString (as described in “value.proto“). + // + // Required: must be non-empty + WitnessParties []string `protobuf:"bytes,10,rep,name=witness_parties,json=witnessParties,proto3" json:"witness_parties,omitempty"` + // Specifies the upper boundary of the node ids of the events in the same transaction that appeared as a result of + // this “ExercisedEvent“. This allows unambiguous identification of all the members of the subtree rooted at this + // node. A full subtree can be constructed when all descendant nodes are present in the stream. If nodes are heavily + // filtered, it is only possible to determine if a node is in a consequent subtree or not. + // + // Required + LastDescendantNodeId int32 `protobuf:"varint,11,opt,name=last_descendant_node_id,json=lastDescendantNodeId,proto3" json:"last_descendant_node_id,omitempty"` + // The result of exercising the choice. + // + // Optional + ExerciseResult *Value `protobuf:"bytes,12,opt,name=exercise_result,json=exerciseResult,proto3" json:"exercise_result,omitempty"` + // The package name of the contract. + // + // Required + PackageName string `protobuf:"bytes,13,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // If the event is consuming, the interfaces implemented by the target template that have been + // matched from the interface filter query. + // Populated only in case interface filters with include_interface_view set. + // + // The identifier uses the package-id reference format. + // + // Optional: can be empty + ImplementedInterfaces []*Identifier `protobuf:"bytes,14,rep,name=implemented_interfaces,json=implementedInterfaces,proto3" json:"implemented_interfaces,omitempty"` + // Whether this event would be part of respective ACS_DELTA shaped stream, + // and should therefore considered when tracking contract activeness on the client-side. + // + // Required + AcsDelta bool `protobuf:"varint,15,opt,name=acs_delta,json=acsDelta,proto3" json:"acs_delta,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExercisedEvent) Reset() { + *x = ExercisedEvent{} + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExercisedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExercisedEvent) ProtoMessage() {} + +func (x *ExercisedEvent) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExercisedEvent.ProtoReflect.Descriptor instead. +func (*ExercisedEvent) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_proto_rawDescGZIP(), []int{4} +} + +func (x *ExercisedEvent) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *ExercisedEvent) GetNodeId() int32 { + if x != nil { + return x.NodeId + } + return 0 +} + +func (x *ExercisedEvent) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *ExercisedEvent) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *ExercisedEvent) GetInterfaceId() *Identifier { + if x != nil { + return x.InterfaceId + } + return nil +} + +func (x *ExercisedEvent) GetChoice() string { + if x != nil { + return x.Choice + } + return "" +} + +func (x *ExercisedEvent) GetChoiceArgument() *Value { + if x != nil { + return x.ChoiceArgument + } + return nil +} + +func (x *ExercisedEvent) GetActingParties() []string { + if x != nil { + return x.ActingParties + } + return nil +} + +func (x *ExercisedEvent) GetConsuming() bool { + if x != nil { + return x.Consuming + } + return false +} + +func (x *ExercisedEvent) GetWitnessParties() []string { + if x != nil { + return x.WitnessParties + } + return nil +} + +func (x *ExercisedEvent) GetLastDescendantNodeId() int32 { + if x != nil { + return x.LastDescendantNodeId + } + return 0 +} + +func (x *ExercisedEvent) GetExerciseResult() *Value { + if x != nil { + return x.ExerciseResult + } + return nil +} + +func (x *ExercisedEvent) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *ExercisedEvent) GetImplementedInterfaces() []*Identifier { + if x != nil { + return x.ImplementedInterfaces + } + return nil +} + +func (x *ExercisedEvent) GetAcsDelta() bool { + if x != nil { + return x.AcsDelta + } + return false +} + +var File_com_daml_ledger_api_v2_event_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_event_proto_rawDesc = "" + + "\n" + + "\"com/daml/ledger/api/v2/event.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/value.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17google/rpc/status.proto\"\xdf\x01\n" + + "\x05Event\x12@\n" + + "\acreated\x18\x01 \x01(\v2$.com.daml.ledger.api.v2.CreatedEventH\x00R\acreated\x12C\n" + + "\barchived\x18\x02 \x01(\v2%.com.daml.ledger.api.v2.ArchivedEventH\x00R\barchived\x12F\n" + + "\texercised\x18\x03 \x01(\v2&.com.daml.ledger.api.v2.ExercisedEventH\x00R\texercisedB\a\n" + + "\x05event\"\xfc\x05\n" + + "\fCreatedEvent\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x03R\x06offset\x12\x17\n" + + "\anode_id\x18\x02 \x01(\x05R\x06nodeId\x12\x1f\n" + + "\vcontract_id\x18\x03 \x01(\tR\n" + + "contractId\x12C\n" + + "\vtemplate_id\x18\x04 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12@\n" + + "\fcontract_key\x18\x05 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\vcontractKey\x12*\n" + + "\x11contract_key_hash\x18\x10 \x01(\fR\x0fcontractKeyHash\x12I\n" + + "\x10create_arguments\x18\x06 \x01(\v2\x1e.com.daml.ledger.api.v2.RecordR\x0fcreateArguments\x12,\n" + + "\x12created_event_blob\x18\a \x01(\fR\x10createdEventBlob\x12N\n" + + "\x0finterface_views\x18\b \x03(\v2%.com.daml.ledger.api.v2.InterfaceViewR\x0einterfaceViews\x12'\n" + + "\x0fwitness_parties\x18\t \x03(\tR\x0ewitnessParties\x12 \n" + + "\vsignatories\x18\n" + + " \x03(\tR\vsignatories\x12\x1c\n" + + "\tobservers\x18\v \x03(\tR\tobservers\x129\n" + + "\n" + + "created_at\x18\f \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x12!\n" + + "\fpackage_name\x18\r \x01(\tR\vpackageName\x12\x1b\n" + + "\tacs_delta\x18\x0e \x01(\bR\bacsDelta\x12:\n" + + "\x19representative_package_id\x18\x0f \x01(\tR\x17representativePackageId\"\x86\x02\n" + + "\rInterfaceView\x12E\n" + + "\finterface_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\vinterfaceId\x123\n" + + "\vview_status\x18\x02 \x01(\v2\x12.google.rpc.StatusR\n" + + "viewStatus\x12=\n" + + "\n" + + "view_value\x18\x03 \x01(\v2\x1e.com.daml.ledger.api.v2.RecordR\tviewValue\x12:\n" + + "\x19implementation_package_id\x18\x04 \x01(\tR\x17implementationPackageId\"\xcd\x02\n" + + "\rArchivedEvent\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x03R\x06offset\x12\x17\n" + + "\anode_id\x18\x02 \x01(\x05R\x06nodeId\x12\x1f\n" + + "\vcontract_id\x18\x03 \x01(\tR\n" + + "contractId\x12C\n" + + "\vtemplate_id\x18\x04 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12'\n" + + "\x0fwitness_parties\x18\x05 \x03(\tR\x0ewitnessParties\x12!\n" + + "\fpackage_name\x18\x06 \x01(\tR\vpackageName\x12Y\n" + + "\x16implemented_interfaces\x18\a \x03(\v2\".com.daml.ledger.api.v2.IdentifierR\x15implementedInterfaces\"\xd6\x05\n" + + "\x0eExercisedEvent\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x03R\x06offset\x12\x17\n" + + "\anode_id\x18\x02 \x01(\x05R\x06nodeId\x12\x1f\n" + + "\vcontract_id\x18\x03 \x01(\tR\n" + + "contractId\x12C\n" + + "\vtemplate_id\x18\x04 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12E\n" + + "\finterface_id\x18\x05 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\vinterfaceId\x12\x16\n" + + "\x06choice\x18\x06 \x01(\tR\x06choice\x12F\n" + + "\x0fchoice_argument\x18\a \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x0echoiceArgument\x12%\n" + + "\x0eacting_parties\x18\b \x03(\tR\ractingParties\x12\x1c\n" + + "\tconsuming\x18\t \x01(\bR\tconsuming\x12'\n" + + "\x0fwitness_parties\x18\n" + + " \x03(\tR\x0ewitnessParties\x125\n" + + "\x17last_descendant_node_id\x18\v \x01(\x05R\x14lastDescendantNodeId\x12F\n" + + "\x0fexercise_result\x18\f \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x0eexerciseResult\x12!\n" + + "\fpackage_name\x18\r \x01(\tR\vpackageName\x12Y\n" + + "\x16implemented_interfaces\x18\x0e \x03(\v2\".com.daml.ledger.api.v2.IdentifierR\x15implementedInterfaces\x12\x1b\n" + + "\tacs_delta\x18\x0f \x01(\bR\bacsDeltaB\xf7\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\n" + + "EventProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_event_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_event_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_event_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_event_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_event_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_event_proto_rawDesc), len(file_com_daml_ledger_api_v2_event_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_event_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_event_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_com_daml_ledger_api_v2_event_proto_goTypes = []any{ + (*Event)(nil), // 0: com.daml.ledger.api.v2.Event + (*CreatedEvent)(nil), // 1: com.daml.ledger.api.v2.CreatedEvent + (*InterfaceView)(nil), // 2: com.daml.ledger.api.v2.InterfaceView + (*ArchivedEvent)(nil), // 3: com.daml.ledger.api.v2.ArchivedEvent + (*ExercisedEvent)(nil), // 4: com.daml.ledger.api.v2.ExercisedEvent + (*Identifier)(nil), // 5: com.daml.ledger.api.v2.Identifier + (*Value)(nil), // 6: com.daml.ledger.api.v2.Value + (*Record)(nil), // 7: com.daml.ledger.api.v2.Record + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*rpc.Status)(nil), // 9: google.rpc.Status +} +var file_com_daml_ledger_api_v2_event_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.Event.created:type_name -> com.daml.ledger.api.v2.CreatedEvent + 3, // 1: com.daml.ledger.api.v2.Event.archived:type_name -> com.daml.ledger.api.v2.ArchivedEvent + 4, // 2: com.daml.ledger.api.v2.Event.exercised:type_name -> com.daml.ledger.api.v2.ExercisedEvent + 5, // 3: com.daml.ledger.api.v2.CreatedEvent.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 6, // 4: com.daml.ledger.api.v2.CreatedEvent.contract_key:type_name -> com.daml.ledger.api.v2.Value + 7, // 5: com.daml.ledger.api.v2.CreatedEvent.create_arguments:type_name -> com.daml.ledger.api.v2.Record + 2, // 6: com.daml.ledger.api.v2.CreatedEvent.interface_views:type_name -> com.daml.ledger.api.v2.InterfaceView + 8, // 7: com.daml.ledger.api.v2.CreatedEvent.created_at:type_name -> google.protobuf.Timestamp + 5, // 8: com.daml.ledger.api.v2.InterfaceView.interface_id:type_name -> com.daml.ledger.api.v2.Identifier + 9, // 9: com.daml.ledger.api.v2.InterfaceView.view_status:type_name -> google.rpc.Status + 7, // 10: com.daml.ledger.api.v2.InterfaceView.view_value:type_name -> com.daml.ledger.api.v2.Record + 5, // 11: com.daml.ledger.api.v2.ArchivedEvent.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 5, // 12: com.daml.ledger.api.v2.ArchivedEvent.implemented_interfaces:type_name -> com.daml.ledger.api.v2.Identifier + 5, // 13: com.daml.ledger.api.v2.ExercisedEvent.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 5, // 14: com.daml.ledger.api.v2.ExercisedEvent.interface_id:type_name -> com.daml.ledger.api.v2.Identifier + 6, // 15: com.daml.ledger.api.v2.ExercisedEvent.choice_argument:type_name -> com.daml.ledger.api.v2.Value + 6, // 16: com.daml.ledger.api.v2.ExercisedEvent.exercise_result:type_name -> com.daml.ledger.api.v2.Value + 5, // 17: com.daml.ledger.api.v2.ExercisedEvent.implemented_interfaces:type_name -> com.daml.ledger.api.v2.Identifier + 18, // [18:18] is the sub-list for method output_type + 18, // [18:18] is the sub-list for method input_type + 18, // [18:18] is the sub-list for extension type_name + 18, // [18:18] is the sub-list for extension extendee + 0, // [0:18] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_event_proto_init() } +func file_com_daml_ledger_api_v2_event_proto_init() { + if File_com_daml_ledger_api_v2_event_proto != nil { + return + } + file_com_daml_ledger_api_v2_value_proto_init() + file_com_daml_ledger_api_v2_event_proto_msgTypes[0].OneofWrappers = []any{ + (*Event_Created)(nil), + (*Event_Archived)(nil), + (*Event_Exercised)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_event_proto_rawDesc), len(file_com_daml_ledger_api_v2_event_proto_rawDesc)), + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_event_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_event_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_event_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_event_proto = out.File + file_com_daml_ledger_api_v2_event_proto_goTypes = nil + file_com_daml_ledger_api_v2_event_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/event_query_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/event_query_service.pb.go new file mode 100644 index 00000000..bf1e169b --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/event_query_service.pb.go @@ -0,0 +1,344 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/event_query_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetEventsByContractIdRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The contract id being queried. + // + // Required + ContractId string `protobuf:"bytes,1,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // Format of the events in the result, the presentation will be of TRANSACTION_SHAPE_ACS_DELTA. + // + // Required + EventFormat *EventFormat `protobuf:"bytes,3,opt,name=event_format,json=eventFormat,proto3" json:"event_format,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEventsByContractIdRequest) Reset() { + *x = GetEventsByContractIdRequest{} + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEventsByContractIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEventsByContractIdRequest) ProtoMessage() {} + +func (x *GetEventsByContractIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEventsByContractIdRequest.ProtoReflect.Descriptor instead. +func (*GetEventsByContractIdRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_query_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetEventsByContractIdRequest) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *GetEventsByContractIdRequest) GetEventFormat() *EventFormat { + if x != nil { + return x.EventFormat + } + return nil +} + +type GetEventsByContractIdResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The create event for the contract with the “contract_id“ given in the request + // provided it exists and has not yet been pruned. + // + // Optional + Created *Created `protobuf:"bytes,1,opt,name=created,proto3" json:"created,omitempty"` + // The archive event for the contract with the “contract_id“ given in the request + // provided such an archive event exists and it has not yet been pruned. + // + // Optional + Archived *Archived `protobuf:"bytes,2,opt,name=archived,proto3" json:"archived,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetEventsByContractIdResponse) Reset() { + *x = GetEventsByContractIdResponse{} + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetEventsByContractIdResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEventsByContractIdResponse) ProtoMessage() {} + +func (x *GetEventsByContractIdResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEventsByContractIdResponse.ProtoReflect.Descriptor instead. +func (*GetEventsByContractIdResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_query_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetEventsByContractIdResponse) GetCreated() *Created { + if x != nil { + return x.Created + } + return nil +} + +func (x *GetEventsByContractIdResponse) GetArchived() *Archived { + if x != nil { + return x.Archived + } + return nil +} + +type Created struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The event as it appeared in the context of its original update (i.e. daml transaction or + // reassignment) on this participant node. You can use its offset and node_id to find the + // corresponding update and the node within it. + // + // Required + CreatedEvent *CreatedEvent `protobuf:"bytes,1,opt,name=created_event,json=createdEvent,proto3" json:"created_event,omitempty"` + // The synchronizer which sequenced the creation of the contract + // + // Required + SynchronizerId string `protobuf:"bytes,2,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Created) Reset() { + *x = Created{} + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Created) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Created) ProtoMessage() {} + +func (x *Created) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Created.ProtoReflect.Descriptor instead. +func (*Created) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_query_service_proto_rawDescGZIP(), []int{2} +} + +func (x *Created) GetCreatedEvent() *CreatedEvent { + if x != nil { + return x.CreatedEvent + } + return nil +} + +func (x *Created) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +type Archived struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + ArchivedEvent *ArchivedEvent `protobuf:"bytes,1,opt,name=archived_event,json=archivedEvent,proto3" json:"archived_event,omitempty"` + // The synchronizer which sequenced the archival of the contract + // + // Required + SynchronizerId string `protobuf:"bytes,2,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Archived) Reset() { + *x = Archived{} + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Archived) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Archived) ProtoMessage() {} + +func (x *Archived) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Archived.ProtoReflect.Descriptor instead. +func (*Archived) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_event_query_service_proto_rawDescGZIP(), []int{3} +} + +func (x *Archived) GetArchivedEvent() *ArchivedEvent { + if x != nil { + return x.ArchivedEvent + } + return nil +} + +func (x *Archived) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +var File_com_daml_ledger_api_v2_event_query_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_event_query_service_proto_rawDesc = "" + + "\n" + + "0com/daml/ledger/api/v2/event_query_service.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/event.proto\x1a/com/daml/ledger/api/v2/transaction_filter.proto\"\xa1\x01\n" + + "\x1cGetEventsByContractIdRequest\x12\x1f\n" + + "\vcontract_id\x18\x01 \x01(\tR\n" + + "contractId\x12F\n" + + "\fevent_format\x18\x03 \x01(\v2#.com.daml.ledger.api.v2.EventFormatR\veventFormatJ\x04\b\x02\x10\x03R\x12requesting_parties\"\x98\x01\n" + + "\x1dGetEventsByContractIdResponse\x129\n" + + "\acreated\x18\x01 \x01(\v2\x1f.com.daml.ledger.api.v2.CreatedR\acreated\x12<\n" + + "\barchived\x18\x02 \x01(\v2 .com.daml.ledger.api.v2.ArchivedR\barchived\"}\n" + + "\aCreated\x12I\n" + + "\rcreated_event\x18\x01 \x01(\v2$.com.daml.ledger.api.v2.CreatedEventR\fcreatedEvent\x12'\n" + + "\x0fsynchronizer_id\x18\x02 \x01(\tR\x0esynchronizerId\"\x81\x01\n" + + "\bArchived\x12L\n" + + "\x0earchived_event\x18\x01 \x01(\v2%.com.daml.ledger.api.v2.ArchivedEventR\rarchivedEvent\x12'\n" + + "\x0fsynchronizer_id\x18\x02 \x01(\tR\x0esynchronizerId2\x9a\x01\n" + + "\x11EventQueryService\x12\x84\x01\n" + + "\x15GetEventsByContractId\x124.com.daml.ledger.api.v2.GetEventsByContractIdRequest\x1a5.com.daml.ledger.api.v2.GetEventsByContractIdResponseB\x83\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x16EventQueryServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_event_query_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_event_query_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_event_query_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_event_query_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_event_query_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_event_query_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_event_query_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_event_query_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_com_daml_ledger_api_v2_event_query_service_proto_goTypes = []any{ + (*GetEventsByContractIdRequest)(nil), // 0: com.daml.ledger.api.v2.GetEventsByContractIdRequest + (*GetEventsByContractIdResponse)(nil), // 1: com.daml.ledger.api.v2.GetEventsByContractIdResponse + (*Created)(nil), // 2: com.daml.ledger.api.v2.Created + (*Archived)(nil), // 3: com.daml.ledger.api.v2.Archived + (*EventFormat)(nil), // 4: com.daml.ledger.api.v2.EventFormat + (*CreatedEvent)(nil), // 5: com.daml.ledger.api.v2.CreatedEvent + (*ArchivedEvent)(nil), // 6: com.daml.ledger.api.v2.ArchivedEvent +} +var file_com_daml_ledger_api_v2_event_query_service_proto_depIdxs = []int32{ + 4, // 0: com.daml.ledger.api.v2.GetEventsByContractIdRequest.event_format:type_name -> com.daml.ledger.api.v2.EventFormat + 2, // 1: com.daml.ledger.api.v2.GetEventsByContractIdResponse.created:type_name -> com.daml.ledger.api.v2.Created + 3, // 2: com.daml.ledger.api.v2.GetEventsByContractIdResponse.archived:type_name -> com.daml.ledger.api.v2.Archived + 5, // 3: com.daml.ledger.api.v2.Created.created_event:type_name -> com.daml.ledger.api.v2.CreatedEvent + 6, // 4: com.daml.ledger.api.v2.Archived.archived_event:type_name -> com.daml.ledger.api.v2.ArchivedEvent + 0, // 5: com.daml.ledger.api.v2.EventQueryService.GetEventsByContractId:input_type -> com.daml.ledger.api.v2.GetEventsByContractIdRequest + 1, // 6: com.daml.ledger.api.v2.EventQueryService.GetEventsByContractId:output_type -> com.daml.ledger.api.v2.GetEventsByContractIdResponse + 6, // [6:7] is the sub-list for method output_type + 5, // [5:6] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_event_query_service_proto_init() } +func file_com_daml_ledger_api_v2_event_query_service_proto_init() { + if File_com_daml_ledger_api_v2_event_query_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_event_proto_init() + file_com_daml_ledger_api_v2_transaction_filter_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_event_query_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_event_query_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_event_query_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_event_query_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_event_query_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_event_query_service_proto = out.File + file_com_daml_ledger_api_v2_event_query_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_event_query_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/event_query_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/event_query_service_grpc.pb.go new file mode 100644 index 00000000..37141e0b --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/event_query_service_grpc.pb.go @@ -0,0 +1,142 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/event_query_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + EventQueryService_GetEventsByContractId_FullMethodName = "/com.daml.ledger.api.v2.EventQueryService/GetEventsByContractId" +) + +// EventQueryServiceClient is the client API for EventQueryService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Query events by contract id. +// +// Note that querying by contract key is not (yet) supported, as contract keys +// are not supported (yet) in multi-synchronizer scenarios. +type EventQueryServiceClient interface { + // Get the create and the consuming exercise event for the contract with the provided ID. + // No events will be returned for contracts that have been pruned because they + // have already been archived before the latest pruning offset. + // If the contract cannot be found for the request, or all the contract-events are filtered, a CONTRACT_EVENTS_NOT_FOUND error will be raised. + GetEventsByContractId(ctx context.Context, in *GetEventsByContractIdRequest, opts ...grpc.CallOption) (*GetEventsByContractIdResponse, error) +} + +type eventQueryServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewEventQueryServiceClient(cc grpc.ClientConnInterface) EventQueryServiceClient { + return &eventQueryServiceClient{cc} +} + +func (c *eventQueryServiceClient) GetEventsByContractId(ctx context.Context, in *GetEventsByContractIdRequest, opts ...grpc.CallOption) (*GetEventsByContractIdResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetEventsByContractIdResponse) + err := c.cc.Invoke(ctx, EventQueryService_GetEventsByContractId_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EventQueryServiceServer is the server API for EventQueryService service. +// All implementations must embed UnimplementedEventQueryServiceServer +// for forward compatibility. +// +// Query events by contract id. +// +// Note that querying by contract key is not (yet) supported, as contract keys +// are not supported (yet) in multi-synchronizer scenarios. +type EventQueryServiceServer interface { + // Get the create and the consuming exercise event for the contract with the provided ID. + // No events will be returned for contracts that have been pruned because they + // have already been archived before the latest pruning offset. + // If the contract cannot be found for the request, or all the contract-events are filtered, a CONTRACT_EVENTS_NOT_FOUND error will be raised. + GetEventsByContractId(context.Context, *GetEventsByContractIdRequest) (*GetEventsByContractIdResponse, error) + mustEmbedUnimplementedEventQueryServiceServer() +} + +// UnimplementedEventQueryServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedEventQueryServiceServer struct{} + +func (UnimplementedEventQueryServiceServer) GetEventsByContractId(context.Context, *GetEventsByContractIdRequest) (*GetEventsByContractIdResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetEventsByContractId not implemented") +} +func (UnimplementedEventQueryServiceServer) mustEmbedUnimplementedEventQueryServiceServer() {} +func (UnimplementedEventQueryServiceServer) testEmbeddedByValue() {} + +// UnsafeEventQueryServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to EventQueryServiceServer will +// result in compilation errors. +type UnsafeEventQueryServiceServer interface { + mustEmbedUnimplementedEventQueryServiceServer() +} + +func RegisterEventQueryServiceServer(s grpc.ServiceRegistrar, srv EventQueryServiceServer) { + // If the following call pancis, it indicates UnimplementedEventQueryServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&EventQueryService_ServiceDesc, srv) +} + +func _EventQueryService_GetEventsByContractId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetEventsByContractIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventQueryServiceServer).GetEventsByContractId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: EventQueryService_GetEventsByContractId_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventQueryServiceServer).GetEventsByContractId(ctx, req.(*GetEventsByContractIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// EventQueryService_ServiceDesc is the grpc.ServiceDesc for EventQueryService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var EventQueryService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.EventQueryService", + HandlerType: (*EventQueryServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetEventsByContractId", + Handler: _EventQueryService_GetEventsByContractId_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/event_query_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/experimental_features.pb.go b/chain/canton/types/com/daml/ledger/api/v2/experimental_features.pb.go new file mode 100644 index 00000000..6bbdb00e --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/experimental_features.pb.go @@ -0,0 +1,288 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/experimental_features.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// See the feature message definitions for descriptions. +type ExperimentalFeatures struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional + StaticTime *ExperimentalStaticTime `protobuf:"bytes,1,opt,name=static_time,json=staticTime,proto3" json:"static_time,omitempty"` + // Optional + CommandInspectionService *ExperimentalCommandInspectionService `protobuf:"bytes,2,opt,name=command_inspection_service,json=commandInspectionService,proto3" json:"command_inspection_service,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExperimentalFeatures) Reset() { + *x = ExperimentalFeatures{} + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExperimentalFeatures) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExperimentalFeatures) ProtoMessage() {} + +func (x *ExperimentalFeatures) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExperimentalFeatures.ProtoReflect.Descriptor instead. +func (*ExperimentalFeatures) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_experimental_features_proto_rawDescGZIP(), []int{0} +} + +func (x *ExperimentalFeatures) GetStaticTime() *ExperimentalStaticTime { + if x != nil { + return x.StaticTime + } + return nil +} + +func (x *ExperimentalFeatures) GetCommandInspectionService() *ExperimentalCommandInspectionService { + if x != nil { + return x.CommandInspectionService + } + return nil +} + +// Ledger is in the static time mode and exposes a time service. +type ExperimentalStaticTime struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + Supported bool `protobuf:"varint,1,opt,name=supported,proto3" json:"supported,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExperimentalStaticTime) Reset() { + *x = ExperimentalStaticTime{} + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExperimentalStaticTime) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExperimentalStaticTime) ProtoMessage() {} + +func (x *ExperimentalStaticTime) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExperimentalStaticTime.ProtoReflect.Descriptor instead. +func (*ExperimentalStaticTime) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_experimental_features_proto_rawDescGZIP(), []int{1} +} + +func (x *ExperimentalStaticTime) GetSupported() bool { + if x != nil { + return x.Supported + } + return false +} + +// Whether the Ledger API supports command inspection service +type ExperimentalCommandInspectionService struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + Supported bool `protobuf:"varint,1,opt,name=supported,proto3" json:"supported,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExperimentalCommandInspectionService) Reset() { + *x = ExperimentalCommandInspectionService{} + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExperimentalCommandInspectionService) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExperimentalCommandInspectionService) ProtoMessage() {} + +func (x *ExperimentalCommandInspectionService) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExperimentalCommandInspectionService.ProtoReflect.Descriptor instead. +func (*ExperimentalCommandInspectionService) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_experimental_features_proto_rawDescGZIP(), []int{2} +} + +func (x *ExperimentalCommandInspectionService) GetSupported() bool { + if x != nil { + return x.Supported + } + return false +} + +// Whether the Ledger API supports party events +type ExperimentalPartyTopologyEvents struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + Supported bool `protobuf:"varint,1,opt,name=supported,proto3" json:"supported,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExperimentalPartyTopologyEvents) Reset() { + *x = ExperimentalPartyTopologyEvents{} + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExperimentalPartyTopologyEvents) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExperimentalPartyTopologyEvents) ProtoMessage() {} + +func (x *ExperimentalPartyTopologyEvents) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExperimentalPartyTopologyEvents.ProtoReflect.Descriptor instead. +func (*ExperimentalPartyTopologyEvents) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_experimental_features_proto_rawDescGZIP(), []int{3} +} + +func (x *ExperimentalPartyTopologyEvents) GetSupported() bool { + if x != nil { + return x.Supported + } + return false +} + +var File_com_daml_ledger_api_v2_experimental_features_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_experimental_features_proto_rawDesc = "" + + "\n" + + "2com/daml/ledger/api/v2/experimental_features.proto\x12\x16com.daml.ledger.api.v2\"\xe3\x01\n" + + "\x14ExperimentalFeatures\x12O\n" + + "\vstatic_time\x18\x01 \x01(\v2..com.daml.ledger.api.v2.ExperimentalStaticTimeR\n" + + "staticTime\x12z\n" + + "\x1acommand_inspection_service\x18\x02 \x01(\v2<.com.daml.ledger.api.v2.ExperimentalCommandInspectionServiceR\x18commandInspectionService\"6\n" + + "\x16ExperimentalStaticTime\x12\x1c\n" + + "\tsupported\x18\x01 \x01(\bR\tsupported\"D\n" + + "$ExperimentalCommandInspectionService\x12\x1c\n" + + "\tsupported\x18\x01 \x01(\bR\tsupported\"?\n" + + "\x1fExperimentalPartyTopologyEvents\x12\x1c\n" + + "\tsupported\x18\x01 \x01(\bR\tsupportedB\x86\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x19ExperimentalFeaturesProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_experimental_features_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_experimental_features_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_experimental_features_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_experimental_features_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_experimental_features_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_experimental_features_proto_rawDesc), len(file_com_daml_ledger_api_v2_experimental_features_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_experimental_features_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_com_daml_ledger_api_v2_experimental_features_proto_goTypes = []any{ + (*ExperimentalFeatures)(nil), // 0: com.daml.ledger.api.v2.ExperimentalFeatures + (*ExperimentalStaticTime)(nil), // 1: com.daml.ledger.api.v2.ExperimentalStaticTime + (*ExperimentalCommandInspectionService)(nil), // 2: com.daml.ledger.api.v2.ExperimentalCommandInspectionService + (*ExperimentalPartyTopologyEvents)(nil), // 3: com.daml.ledger.api.v2.ExperimentalPartyTopologyEvents +} +var file_com_daml_ledger_api_v2_experimental_features_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.ExperimentalFeatures.static_time:type_name -> com.daml.ledger.api.v2.ExperimentalStaticTime + 2, // 1: com.daml.ledger.api.v2.ExperimentalFeatures.command_inspection_service:type_name -> com.daml.ledger.api.v2.ExperimentalCommandInspectionService + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_experimental_features_proto_init() } +func file_com_daml_ledger_api_v2_experimental_features_proto_init() { + if File_com_daml_ledger_api_v2_experimental_features_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_experimental_features_proto_rawDesc), len(file_com_daml_ledger_api_v2_experimental_features_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_experimental_features_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_experimental_features_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_experimental_features_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_experimental_features_proto = out.File + file_com_daml_ledger_api_v2_experimental_features_proto_goTypes = nil + file_com_daml_ledger_api_v2_experimental_features_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.pb.go b/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.pb.go new file mode 100644 index 00000000..05a4af66 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_common_data.pb.go @@ -0,0 +1,165 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto + +package interactive + +import ( + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GlobalKey struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The identifier uses the package-id reference format. + // + // Required + TemplateId *v2.Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // Required + PackageName string `protobuf:"bytes,2,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // Required + Key *v2.Value `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + // Required: must be non-empty + Hash []byte `protobuf:"bytes,4,opt,name=hash,proto3" json:"hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GlobalKey) Reset() { + *x = GlobalKey{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GlobalKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GlobalKey) ProtoMessage() {} + +func (x *GlobalKey) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GlobalKey.ProtoReflect.Descriptor instead. +func (*GlobalKey) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDescGZIP(), []int{0} +} + +func (x *GlobalKey) GetTemplateId() *v2.Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *GlobalKey) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *GlobalKey) GetKey() *v2.Value { + if x != nil { + return x.Key + } + return nil +} + +func (x *GlobalKey) GetHash() []byte { + if x != nil { + return x.Hash + } + return nil +} + +var File_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDesc = "" + + "\n" + + "Kcom/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto\x12\"com.daml.ledger.api.v2.interactive\x1a\"com/daml/ledger/api/v2/value.proto\"\xb8\x01\n" + + "\tGlobalKey\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12!\n" + + "\fpackage_name\x18\x02 \x01(\tR\vpackageName\x12/\n" + + "\x03key\x18\x03 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x03key\x12\x12\n" + + "\x04hash\x18\x04 \x01(\fR\x04hashB\xd6\x02\n" + + "&com.com.daml.ledger.api.v2.interactiveB$InteractiveSubmissionCommonDataProtoP\x01ZVgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive\xa2\x02\x06CDLAVI\xaa\x02\"Com.Daml.Ledger.Api.V2.Interactive\xca\x02\"Com\\Daml\\Ledger\\Api\\V2\\Interactive\xe2\x02.Com\\Daml\\Ledger\\Api\\V2\\Interactive\\GPBMetadata\xea\x02'Com::Daml::Ledger::Api::V2::Interactiveb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDesc), len(file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_goTypes = []any{ + (*GlobalKey)(nil), // 0: com.daml.ledger.api.v2.interactive.GlobalKey + (*v2.Identifier)(nil), // 1: com.daml.ledger.api.v2.Identifier + (*v2.Value)(nil), // 2: com.daml.ledger.api.v2.Value +} +var file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.interactive.GlobalKey.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 2, // 1: com.daml.ledger.api.v2.interactive.GlobalKey.key:type_name -> com.daml.ledger.api.v2.Value + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_init() } +func file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_init() { + if File_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDesc), len(file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_rawDesc)), + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto = out.File + file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_goTypes = nil + file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service.pb.go new file mode 100644 index 00000000..896b57af --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service.pb.go @@ -0,0 +1,2796 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/interactive/interactive_submission_service.proto + +package interactive + +import ( + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + v1 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// [docs-entry-start: HashingSchemeVersion] +// The hashing scheme version used when building the hash of the PreparedTransaction +type HashingSchemeVersion int32 + +const ( + HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED HashingSchemeVersion = 0 + HashingSchemeVersion_HASHING_SCHEME_VERSION_V2 HashingSchemeVersion = 2 + HashingSchemeVersion_HASHING_SCHEME_VERSION_V3 HashingSchemeVersion = 3 +) + +// Enum value maps for HashingSchemeVersion. +var ( + HashingSchemeVersion_name = map[int32]string{ + 0: "HASHING_SCHEME_VERSION_UNSPECIFIED", + 2: "HASHING_SCHEME_VERSION_V2", + 3: "HASHING_SCHEME_VERSION_V3", + } + HashingSchemeVersion_value = map[string]int32{ + "HASHING_SCHEME_VERSION_UNSPECIFIED": 0, + "HASHING_SCHEME_VERSION_V2": 2, + "HASHING_SCHEME_VERSION_V3": 3, + } +) + +func (x HashingSchemeVersion) Enum() *HashingSchemeVersion { + p := new(HashingSchemeVersion) + *p = x + return p +} + +func (x HashingSchemeVersion) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (HashingSchemeVersion) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_enumTypes[0].Descriptor() +} + +func (HashingSchemeVersion) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_enumTypes[0] +} + +func (x HashingSchemeVersion) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use HashingSchemeVersion.Descriptor instead. +func (HashingSchemeVersion) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{0} +} + +// Hints to improve cost estimation precision of a prepared transaction +type CostEstimationHints struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Disable cost estimation + // Default (not set) is false + // + // Optional + Disabled bool `protobuf:"varint,1,opt,name=disabled,proto3" json:"disabled,omitempty"` + // Details on the keys that will be used to sign the transaction (how many and of which type). + // Signature size impacts the cost of the transaction. + // If empty, the signature sizes will be approximated with threshold-many signatures (where threshold is defined + // in the PartyToParticipant of the external party), using keys in the order they are registered. + // Empty list is equivalent to not providing this field + // + // Optional: can be empty + ExpectedSignatures []v2.SigningAlgorithmSpec `protobuf:"varint,2,rep,packed,name=expected_signatures,json=expectedSignatures,proto3,enum=com.daml.ledger.api.v2.SigningAlgorithmSpec" json:"expected_signatures,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CostEstimationHints) Reset() { + *x = CostEstimationHints{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CostEstimationHints) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CostEstimationHints) ProtoMessage() {} + +func (x *CostEstimationHints) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CostEstimationHints.ProtoReflect.Descriptor instead. +func (*CostEstimationHints) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{0} +} + +func (x *CostEstimationHints) GetDisabled() bool { + if x != nil { + return x.Disabled + } + return false +} + +func (x *CostEstimationHints) GetExpectedSignatures() []v2.SigningAlgorithmSpec { + if x != nil { + return x.ExpectedSignatures + } + return nil +} + +// Estimation of the cost of submitting the prepared transaction +// The estimation is done against the synchronizer chosen during preparation of the transaction +// (or the one explicitly requested). +// The cost of re-assigning contracts to another synchronizer when necessary is not included in the estimation. +type CostEstimation struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Timestamp at which the estimation was made + // + // Required + EstimationTimestamp *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=estimation_timestamp,json=estimationTimestamp,proto3" json:"estimation_timestamp,omitempty"` + // Estimated traffic cost of the confirmation request associated with the transaction + // + // Required + ConfirmationRequestTrafficCostEstimation uint64 `protobuf:"varint,2,opt,name=confirmation_request_traffic_cost_estimation,json=confirmationRequestTrafficCostEstimation,proto3" json:"confirmation_request_traffic_cost_estimation,omitempty"` + // Estimated traffic cost of the confirmation response associated with the transaction + // This field can also be used as an indication of the cost that other potential confirming nodes + // of the party will incur to approve or reject the transaction + // + // Required + ConfirmationResponseTrafficCostEstimation uint64 `protobuf:"varint,3,opt,name=confirmation_response_traffic_cost_estimation,json=confirmationResponseTrafficCostEstimation,proto3" json:"confirmation_response_traffic_cost_estimation,omitempty"` + // Sum of the fields above + // + // Required + TotalTrafficCostEstimation uint64 `protobuf:"varint,4,opt,name=total_traffic_cost_estimation,json=totalTrafficCostEstimation,proto3" json:"total_traffic_cost_estimation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CostEstimation) Reset() { + *x = CostEstimation{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CostEstimation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CostEstimation) ProtoMessage() {} + +func (x *CostEstimation) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CostEstimation.ProtoReflect.Descriptor instead. +func (*CostEstimation) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{1} +} + +func (x *CostEstimation) GetEstimationTimestamp() *timestamppb.Timestamp { + if x != nil { + return x.EstimationTimestamp + } + return nil +} + +func (x *CostEstimation) GetConfirmationRequestTrafficCostEstimation() uint64 { + if x != nil { + return x.ConfirmationRequestTrafficCostEstimation + } + return 0 +} + +func (x *CostEstimation) GetConfirmationResponseTrafficCostEstimation() uint64 { + if x != nil { + return x.ConfirmationResponseTrafficCostEstimation + } + return 0 +} + +func (x *CostEstimation) GetTotalTrafficCostEstimation() uint64 { + if x != nil { + return x.TotalTrafficCostEstimation + } + return 0 +} + +type PrepareSubmissionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Uniquely identifies the participant user that prepares the transaction. + // Must be a valid UserIdString (as described in “value.proto“). + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // Uniquely identifies the command. + // The triple (user_id, act_as, command_id) constitutes the change ID for the intended ledger change, + // where act_as is interpreted as a set of party names. + // The change ID can be used for matching the intended ledger changes with all their completions. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + // Individual elements of this atomic command. Must be non-empty. + // Limitation: Only single command transaction are currently supported by the API. + // The field is marked as repeated in preparation for future support of multiple commands. + // + // Required: must be non-empty + Commands []*v2.Command `protobuf:"bytes,3,rep,name=commands,proto3" json:"commands,omitempty"` + // Optional + MinLedgerTime *MinLedgerTime `protobuf:"bytes,4,opt,name=min_ledger_time,json=minLedgerTime,proto3" json:"min_ledger_time,omitempty"` + // Maximum timestamp at which the transaction can be recorded onto the ledger via the synchronizer specified in the `PrepareSubmissionResponse`. + // If submitted after it will be rejected even if otherwise valid, in which case it needs to be prepared and signed again + // with a new valid max_record_time. + // Use this to limit the time-to-life of a prepared transaction, + // which is useful to know when it can definitely not be accepted + // anymore and resorting to preparing another transaction for the same + // intent is safe again. + // + // Optional + MaxRecordTime *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=max_record_time,json=maxRecordTime,proto3,oneof" json:"max_record_time,omitempty"` + // Set of parties on whose behalf the command should be executed, if submitted. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to **read** (not act) on behalf of each of the given parties. This is because this RPC merely prepares a transaction + // and does not execute it. Therefore read authorization is sufficient even for actAs parties. + // Note: This may change, and more specific authorization scope may be introduced in the future. + // Each element must be a valid PartyIdString (as described in “value.proto“). + // + // Required: must be non-empty + ActAs []string `protobuf:"bytes,5,rep,name=act_as,json=actAs,proto3" json:"act_as,omitempty"` + // Set of parties on whose behalf (in addition to all parties listed in “act_as“) contracts can be retrieved. + // This affects Daml operations such as “fetch“, “fetchByKey“, “lookupByKey“, “exercise“, and “exerciseByKey“. + // Note: A command can only use contracts that are visible to at least + // one of the parties in “act_as“ or “read_as“. This visibility check is independent from the Daml authorization + // rules for fetch operations. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to read contract data on behalf of each of the given parties. + // + // Optional: can be empty + ReadAs []string `protobuf:"bytes,6,rep,name=read_as,json=readAs,proto3" json:"read_as,omitempty"` + // Additional contracts used to resolve contract & contract key lookups. + // + // Optional: can be empty + DisclosedContracts []*v2.DisclosedContract `protobuf:"bytes,7,rep,name=disclosed_contracts,json=disclosedContracts,proto3" json:"disclosed_contracts,omitempty"` + // Must be a valid synchronizer id + // If not set, a suitable synchronizer that this node is connected to will be chosen + // + // Optional + SynchronizerId string `protobuf:"bytes,8,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The package-id selection preference of the client for resolving + // package names and interface instances in command submission and interpretation + // + // Optional: can be empty + PackageIdSelectionPreference []string `protobuf:"bytes,9,rep,name=package_id_selection_preference,json=packageIdSelectionPreference,proto3" json:"package_id_selection_preference,omitempty"` + // When true, the response will contain additional details on how the transaction was encoded and hashed + // This can be useful for troubleshooting of hash mismatches. Should only be used for debugging. + // Defaults to false + // + // Optional + VerboseHashing bool `protobuf:"varint,10,opt,name=verbose_hashing,json=verboseHashing,proto3" json:"verbose_hashing,omitempty"` + // Fetches the contract keys into the caches to speed up the command processing. + // Should only contain contract keys that are expected to be resolved during interpretation of the commands. + // Keys of disclosed contracts do not need prefetching. + // + // Optional: can be empty + PrefetchContractKeys []*v2.PrefetchContractKey `protobuf:"bytes,15,rep,name=prefetch_contract_keys,json=prefetchContractKeys,proto3" json:"prefetch_contract_keys,omitempty"` + // Hints to improve the accuracy of traffic cost estimation. + // The estimation logic assumes that this node will be used for the execution of the transaction + // If another node is used instead, the estimation may be less precise. + // Request amplification is not accounted for in the estimation: each amplified request will + // result in the cost of the confirmation request to be charged additionally. + // + // Traffic cost estimation is enabled by default if this field is not set + // To turn off cost estimation, set the CostEstimationHints#disabled field to true + // + // Optional + EstimateTrafficCost *CostEstimationHints `protobuf:"bytes,16,opt,name=estimate_traffic_cost,json=estimateTrafficCost,proto3,oneof" json:"estimate_traffic_cost,omitempty"` + // The hashing scheme version to be used when building the hash. + // Defaults to HASHING_SCHEME_VERSION_V2. + // + // Optional + HashingSchemeVersion *HashingSchemeVersion `protobuf:"varint,17,opt,name=hashing_scheme_version,json=hashingSchemeVersion,proto3,enum=com.daml.ledger.api.v2.interactive.HashingSchemeVersion,oneof" json:"hashing_scheme_version,omitempty"` + // The maximum number of passes for the Topology-Aware Package Selection (TAPS). + // Higher values can increase the chance of successful package selection for routing of interpreted transactions. + // If unset, this defaults to the value defined in the participant configuration. + // The provided value must not exceed the limit specified in the participant configuration. + // + // Optional + TapsMaxPasses *uint32 `protobuf:"varint,18,opt,name=taps_max_passes,json=tapsMaxPasses,proto3,oneof" json:"taps_max_passes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PrepareSubmissionRequest) Reset() { + *x = PrepareSubmissionRequest{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PrepareSubmissionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrepareSubmissionRequest) ProtoMessage() {} + +func (x *PrepareSubmissionRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrepareSubmissionRequest.ProtoReflect.Descriptor instead. +func (*PrepareSubmissionRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{2} +} + +func (x *PrepareSubmissionRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *PrepareSubmissionRequest) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *PrepareSubmissionRequest) GetCommands() []*v2.Command { + if x != nil { + return x.Commands + } + return nil +} + +func (x *PrepareSubmissionRequest) GetMinLedgerTime() *MinLedgerTime { + if x != nil { + return x.MinLedgerTime + } + return nil +} + +func (x *PrepareSubmissionRequest) GetMaxRecordTime() *timestamppb.Timestamp { + if x != nil { + return x.MaxRecordTime + } + return nil +} + +func (x *PrepareSubmissionRequest) GetActAs() []string { + if x != nil { + return x.ActAs + } + return nil +} + +func (x *PrepareSubmissionRequest) GetReadAs() []string { + if x != nil { + return x.ReadAs + } + return nil +} + +func (x *PrepareSubmissionRequest) GetDisclosedContracts() []*v2.DisclosedContract { + if x != nil { + return x.DisclosedContracts + } + return nil +} + +func (x *PrepareSubmissionRequest) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *PrepareSubmissionRequest) GetPackageIdSelectionPreference() []string { + if x != nil { + return x.PackageIdSelectionPreference + } + return nil +} + +func (x *PrepareSubmissionRequest) GetVerboseHashing() bool { + if x != nil { + return x.VerboseHashing + } + return false +} + +func (x *PrepareSubmissionRequest) GetPrefetchContractKeys() []*v2.PrefetchContractKey { + if x != nil { + return x.PrefetchContractKeys + } + return nil +} + +func (x *PrepareSubmissionRequest) GetEstimateTrafficCost() *CostEstimationHints { + if x != nil { + return x.EstimateTrafficCost + } + return nil +} + +func (x *PrepareSubmissionRequest) GetHashingSchemeVersion() HashingSchemeVersion { + if x != nil && x.HashingSchemeVersion != nil { + return *x.HashingSchemeVersion + } + return HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED +} + +func (x *PrepareSubmissionRequest) GetTapsMaxPasses() uint32 { + if x != nil && x.TapsMaxPasses != nil { + return *x.TapsMaxPasses + } + return 0 +} + +type PrepareSubmissionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The interpreted transaction, it represents the ledger changes necessary to execute the commands specified in the request. + // Clients MUST display the content of the transaction to the user for them to validate before signing the hash if the preparing participant is not trusted. + // + // Required + PreparedTransaction *PreparedTransaction `protobuf:"bytes,1,opt,name=prepared_transaction,json=preparedTransaction,proto3" json:"prepared_transaction,omitempty"` + // Hash of the transaction, this is what needs to be signed by the party to authorize the transaction. + // Only provided for convenience, clients MUST recompute the hash from the raw transaction if the preparing participant is not trusted. + // May be removed in future versions + // + // Required: must be non-empty + PreparedTransactionHash []byte `protobuf:"bytes,2,opt,name=prepared_transaction_hash,json=preparedTransactionHash,proto3" json:"prepared_transaction_hash,omitempty"` + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion HashingSchemeVersion `protobuf:"varint,3,opt,name=hashing_scheme_version,json=hashingSchemeVersion,proto3,enum=com.daml.ledger.api.v2.interactive.HashingSchemeVersion" json:"hashing_scheme_version,omitempty"` + // Optional additional details on how the transaction was encoded and hashed. Only set if verbose_hashing = true in the request + // Note that there are no guarantees on the stability of the format or content of this field. + // Its content should NOT be parsed and should only be used for troubleshooting purposes. + // + // Optional + HashingDetails *string `protobuf:"bytes,4,opt,name=hashing_details,json=hashingDetails,proto3,oneof" json:"hashing_details,omitempty"` + // Traffic cost estimation of the prepared transaction + // + // Optional + CostEstimation *CostEstimation `protobuf:"bytes,5,opt,name=cost_estimation,json=costEstimation,proto3,oneof" json:"cost_estimation,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PrepareSubmissionResponse) Reset() { + *x = PrepareSubmissionResponse{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PrepareSubmissionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrepareSubmissionResponse) ProtoMessage() {} + +func (x *PrepareSubmissionResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrepareSubmissionResponse.ProtoReflect.Descriptor instead. +func (*PrepareSubmissionResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{3} +} + +func (x *PrepareSubmissionResponse) GetPreparedTransaction() *PreparedTransaction { + if x != nil { + return x.PreparedTransaction + } + return nil +} + +func (x *PrepareSubmissionResponse) GetPreparedTransactionHash() []byte { + if x != nil { + return x.PreparedTransactionHash + } + return nil +} + +func (x *PrepareSubmissionResponse) GetHashingSchemeVersion() HashingSchemeVersion { + if x != nil { + return x.HashingSchemeVersion + } + return HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED +} + +func (x *PrepareSubmissionResponse) GetHashingDetails() string { + if x != nil && x.HashingDetails != nil { + return *x.HashingDetails + } + return "" +} + +func (x *PrepareSubmissionResponse) GetCostEstimation() *CostEstimation { + if x != nil { + return x.CostEstimation + } + return nil +} + +// Signatures provided by a single party +type SinglePartySignatures struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Submitting party + // + // Required + Party string `protobuf:"bytes,1,opt,name=party,proto3" json:"party,omitempty"` + // Signatures + // + // Required: must be non-empty + Signatures []*v2.Signature `protobuf:"bytes,2,rep,name=signatures,proto3" json:"signatures,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SinglePartySignatures) Reset() { + *x = SinglePartySignatures{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SinglePartySignatures) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SinglePartySignatures) ProtoMessage() {} + +func (x *SinglePartySignatures) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SinglePartySignatures.ProtoReflect.Descriptor instead. +func (*SinglePartySignatures) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{4} +} + +func (x *SinglePartySignatures) GetParty() string { + if x != nil { + return x.Party + } + return "" +} + +func (x *SinglePartySignatures) GetSignatures() []*v2.Signature { + if x != nil { + return x.Signatures + } + return nil +} + +// Additional signatures provided by the submitting parties +type PartySignatures struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Additional signatures provided by all individual parties + // + // Required: must be non-empty + Signatures []*SinglePartySignatures `protobuf:"bytes,1,rep,name=signatures,proto3" json:"signatures,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PartySignatures) Reset() { + *x = PartySignatures{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PartySignatures) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PartySignatures) ProtoMessage() {} + +func (x *PartySignatures) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PartySignatures.ProtoReflect.Descriptor instead. +func (*PartySignatures) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{5} +} + +func (x *PartySignatures) GetSignatures() []*SinglePartySignatures { + if x != nil { + return x.Signatures + } + return nil +} + +type ExecuteSubmissionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // the prepared transaction + // Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` + // obtained from calling `prepareSubmission`. + // + // Required + PreparedTransaction *PreparedTransaction `protobuf:"bytes,1,opt,name=prepared_transaction,json=preparedTransaction,proto3" json:"prepared_transaction,omitempty"` + // The party(ies) signatures that authorize the prepared submission to be executed by this node. + // Each party can provide one or more signatures.. + // and one or more parties can sign. + // Note that currently, only single party submissions are supported. + // + // Required + PartySignatures *PartySignatures `protobuf:"bytes,2,opt,name=party_signatures,json=partySignatures,proto3" json:"party_signatures,omitempty"` + // Specifies the deduplication period for the change ID (See PrepareSubmissionRequest). + // If omitted, the participant will assume the configured maximum deduplication time. + // + // # Optional + // + // Types that are valid to be assigned to DeduplicationPeriod: + // + // *ExecuteSubmissionRequest_DeduplicationDuration + // *ExecuteSubmissionRequest_DeduplicationOffset + DeduplicationPeriod isExecuteSubmissionRequest_DeduplicationPeriod `protobuf_oneof:"deduplication_period"` + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + SubmissionId string `protobuf:"bytes,5,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // See [PrepareSubmissionRequest.user_id] + // + // Optional + UserId string `protobuf:"bytes,6,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion HashingSchemeVersion `protobuf:"varint,7,opt,name=hashing_scheme_version,json=hashingSchemeVersion,proto3,enum=com.daml.ledger.api.v2.interactive.HashingSchemeVersion" json:"hashing_scheme_version,omitempty"` + // If set will influence the chosen ledger effective time but will not result in a submission delay so any override + // should be scheduled to executed within the window allowed by synchronizer. + // + // Optional + MinLedgerTime *MinLedgerTime `protobuf:"bytes,8,opt,name=min_ledger_time,json=minLedgerTime,proto3" json:"min_ledger_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecuteSubmissionRequest) Reset() { + *x = ExecuteSubmissionRequest{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecuteSubmissionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecuteSubmissionRequest) ProtoMessage() {} + +func (x *ExecuteSubmissionRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecuteSubmissionRequest.ProtoReflect.Descriptor instead. +func (*ExecuteSubmissionRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{6} +} + +func (x *ExecuteSubmissionRequest) GetPreparedTransaction() *PreparedTransaction { + if x != nil { + return x.PreparedTransaction + } + return nil +} + +func (x *ExecuteSubmissionRequest) GetPartySignatures() *PartySignatures { + if x != nil { + return x.PartySignatures + } + return nil +} + +func (x *ExecuteSubmissionRequest) GetDeduplicationPeriod() isExecuteSubmissionRequest_DeduplicationPeriod { + if x != nil { + return x.DeduplicationPeriod + } + return nil +} + +func (x *ExecuteSubmissionRequest) GetDeduplicationDuration() *durationpb.Duration { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*ExecuteSubmissionRequest_DeduplicationDuration); ok { + return x.DeduplicationDuration + } + } + return nil +} + +func (x *ExecuteSubmissionRequest) GetDeduplicationOffset() int64 { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*ExecuteSubmissionRequest_DeduplicationOffset); ok { + return x.DeduplicationOffset + } + } + return 0 +} + +func (x *ExecuteSubmissionRequest) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *ExecuteSubmissionRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *ExecuteSubmissionRequest) GetHashingSchemeVersion() HashingSchemeVersion { + if x != nil { + return x.HashingSchemeVersion + } + return HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED +} + +func (x *ExecuteSubmissionRequest) GetMinLedgerTime() *MinLedgerTime { + if x != nil { + return x.MinLedgerTime + } + return nil +} + +type isExecuteSubmissionRequest_DeduplicationPeriod interface { + isExecuteSubmissionRequest_DeduplicationPeriod() +} + +type ExecuteSubmissionRequest_DeduplicationDuration struct { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + DeduplicationDuration *durationpb.Duration `protobuf:"bytes,3,opt,name=deduplication_duration,json=deduplicationDuration,proto3,oneof"` +} + +type ExecuteSubmissionRequest_DeduplicationOffset struct { + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer). + DeduplicationOffset int64 `protobuf:"varint,4,opt,name=deduplication_offset,json=deduplicationOffset,proto3,oneof"` +} + +func (*ExecuteSubmissionRequest_DeduplicationDuration) isExecuteSubmissionRequest_DeduplicationPeriod() { +} + +func (*ExecuteSubmissionRequest_DeduplicationOffset) isExecuteSubmissionRequest_DeduplicationPeriod() { +} + +type ExecuteSubmissionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecuteSubmissionResponse) Reset() { + *x = ExecuteSubmissionResponse{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecuteSubmissionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecuteSubmissionResponse) ProtoMessage() {} + +func (x *ExecuteSubmissionResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecuteSubmissionResponse.ProtoReflect.Descriptor instead. +func (*ExecuteSubmissionResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{7} +} + +type ExecuteSubmissionAndWaitRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // the prepared transaction + // Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` + // obtained from calling `prepareSubmission`. + // + // Required + PreparedTransaction *PreparedTransaction `protobuf:"bytes,1,opt,name=prepared_transaction,json=preparedTransaction,proto3" json:"prepared_transaction,omitempty"` + // The party(ies) signatures that authorize the prepared submission to be executed by this node. + // Each party can provide one or more signatures.. + // and one or more parties can sign. + // Note that currently, only single party submissions are supported. + // + // Required + PartySignatures *PartySignatures `protobuf:"bytes,2,opt,name=party_signatures,json=partySignatures,proto3" json:"party_signatures,omitempty"` + // Specifies the deduplication period for the change ID (See PrepareSubmissionRequest). + // If omitted, the participant will assume the configured maximum deduplication time. + // + // # Optional + // + // Types that are valid to be assigned to DeduplicationPeriod: + // + // *ExecuteSubmissionAndWaitRequest_DeduplicationDuration + // *ExecuteSubmissionAndWaitRequest_DeduplicationOffset + DeduplicationPeriod isExecuteSubmissionAndWaitRequest_DeduplicationPeriod `protobuf_oneof:"deduplication_period"` + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + SubmissionId string `protobuf:"bytes,5,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // See [PrepareSubmissionRequest.user_id] + // + // Optional + UserId string `protobuf:"bytes,6,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion HashingSchemeVersion `protobuf:"varint,7,opt,name=hashing_scheme_version,json=hashingSchemeVersion,proto3,enum=com.daml.ledger.api.v2.interactive.HashingSchemeVersion" json:"hashing_scheme_version,omitempty"` + // If set will influence the chosen ledger effective time but will not result in a submission delay so any override + // should be scheduled to executed within the window allowed by synchronizer. + // + // Optional + MinLedgerTime *MinLedgerTime `protobuf:"bytes,8,opt,name=min_ledger_time,json=minLedgerTime,proto3" json:"min_ledger_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecuteSubmissionAndWaitRequest) Reset() { + *x = ExecuteSubmissionAndWaitRequest{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecuteSubmissionAndWaitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecuteSubmissionAndWaitRequest) ProtoMessage() {} + +func (x *ExecuteSubmissionAndWaitRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecuteSubmissionAndWaitRequest.ProtoReflect.Descriptor instead. +func (*ExecuteSubmissionAndWaitRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{8} +} + +func (x *ExecuteSubmissionAndWaitRequest) GetPreparedTransaction() *PreparedTransaction { + if x != nil { + return x.PreparedTransaction + } + return nil +} + +func (x *ExecuteSubmissionAndWaitRequest) GetPartySignatures() *PartySignatures { + if x != nil { + return x.PartySignatures + } + return nil +} + +func (x *ExecuteSubmissionAndWaitRequest) GetDeduplicationPeriod() isExecuteSubmissionAndWaitRequest_DeduplicationPeriod { + if x != nil { + return x.DeduplicationPeriod + } + return nil +} + +func (x *ExecuteSubmissionAndWaitRequest) GetDeduplicationDuration() *durationpb.Duration { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*ExecuteSubmissionAndWaitRequest_DeduplicationDuration); ok { + return x.DeduplicationDuration + } + } + return nil +} + +func (x *ExecuteSubmissionAndWaitRequest) GetDeduplicationOffset() int64 { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*ExecuteSubmissionAndWaitRequest_DeduplicationOffset); ok { + return x.DeduplicationOffset + } + } + return 0 +} + +func (x *ExecuteSubmissionAndWaitRequest) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *ExecuteSubmissionAndWaitRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *ExecuteSubmissionAndWaitRequest) GetHashingSchemeVersion() HashingSchemeVersion { + if x != nil { + return x.HashingSchemeVersion + } + return HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED +} + +func (x *ExecuteSubmissionAndWaitRequest) GetMinLedgerTime() *MinLedgerTime { + if x != nil { + return x.MinLedgerTime + } + return nil +} + +type isExecuteSubmissionAndWaitRequest_DeduplicationPeriod interface { + isExecuteSubmissionAndWaitRequest_DeduplicationPeriod() +} + +type ExecuteSubmissionAndWaitRequest_DeduplicationDuration struct { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + DeduplicationDuration *durationpb.Duration `protobuf:"bytes,3,opt,name=deduplication_duration,json=deduplicationDuration,proto3,oneof"` +} + +type ExecuteSubmissionAndWaitRequest_DeduplicationOffset struct { + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer). + DeduplicationOffset int64 `protobuf:"varint,4,opt,name=deduplication_offset,json=deduplicationOffset,proto3,oneof"` +} + +func (*ExecuteSubmissionAndWaitRequest_DeduplicationDuration) isExecuteSubmissionAndWaitRequest_DeduplicationPeriod() { +} + +func (*ExecuteSubmissionAndWaitRequest_DeduplicationOffset) isExecuteSubmissionAndWaitRequest_DeduplicationPeriod() { +} + +type ExecuteSubmissionAndWaitResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The id of the transaction that resulted from the submitted command. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // The details of the offset field are described in “community/ledger-api/README.md“. + // + // Required + CompletionOffset int64 `protobuf:"varint,2,opt,name=completion_offset,json=completionOffset,proto3" json:"completion_offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecuteSubmissionAndWaitResponse) Reset() { + *x = ExecuteSubmissionAndWaitResponse{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecuteSubmissionAndWaitResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecuteSubmissionAndWaitResponse) ProtoMessage() {} + +func (x *ExecuteSubmissionAndWaitResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecuteSubmissionAndWaitResponse.ProtoReflect.Descriptor instead. +func (*ExecuteSubmissionAndWaitResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{9} +} + +func (x *ExecuteSubmissionAndWaitResponse) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *ExecuteSubmissionAndWaitResponse) GetCompletionOffset() int64 { + if x != nil { + return x.CompletionOffset + } + return 0 +} + +type ExecuteSubmissionAndWaitForTransactionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // the prepared transaction + // Typically this is the value of the `prepared_transaction` field in `PrepareSubmissionResponse` + // obtained from calling `prepareSubmission`. + // + // Required + PreparedTransaction *PreparedTransaction `protobuf:"bytes,1,opt,name=prepared_transaction,json=preparedTransaction,proto3" json:"prepared_transaction,omitempty"` + // The party(ies) signatures that authorize the prepared submission to be executed by this node. + // Each party can provide one or more signatures.. + // and one or more parties can sign. + // Note that currently, only single party submissions are supported. + // + // Required + PartySignatures *PartySignatures `protobuf:"bytes,2,opt,name=party_signatures,json=partySignatures,proto3" json:"party_signatures,omitempty"` + // Specifies the deduplication period for the change ID (See PrepareSubmissionRequest). + // If omitted, the participant will assume the configured maximum deduplication time. + // + // # Optional + // + // Types that are valid to be assigned to DeduplicationPeriod: + // + // *ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationDuration + // *ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationOffset + DeduplicationPeriod isExecuteSubmissionAndWaitForTransactionRequest_DeduplicationPeriod `protobuf_oneof:"deduplication_period"` + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + SubmissionId string `protobuf:"bytes,5,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // See [PrepareSubmissionRequest.user_id] + // + // Optional + UserId string `protobuf:"bytes,6,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // The hashing scheme version used when building the hash + // + // Required + HashingSchemeVersion HashingSchemeVersion `protobuf:"varint,7,opt,name=hashing_scheme_version,json=hashingSchemeVersion,proto3,enum=com.daml.ledger.api.v2.interactive.HashingSchemeVersion" json:"hashing_scheme_version,omitempty"` + // If set will influence the chosen ledger effective time but will not result in a submission delay so any override + // should be scheduled to executed within the window allowed by synchronizer. + // + // Optional + MinLedgerTime *MinLedgerTime `protobuf:"bytes,8,opt,name=min_ledger_time,json=minLedgerTime,proto3" json:"min_ledger_time,omitempty"` + // If no “transaction_format“ is provided, a default will be used where “transaction_shape“ is set to + // TRANSACTION_SHAPE_ACS_DELTA, “event_format“ is defined with “filters_by_party“ containing wildcard-template + // filter for all original “act_as“ and “read_as“ parties and the “verbose“ flag is set. + // When the “transaction_shape“ TRANSACTION_SHAPE_ACS_DELTA shape is used (explicitly or is defaulted to as explained above), + // events will only be returned if the submitting party is hosted on this node. + // + // Optional + TransactionFormat *v2.TransactionFormat `protobuf:"bytes,9,opt,name=transaction_format,json=transactionFormat,proto3" json:"transaction_format,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) Reset() { + *x = ExecuteSubmissionAndWaitForTransactionRequest{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecuteSubmissionAndWaitForTransactionRequest) ProtoMessage() {} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecuteSubmissionAndWaitForTransactionRequest.ProtoReflect.Descriptor instead. +func (*ExecuteSubmissionAndWaitForTransactionRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{10} +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetPreparedTransaction() *PreparedTransaction { + if x != nil { + return x.PreparedTransaction + } + return nil +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetPartySignatures() *PartySignatures { + if x != nil { + return x.PartySignatures + } + return nil +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetDeduplicationPeriod() isExecuteSubmissionAndWaitForTransactionRequest_DeduplicationPeriod { + if x != nil { + return x.DeduplicationPeriod + } + return nil +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetDeduplicationDuration() *durationpb.Duration { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationDuration); ok { + return x.DeduplicationDuration + } + } + return nil +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetDeduplicationOffset() int64 { + if x != nil { + if x, ok := x.DeduplicationPeriod.(*ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationOffset); ok { + return x.DeduplicationOffset + } + } + return 0 +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetHashingSchemeVersion() HashingSchemeVersion { + if x != nil { + return x.HashingSchemeVersion + } + return HashingSchemeVersion_HASHING_SCHEME_VERSION_UNSPECIFIED +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetMinLedgerTime() *MinLedgerTime { + if x != nil { + return x.MinLedgerTime + } + return nil +} + +func (x *ExecuteSubmissionAndWaitForTransactionRequest) GetTransactionFormat() *v2.TransactionFormat { + if x != nil { + return x.TransactionFormat + } + return nil +} + +type isExecuteSubmissionAndWaitForTransactionRequest_DeduplicationPeriod interface { + isExecuteSubmissionAndWaitForTransactionRequest_DeduplicationPeriod() +} + +type ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationDuration struct { + // Specifies the length of the deduplication period. + // It is interpreted relative to the local clock at some point during the submission's processing. + // Must be non-negative. Must not exceed the maximum deduplication time. + DeduplicationDuration *durationpb.Duration `protobuf:"bytes,3,opt,name=deduplication_duration,json=deduplicationDuration,proto3,oneof"` +} + +type ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationOffset struct { + // Specifies the start of the deduplication period by a completion stream offset (exclusive). + // Must be a valid absolute offset (positive integer). + DeduplicationOffset int64 `protobuf:"varint,4,opt,name=deduplication_offset,json=deduplicationOffset,proto3,oneof"` +} + +func (*ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationDuration) isExecuteSubmissionAndWaitForTransactionRequest_DeduplicationPeriod() { +} + +func (*ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationOffset) isExecuteSubmissionAndWaitForTransactionRequest_DeduplicationPeriod() { +} + +type ExecuteSubmissionAndWaitForTransactionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The transaction that resulted from the submitted command. + // The transaction might contain no events (request conditions result in filtering out all of them). + // + // Required + Transaction *v2.Transaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExecuteSubmissionAndWaitForTransactionResponse) Reset() { + *x = ExecuteSubmissionAndWaitForTransactionResponse{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExecuteSubmissionAndWaitForTransactionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecuteSubmissionAndWaitForTransactionResponse) ProtoMessage() {} + +func (x *ExecuteSubmissionAndWaitForTransactionResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecuteSubmissionAndWaitForTransactionResponse.ProtoReflect.Descriptor instead. +func (*ExecuteSubmissionAndWaitForTransactionResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{11} +} + +func (x *ExecuteSubmissionAndWaitForTransactionResponse) GetTransaction() *v2.Transaction { + if x != nil { + return x.Transaction + } + return nil +} + +type MinLedgerTime struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Time: + // + // *MinLedgerTime_MinLedgerTimeAbs + // *MinLedgerTime_MinLedgerTimeRel + Time isMinLedgerTime_Time `protobuf_oneof:"time"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MinLedgerTime) Reset() { + *x = MinLedgerTime{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MinLedgerTime) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MinLedgerTime) ProtoMessage() {} + +func (x *MinLedgerTime) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MinLedgerTime.ProtoReflect.Descriptor instead. +func (*MinLedgerTime) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{12} +} + +func (x *MinLedgerTime) GetTime() isMinLedgerTime_Time { + if x != nil { + return x.Time + } + return nil +} + +func (x *MinLedgerTime) GetMinLedgerTimeAbs() *timestamppb.Timestamp { + if x != nil { + if x, ok := x.Time.(*MinLedgerTime_MinLedgerTimeAbs); ok { + return x.MinLedgerTimeAbs + } + } + return nil +} + +func (x *MinLedgerTime) GetMinLedgerTimeRel() *durationpb.Duration { + if x != nil { + if x, ok := x.Time.(*MinLedgerTime_MinLedgerTimeRel); ok { + return x.MinLedgerTimeRel + } + } + return nil +} + +type isMinLedgerTime_Time interface { + isMinLedgerTime_Time() +} + +type MinLedgerTime_MinLedgerTimeAbs struct { + // Lower bound for the ledger time assigned to the resulting transaction. + // The ledger time of a transaction is assigned as part of command interpretation. + // Important note: for interactive submissions, if the transaction depends on time, it **must** be signed + // and submitted within a time window around the ledger time assigned to the transaction during the prepare method. + // The time delta around that ledger time is a configuration of the ledger, usually short, around 1 minute. + // If however the transaction does not depend on time, the available time window to sign and submit the transaction is bound + // by the preparation time, which is also assigned in the "prepare" step (this request), + // but can be configured with a much larger skew, allowing for more time to sign the request (in the order of hours). + // Must not be set at the same time as min_ledger_time_rel. + // Optional + MinLedgerTimeAbs *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=min_ledger_time_abs,json=minLedgerTimeAbs,proto3,oneof"` +} + +type MinLedgerTime_MinLedgerTimeRel struct { + // Same as min_ledger_time_abs, but specified as a duration, starting from the time this request is received by the server. + // Must not be set at the same time as min_ledger_time_abs. + // Optional + MinLedgerTimeRel *durationpb.Duration `protobuf:"bytes,2,opt,name=min_ledger_time_rel,json=minLedgerTimeRel,proto3,oneof"` +} + +func (*MinLedgerTime_MinLedgerTimeAbs) isMinLedgerTime_Time() {} + +func (*MinLedgerTime_MinLedgerTimeRel) isMinLedgerTime_Time() {} + +// * +// Prepared Transaction Message +type PreparedTransaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Daml Transaction representing the ledger effect if executed. See below + // + // Required + Transaction *DamlTransaction `protobuf:"bytes,1,opt,name=transaction,proto3" json:"transaction,omitempty"` + // Metadata context necessary to execute the transaction + // + // Required + Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PreparedTransaction) Reset() { + *x = PreparedTransaction{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PreparedTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PreparedTransaction) ProtoMessage() {} + +func (x *PreparedTransaction) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PreparedTransaction.ProtoReflect.Descriptor instead. +func (*PreparedTransaction) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{13} +} + +func (x *PreparedTransaction) GetTransaction() *DamlTransaction { + if x != nil { + return x.Transaction + } + return nil +} + +func (x *PreparedTransaction) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +// Transaction Metadata +// Refer to the hashing documentation for information on how it should be hashed. +type Metadata struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + SubmitterInfo *Metadata_SubmitterInfo `protobuf:"bytes,2,opt,name=submitter_info,json=submitterInfo,proto3" json:"submitter_info,omitempty"` + // Required + SynchronizerId string `protobuf:"bytes,3,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // Required + MediatorGroup uint32 `protobuf:"varint,4,opt,name=mediator_group,json=mediatorGroup,proto3" json:"mediator_group,omitempty"` + // Required + TransactionUuid string `protobuf:"bytes,5,opt,name=transaction_uuid,json=transactionUuid,proto3" json:"transaction_uuid,omitempty"` + // Required + PreparationTime uint64 `protobuf:"varint,6,opt,name=preparation_time,json=preparationTime,proto3" json:"preparation_time,omitempty"` + // Not populated if the transaction has no input contracts + // + // Optional: can be empty + InputContracts []*Metadata_InputContract `protobuf:"bytes,7,rep,name=input_contracts,json=inputContracts,proto3" json:"input_contracts,omitempty"` + // Optional + MinLedgerEffectiveTime *uint64 `protobuf:"varint,9,opt,name=min_ledger_effective_time,json=minLedgerEffectiveTime,proto3,oneof" json:"min_ledger_effective_time,omitempty"` + // Optional + MaxLedgerEffectiveTime *uint64 `protobuf:"varint,10,opt,name=max_ledger_effective_time,json=maxLedgerEffectiveTime,proto3,oneof" json:"max_ledger_effective_time,omitempty"` + // Contextual information needed to process the transaction but not signed, either because it's already indirectly + // signed by signing the transaction, or because it doesn't impact the ledger state + // + // Optional: can be empty + GlobalKeyMapping []*Metadata_GlobalKeyMappingEntry `protobuf:"bytes,8,rep,name=global_key_mapping,json=globalKeyMapping,proto3" json:"global_key_mapping,omitempty"` + // Maximum timestamp at which the transaction can be recorded onto the ledger via the synchronizer `synchronizer_id`. + // If submitted after it will be rejected even if otherwise valid, in which case it needs to be prepared and signed again + // with a new valid max_record_time. + // Unsigned in 3.3 to avoid a breaking protocol change + // Will be signed in 3.4+ + // Set max_record_time in the PreparedTransactionRequest to get this field set accordingly + // + // Optional + MaxRecordTime *uint64 `protobuf:"varint,11,opt,name=max_record_time,json=maxRecordTime,proto3,oneof" json:"max_record_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Metadata) Reset() { + *x = Metadata{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Metadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metadata) ProtoMessage() {} + +func (x *Metadata) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Metadata.ProtoReflect.Descriptor instead. +func (*Metadata) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{14} +} + +func (x *Metadata) GetSubmitterInfo() *Metadata_SubmitterInfo { + if x != nil { + return x.SubmitterInfo + } + return nil +} + +func (x *Metadata) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *Metadata) GetMediatorGroup() uint32 { + if x != nil { + return x.MediatorGroup + } + return 0 +} + +func (x *Metadata) GetTransactionUuid() string { + if x != nil { + return x.TransactionUuid + } + return "" +} + +func (x *Metadata) GetPreparationTime() uint64 { + if x != nil { + return x.PreparationTime + } + return 0 +} + +func (x *Metadata) GetInputContracts() []*Metadata_InputContract { + if x != nil { + return x.InputContracts + } + return nil +} + +func (x *Metadata) GetMinLedgerEffectiveTime() uint64 { + if x != nil && x.MinLedgerEffectiveTime != nil { + return *x.MinLedgerEffectiveTime + } + return 0 +} + +func (x *Metadata) GetMaxLedgerEffectiveTime() uint64 { + if x != nil && x.MaxLedgerEffectiveTime != nil { + return *x.MaxLedgerEffectiveTime + } + return 0 +} + +func (x *Metadata) GetGlobalKeyMapping() []*Metadata_GlobalKeyMappingEntry { + if x != nil { + return x.GlobalKeyMapping + } + return nil +} + +func (x *Metadata) GetMaxRecordTime() uint64 { + if x != nil && x.MaxRecordTime != nil { + return *x.MaxRecordTime + } + return 0 +} + +// Daml Transaction. +// This represents the effect on the ledger if this transaction is successfully committed. +type DamlTransaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + // serialization version, will be >= max(nodes version) + // + // Required + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + // Root nodes of the transaction + // + // Required: must be non-empty + Roots []string `protobuf:"bytes,2,rep,name=roots,proto3" json:"roots,omitempty"` + // List of nodes in the transaction + // + // Required: must be non-empty + Nodes []*DamlTransaction_Node `protobuf:"bytes,3,rep,name=nodes,proto3" json:"nodes,omitempty"` + // Node seeds are values associated with certain nodes used for generating cryptographic salts + // + // Required: must be non-empty + NodeSeeds []*DamlTransaction_NodeSeed `protobuf:"bytes,4,rep,name=node_seeds,json=nodeSeeds,proto3" json:"node_seeds,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DamlTransaction) Reset() { + *x = DamlTransaction{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DamlTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DamlTransaction) ProtoMessage() {} + +func (x *DamlTransaction) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DamlTransaction.ProtoReflect.Descriptor instead. +func (*DamlTransaction) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{15} +} + +func (x *DamlTransaction) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *DamlTransaction) GetRoots() []string { + if x != nil { + return x.Roots + } + return nil +} + +func (x *DamlTransaction) GetNodes() []*DamlTransaction_Node { + if x != nil { + return x.Nodes + } + return nil +} + +func (x *DamlTransaction) GetNodeSeeds() []*DamlTransaction_NodeSeed { + if x != nil { + return x.NodeSeeds + } + return nil +} + +type GetPreferredPackageVersionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The parties whose participants' vetting state should be considered when resolving the preferred package. + // + // Required: must be non-empty + Parties []string `protobuf:"bytes,1,rep,name=parties,proto3" json:"parties,omitempty"` + // The package-name for which the preferred package should be resolved. + // + // Required + PackageName string `protobuf:"bytes,2,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // The synchronizer whose vetting state should be used for resolving this query. + // If not specified, the vetting states of all synchronizers to which the participant is connected are used. + // + // Optional + SynchronizerId string `protobuf:"bytes,3,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The timestamp at which the package vetting validity should be computed + // on the latest topology snapshot as seen by the participant. + // If not provided, the participant's current clock time is used. + // + // Optional + VettingValidAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=vetting_valid_at,json=vettingValidAt,proto3" json:"vetting_valid_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPreferredPackageVersionRequest) Reset() { + *x = GetPreferredPackageVersionRequest{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPreferredPackageVersionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPreferredPackageVersionRequest) ProtoMessage() {} + +func (x *GetPreferredPackageVersionRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPreferredPackageVersionRequest.ProtoReflect.Descriptor instead. +func (*GetPreferredPackageVersionRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{16} +} + +func (x *GetPreferredPackageVersionRequest) GetParties() []string { + if x != nil { + return x.Parties + } + return nil +} + +func (x *GetPreferredPackageVersionRequest) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *GetPreferredPackageVersionRequest) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *GetPreferredPackageVersionRequest) GetVettingValidAt() *timestamppb.Timestamp { + if x != nil { + return x.VettingValidAt + } + return nil +} + +type GetPreferredPackageVersionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Not populated when no preferred package is found + // + // Optional + PackagePreference *PackagePreference `protobuf:"bytes,1,opt,name=package_preference,json=packagePreference,proto3" json:"package_preference,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPreferredPackageVersionResponse) Reset() { + *x = GetPreferredPackageVersionResponse{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPreferredPackageVersionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPreferredPackageVersionResponse) ProtoMessage() {} + +func (x *GetPreferredPackageVersionResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPreferredPackageVersionResponse.ProtoReflect.Descriptor instead. +func (*GetPreferredPackageVersionResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{17} +} + +func (x *GetPreferredPackageVersionResponse) GetPackagePreference() *PackagePreference { + if x != nil { + return x.PackagePreference + } + return nil +} + +type PackagePreference struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The package reference of the preferred package. + // + // Required + PackageReference *v2.PackageReference `protobuf:"bytes,1,opt,name=package_reference,json=packageReference,proto3" json:"package_reference,omitempty"` + // The synchronizer for which the preferred package was computed. + // If the synchronizer_id was specified in the request, then it matches the request synchronizer_id. + // + // Required + SynchronizerId string `protobuf:"bytes,2,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PackagePreference) Reset() { + *x = PackagePreference{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PackagePreference) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PackagePreference) ProtoMessage() {} + +func (x *PackagePreference) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[18] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PackagePreference.ProtoReflect.Descriptor instead. +func (*PackagePreference) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{18} +} + +func (x *PackagePreference) GetPackageReference() *v2.PackageReference { + if x != nil { + return x.PackageReference + } + return nil +} + +func (x *PackagePreference) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +// Defines a package-name for which the commonly vetted package with the highest version must be found. +type PackageVettingRequirement struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The parties whose participants' vetting state should be considered when resolving the preferred package. + // + // Required: must be non-empty + Parties []string `protobuf:"bytes,1,rep,name=parties,proto3" json:"parties,omitempty"` + // The package-name for which the preferred package should be resolved. + // + // Required + PackageName string `protobuf:"bytes,2,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PackageVettingRequirement) Reset() { + *x = PackageVettingRequirement{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PackageVettingRequirement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PackageVettingRequirement) ProtoMessage() {} + +func (x *PackageVettingRequirement) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PackageVettingRequirement.ProtoReflect.Descriptor instead. +func (*PackageVettingRequirement) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{19} +} + +func (x *PackageVettingRequirement) GetParties() []string { + if x != nil { + return x.Parties + } + return nil +} + +func (x *PackageVettingRequirement) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +type GetPreferredPackagesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The package-name vetting requirements for which the preferred packages should be resolved. + // + // Generally it is enough to provide the requirements for the intended command's root package-names. + // Additional package-name requirements can be provided when additional Daml transaction informees need to use + // package dependencies of the command's root packages. + // + // Required: must be non-empty + PackageVettingRequirements []*PackageVettingRequirement `protobuf:"bytes,1,rep,name=package_vetting_requirements,json=packageVettingRequirements,proto3" json:"package_vetting_requirements,omitempty"` + // The synchronizer whose vetting state should be used for resolving this query. + // If not specified, the vetting states of all synchronizers to which the participant is connected are used. + // + // Optional + SynchronizerId string `protobuf:"bytes,2,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The timestamp at which the package vetting validity should be computed + // on the latest topology snapshot as seen by the participant. + // If not provided, the participant's current clock time is used. + // + // Optional + VettingValidAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=vetting_valid_at,json=vettingValidAt,proto3" json:"vetting_valid_at,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPreferredPackagesRequest) Reset() { + *x = GetPreferredPackagesRequest{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPreferredPackagesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPreferredPackagesRequest) ProtoMessage() {} + +func (x *GetPreferredPackagesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[20] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPreferredPackagesRequest.ProtoReflect.Descriptor instead. +func (*GetPreferredPackagesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{20} +} + +func (x *GetPreferredPackagesRequest) GetPackageVettingRequirements() []*PackageVettingRequirement { + if x != nil { + return x.PackageVettingRequirements + } + return nil +} + +func (x *GetPreferredPackagesRequest) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *GetPreferredPackagesRequest) GetVettingValidAt() *timestamppb.Timestamp { + if x != nil { + return x.VettingValidAt + } + return nil +} + +type GetPreferredPackagesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The package references of the preferred packages. + // Must contain one package reference for each requested package-name. + // + // If you build command submissions whose content depends on the returned + // preferred packages, then we recommend submitting the preferred package-ids + // in the “package_id_selection_preference“ of the command submission to + // avoid race conditions with concurrent changes of the on-ledger package vetting state. + // + // Required: must be non-empty + PackageReferences []*v2.PackageReference `protobuf:"bytes,1,rep,name=package_references,json=packageReferences,proto3" json:"package_references,omitempty"` + // The synchronizer for which the package preferences are computed. + // If the synchronizer_id was specified in the request, then it matches the request synchronizer_id. + // + // Required + SynchronizerId string `protobuf:"bytes,2,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPreferredPackagesResponse) Reset() { + *x = GetPreferredPackagesResponse{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPreferredPackagesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPreferredPackagesResponse) ProtoMessage() {} + +func (x *GetPreferredPackagesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPreferredPackagesResponse.ProtoReflect.Descriptor instead. +func (*GetPreferredPackagesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{21} +} + +func (x *GetPreferredPackagesResponse) GetPackageReferences() []*v2.PackageReference { + if x != nil { + return x.PackageReferences + } + return nil +} + +func (x *GetPreferredPackagesResponse) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +type Metadata_SubmitterInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required: must be non-empty + ActAs []string `protobuf:"bytes,1,rep,name=act_as,json=actAs,proto3" json:"act_as,omitempty"` + // Required + CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Metadata_SubmitterInfo) Reset() { + *x = Metadata_SubmitterInfo{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Metadata_SubmitterInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metadata_SubmitterInfo) ProtoMessage() {} + +func (x *Metadata_SubmitterInfo) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[22] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Metadata_SubmitterInfo.ProtoReflect.Descriptor instead. +func (*Metadata_SubmitterInfo) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{14, 0} +} + +func (x *Metadata_SubmitterInfo) GetActAs() []string { + if x != nil { + return x.ActAs + } + return nil +} + +func (x *Metadata_SubmitterInfo) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +type Metadata_GlobalKeyMappingEntry struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + Key *GlobalKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // Optional + Value *v2.Value `protobuf:"bytes,2,opt,name=value,proto3,oneof" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Metadata_GlobalKeyMappingEntry) Reset() { + *x = Metadata_GlobalKeyMappingEntry{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Metadata_GlobalKeyMappingEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metadata_GlobalKeyMappingEntry) ProtoMessage() {} + +func (x *Metadata_GlobalKeyMappingEntry) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[23] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Metadata_GlobalKeyMappingEntry.ProtoReflect.Descriptor instead. +func (*Metadata_GlobalKeyMappingEntry) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{14, 1} +} + +func (x *Metadata_GlobalKeyMappingEntry) GetKey() *GlobalKey { + if x != nil { + return x.Key + } + return nil +} + +func (x *Metadata_GlobalKeyMappingEntry) GetValue() *v2.Value { + if x != nil { + return x.Value + } + return nil +} + +type Metadata_InputContract struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Contract: + // + // *Metadata_InputContract_V1 + Contract isMetadata_InputContract_Contract `protobuf_oneof:"contract"` + // Required + CreatedAt uint64 `protobuf:"varint,1000,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + // Required: must be non-empty + EventBlob []byte `protobuf:"bytes,1002,opt,name=event_blob,json=eventBlob,proto3" json:"event_blob,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Metadata_InputContract) Reset() { + *x = Metadata_InputContract{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Metadata_InputContract) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metadata_InputContract) ProtoMessage() {} + +func (x *Metadata_InputContract) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[24] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Metadata_InputContract.ProtoReflect.Descriptor instead. +func (*Metadata_InputContract) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{14, 2} +} + +func (x *Metadata_InputContract) GetContract() isMetadata_InputContract_Contract { + if x != nil { + return x.Contract + } + return nil +} + +func (x *Metadata_InputContract) GetV1() *v1.Create { + if x != nil { + if x, ok := x.Contract.(*Metadata_InputContract_V1); ok { + return x.V1 + } + } + return nil +} + +func (x *Metadata_InputContract) GetCreatedAt() uint64 { + if x != nil { + return x.CreatedAt + } + return 0 +} + +func (x *Metadata_InputContract) GetEventBlob() []byte { + if x != nil { + return x.EventBlob + } + return nil +} + +type isMetadata_InputContract_Contract interface { + isMetadata_InputContract_Contract() +} + +type Metadata_InputContract_V1 struct { + // When new versions will be added, they will show here + V1 *v1.Create `protobuf:"bytes,1,opt,name=v1,proto3,oneof"` +} + +func (*Metadata_InputContract_V1) isMetadata_InputContract_Contract() {} + +type DamlTransaction_NodeSeed struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + NodeId int32 `protobuf:"varint,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // Required: must be non-empty + Seed []byte `protobuf:"bytes,2,opt,name=seed,proto3" json:"seed,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DamlTransaction_NodeSeed) Reset() { + *x = DamlTransaction_NodeSeed{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DamlTransaction_NodeSeed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DamlTransaction_NodeSeed) ProtoMessage() {} + +func (x *DamlTransaction_NodeSeed) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[25] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DamlTransaction_NodeSeed.ProtoReflect.Descriptor instead. +func (*DamlTransaction_NodeSeed) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{15, 0} +} + +func (x *DamlTransaction_NodeSeed) GetNodeId() int32 { + if x != nil { + return x.NodeId + } + return 0 +} + +func (x *DamlTransaction_NodeSeed) GetSeed() []byte { + if x != nil { + return x.Seed + } + return nil +} + +// A transaction may contain nodes with different versions. +// Each node must be hashed using the hashing algorithm corresponding to its specific version. +// [docs-entry-start: DamlTransaction.Node] +type DamlTransaction_Node struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + NodeId string `protobuf:"bytes,1,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + // Versioned node + // + // # Required + // + // Types that are valid to be assigned to VersionedNode: + // + // *DamlTransaction_Node_V1 + VersionedNode isDamlTransaction_Node_VersionedNode `protobuf_oneof:"versioned_node"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DamlTransaction_Node) Reset() { + *x = DamlTransaction_Node{} + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DamlTransaction_Node) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DamlTransaction_Node) ProtoMessage() {} + +func (x *DamlTransaction_Node) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DamlTransaction_Node.ProtoReflect.Descriptor instead. +func (*DamlTransaction_Node) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP(), []int{15, 1} +} + +func (x *DamlTransaction_Node) GetNodeId() string { + if x != nil { + return x.NodeId + } + return "" +} + +func (x *DamlTransaction_Node) GetVersionedNode() isDamlTransaction_Node_VersionedNode { + if x != nil { + return x.VersionedNode + } + return nil +} + +func (x *DamlTransaction_Node) GetV1() *v1.Node { + if x != nil { + if x, ok := x.VersionedNode.(*DamlTransaction_Node_V1); ok { + return x.V1 + } + } + return nil +} + +type isDamlTransaction_Node_VersionedNode interface { + isDamlTransaction_Node_VersionedNode() +} + +type DamlTransaction_Node_V1 struct { + // Start at 1000 so we can add more fields before if necessary + // When new versions will be added, they will show here + // + // Required + V1 *v1.Node `protobuf:"bytes,1000,opt,name=v1,proto3,oneof"` +} + +func (*DamlTransaction_Node_V1) isDamlTransaction_Node_VersionedNode() {} + +var File_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDesc = "" + + "\n" + + "Gcom/daml/ledger/api/v2/interactive/interactive_submission_service.proto\x12\"com.daml.ledger.api.v2.interactive\x1a%com/daml/ledger/api/v2/commands.proto\x1a#com/daml/ledger/api/v2/crypto.proto\x1aKcom/daml/ledger/api/v2/interactive/interactive_submission_common_data.proto\x1aScom/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto\x1a.com/daml/ledger/api/v2/package_reference.proto\x1a(com/daml/ledger/api/v2/transaction.proto\x1a/com/daml/ledger/api/v2/transaction_filter.proto\x1a\"com/daml/ledger/api/v2/value.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x90\x01\n" + + "\x13CostEstimationHints\x12\x1a\n" + + "\bdisabled\x18\x01 \x01(\bR\bdisabled\x12]\n" + + "\x13expected_signatures\x18\x02 \x03(\x0e2,.com.daml.ledger.api.v2.SigningAlgorithmSpecR\x12expectedSignatures\"\xe4\x02\n" + + "\x0eCostEstimation\x12M\n" + + "\x14estimation_timestamp\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\x13estimationTimestamp\x12^\n" + + ",confirmation_request_traffic_cost_estimation\x18\x02 \x01(\x04R(confirmationRequestTrafficCostEstimation\x12`\n" + + "-confirmation_response_traffic_cost_estimation\x18\x03 \x01(\x04R)confirmationResponseTrafficCostEstimation\x12A\n" + + "\x1dtotal_traffic_cost_estimation\x18\x04 \x01(\x04R\x1atotalTrafficCostEstimation\"\xac\b\n" + + "\x18PrepareSubmissionRequest\x12\x17\n" + + "\auser_id\x18\x01 \x01(\tR\x06userId\x12\x1d\n" + + "\n" + + "command_id\x18\x02 \x01(\tR\tcommandId\x12;\n" + + "\bcommands\x18\x03 \x03(\v2\x1f.com.daml.ledger.api.v2.CommandR\bcommands\x12Y\n" + + "\x0fmin_ledger_time\x18\x04 \x01(\v21.com.daml.ledger.api.v2.interactive.MinLedgerTimeR\rminLedgerTime\x12G\n" + + "\x0fmax_record_time\x18\v \x01(\v2\x1a.google.protobuf.TimestampH\x00R\rmaxRecordTime\x88\x01\x01\x12\x15\n" + + "\x06act_as\x18\x05 \x03(\tR\x05actAs\x12\x17\n" + + "\aread_as\x18\x06 \x03(\tR\x06readAs\x12Z\n" + + "\x13disclosed_contracts\x18\a \x03(\v2).com.daml.ledger.api.v2.DisclosedContractR\x12disclosedContracts\x12'\n" + + "\x0fsynchronizer_id\x18\b \x01(\tR\x0esynchronizerId\x12E\n" + + "\x1fpackage_id_selection_preference\x18\t \x03(\tR\x1cpackageIdSelectionPreference\x12'\n" + + "\x0fverbose_hashing\x18\n" + + " \x01(\bR\x0everboseHashing\x12a\n" + + "\x16prefetch_contract_keys\x18\x0f \x03(\v2+.com.daml.ledger.api.v2.PrefetchContractKeyR\x14prefetchContractKeys\x12p\n" + + "\x15estimate_traffic_cost\x18\x10 \x01(\v27.com.daml.ledger.api.v2.interactive.CostEstimationHintsH\x01R\x13estimateTrafficCost\x88\x01\x01\x12s\n" + + "\x16hashing_scheme_version\x18\x11 \x01(\x0e28.com.daml.ledger.api.v2.interactive.HashingSchemeVersionH\x02R\x14hashingSchemeVersion\x88\x01\x01\x12+\n" + + "\x0ftaps_max_passes\x18\x12 \x01(\rH\x03R\rtapsMaxPasses\x88\x01\x01B\x12\n" + + "\x10_max_record_timeB\x18\n" + + "\x16_estimate_traffic_costB\x19\n" + + "\x17_hashing_scheme_versionB\x12\n" + + "\x10_taps_max_passes\"\xeb\x03\n" + + "\x19PrepareSubmissionResponse\x12j\n" + + "\x14prepared_transaction\x18\x01 \x01(\v27.com.daml.ledger.api.v2.interactive.PreparedTransactionR\x13preparedTransaction\x12:\n" + + "\x19prepared_transaction_hash\x18\x02 \x01(\fR\x17preparedTransactionHash\x12n\n" + + "\x16hashing_scheme_version\x18\x03 \x01(\x0e28.com.daml.ledger.api.v2.interactive.HashingSchemeVersionR\x14hashingSchemeVersion\x12,\n" + + "\x0fhashing_details\x18\x04 \x01(\tH\x00R\x0ehashingDetails\x88\x01\x01\x12`\n" + + "\x0fcost_estimation\x18\x05 \x01(\v22.com.daml.ledger.api.v2.interactive.CostEstimationH\x01R\x0ecostEstimation\x88\x01\x01B\x12\n" + + "\x10_hashing_detailsB\x12\n" + + "\x10_cost_estimation\"p\n" + + "\x15SinglePartySignatures\x12\x14\n" + + "\x05party\x18\x01 \x01(\tR\x05party\x12A\n" + + "\n" + + "signatures\x18\x02 \x03(\v2!.com.daml.ledger.api.v2.SignatureR\n" + + "signatures\"l\n" + + "\x0fPartySignatures\x12Y\n" + + "\n" + + "signatures\x18\x01 \x03(\v29.com.daml.ledger.api.v2.interactive.SinglePartySignaturesR\n" + + "signatures\"\x90\x05\n" + + "\x18ExecuteSubmissionRequest\x12j\n" + + "\x14prepared_transaction\x18\x01 \x01(\v27.com.daml.ledger.api.v2.interactive.PreparedTransactionR\x13preparedTransaction\x12^\n" + + "\x10party_signatures\x18\x02 \x01(\v23.com.daml.ledger.api.v2.interactive.PartySignaturesR\x0fpartySignatures\x12R\n" + + "\x16deduplication_duration\x18\x03 \x01(\v2\x19.google.protobuf.DurationH\x00R\x15deduplicationDuration\x123\n" + + "\x14deduplication_offset\x18\x04 \x01(\x03H\x00R\x13deduplicationOffset\x12#\n" + + "\rsubmission_id\x18\x05 \x01(\tR\fsubmissionId\x12\x17\n" + + "\auser_id\x18\x06 \x01(\tR\x06userId\x12n\n" + + "\x16hashing_scheme_version\x18\a \x01(\x0e28.com.daml.ledger.api.v2.interactive.HashingSchemeVersionR\x14hashingSchemeVersion\x12Y\n" + + "\x0fmin_ledger_time\x18\b \x01(\v21.com.daml.ledger.api.v2.interactive.MinLedgerTimeR\rminLedgerTimeB\x16\n" + + "\x14deduplication_period\"\x1b\n" + + "\x19ExecuteSubmissionResponse\"\x97\x05\n" + + "\x1fExecuteSubmissionAndWaitRequest\x12j\n" + + "\x14prepared_transaction\x18\x01 \x01(\v27.com.daml.ledger.api.v2.interactive.PreparedTransactionR\x13preparedTransaction\x12^\n" + + "\x10party_signatures\x18\x02 \x01(\v23.com.daml.ledger.api.v2.interactive.PartySignaturesR\x0fpartySignatures\x12R\n" + + "\x16deduplication_duration\x18\x03 \x01(\v2\x19.google.protobuf.DurationH\x00R\x15deduplicationDuration\x123\n" + + "\x14deduplication_offset\x18\x04 \x01(\x03H\x00R\x13deduplicationOffset\x12#\n" + + "\rsubmission_id\x18\x05 \x01(\tR\fsubmissionId\x12\x17\n" + + "\auser_id\x18\x06 \x01(\tR\x06userId\x12n\n" + + "\x16hashing_scheme_version\x18\a \x01(\x0e28.com.daml.ledger.api.v2.interactive.HashingSchemeVersionR\x14hashingSchemeVersion\x12Y\n" + + "\x0fmin_ledger_time\x18\b \x01(\v21.com.daml.ledger.api.v2.interactive.MinLedgerTimeR\rminLedgerTimeB\x16\n" + + "\x14deduplication_period\"l\n" + + " ExecuteSubmissionAndWaitResponse\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12+\n" + + "\x11completion_offset\x18\x02 \x01(\x03R\x10completionOffset\"\xff\x05\n" + + "-ExecuteSubmissionAndWaitForTransactionRequest\x12j\n" + + "\x14prepared_transaction\x18\x01 \x01(\v27.com.daml.ledger.api.v2.interactive.PreparedTransactionR\x13preparedTransaction\x12^\n" + + "\x10party_signatures\x18\x02 \x01(\v23.com.daml.ledger.api.v2.interactive.PartySignaturesR\x0fpartySignatures\x12R\n" + + "\x16deduplication_duration\x18\x03 \x01(\v2\x19.google.protobuf.DurationH\x00R\x15deduplicationDuration\x123\n" + + "\x14deduplication_offset\x18\x04 \x01(\x03H\x00R\x13deduplicationOffset\x12#\n" + + "\rsubmission_id\x18\x05 \x01(\tR\fsubmissionId\x12\x17\n" + + "\auser_id\x18\x06 \x01(\tR\x06userId\x12n\n" + + "\x16hashing_scheme_version\x18\a \x01(\x0e28.com.daml.ledger.api.v2.interactive.HashingSchemeVersionR\x14hashingSchemeVersion\x12Y\n" + + "\x0fmin_ledger_time\x18\b \x01(\v21.com.daml.ledger.api.v2.interactive.MinLedgerTimeR\rminLedgerTime\x12X\n" + + "\x12transaction_format\x18\t \x01(\v2).com.daml.ledger.api.v2.TransactionFormatR\x11transactionFormatB\x16\n" + + "\x14deduplication_period\"w\n" + + ".ExecuteSubmissionAndWaitForTransactionResponse\x12E\n" + + "\vtransaction\x18\x01 \x01(\v2#.com.daml.ledger.api.v2.TransactionR\vtransaction\"\xb0\x01\n" + + "\rMinLedgerTime\x12K\n" + + "\x13min_ledger_time_abs\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampH\x00R\x10minLedgerTimeAbs\x12J\n" + + "\x13min_ledger_time_rel\x18\x02 \x01(\v2\x19.google.protobuf.DurationH\x00R\x10minLedgerTimeRelB\x06\n" + + "\x04time\"\xb6\x01\n" + + "\x13PreparedTransaction\x12U\n" + + "\vtransaction\x18\x01 \x01(\v23.com.daml.ledger.api.v2.interactive.DamlTransactionR\vtransaction\x12H\n" + + "\bmetadata\x18\x02 \x01(\v2,.com.daml.ledger.api.v2.interactive.MetadataR\bmetadata\"\x86\t\n" + + "\bMetadata\x12a\n" + + "\x0esubmitter_info\x18\x02 \x01(\v2:.com.daml.ledger.api.v2.interactive.Metadata.SubmitterInfoR\rsubmitterInfo\x12'\n" + + "\x0fsynchronizer_id\x18\x03 \x01(\tR\x0esynchronizerId\x12%\n" + + "\x0emediator_group\x18\x04 \x01(\rR\rmediatorGroup\x12)\n" + + "\x10transaction_uuid\x18\x05 \x01(\tR\x0ftransactionUuid\x12)\n" + + "\x10preparation_time\x18\x06 \x01(\x04R\x0fpreparationTime\x12c\n" + + "\x0finput_contracts\x18\a \x03(\v2:.com.daml.ledger.api.v2.interactive.Metadata.InputContractR\x0einputContracts\x12>\n" + + "\x19min_ledger_effective_time\x18\t \x01(\x04H\x00R\x16minLedgerEffectiveTime\x88\x01\x01\x12>\n" + + "\x19max_ledger_effective_time\x18\n" + + " \x01(\x04H\x01R\x16maxLedgerEffectiveTime\x88\x01\x01\x12p\n" + + "\x12global_key_mapping\x18\b \x03(\v2B.com.daml.ledger.api.v2.interactive.Metadata.GlobalKeyMappingEntryR\x10globalKeyMapping\x12+\n" + + "\x0fmax_record_time\x18\v \x01(\x04H\x02R\rmaxRecordTime\x88\x01\x01\x1aE\n" + + "\rSubmitterInfo\x12\x15\n" + + "\x06act_as\x18\x01 \x03(\tR\x05actAs\x12\x1d\n" + + "\n" + + "command_id\x18\x02 \x01(\tR\tcommandId\x1a\x9c\x01\n" + + "\x15GlobalKeyMappingEntry\x12?\n" + + "\x03key\x18\x01 \x01(\v2-.com.daml.ledger.api.v2.interactive.GlobalKeyR\x03key\x128\n" + + "\x05value\x18\x02 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueH\x00R\x05value\x88\x01\x01B\b\n" + + "\x06_value\x1a\xb0\x01\n" + + "\rInputContract\x12K\n" + + "\x02v1\x18\x01 \x01(\v29.com.daml.ledger.api.v2.interactive.transaction.v1.CreateH\x00R\x02v1\x12\x1e\n" + + "\n" + + "created_at\x18\xe8\a \x01(\x04R\tcreatedAt\x12\x1e\n" + + "\n" + + "event_blob\x18\xea\a \x01(\fR\teventBlobB\n" + + "\n" + + "\bcontractJ\x06\b\xe9\a\x10\xea\aB\x1c\n" + + "\x1a_min_ledger_effective_timeB\x1c\n" + + "\x1a_max_ledger_effective_timeB\x12\n" + + "\x10_max_record_timeJ\x04\b\x01\x10\x02\"\xa6\x03\n" + + "\x0fDamlTransaction\x12\x18\n" + + "\aversion\x18\x01 \x01(\tR\aversion\x12\x14\n" + + "\x05roots\x18\x02 \x03(\tR\x05roots\x12N\n" + + "\x05nodes\x18\x03 \x03(\v28.com.daml.ledger.api.v2.interactive.DamlTransaction.NodeR\x05nodes\x12[\n" + + "\n" + + "node_seeds\x18\x04 \x03(\v2<.com.daml.ledger.api.v2.interactive.DamlTransaction.NodeSeedR\tnodeSeeds\x1a7\n" + + "\bNodeSeed\x12\x17\n" + + "\anode_id\x18\x01 \x01(\x05R\x06nodeId\x12\x12\n" + + "\x04seed\x18\x02 \x01(\fR\x04seed\x1a}\n" + + "\x04Node\x12\x17\n" + + "\anode_id\x18\x01 \x01(\tR\x06nodeId\x12J\n" + + "\x02v1\x18\xe8\a \x01(\v27.com.daml.ledger.api.v2.interactive.transaction.v1.NodeH\x00R\x02v1B\x10\n" + + "\x0eversioned_node\"\xcf\x01\n" + + "!GetPreferredPackageVersionRequest\x12\x18\n" + + "\aparties\x18\x01 \x03(\tR\aparties\x12!\n" + + "\fpackage_name\x18\x02 \x01(\tR\vpackageName\x12'\n" + + "\x0fsynchronizer_id\x18\x03 \x01(\tR\x0esynchronizerId\x12D\n" + + "\x10vetting_valid_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\x0evettingValidAt\"\x8a\x01\n" + + "\"GetPreferredPackageVersionResponse\x12d\n" + + "\x12package_preference\x18\x01 \x01(\v25.com.daml.ledger.api.v2.interactive.PackagePreferenceR\x11packagePreference\"\x93\x01\n" + + "\x11PackagePreference\x12U\n" + + "\x11package_reference\x18\x01 \x01(\v2(.com.daml.ledger.api.v2.PackageReferenceR\x10packageReference\x12'\n" + + "\x0fsynchronizer_id\x18\x02 \x01(\tR\x0esynchronizerId\"X\n" + + "\x19PackageVettingRequirement\x12\x18\n" + + "\aparties\x18\x01 \x03(\tR\aparties\x12!\n" + + "\fpackage_name\x18\x02 \x01(\tR\vpackageName\"\x8d\x02\n" + + "\x1bGetPreferredPackagesRequest\x12\x7f\n" + + "\x1cpackage_vetting_requirements\x18\x01 \x03(\v2=.com.daml.ledger.api.v2.interactive.PackageVettingRequirementR\x1apackageVettingRequirements\x12'\n" + + "\x0fsynchronizer_id\x18\x02 \x01(\tR\x0esynchronizerId\x12D\n" + + "\x10vetting_valid_at\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x0evettingValidAt\"\xa0\x01\n" + + "\x1cGetPreferredPackagesResponse\x12W\n" + + "\x12package_references\x18\x01 \x03(\v2(.com.daml.ledger.api.v2.PackageReferenceR\x11packageReferences\x12'\n" + + "\x0fsynchronizer_id\x18\x02 \x01(\tR\x0esynchronizerId*\x82\x01\n" + + "\x14HashingSchemeVersion\x12&\n" + + "\"HASHING_SCHEME_VERSION_UNSPECIFIED\x10\x00\x12\x1d\n" + + "\x19HASHING_SCHEME_VERSION_V2\x10\x02\x12\x1d\n" + + "\x19HASHING_SCHEME_VERSION_V3\x10\x03\"\x04\b\x01\x10\x012\x88\b\n" + + "\x1cInteractiveSubmissionService\x12\x90\x01\n" + + "\x11PrepareSubmission\x12<.com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest\x1a=.com.daml.ledger.api.v2.interactive.PrepareSubmissionResponse\x12\x90\x01\n" + + "\x11ExecuteSubmission\x12<.com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest\x1a=.com.daml.ledger.api.v2.interactive.ExecuteSubmissionResponse\x12\xa5\x01\n" + + "\x18ExecuteSubmissionAndWait\x12C.com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest\x1aD.com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitResponse\x12\xcf\x01\n" + + "&ExecuteSubmissionAndWaitForTransaction\x12Q.com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest\x1aR.com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionResponse\x12\xab\x01\n" + + "\x1aGetPreferredPackageVersion\x12E.com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionRequest\x1aF.com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionResponse\x12\x99\x01\n" + + "\x14GetPreferredPackages\x12?.com.daml.ledger.api.v2.interactive.GetPreferredPackagesRequest\x1a@.com.daml.ledger.api.v2.interactive.GetPreferredPackagesResponseB\xd3\x02\n" + + "&com.com.daml.ledger.api.v2.interactiveB!InteractiveSubmissionServiceProtoP\x01ZVgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive\xa2\x02\x06CDLAVI\xaa\x02\"Com.Daml.Ledger.Api.V2.Interactive\xca\x02\"Com\\Daml\\Ledger\\Api\\V2\\Interactive\xe2\x02.Com\\Daml\\Ledger\\Api\\V2\\Interactive\\GPBMetadata\xea\x02'Com::Daml::Ledger::Api::V2::Interactiveb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_goTypes = []any{ + (HashingSchemeVersion)(0), // 0: com.daml.ledger.api.v2.interactive.HashingSchemeVersion + (*CostEstimationHints)(nil), // 1: com.daml.ledger.api.v2.interactive.CostEstimationHints + (*CostEstimation)(nil), // 2: com.daml.ledger.api.v2.interactive.CostEstimation + (*PrepareSubmissionRequest)(nil), // 3: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest + (*PrepareSubmissionResponse)(nil), // 4: com.daml.ledger.api.v2.interactive.PrepareSubmissionResponse + (*SinglePartySignatures)(nil), // 5: com.daml.ledger.api.v2.interactive.SinglePartySignatures + (*PartySignatures)(nil), // 6: com.daml.ledger.api.v2.interactive.PartySignatures + (*ExecuteSubmissionRequest)(nil), // 7: com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest + (*ExecuteSubmissionResponse)(nil), // 8: com.daml.ledger.api.v2.interactive.ExecuteSubmissionResponse + (*ExecuteSubmissionAndWaitRequest)(nil), // 9: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest + (*ExecuteSubmissionAndWaitResponse)(nil), // 10: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitResponse + (*ExecuteSubmissionAndWaitForTransactionRequest)(nil), // 11: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest + (*ExecuteSubmissionAndWaitForTransactionResponse)(nil), // 12: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionResponse + (*MinLedgerTime)(nil), // 13: com.daml.ledger.api.v2.interactive.MinLedgerTime + (*PreparedTransaction)(nil), // 14: com.daml.ledger.api.v2.interactive.PreparedTransaction + (*Metadata)(nil), // 15: com.daml.ledger.api.v2.interactive.Metadata + (*DamlTransaction)(nil), // 16: com.daml.ledger.api.v2.interactive.DamlTransaction + (*GetPreferredPackageVersionRequest)(nil), // 17: com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionRequest + (*GetPreferredPackageVersionResponse)(nil), // 18: com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionResponse + (*PackagePreference)(nil), // 19: com.daml.ledger.api.v2.interactive.PackagePreference + (*PackageVettingRequirement)(nil), // 20: com.daml.ledger.api.v2.interactive.PackageVettingRequirement + (*GetPreferredPackagesRequest)(nil), // 21: com.daml.ledger.api.v2.interactive.GetPreferredPackagesRequest + (*GetPreferredPackagesResponse)(nil), // 22: com.daml.ledger.api.v2.interactive.GetPreferredPackagesResponse + (*Metadata_SubmitterInfo)(nil), // 23: com.daml.ledger.api.v2.interactive.Metadata.SubmitterInfo + (*Metadata_GlobalKeyMappingEntry)(nil), // 24: com.daml.ledger.api.v2.interactive.Metadata.GlobalKeyMappingEntry + (*Metadata_InputContract)(nil), // 25: com.daml.ledger.api.v2.interactive.Metadata.InputContract + (*DamlTransaction_NodeSeed)(nil), // 26: com.daml.ledger.api.v2.interactive.DamlTransaction.NodeSeed + (*DamlTransaction_Node)(nil), // 27: com.daml.ledger.api.v2.interactive.DamlTransaction.Node + (v2.SigningAlgorithmSpec)(0), // 28: com.daml.ledger.api.v2.SigningAlgorithmSpec + (*timestamppb.Timestamp)(nil), // 29: google.protobuf.Timestamp + (*v2.Command)(nil), // 30: com.daml.ledger.api.v2.Command + (*v2.DisclosedContract)(nil), // 31: com.daml.ledger.api.v2.DisclosedContract + (*v2.PrefetchContractKey)(nil), // 32: com.daml.ledger.api.v2.PrefetchContractKey + (*v2.Signature)(nil), // 33: com.daml.ledger.api.v2.Signature + (*durationpb.Duration)(nil), // 34: google.protobuf.Duration + (*v2.TransactionFormat)(nil), // 35: com.daml.ledger.api.v2.TransactionFormat + (*v2.Transaction)(nil), // 36: com.daml.ledger.api.v2.Transaction + (*v2.PackageReference)(nil), // 37: com.daml.ledger.api.v2.PackageReference + (*GlobalKey)(nil), // 38: com.daml.ledger.api.v2.interactive.GlobalKey + (*v2.Value)(nil), // 39: com.daml.ledger.api.v2.Value + (*v1.Create)(nil), // 40: com.daml.ledger.api.v2.interactive.transaction.v1.Create + (*v1.Node)(nil), // 41: com.daml.ledger.api.v2.interactive.transaction.v1.Node +} +var file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_depIdxs = []int32{ + 28, // 0: com.daml.ledger.api.v2.interactive.CostEstimationHints.expected_signatures:type_name -> com.daml.ledger.api.v2.SigningAlgorithmSpec + 29, // 1: com.daml.ledger.api.v2.interactive.CostEstimation.estimation_timestamp:type_name -> google.protobuf.Timestamp + 30, // 2: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest.commands:type_name -> com.daml.ledger.api.v2.Command + 13, // 3: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest.min_ledger_time:type_name -> com.daml.ledger.api.v2.interactive.MinLedgerTime + 29, // 4: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest.max_record_time:type_name -> google.protobuf.Timestamp + 31, // 5: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest.disclosed_contracts:type_name -> com.daml.ledger.api.v2.DisclosedContract + 32, // 6: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest.prefetch_contract_keys:type_name -> com.daml.ledger.api.v2.PrefetchContractKey + 1, // 7: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest.estimate_traffic_cost:type_name -> com.daml.ledger.api.v2.interactive.CostEstimationHints + 0, // 8: com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest.hashing_scheme_version:type_name -> com.daml.ledger.api.v2.interactive.HashingSchemeVersion + 14, // 9: com.daml.ledger.api.v2.interactive.PrepareSubmissionResponse.prepared_transaction:type_name -> com.daml.ledger.api.v2.interactive.PreparedTransaction + 0, // 10: com.daml.ledger.api.v2.interactive.PrepareSubmissionResponse.hashing_scheme_version:type_name -> com.daml.ledger.api.v2.interactive.HashingSchemeVersion + 2, // 11: com.daml.ledger.api.v2.interactive.PrepareSubmissionResponse.cost_estimation:type_name -> com.daml.ledger.api.v2.interactive.CostEstimation + 33, // 12: com.daml.ledger.api.v2.interactive.SinglePartySignatures.signatures:type_name -> com.daml.ledger.api.v2.Signature + 5, // 13: com.daml.ledger.api.v2.interactive.PartySignatures.signatures:type_name -> com.daml.ledger.api.v2.interactive.SinglePartySignatures + 14, // 14: com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest.prepared_transaction:type_name -> com.daml.ledger.api.v2.interactive.PreparedTransaction + 6, // 15: com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest.party_signatures:type_name -> com.daml.ledger.api.v2.interactive.PartySignatures + 34, // 16: com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest.deduplication_duration:type_name -> google.protobuf.Duration + 0, // 17: com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest.hashing_scheme_version:type_name -> com.daml.ledger.api.v2.interactive.HashingSchemeVersion + 13, // 18: com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest.min_ledger_time:type_name -> com.daml.ledger.api.v2.interactive.MinLedgerTime + 14, // 19: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest.prepared_transaction:type_name -> com.daml.ledger.api.v2.interactive.PreparedTransaction + 6, // 20: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest.party_signatures:type_name -> com.daml.ledger.api.v2.interactive.PartySignatures + 34, // 21: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest.deduplication_duration:type_name -> google.protobuf.Duration + 0, // 22: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest.hashing_scheme_version:type_name -> com.daml.ledger.api.v2.interactive.HashingSchemeVersion + 13, // 23: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest.min_ledger_time:type_name -> com.daml.ledger.api.v2.interactive.MinLedgerTime + 14, // 24: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest.prepared_transaction:type_name -> com.daml.ledger.api.v2.interactive.PreparedTransaction + 6, // 25: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest.party_signatures:type_name -> com.daml.ledger.api.v2.interactive.PartySignatures + 34, // 26: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest.deduplication_duration:type_name -> google.protobuf.Duration + 0, // 27: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest.hashing_scheme_version:type_name -> com.daml.ledger.api.v2.interactive.HashingSchemeVersion + 13, // 28: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest.min_ledger_time:type_name -> com.daml.ledger.api.v2.interactive.MinLedgerTime + 35, // 29: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest.transaction_format:type_name -> com.daml.ledger.api.v2.TransactionFormat + 36, // 30: com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionResponse.transaction:type_name -> com.daml.ledger.api.v2.Transaction + 29, // 31: com.daml.ledger.api.v2.interactive.MinLedgerTime.min_ledger_time_abs:type_name -> google.protobuf.Timestamp + 34, // 32: com.daml.ledger.api.v2.interactive.MinLedgerTime.min_ledger_time_rel:type_name -> google.protobuf.Duration + 16, // 33: com.daml.ledger.api.v2.interactive.PreparedTransaction.transaction:type_name -> com.daml.ledger.api.v2.interactive.DamlTransaction + 15, // 34: com.daml.ledger.api.v2.interactive.PreparedTransaction.metadata:type_name -> com.daml.ledger.api.v2.interactive.Metadata + 23, // 35: com.daml.ledger.api.v2.interactive.Metadata.submitter_info:type_name -> com.daml.ledger.api.v2.interactive.Metadata.SubmitterInfo + 25, // 36: com.daml.ledger.api.v2.interactive.Metadata.input_contracts:type_name -> com.daml.ledger.api.v2.interactive.Metadata.InputContract + 24, // 37: com.daml.ledger.api.v2.interactive.Metadata.global_key_mapping:type_name -> com.daml.ledger.api.v2.interactive.Metadata.GlobalKeyMappingEntry + 27, // 38: com.daml.ledger.api.v2.interactive.DamlTransaction.nodes:type_name -> com.daml.ledger.api.v2.interactive.DamlTransaction.Node + 26, // 39: com.daml.ledger.api.v2.interactive.DamlTransaction.node_seeds:type_name -> com.daml.ledger.api.v2.interactive.DamlTransaction.NodeSeed + 29, // 40: com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionRequest.vetting_valid_at:type_name -> google.protobuf.Timestamp + 19, // 41: com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionResponse.package_preference:type_name -> com.daml.ledger.api.v2.interactive.PackagePreference + 37, // 42: com.daml.ledger.api.v2.interactive.PackagePreference.package_reference:type_name -> com.daml.ledger.api.v2.PackageReference + 20, // 43: com.daml.ledger.api.v2.interactive.GetPreferredPackagesRequest.package_vetting_requirements:type_name -> com.daml.ledger.api.v2.interactive.PackageVettingRequirement + 29, // 44: com.daml.ledger.api.v2.interactive.GetPreferredPackagesRequest.vetting_valid_at:type_name -> google.protobuf.Timestamp + 37, // 45: com.daml.ledger.api.v2.interactive.GetPreferredPackagesResponse.package_references:type_name -> com.daml.ledger.api.v2.PackageReference + 38, // 46: com.daml.ledger.api.v2.interactive.Metadata.GlobalKeyMappingEntry.key:type_name -> com.daml.ledger.api.v2.interactive.GlobalKey + 39, // 47: com.daml.ledger.api.v2.interactive.Metadata.GlobalKeyMappingEntry.value:type_name -> com.daml.ledger.api.v2.Value + 40, // 48: com.daml.ledger.api.v2.interactive.Metadata.InputContract.v1:type_name -> com.daml.ledger.api.v2.interactive.transaction.v1.Create + 41, // 49: com.daml.ledger.api.v2.interactive.DamlTransaction.Node.v1:type_name -> com.daml.ledger.api.v2.interactive.transaction.v1.Node + 3, // 50: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.PrepareSubmission:input_type -> com.daml.ledger.api.v2.interactive.PrepareSubmissionRequest + 7, // 51: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.ExecuteSubmission:input_type -> com.daml.ledger.api.v2.interactive.ExecuteSubmissionRequest + 9, // 52: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.ExecuteSubmissionAndWait:input_type -> com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitRequest + 11, // 53: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.ExecuteSubmissionAndWaitForTransaction:input_type -> com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionRequest + 17, // 54: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.GetPreferredPackageVersion:input_type -> com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionRequest + 21, // 55: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.GetPreferredPackages:input_type -> com.daml.ledger.api.v2.interactive.GetPreferredPackagesRequest + 4, // 56: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.PrepareSubmission:output_type -> com.daml.ledger.api.v2.interactive.PrepareSubmissionResponse + 8, // 57: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.ExecuteSubmission:output_type -> com.daml.ledger.api.v2.interactive.ExecuteSubmissionResponse + 10, // 58: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.ExecuteSubmissionAndWait:output_type -> com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitResponse + 12, // 59: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.ExecuteSubmissionAndWaitForTransaction:output_type -> com.daml.ledger.api.v2.interactive.ExecuteSubmissionAndWaitForTransactionResponse + 18, // 60: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.GetPreferredPackageVersion:output_type -> com.daml.ledger.api.v2.interactive.GetPreferredPackageVersionResponse + 22, // 61: com.daml.ledger.api.v2.interactive.InteractiveSubmissionService.GetPreferredPackages:output_type -> com.daml.ledger.api.v2.interactive.GetPreferredPackagesResponse + 56, // [56:62] is the sub-list for method output_type + 50, // [50:56] is the sub-list for method input_type + 50, // [50:50] is the sub-list for extension type_name + 50, // [50:50] is the sub-list for extension extendee + 0, // [0:50] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_init() } +func file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_init() { + if File_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_interactive_interactive_submission_common_data_proto_init() + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[2].OneofWrappers = []any{} + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[3].OneofWrappers = []any{} + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[6].OneofWrappers = []any{ + (*ExecuteSubmissionRequest_DeduplicationDuration)(nil), + (*ExecuteSubmissionRequest_DeduplicationOffset)(nil), + } + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[8].OneofWrappers = []any{ + (*ExecuteSubmissionAndWaitRequest_DeduplicationDuration)(nil), + (*ExecuteSubmissionAndWaitRequest_DeduplicationOffset)(nil), + } + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[10].OneofWrappers = []any{ + (*ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationDuration)(nil), + (*ExecuteSubmissionAndWaitForTransactionRequest_DeduplicationOffset)(nil), + } + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[12].OneofWrappers = []any{ + (*MinLedgerTime_MinLedgerTimeAbs)(nil), + (*MinLedgerTime_MinLedgerTimeRel)(nil), + } + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[14].OneofWrappers = []any{} + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[23].OneofWrappers = []any{} + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[24].OneofWrappers = []any{ + (*Metadata_InputContract_V1)(nil), + } + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes[26].OneofWrappers = []any{ + (*DamlTransaction_Node_V1)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_rawDesc)), + NumEnums: 1, + NumMessages: 27, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_depIdxs, + EnumInfos: file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_enumTypes, + MessageInfos: file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto = out.File + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_interactive_interactive_submission_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service_grpc.pb.go new file mode 100644 index 00000000..f2a1a55e --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/interactive/interactive_submission_service_grpc.pb.go @@ -0,0 +1,407 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/interactive/interactive_submission_service.proto + +package interactive + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + InteractiveSubmissionService_PrepareSubmission_FullMethodName = "/com.daml.ledger.api.v2.interactive.InteractiveSubmissionService/PrepareSubmission" + InteractiveSubmissionService_ExecuteSubmission_FullMethodName = "/com.daml.ledger.api.v2.interactive.InteractiveSubmissionService/ExecuteSubmission" + InteractiveSubmissionService_ExecuteSubmissionAndWait_FullMethodName = "/com.daml.ledger.api.v2.interactive.InteractiveSubmissionService/ExecuteSubmissionAndWait" + InteractiveSubmissionService_ExecuteSubmissionAndWaitForTransaction_FullMethodName = "/com.daml.ledger.api.v2.interactive.InteractiveSubmissionService/ExecuteSubmissionAndWaitForTransaction" + InteractiveSubmissionService_GetPreferredPackageVersion_FullMethodName = "/com.daml.ledger.api.v2.interactive.InteractiveSubmissionService/GetPreferredPackageVersion" + InteractiveSubmissionService_GetPreferredPackages_FullMethodName = "/com.daml.ledger.api.v2.interactive.InteractiveSubmissionService/GetPreferredPackages" +) + +// InteractiveSubmissionServiceClient is the client API for InteractiveSubmissionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// # Service allowing interactive construction of command submissions +// +// The prepare and execute endpoints allow to submit commands in 2-steps: +// +// 1. prepare transaction from commands, +// 2. submit the prepared transaction +// +// This gives callers the ability to sign the daml transaction with their own signing keys +type InteractiveSubmissionServiceClient interface { + // Requires `readAs` scope for the submitting party when LAPI User authorization is enabled + PrepareSubmission(ctx context.Context, in *PrepareSubmissionRequest, opts ...grpc.CallOption) (*PrepareSubmissionResponse, error) + // Execute a prepared submission _asynchronously_ on the ledger. + // Requires a signature of the transaction from the submitting external party. + ExecuteSubmission(ctx context.Context, in *ExecuteSubmissionRequest, opts ...grpc.CallOption) (*ExecuteSubmissionResponse, error) + // Similar to ExecuteSubmission but _synchronously_ wait for the completion of the transaction + // IMPORTANT: Relying on the response from this endpoint requires trusting the Participant Node to be honest. + // A malicious node could make a successfully committed request appeared failed and vice versa + ExecuteSubmissionAndWait(ctx context.Context, in *ExecuteSubmissionAndWaitRequest, opts ...grpc.CallOption) (*ExecuteSubmissionAndWaitResponse, error) + // Similar to ExecuteSubmissionAndWait but additionally returns the transaction + // IMPORTANT: Relying on the response from this endpoint requires trusting the Participant Node to be honest. + // A malicious node could make a successfully committed request appear as failed and vice versa + ExecuteSubmissionAndWaitForTransaction(ctx context.Context, in *ExecuteSubmissionAndWaitForTransactionRequest, opts ...grpc.CallOption) (*ExecuteSubmissionAndWaitForTransactionResponse, error) + // A preferred package is the highest-versioned package for a provided package-name + // that is vetted by all the participants hosting the provided parties. + // + // Ledger API clients should use this endpoint for constructing command submissions + // that are compatible with the provided preferred package, by making informed decisions on: + // - which are the compatible packages that can be used to create contracts + // - which contract or exercise choice argument version can be used in the command + // - which choices can be executed on a template or interface of a contract + // + // Can be accessed by any Ledger API client with a valid token when Ledger API authorization is enabled. + // + // Provided for backwards compatibility, it will be removed in the Canton version 3.4.0 + GetPreferredPackageVersion(ctx context.Context, in *GetPreferredPackageVersionRequest, opts ...grpc.CallOption) (*GetPreferredPackageVersionResponse, error) + // Compute the preferred packages for the vetting requirements in the request. + // A preferred package is the highest-versioned package for a provided package-name + // that is vetted by all the participants hosting the provided parties. + // + // Ledger API clients should use this endpoint for constructing command submissions + // that are compatible with the provided preferred packages, by making informed decisions on: + // - which are the compatible packages that can be used to create contracts + // - which contract or exercise choice argument version can be used in the command + // - which choices can be executed on a template or interface of a contract + // + // If the package preferences could not be computed due to no selection satisfying the requirements, + // a `FAILED_PRECONDITION` error will be returned. + // + // Can be accessed by any Ledger API client with a valid token when Ledger API authorization is enabled. + // + // Experimental API: this endpoint is not guaranteed to provide backwards compatibility in future releases + GetPreferredPackages(ctx context.Context, in *GetPreferredPackagesRequest, opts ...grpc.CallOption) (*GetPreferredPackagesResponse, error) +} + +type interactiveSubmissionServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewInteractiveSubmissionServiceClient(cc grpc.ClientConnInterface) InteractiveSubmissionServiceClient { + return &interactiveSubmissionServiceClient{cc} +} + +func (c *interactiveSubmissionServiceClient) PrepareSubmission(ctx context.Context, in *PrepareSubmissionRequest, opts ...grpc.CallOption) (*PrepareSubmissionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PrepareSubmissionResponse) + err := c.cc.Invoke(ctx, InteractiveSubmissionService_PrepareSubmission_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *interactiveSubmissionServiceClient) ExecuteSubmission(ctx context.Context, in *ExecuteSubmissionRequest, opts ...grpc.CallOption) (*ExecuteSubmissionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ExecuteSubmissionResponse) + err := c.cc.Invoke(ctx, InteractiveSubmissionService_ExecuteSubmission_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *interactiveSubmissionServiceClient) ExecuteSubmissionAndWait(ctx context.Context, in *ExecuteSubmissionAndWaitRequest, opts ...grpc.CallOption) (*ExecuteSubmissionAndWaitResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ExecuteSubmissionAndWaitResponse) + err := c.cc.Invoke(ctx, InteractiveSubmissionService_ExecuteSubmissionAndWait_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *interactiveSubmissionServiceClient) ExecuteSubmissionAndWaitForTransaction(ctx context.Context, in *ExecuteSubmissionAndWaitForTransactionRequest, opts ...grpc.CallOption) (*ExecuteSubmissionAndWaitForTransactionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ExecuteSubmissionAndWaitForTransactionResponse) + err := c.cc.Invoke(ctx, InteractiveSubmissionService_ExecuteSubmissionAndWaitForTransaction_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *interactiveSubmissionServiceClient) GetPreferredPackageVersion(ctx context.Context, in *GetPreferredPackageVersionRequest, opts ...grpc.CallOption) (*GetPreferredPackageVersionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetPreferredPackageVersionResponse) + err := c.cc.Invoke(ctx, InteractiveSubmissionService_GetPreferredPackageVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *interactiveSubmissionServiceClient) GetPreferredPackages(ctx context.Context, in *GetPreferredPackagesRequest, opts ...grpc.CallOption) (*GetPreferredPackagesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetPreferredPackagesResponse) + err := c.cc.Invoke(ctx, InteractiveSubmissionService_GetPreferredPackages_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// InteractiveSubmissionServiceServer is the server API for InteractiveSubmissionService service. +// All implementations must embed UnimplementedInteractiveSubmissionServiceServer +// for forward compatibility. +// +// # Service allowing interactive construction of command submissions +// +// The prepare and execute endpoints allow to submit commands in 2-steps: +// +// 1. prepare transaction from commands, +// 2. submit the prepared transaction +// +// This gives callers the ability to sign the daml transaction with their own signing keys +type InteractiveSubmissionServiceServer interface { + // Requires `readAs` scope for the submitting party when LAPI User authorization is enabled + PrepareSubmission(context.Context, *PrepareSubmissionRequest) (*PrepareSubmissionResponse, error) + // Execute a prepared submission _asynchronously_ on the ledger. + // Requires a signature of the transaction from the submitting external party. + ExecuteSubmission(context.Context, *ExecuteSubmissionRequest) (*ExecuteSubmissionResponse, error) + // Similar to ExecuteSubmission but _synchronously_ wait for the completion of the transaction + // IMPORTANT: Relying on the response from this endpoint requires trusting the Participant Node to be honest. + // A malicious node could make a successfully committed request appeared failed and vice versa + ExecuteSubmissionAndWait(context.Context, *ExecuteSubmissionAndWaitRequest) (*ExecuteSubmissionAndWaitResponse, error) + // Similar to ExecuteSubmissionAndWait but additionally returns the transaction + // IMPORTANT: Relying on the response from this endpoint requires trusting the Participant Node to be honest. + // A malicious node could make a successfully committed request appear as failed and vice versa + ExecuteSubmissionAndWaitForTransaction(context.Context, *ExecuteSubmissionAndWaitForTransactionRequest) (*ExecuteSubmissionAndWaitForTransactionResponse, error) + // A preferred package is the highest-versioned package for a provided package-name + // that is vetted by all the participants hosting the provided parties. + // + // Ledger API clients should use this endpoint for constructing command submissions + // that are compatible with the provided preferred package, by making informed decisions on: + // - which are the compatible packages that can be used to create contracts + // - which contract or exercise choice argument version can be used in the command + // - which choices can be executed on a template or interface of a contract + // + // Can be accessed by any Ledger API client with a valid token when Ledger API authorization is enabled. + // + // Provided for backwards compatibility, it will be removed in the Canton version 3.4.0 + GetPreferredPackageVersion(context.Context, *GetPreferredPackageVersionRequest) (*GetPreferredPackageVersionResponse, error) + // Compute the preferred packages for the vetting requirements in the request. + // A preferred package is the highest-versioned package for a provided package-name + // that is vetted by all the participants hosting the provided parties. + // + // Ledger API clients should use this endpoint for constructing command submissions + // that are compatible with the provided preferred packages, by making informed decisions on: + // - which are the compatible packages that can be used to create contracts + // - which contract or exercise choice argument version can be used in the command + // - which choices can be executed on a template or interface of a contract + // + // If the package preferences could not be computed due to no selection satisfying the requirements, + // a `FAILED_PRECONDITION` error will be returned. + // + // Can be accessed by any Ledger API client with a valid token when Ledger API authorization is enabled. + // + // Experimental API: this endpoint is not guaranteed to provide backwards compatibility in future releases + GetPreferredPackages(context.Context, *GetPreferredPackagesRequest) (*GetPreferredPackagesResponse, error) + mustEmbedUnimplementedInteractiveSubmissionServiceServer() +} + +// UnimplementedInteractiveSubmissionServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedInteractiveSubmissionServiceServer struct{} + +func (UnimplementedInteractiveSubmissionServiceServer) PrepareSubmission(context.Context, *PrepareSubmissionRequest) (*PrepareSubmissionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PrepareSubmission not implemented") +} +func (UnimplementedInteractiveSubmissionServiceServer) ExecuteSubmission(context.Context, *ExecuteSubmissionRequest) (*ExecuteSubmissionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExecuteSubmission not implemented") +} +func (UnimplementedInteractiveSubmissionServiceServer) ExecuteSubmissionAndWait(context.Context, *ExecuteSubmissionAndWaitRequest) (*ExecuteSubmissionAndWaitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExecuteSubmissionAndWait not implemented") +} +func (UnimplementedInteractiveSubmissionServiceServer) ExecuteSubmissionAndWaitForTransaction(context.Context, *ExecuteSubmissionAndWaitForTransactionRequest) (*ExecuteSubmissionAndWaitForTransactionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExecuteSubmissionAndWaitForTransaction not implemented") +} +func (UnimplementedInteractiveSubmissionServiceServer) GetPreferredPackageVersion(context.Context, *GetPreferredPackageVersionRequest) (*GetPreferredPackageVersionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPreferredPackageVersion not implemented") +} +func (UnimplementedInteractiveSubmissionServiceServer) GetPreferredPackages(context.Context, *GetPreferredPackagesRequest) (*GetPreferredPackagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPreferredPackages not implemented") +} +func (UnimplementedInteractiveSubmissionServiceServer) mustEmbedUnimplementedInteractiveSubmissionServiceServer() { +} +func (UnimplementedInteractiveSubmissionServiceServer) testEmbeddedByValue() {} + +// UnsafeInteractiveSubmissionServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to InteractiveSubmissionServiceServer will +// result in compilation errors. +type UnsafeInteractiveSubmissionServiceServer interface { + mustEmbedUnimplementedInteractiveSubmissionServiceServer() +} + +func RegisterInteractiveSubmissionServiceServer(s grpc.ServiceRegistrar, srv InteractiveSubmissionServiceServer) { + // If the following call pancis, it indicates UnimplementedInteractiveSubmissionServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&InteractiveSubmissionService_ServiceDesc, srv) +} + +func _InteractiveSubmissionService_PrepareSubmission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PrepareSubmissionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InteractiveSubmissionServiceServer).PrepareSubmission(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: InteractiveSubmissionService_PrepareSubmission_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InteractiveSubmissionServiceServer).PrepareSubmission(ctx, req.(*PrepareSubmissionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _InteractiveSubmissionService_ExecuteSubmission_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExecuteSubmissionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InteractiveSubmissionServiceServer).ExecuteSubmission(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: InteractiveSubmissionService_ExecuteSubmission_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InteractiveSubmissionServiceServer).ExecuteSubmission(ctx, req.(*ExecuteSubmissionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _InteractiveSubmissionService_ExecuteSubmissionAndWait_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExecuteSubmissionAndWaitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InteractiveSubmissionServiceServer).ExecuteSubmissionAndWait(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: InteractiveSubmissionService_ExecuteSubmissionAndWait_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InteractiveSubmissionServiceServer).ExecuteSubmissionAndWait(ctx, req.(*ExecuteSubmissionAndWaitRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _InteractiveSubmissionService_ExecuteSubmissionAndWaitForTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExecuteSubmissionAndWaitForTransactionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InteractiveSubmissionServiceServer).ExecuteSubmissionAndWaitForTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: InteractiveSubmissionService_ExecuteSubmissionAndWaitForTransaction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InteractiveSubmissionServiceServer).ExecuteSubmissionAndWaitForTransaction(ctx, req.(*ExecuteSubmissionAndWaitForTransactionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _InteractiveSubmissionService_GetPreferredPackageVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPreferredPackageVersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InteractiveSubmissionServiceServer).GetPreferredPackageVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: InteractiveSubmissionService_GetPreferredPackageVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InteractiveSubmissionServiceServer).GetPreferredPackageVersion(ctx, req.(*GetPreferredPackageVersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _InteractiveSubmissionService_GetPreferredPackages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPreferredPackagesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(InteractiveSubmissionServiceServer).GetPreferredPackages(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: InteractiveSubmissionService_GetPreferredPackages_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(InteractiveSubmissionServiceServer).GetPreferredPackages(ctx, req.(*GetPreferredPackagesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// InteractiveSubmissionService_ServiceDesc is the grpc.ServiceDesc for InteractiveSubmissionService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var InteractiveSubmissionService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.interactive.InteractiveSubmissionService", + HandlerType: (*InteractiveSubmissionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "PrepareSubmission", + Handler: _InteractiveSubmissionService_PrepareSubmission_Handler, + }, + { + MethodName: "ExecuteSubmission", + Handler: _InteractiveSubmissionService_ExecuteSubmission_Handler, + }, + { + MethodName: "ExecuteSubmissionAndWait", + Handler: _InteractiveSubmissionService_ExecuteSubmissionAndWait_Handler, + }, + { + MethodName: "ExecuteSubmissionAndWaitForTransaction", + Handler: _InteractiveSubmissionService_ExecuteSubmissionAndWaitForTransaction_Handler, + }, + { + MethodName: "GetPreferredPackageVersion", + Handler: _InteractiveSubmissionService_GetPreferredPackageVersion_Handler, + }, + { + MethodName: "GetPreferredPackages", + Handler: _InteractiveSubmissionService_GetPreferredPackages_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/interactive/interactive_submission_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.pb.go b/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.pb.go new file mode 100644 index 00000000..93ae85d0 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.pb.go @@ -0,0 +1,705 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto + +package transactionv1 + +import ( + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Fetch node +type Fetch struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Specific LF version of the node + // + // Required + LfVersion string `protobuf:"bytes,1,opt,name=lf_version,json=lfVersion,proto3" json:"lf_version,omitempty"` + // Required + ContractId string `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // Required + PackageName string `protobuf:"bytes,3,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // The identifier uses the package-id reference format. + // + // Required + TemplateId *v2.Identifier `protobuf:"bytes,4,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // Required: must be non-empty + Signatories []string `protobuf:"bytes,5,rep,name=signatories,proto3" json:"signatories,omitempty"` + // Required: must be non-empty + Stakeholders []string `protobuf:"bytes,6,rep,name=stakeholders,proto3" json:"stakeholders,omitempty"` + // Required: must be non-empty + ActingParties []string `protobuf:"bytes,7,rep,name=acting_parties,json=actingParties,proto3" json:"acting_parties,omitempty"` + // Optional + InterfaceId *v2.Identifier `protobuf:"bytes,8,opt,name=interface_id,json=interfaceId,proto3" json:"interface_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Fetch) Reset() { + *x = Fetch{} + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Fetch) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Fetch) ProtoMessage() {} + +func (x *Fetch) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Fetch.ProtoReflect.Descriptor instead. +func (*Fetch) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescGZIP(), []int{0} +} + +func (x *Fetch) GetLfVersion() string { + if x != nil { + return x.LfVersion + } + return "" +} + +func (x *Fetch) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *Fetch) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *Fetch) GetTemplateId() *v2.Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *Fetch) GetSignatories() []string { + if x != nil { + return x.Signatories + } + return nil +} + +func (x *Fetch) GetStakeholders() []string { + if x != nil { + return x.Stakeholders + } + return nil +} + +func (x *Fetch) GetActingParties() []string { + if x != nil { + return x.ActingParties + } + return nil +} + +func (x *Fetch) GetInterfaceId() *v2.Identifier { + if x != nil { + return x.InterfaceId + } + return nil +} + +// Exercise node +type Exercise struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Specific LF version of the node + // + // Required + LfVersion string `protobuf:"bytes,1,opt,name=lf_version,json=lfVersion,proto3" json:"lf_version,omitempty"` + // Required + ContractId string `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // Required + PackageName string `protobuf:"bytes,3,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // The identifier uses the package-id reference format. + // + // Required + TemplateId *v2.Identifier `protobuf:"bytes,4,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // Required: must be non-empty + Signatories []string `protobuf:"bytes,5,rep,name=signatories,proto3" json:"signatories,omitempty"` + // Required: must be non-empty + Stakeholders []string `protobuf:"bytes,6,rep,name=stakeholders,proto3" json:"stakeholders,omitempty"` + // Required: must be non-empty + ActingParties []string `protobuf:"bytes,7,rep,name=acting_parties,json=actingParties,proto3" json:"acting_parties,omitempty"` + // The identifier uses the package-id reference format. + // + // Optional + InterfaceId *v2.Identifier `protobuf:"bytes,8,opt,name=interface_id,json=interfaceId,proto3" json:"interface_id,omitempty"` + // Required + ChoiceId string `protobuf:"bytes,9,opt,name=choice_id,json=choiceId,proto3" json:"choice_id,omitempty"` + // Required + ChosenValue *v2.Value `protobuf:"bytes,10,opt,name=chosen_value,json=chosenValue,proto3" json:"chosen_value,omitempty"` + // Required + Consuming bool `protobuf:"varint,11,opt,name=consuming,proto3" json:"consuming,omitempty"` + // Optional: can be empty + Children []string `protobuf:"bytes,12,rep,name=children,proto3" json:"children,omitempty"` + // Optional + ExerciseResult *v2.Value `protobuf:"bytes,13,opt,name=exercise_result,json=exerciseResult,proto3" json:"exercise_result,omitempty"` + // Optional: can be empty + ChoiceObservers []string `protobuf:"bytes,14,rep,name=choice_observers,json=choiceObservers,proto3" json:"choice_observers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Exercise) Reset() { + *x = Exercise{} + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Exercise) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Exercise) ProtoMessage() {} + +func (x *Exercise) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Exercise.ProtoReflect.Descriptor instead. +func (*Exercise) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescGZIP(), []int{1} +} + +func (x *Exercise) GetLfVersion() string { + if x != nil { + return x.LfVersion + } + return "" +} + +func (x *Exercise) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *Exercise) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *Exercise) GetTemplateId() *v2.Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *Exercise) GetSignatories() []string { + if x != nil { + return x.Signatories + } + return nil +} + +func (x *Exercise) GetStakeholders() []string { + if x != nil { + return x.Stakeholders + } + return nil +} + +func (x *Exercise) GetActingParties() []string { + if x != nil { + return x.ActingParties + } + return nil +} + +func (x *Exercise) GetInterfaceId() *v2.Identifier { + if x != nil { + return x.InterfaceId + } + return nil +} + +func (x *Exercise) GetChoiceId() string { + if x != nil { + return x.ChoiceId + } + return "" +} + +func (x *Exercise) GetChosenValue() *v2.Value { + if x != nil { + return x.ChosenValue + } + return nil +} + +func (x *Exercise) GetConsuming() bool { + if x != nil { + return x.Consuming + } + return false +} + +func (x *Exercise) GetChildren() []string { + if x != nil { + return x.Children + } + return nil +} + +func (x *Exercise) GetExerciseResult() *v2.Value { + if x != nil { + return x.ExerciseResult + } + return nil +} + +func (x *Exercise) GetChoiceObservers() []string { + if x != nil { + return x.ChoiceObservers + } + return nil +} + +// Create Node +type Create struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Specific LF version of the node + // + // Required + LfVersion string `protobuf:"bytes,1,opt,name=lf_version,json=lfVersion,proto3" json:"lf_version,omitempty"` + // Required + ContractId string `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // Required + PackageName string `protobuf:"bytes,3,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // The identifier uses the package-id reference format. + // + // Required + TemplateId *v2.Identifier `protobuf:"bytes,4,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // Required + Argument *v2.Value `protobuf:"bytes,5,opt,name=argument,proto3" json:"argument,omitempty"` + // Required: must be non-empty + Signatories []string `protobuf:"bytes,6,rep,name=signatories,proto3" json:"signatories,omitempty"` + // Required: must be non-empty + Stakeholders []string `protobuf:"bytes,7,rep,name=stakeholders,proto3" json:"stakeholders,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Create) Reset() { + *x = Create{} + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Create) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Create) ProtoMessage() {} + +func (x *Create) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Create.ProtoReflect.Descriptor instead. +func (*Create) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescGZIP(), []int{2} +} + +func (x *Create) GetLfVersion() string { + if x != nil { + return x.LfVersion + } + return "" +} + +func (x *Create) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *Create) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *Create) GetTemplateId() *v2.Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *Create) GetArgument() *v2.Value { + if x != nil { + return x.Argument + } + return nil +} + +func (x *Create) GetSignatories() []string { + if x != nil { + return x.Signatories + } + return nil +} + +func (x *Create) GetStakeholders() []string { + if x != nil { + return x.Stakeholders + } + return nil +} + +// Rollback Node +type Rollback struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required: must be non-empty + Children []string `protobuf:"bytes,1,rep,name=children,proto3" json:"children,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Rollback) Reset() { + *x = Rollback{} + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Rollback) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Rollback) ProtoMessage() {} + +func (x *Rollback) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Rollback.ProtoReflect.Descriptor instead. +func (*Rollback) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescGZIP(), []int{3} +} + +func (x *Rollback) GetChildren() []string { + if x != nil { + return x.Children + } + return nil +} + +type Node struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to NodeType: + // + // *Node_Create + // *Node_Fetch + // *Node_Exercise + // *Node_Rollback + NodeType isNode_NodeType `protobuf_oneof:"node_type"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Node) Reset() { + *x = Node{} + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Node) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Node) ProtoMessage() {} + +func (x *Node) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Node.ProtoReflect.Descriptor instead. +func (*Node) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescGZIP(), []int{4} +} + +func (x *Node) GetNodeType() isNode_NodeType { + if x != nil { + return x.NodeType + } + return nil +} + +func (x *Node) GetCreate() *Create { + if x != nil { + if x, ok := x.NodeType.(*Node_Create); ok { + return x.Create + } + } + return nil +} + +func (x *Node) GetFetch() *Fetch { + if x != nil { + if x, ok := x.NodeType.(*Node_Fetch); ok { + return x.Fetch + } + } + return nil +} + +func (x *Node) GetExercise() *Exercise { + if x != nil { + if x, ok := x.NodeType.(*Node_Exercise); ok { + return x.Exercise + } + } + return nil +} + +func (x *Node) GetRollback() *Rollback { + if x != nil { + if x, ok := x.NodeType.(*Node_Rollback); ok { + return x.Rollback + } + } + return nil +} + +type isNode_NodeType interface { + isNode_NodeType() +} + +type Node_Create struct { + Create *Create `protobuf:"bytes,1,opt,name=create,proto3,oneof"` +} + +type Node_Fetch struct { + Fetch *Fetch `protobuf:"bytes,2,opt,name=fetch,proto3,oneof"` +} + +type Node_Exercise struct { + Exercise *Exercise `protobuf:"bytes,3,opt,name=exercise,proto3,oneof"` +} + +type Node_Rollback struct { + Rollback *Rollback `protobuf:"bytes,4,opt,name=rollback,proto3,oneof"` +} + +func (*Node_Create) isNode_NodeType() {} + +func (*Node_Fetch) isNode_NodeType() {} + +func (*Node_Exercise) isNode_NodeType() {} + +func (*Node_Rollback) isNode_NodeType() {} + +var File_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDesc = "" + + "\n" + + "Scom/daml/ledger/api/v2/interactive/transaction/v1/interactive_submission_data.proto\x121com.daml.ledger.api.v2.interactive.transaction.v1\x1a\"com/daml/ledger/api/v2/value.proto\"\xe3\x02\n" + + "\x05Fetch\x12\x1d\n" + + "\n" + + "lf_version\x18\x01 \x01(\tR\tlfVersion\x12\x1f\n" + + "\vcontract_id\x18\x02 \x01(\tR\n" + + "contractId\x12!\n" + + "\fpackage_name\x18\x03 \x01(\tR\vpackageName\x12C\n" + + "\vtemplate_id\x18\x04 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12 \n" + + "\vsignatories\x18\x05 \x03(\tR\vsignatories\x12\"\n" + + "\fstakeholders\x18\x06 \x03(\tR\fstakeholders\x12%\n" + + "\x0eacting_parties\x18\a \x03(\tR\ractingParties\x12E\n" + + "\finterface_id\x18\b \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\vinterfaceId\"\xf2\x04\n" + + "\bExercise\x12\x1d\n" + + "\n" + + "lf_version\x18\x01 \x01(\tR\tlfVersion\x12\x1f\n" + + "\vcontract_id\x18\x02 \x01(\tR\n" + + "contractId\x12!\n" + + "\fpackage_name\x18\x03 \x01(\tR\vpackageName\x12C\n" + + "\vtemplate_id\x18\x04 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12 \n" + + "\vsignatories\x18\x05 \x03(\tR\vsignatories\x12\"\n" + + "\fstakeholders\x18\x06 \x03(\tR\fstakeholders\x12%\n" + + "\x0eacting_parties\x18\a \x03(\tR\ractingParties\x12E\n" + + "\finterface_id\x18\b \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\vinterfaceId\x12\x1b\n" + + "\tchoice_id\x18\t \x01(\tR\bchoiceId\x12@\n" + + "\fchosen_value\x18\n" + + " \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\vchosenValue\x12\x1c\n" + + "\tconsuming\x18\v \x01(\bR\tconsuming\x12\x1a\n" + + "\bchildren\x18\f \x03(\tR\bchildren\x12F\n" + + "\x0fexercise_result\x18\r \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x0eexerciseResult\x12)\n" + + "\x10choice_observers\x18\x0e \x03(\tR\x0fchoiceObservers\"\xb1\x02\n" + + "\x06Create\x12\x1d\n" + + "\n" + + "lf_version\x18\x01 \x01(\tR\tlfVersion\x12\x1f\n" + + "\vcontract_id\x18\x02 \x01(\tR\n" + + "contractId\x12!\n" + + "\fpackage_name\x18\x03 \x01(\tR\vpackageName\x12C\n" + + "\vtemplate_id\x18\x04 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x129\n" + + "\bargument\x18\x05 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\bargument\x12 \n" + + "\vsignatories\x18\x06 \x03(\tR\vsignatories\x12\"\n" + + "\fstakeholders\x18\a \x03(\tR\fstakeholders\"&\n" + + "\bRollback\x12\x1a\n" + + "\bchildren\x18\x01 \x03(\tR\bchildren\"\xf0\x02\n" + + "\x04Node\x12S\n" + + "\x06create\x18\x01 \x01(\v29.com.daml.ledger.api.v2.interactive.transaction.v1.CreateH\x00R\x06create\x12P\n" + + "\x05fetch\x18\x02 \x01(\v28.com.daml.ledger.api.v2.interactive.transaction.v1.FetchH\x00R\x05fetch\x12Y\n" + + "\bexercise\x18\x03 \x01(\v2;.com.daml.ledger.api.v2.interactive.transaction.v1.ExerciseH\x00R\bexercise\x12Y\n" + + "\brollback\x18\x04 \x01(\v2;.com.daml.ledger.api.v2.interactive.transaction.v1.RollbackH\x00R\brollbackB\v\n" + + "\tnode_typeB\xbb\x03\n" + + "5com.com.daml.ledger.api.v2.interactive.transaction.v1B\x1eInteractiveSubmissionDataProtoP\x01Zsgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1;transactionv1\xa2\x02\aCDLAVIT\xaa\x021Com.Daml.Ledger.Api.V2.Interactive.Transaction.V1\xca\x021Com\\Daml\\Ledger\\Api\\V2\\Interactive\\Transaction\\V1\xe2\x02=Com\\Daml\\Ledger\\Api\\V2\\Interactive\\Transaction\\V1\\GPBMetadata\xea\x028Com::Daml::Ledger::Api::V2::Interactive::Transaction::V1b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDesc), len(file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_goTypes = []any{ + (*Fetch)(nil), // 0: com.daml.ledger.api.v2.interactive.transaction.v1.Fetch + (*Exercise)(nil), // 1: com.daml.ledger.api.v2.interactive.transaction.v1.Exercise + (*Create)(nil), // 2: com.daml.ledger.api.v2.interactive.transaction.v1.Create + (*Rollback)(nil), // 3: com.daml.ledger.api.v2.interactive.transaction.v1.Rollback + (*Node)(nil), // 4: com.daml.ledger.api.v2.interactive.transaction.v1.Node + (*v2.Identifier)(nil), // 5: com.daml.ledger.api.v2.Identifier + (*v2.Value)(nil), // 6: com.daml.ledger.api.v2.Value +} +var file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_depIdxs = []int32{ + 5, // 0: com.daml.ledger.api.v2.interactive.transaction.v1.Fetch.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 5, // 1: com.daml.ledger.api.v2.interactive.transaction.v1.Fetch.interface_id:type_name -> com.daml.ledger.api.v2.Identifier + 5, // 2: com.daml.ledger.api.v2.interactive.transaction.v1.Exercise.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 5, // 3: com.daml.ledger.api.v2.interactive.transaction.v1.Exercise.interface_id:type_name -> com.daml.ledger.api.v2.Identifier + 6, // 4: com.daml.ledger.api.v2.interactive.transaction.v1.Exercise.chosen_value:type_name -> com.daml.ledger.api.v2.Value + 6, // 5: com.daml.ledger.api.v2.interactive.transaction.v1.Exercise.exercise_result:type_name -> com.daml.ledger.api.v2.Value + 5, // 6: com.daml.ledger.api.v2.interactive.transaction.v1.Create.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 6, // 7: com.daml.ledger.api.v2.interactive.transaction.v1.Create.argument:type_name -> com.daml.ledger.api.v2.Value + 2, // 8: com.daml.ledger.api.v2.interactive.transaction.v1.Node.create:type_name -> com.daml.ledger.api.v2.interactive.transaction.v1.Create + 0, // 9: com.daml.ledger.api.v2.interactive.transaction.v1.Node.fetch:type_name -> com.daml.ledger.api.v2.interactive.transaction.v1.Fetch + 1, // 10: com.daml.ledger.api.v2.interactive.transaction.v1.Node.exercise:type_name -> com.daml.ledger.api.v2.interactive.transaction.v1.Exercise + 3, // 11: com.daml.ledger.api.v2.interactive.transaction.v1.Node.rollback:type_name -> com.daml.ledger.api.v2.interactive.transaction.v1.Rollback + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_init() +} +func file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_init() { + if File_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto != nil { + return + } + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes[4].OneofWrappers = []any{ + (*Node_Create)(nil), + (*Node_Fetch)(nil), + (*Node_Exercise)(nil), + (*Node_Rollback)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDesc), len(file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_rawDesc)), + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto = out.File + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_goTypes = nil + file_com_daml_ledger_api_v2_interactive_transaction_v1_interactive_submission_data_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/offset_checkpoint.pb.go b/chain/canton/types/com/daml/ledger/api/v2/offset_checkpoint.pb.go new file mode 100644 index 00000000..a874154b --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/offset_checkpoint.pb.go @@ -0,0 +1,213 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/offset_checkpoint.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// OffsetCheckpoints may be used to: +// +// - detect time out of commands. +// - provide an offset which can be used to restart consumption. +type OffsetCheckpoint struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The participant's offset, the details of the offset field are described in “community/ledger-api/README.md“. + // Must be a valid absolute offset (positive integer). + // + // Required + Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + // The times associated with each synchronizer at this offset. + // + // Optional: can be empty + SynchronizerTimes []*SynchronizerTime `protobuf:"bytes,2,rep,name=synchronizer_times,json=synchronizerTimes,proto3" json:"synchronizer_times,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *OffsetCheckpoint) Reset() { + *x = OffsetCheckpoint{} + mi := &file_com_daml_ledger_api_v2_offset_checkpoint_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OffsetCheckpoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OffsetCheckpoint) ProtoMessage() {} + +func (x *OffsetCheckpoint) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_offset_checkpoint_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OffsetCheckpoint.ProtoReflect.Descriptor instead. +func (*OffsetCheckpoint) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescGZIP(), []int{0} +} + +func (x *OffsetCheckpoint) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *OffsetCheckpoint) GetSynchronizerTimes() []*SynchronizerTime { + if x != nil { + return x.SynchronizerTimes + } + return nil +} + +type SynchronizerTime struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The id of the synchronizer. + // + // Required + SynchronizerId string `protobuf:"bytes,1,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // All commands with a maximum record time below this value MUST be considered lost if their completion has not arrived before this checkpoint. + // + // Required + RecordTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=record_time,json=recordTime,proto3" json:"record_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SynchronizerTime) Reset() { + *x = SynchronizerTime{} + mi := &file_com_daml_ledger_api_v2_offset_checkpoint_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SynchronizerTime) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SynchronizerTime) ProtoMessage() {} + +func (x *SynchronizerTime) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_offset_checkpoint_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SynchronizerTime.ProtoReflect.Descriptor instead. +func (*SynchronizerTime) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescGZIP(), []int{1} +} + +func (x *SynchronizerTime) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *SynchronizerTime) GetRecordTime() *timestamppb.Timestamp { + if x != nil { + return x.RecordTime + } + return nil +} + +var File_com_daml_ledger_api_v2_offset_checkpoint_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDesc = "" + + "\n" + + ".com/daml/ledger/api/v2/offset_checkpoint.proto\x12\x16com.daml.ledger.api.v2\x1a\x1fgoogle/protobuf/timestamp.proto\"\x83\x01\n" + + "\x10OffsetCheckpoint\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x03R\x06offset\x12W\n" + + "\x12synchronizer_times\x18\x02 \x03(\v2(.com.daml.ledger.api.v2.SynchronizerTimeR\x11synchronizerTimes\"x\n" + + "\x10SynchronizerTime\x12'\n" + + "\x0fsynchronizer_id\x18\x01 \x01(\tR\x0esynchronizerId\x12;\n" + + "\vrecord_time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "recordTimeB\x82\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x15OffsetCheckpointProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDesc), len(file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_offset_checkpoint_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_com_daml_ledger_api_v2_offset_checkpoint_proto_goTypes = []any{ + (*OffsetCheckpoint)(nil), // 0: com.daml.ledger.api.v2.OffsetCheckpoint + (*SynchronizerTime)(nil), // 1: com.daml.ledger.api.v2.SynchronizerTime + (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp +} +var file_com_daml_ledger_api_v2_offset_checkpoint_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.OffsetCheckpoint.synchronizer_times:type_name -> com.daml.ledger.api.v2.SynchronizerTime + 2, // 1: com.daml.ledger.api.v2.SynchronizerTime.record_time:type_name -> google.protobuf.Timestamp + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_offset_checkpoint_proto_init() } +func file_com_daml_ledger_api_v2_offset_checkpoint_proto_init() { + if File_com_daml_ledger_api_v2_offset_checkpoint_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDesc), len(file_com_daml_ledger_api_v2_offset_checkpoint_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_offset_checkpoint_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_offset_checkpoint_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_offset_checkpoint_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_offset_checkpoint_proto = out.File + file_com_daml_ledger_api_v2_offset_checkpoint_proto_goTypes = nil + file_com_daml_ledger_api_v2_offset_checkpoint_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/package_reference.pb.go b/chain/canton/types/com/daml/ledger/api/v2/package_reference.pb.go new file mode 100644 index 00000000..84ca7466 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/package_reference.pb.go @@ -0,0 +1,451 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/package_reference.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PackageReference struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + PackageId string `protobuf:"bytes,1,opt,name=package_id,json=packageId,proto3" json:"package_id,omitempty"` + // Required + PackageName string `protobuf:"bytes,2,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // Required + PackageVersion string `protobuf:"bytes,3,opt,name=package_version,json=packageVersion,proto3" json:"package_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PackageReference) Reset() { + *x = PackageReference{} + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PackageReference) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PackageReference) ProtoMessage() {} + +func (x *PackageReference) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PackageReference.ProtoReflect.Descriptor instead. +func (*PackageReference) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_reference_proto_rawDescGZIP(), []int{0} +} + +func (x *PackageReference) GetPackageId() string { + if x != nil { + return x.PackageId + } + return "" +} + +func (x *PackageReference) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *PackageReference) GetPackageVersion() string { + if x != nil { + return x.PackageVersion + } + return "" +} + +// A package that is vetting on a given participant and synchronizer, +// modelled after “VettedPackage“ in `topology.proto `_, +// enriched with the package name and version. +type VettedPackage struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Package ID of this package + // + // Required + PackageId string `protobuf:"bytes,1,opt,name=package_id,json=packageId,proto3" json:"package_id,omitempty"` + // The time from which this package is vetted. Empty if vetting time has no + // lower bound. + // + // Optional + ValidFromInclusive *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=valid_from_inclusive,json=validFromInclusive,proto3" json:"valid_from_inclusive,omitempty"` + // The time until which this package is vetted. Empty if vetting time has no + // upper bound. + // + // Optional + ValidUntilExclusive *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=valid_until_exclusive,json=validUntilExclusive,proto3" json:"valid_until_exclusive,omitempty"` + // Name of this package. + // Only available if the package has been uploaded to the current participant. + // + // Optional + PackageName string `protobuf:"bytes,4,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // Version of this package. + // Only available if the package has been uploaded to the current participant. + // + // Optional + PackageVersion string `protobuf:"bytes,5,opt,name=package_version,json=packageVersion,proto3" json:"package_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VettedPackage) Reset() { + *x = VettedPackage{} + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VettedPackage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VettedPackage) ProtoMessage() {} + +func (x *VettedPackage) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VettedPackage.ProtoReflect.Descriptor instead. +func (*VettedPackage) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_reference_proto_rawDescGZIP(), []int{1} +} + +func (x *VettedPackage) GetPackageId() string { + if x != nil { + return x.PackageId + } + return "" +} + +func (x *VettedPackage) GetValidFromInclusive() *timestamppb.Timestamp { + if x != nil { + return x.ValidFromInclusive + } + return nil +} + +func (x *VettedPackage) GetValidUntilExclusive() *timestamppb.Timestamp { + if x != nil { + return x.ValidUntilExclusive + } + return nil +} + +func (x *VettedPackage) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *VettedPackage) GetPackageVersion() string { + if x != nil { + return x.PackageVersion + } + return "" +} + +// The list of packages vetted on a given participant and synchronizer, modelled +// after “VettedPackages“ in `topology.proto `_. +// The list only contains packages that matched a filter in the query that +// originated it. +type VettedPackages struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Sorted by package_name and package_version where known, and package_id as a + // last resort. + // + // Required: must be non-empty + Packages []*VettedPackage `protobuf:"bytes,1,rep,name=packages,proto3" json:"packages,omitempty"` + // Participant on which these packages are vetted. + // + // Required + ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + // Synchronizer on which these packages are vetted. + // + // Required + SynchronizerId string `protobuf:"bytes,3,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // Serial of last “VettedPackages“ topology transaction of this participant + // and on this synchronizer. + // + // Required + TopologySerial uint32 `protobuf:"varint,4,opt,name=topology_serial,json=topologySerial,proto3" json:"topology_serial,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *VettedPackages) Reset() { + *x = VettedPackages{} + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *VettedPackages) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VettedPackages) ProtoMessage() {} + +func (x *VettedPackages) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VettedPackages.ProtoReflect.Descriptor instead. +func (*VettedPackages) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_reference_proto_rawDescGZIP(), []int{2} +} + +func (x *VettedPackages) GetPackages() []*VettedPackage { + if x != nil { + return x.Packages + } + return nil +} + +func (x *VettedPackages) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +func (x *VettedPackages) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *VettedPackages) GetTopologySerial() uint32 { + if x != nil { + return x.TopologySerial + } + return 0 +} + +// The serial of last “VettedPackages“ topology transaction on a given +// participant and synchronizer. +type PriorTopologySerial struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional + // + // Types that are valid to be assigned to Serial: + // + // *PriorTopologySerial_Prior + // *PriorTopologySerial_NoPrior + Serial isPriorTopologySerial_Serial `protobuf_oneof:"serial"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PriorTopologySerial) Reset() { + *x = PriorTopologySerial{} + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PriorTopologySerial) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PriorTopologySerial) ProtoMessage() {} + +func (x *PriorTopologySerial) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PriorTopologySerial.ProtoReflect.Descriptor instead. +func (*PriorTopologySerial) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_reference_proto_rawDescGZIP(), []int{3} +} + +func (x *PriorTopologySerial) GetSerial() isPriorTopologySerial_Serial { + if x != nil { + return x.Serial + } + return nil +} + +func (x *PriorTopologySerial) GetPrior() uint32 { + if x != nil { + if x, ok := x.Serial.(*PriorTopologySerial_Prior); ok { + return x.Prior + } + } + return 0 +} + +func (x *PriorTopologySerial) GetNoPrior() *emptypb.Empty { + if x != nil { + if x, ok := x.Serial.(*PriorTopologySerial_NoPrior); ok { + return x.NoPrior + } + } + return nil +} + +type isPriorTopologySerial_Serial interface { + isPriorTopologySerial_Serial() +} + +type PriorTopologySerial_Prior struct { + // Previous transaction's serial. + Prior uint32 `protobuf:"varint,1,opt,name=prior,proto3,oneof"` +} + +type PriorTopologySerial_NoPrior struct { + // No previous transaction exists. + NoPrior *emptypb.Empty `protobuf:"bytes,2,opt,name=no_prior,json=noPrior,proto3,oneof"` +} + +func (*PriorTopologySerial_Prior) isPriorTopologySerial_Serial() {} + +func (*PriorTopologySerial_NoPrior) isPriorTopologySerial_Serial() {} + +var File_com_daml_ledger_api_v2_package_reference_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_package_reference_proto_rawDesc = "" + + "\n" + + ".com/daml/ledger/api/v2/package_reference.proto\x12\x16com.daml.ledger.api.v2\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"}\n" + + "\x10PackageReference\x12\x1d\n" + + "\n" + + "package_id\x18\x01 \x01(\tR\tpackageId\x12!\n" + + "\fpackage_name\x18\x02 \x01(\tR\vpackageName\x12'\n" + + "\x0fpackage_version\x18\x03 \x01(\tR\x0epackageVersion\"\x98\x02\n" + + "\rVettedPackage\x12\x1d\n" + + "\n" + + "package_id\x18\x01 \x01(\tR\tpackageId\x12L\n" + + "\x14valid_from_inclusive\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x12validFromInclusive\x12N\n" + + "\x15valid_until_exclusive\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x13validUntilExclusive\x12!\n" + + "\fpackage_name\x18\x04 \x01(\tR\vpackageName\x12'\n" + + "\x0fpackage_version\x18\x05 \x01(\tR\x0epackageVersion\"\xcc\x01\n" + + "\x0eVettedPackages\x12A\n" + + "\bpackages\x18\x01 \x03(\v2%.com.daml.ledger.api.v2.VettedPackageR\bpackages\x12%\n" + + "\x0eparticipant_id\x18\x02 \x01(\tR\rparticipantId\x12'\n" + + "\x0fsynchronizer_id\x18\x03 \x01(\tR\x0esynchronizerId\x12'\n" + + "\x0ftopology_serial\x18\x04 \x01(\rR\x0etopologySerial\"l\n" + + "\x13PriorTopologySerial\x12\x16\n" + + "\x05prior\x18\x01 \x01(\rH\x00R\x05prior\x123\n" + + "\bno_prior\x18\x02 \x01(\v2\x16.google.protobuf.EmptyH\x00R\anoPriorB\b\n" + + "\x06serialB\x82\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x15PackageReferenceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_package_reference_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_package_reference_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_package_reference_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_package_reference_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_package_reference_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_package_reference_proto_rawDesc), len(file_com_daml_ledger_api_v2_package_reference_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_package_reference_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_package_reference_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_com_daml_ledger_api_v2_package_reference_proto_goTypes = []any{ + (*PackageReference)(nil), // 0: com.daml.ledger.api.v2.PackageReference + (*VettedPackage)(nil), // 1: com.daml.ledger.api.v2.VettedPackage + (*VettedPackages)(nil), // 2: com.daml.ledger.api.v2.VettedPackages + (*PriorTopologySerial)(nil), // 3: com.daml.ledger.api.v2.PriorTopologySerial + (*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 5: google.protobuf.Empty +} +var file_com_daml_ledger_api_v2_package_reference_proto_depIdxs = []int32{ + 4, // 0: com.daml.ledger.api.v2.VettedPackage.valid_from_inclusive:type_name -> google.protobuf.Timestamp + 4, // 1: com.daml.ledger.api.v2.VettedPackage.valid_until_exclusive:type_name -> google.protobuf.Timestamp + 1, // 2: com.daml.ledger.api.v2.VettedPackages.packages:type_name -> com.daml.ledger.api.v2.VettedPackage + 5, // 3: com.daml.ledger.api.v2.PriorTopologySerial.no_prior:type_name -> google.protobuf.Empty + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_package_reference_proto_init() } +func file_com_daml_ledger_api_v2_package_reference_proto_init() { + if File_com_daml_ledger_api_v2_package_reference_proto != nil { + return + } + file_com_daml_ledger_api_v2_package_reference_proto_msgTypes[3].OneofWrappers = []any{ + (*PriorTopologySerial_Prior)(nil), + (*PriorTopologySerial_NoPrior)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_package_reference_proto_rawDesc), len(file_com_daml_ledger_api_v2_package_reference_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_package_reference_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_package_reference_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_package_reference_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_package_reference_proto = out.File + file_com_daml_ledger_api_v2_package_reference_proto_goTypes = nil + file_com_daml_ledger_api_v2_package_reference_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/package_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/package_service.pb.go new file mode 100644 index 00000000..6daec049 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/package_service.pb.go @@ -0,0 +1,838 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/package_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PackageStatus int32 + +const ( + // The server is not aware of such a package. + PackageStatus_PACKAGE_STATUS_UNSPECIFIED PackageStatus = 0 + // The server is able to execute Daml commands operating on this package. + PackageStatus_PACKAGE_STATUS_REGISTERED PackageStatus = 1 +) + +// Enum value maps for PackageStatus. +var ( + PackageStatus_name = map[int32]string{ + 0: "PACKAGE_STATUS_UNSPECIFIED", + 1: "PACKAGE_STATUS_REGISTERED", + } + PackageStatus_value = map[string]int32{ + "PACKAGE_STATUS_UNSPECIFIED": 0, + "PACKAGE_STATUS_REGISTERED": 1, + } +) + +func (x PackageStatus) Enum() *PackageStatus { + p := new(PackageStatus) + *p = x + return p +} + +func (x PackageStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (PackageStatus) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_package_service_proto_enumTypes[0].Descriptor() +} + +func (PackageStatus) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_package_service_proto_enumTypes[0] +} + +func (x PackageStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use PackageStatus.Descriptor instead. +func (PackageStatus) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{0} +} + +type HashFunction int32 + +const ( + HashFunction_HASH_FUNCTION_SHA256 HashFunction = 0 +) + +// Enum value maps for HashFunction. +var ( + HashFunction_name = map[int32]string{ + 0: "HASH_FUNCTION_SHA256", + } + HashFunction_value = map[string]int32{ + "HASH_FUNCTION_SHA256": 0, + } +) + +func (x HashFunction) Enum() *HashFunction { + p := new(HashFunction) + *p = x + return p +} + +func (x HashFunction) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (HashFunction) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_package_service_proto_enumTypes[1].Descriptor() +} + +func (HashFunction) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_package_service_proto_enumTypes[1] +} + +func (x HashFunction) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use HashFunction.Descriptor instead. +func (HashFunction) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{1} +} + +type ListPackagesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The IDs of all Daml-LF packages supported by the server. + // Each element must be a valid PackageIdString (as described in “value.proto“). + // + // Required: must be non-empty + PackageIds []string `protobuf:"bytes,1,rep,name=package_ids,json=packageIds,proto3" json:"package_ids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListPackagesResponse) Reset() { + *x = ListPackagesResponse{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListPackagesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListPackagesResponse) ProtoMessage() {} + +func (x *ListPackagesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListPackagesResponse.ProtoReflect.Descriptor instead. +func (*ListPackagesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{0} +} + +func (x *ListPackagesResponse) GetPackageIds() []string { + if x != nil { + return x.PackageIds + } + return nil +} + +type GetPackageResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The hash function we use to calculate the hash. + // + // Required + HashFunction HashFunction `protobuf:"varint,1,opt,name=hash_function,json=hashFunction,proto3,enum=com.daml.ledger.api.v2.HashFunction" json:"hash_function,omitempty"` + // Contains a “daml_lf“ ArchivePayload. See further details in “daml_lf.proto“. + // + // Required: must be non-empty + ArchivePayload []byte `protobuf:"bytes,2,opt,name=archive_payload,json=archivePayload,proto3" json:"archive_payload,omitempty"` + // The hash of the archive payload, can also used as a “package_id“. + // Must be a valid PackageIdString (as described in “value.proto“). + // + // Required + Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPackageResponse) Reset() { + *x = GetPackageResponse{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPackageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPackageResponse) ProtoMessage() {} + +func (x *GetPackageResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPackageResponse.ProtoReflect.Descriptor instead. +func (*GetPackageResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetPackageResponse) GetHashFunction() HashFunction { + if x != nil { + return x.HashFunction + } + return HashFunction_HASH_FUNCTION_SHA256 +} + +func (x *GetPackageResponse) GetArchivePayload() []byte { + if x != nil { + return x.ArchivePayload + } + return nil +} + +func (x *GetPackageResponse) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +type GetPackageStatusResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The status of the package. + // + // Required + PackageStatus PackageStatus `protobuf:"varint,1,opt,name=package_status,json=packageStatus,proto3,enum=com.daml.ledger.api.v2.PackageStatus" json:"package_status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPackageStatusResponse) Reset() { + *x = GetPackageStatusResponse{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPackageStatusResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPackageStatusResponse) ProtoMessage() {} + +func (x *GetPackageStatusResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPackageStatusResponse.ProtoReflect.Descriptor instead. +func (*GetPackageStatusResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{2} +} + +func (x *GetPackageStatusResponse) GetPackageStatus() PackageStatus { + if x != nil { + return x.PackageStatus + } + return PackageStatus_PACKAGE_STATUS_UNSPECIFIED +} + +type ListPackagesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListPackagesRequest) Reset() { + *x = ListPackagesRequest{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListPackagesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListPackagesRequest) ProtoMessage() {} + +func (x *ListPackagesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListPackagesRequest.ProtoReflect.Descriptor instead. +func (*ListPackagesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{3} +} + +type GetPackageRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the requested package. + // Must be a valid PackageIdString (as described in “value.proto“). + // + // Required + PackageId string `protobuf:"bytes,1,opt,name=package_id,json=packageId,proto3" json:"package_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPackageRequest) Reset() { + *x = GetPackageRequest{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPackageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPackageRequest) ProtoMessage() {} + +func (x *GetPackageRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPackageRequest.ProtoReflect.Descriptor instead. +func (*GetPackageRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{4} +} + +func (x *GetPackageRequest) GetPackageId() string { + if x != nil { + return x.PackageId + } + return "" +} + +type GetPackageStatusRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the requested package. + // Must be a valid PackageIdString (as described in “value.proto“). + // + // Required + PackageId string `protobuf:"bytes,1,opt,name=package_id,json=packageId,proto3" json:"package_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetPackageStatusRequest) Reset() { + *x = GetPackageStatusRequest{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetPackageStatusRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetPackageStatusRequest) ProtoMessage() {} + +func (x *GetPackageStatusRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetPackageStatusRequest.ProtoReflect.Descriptor instead. +func (*GetPackageStatusRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{5} +} + +func (x *GetPackageStatusRequest) GetPackageId() string { + if x != nil { + return x.PackageId + } + return "" +} + +// Filter the VettedPackages by package metadata. +// +// A PackageMetadataFilter without package_ids and without package_name_prefixes +// matches any vetted package. +// +// Non-empty fields specify candidate values of which at least one must match. +// If both fields are set, then a candidate is returned if it matches one of the fields. +type PackageMetadataFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + // If this list is non-empty, any vetted package with a package ID in this + // list will match the filter. + // + // Optional: can be empty + PackageIds []string `protobuf:"bytes,1,rep,name=package_ids,json=packageIds,proto3" json:"package_ids,omitempty"` + // If this list is non-empty, any vetted package with a name matching at least + // one prefix in this list will match the filter. + // + // Optional: can be empty + PackageNamePrefixes []string `protobuf:"bytes,2,rep,name=package_name_prefixes,json=packageNamePrefixes,proto3" json:"package_name_prefixes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PackageMetadataFilter) Reset() { + *x = PackageMetadataFilter{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PackageMetadataFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PackageMetadataFilter) ProtoMessage() {} + +func (x *PackageMetadataFilter) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PackageMetadataFilter.ProtoReflect.Descriptor instead. +func (*PackageMetadataFilter) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{6} +} + +func (x *PackageMetadataFilter) GetPackageIds() []string { + if x != nil { + return x.PackageIds + } + return nil +} + +func (x *PackageMetadataFilter) GetPackageNamePrefixes() []string { + if x != nil { + return x.PackageNamePrefixes + } + return nil +} + +// Filter the vetted packages by the participant and synchronizer that they are +// hosted on. +// +// Empty fields are ignored, such that a “TopologyStateFilter“ without +// participant_ids and without synchronizer_ids matches a vetted package hosted +// on any participant and synchronizer. +// +// Non-empty fields specify candidate values of which at least one must match. +// If both fields are set then at least one candidate value must match from each +// field. +type TopologyStateFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + // If this list is non-empty, only vetted packages hosted on participants + // listed in this field match the filter. + // Query the current Ledger API's participant's ID via the public + // “GetParticipantId“ command in “PartyManagementService“. + // + // Optional: can be empty + ParticipantIds []string `protobuf:"bytes,1,rep,name=participant_ids,json=participantIds,proto3" json:"participant_ids,omitempty"` + // If this list is non-empty, only vetted packages from the topology state of + // the synchronizers in this list match the filter. + // + // Optional: can be empty + SynchronizerIds []string `protobuf:"bytes,2,rep,name=synchronizer_ids,json=synchronizerIds,proto3" json:"synchronizer_ids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyStateFilter) Reset() { + *x = TopologyStateFilter{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyStateFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyStateFilter) ProtoMessage() {} + +func (x *TopologyStateFilter) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyStateFilter.ProtoReflect.Descriptor instead. +func (*TopologyStateFilter) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{7} +} + +func (x *TopologyStateFilter) GetParticipantIds() []string { + if x != nil { + return x.ParticipantIds + } + return nil +} + +func (x *TopologyStateFilter) GetSynchronizerIds() []string { + if x != nil { + return x.SynchronizerIds + } + return nil +} + +type ListVettedPackagesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The package metadata filter the returned vetted packages set must satisfy. + // + // Optional + PackageMetadataFilter *PackageMetadataFilter `protobuf:"bytes,1,opt,name=package_metadata_filter,json=packageMetadataFilter,proto3" json:"package_metadata_filter,omitempty"` + // The topology filter the returned vetted packages set must satisfy. + // + // Optional + TopologyStateFilter *TopologyStateFilter `protobuf:"bytes,2,opt,name=topology_state_filter,json=topologyStateFilter,proto3" json:"topology_state_filter,omitempty"` + // Pagination token to determine the specific page to fetch. Using the token + // guarantees that “VettedPackages“ on a subsequent page are all greater + // (“VettedPackages“ are sorted by synchronizer ID then participant ID) than + // the last “VettedPackages“ on a previous page. + // + // The server does not store intermediate results between calls chained by a + // series of page tokens. As a consequence, if new vetted packages are being + // added and a page is requested twice using the same token, more packages can + // be returned on the second call. + // + // Leave unspecified (i.e. as empty string) to fetch the first page. + // + // Optional + PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + // Maximum number of “VettedPackages“ results to return in a single page. + // + // If the page_size is unspecified (i.e. left as 0), the server will decide + // the number of results to be returned. + // + // If the page_size exceeds the maximum supported by the server, an + // error will be returned. + // + // To obtain the server's maximum consult the PackageService descriptor + // available in the VersionService. + // + // Optional + PageSize uint32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListVettedPackagesRequest) Reset() { + *x = ListVettedPackagesRequest{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListVettedPackagesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListVettedPackagesRequest) ProtoMessage() {} + +func (x *ListVettedPackagesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListVettedPackagesRequest.ProtoReflect.Descriptor instead. +func (*ListVettedPackagesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{8} +} + +func (x *ListVettedPackagesRequest) GetPackageMetadataFilter() *PackageMetadataFilter { + if x != nil { + return x.PackageMetadataFilter + } + return nil +} + +func (x *ListVettedPackagesRequest) GetTopologyStateFilter() *TopologyStateFilter { + if x != nil { + return x.TopologyStateFilter + } + return nil +} + +func (x *ListVettedPackagesRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +func (x *ListVettedPackagesRequest) GetPageSize() uint32 { + if x != nil { + return x.PageSize + } + return 0 +} + +type ListVettedPackagesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // All “VettedPackages“ that contain at least one “VettedPackage“ matching + // both a “PackageMetadataFilter“ and a “TopologyStateFilter“. + // Sorted by synchronizer_id then participant_id. + // + // Optional: can be empty + VettedPackages []*VettedPackages `protobuf:"bytes,1,rep,name=vetted_packages,json=vettedPackages,proto3" json:"vetted_packages,omitempty"` + // Pagination token to retrieve the next page. + // Empty string if there are no further results. + // + // Optional + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListVettedPackagesResponse) Reset() { + *x = ListVettedPackagesResponse{} + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListVettedPackagesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListVettedPackagesResponse) ProtoMessage() {} + +func (x *ListVettedPackagesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_package_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListVettedPackagesResponse.ProtoReflect.Descriptor instead. +func (*ListVettedPackagesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP(), []int{9} +} + +func (x *ListVettedPackagesResponse) GetVettedPackages() []*VettedPackages { + if x != nil { + return x.VettedPackages + } + return nil +} + +func (x *ListVettedPackagesResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +var File_com_daml_ledger_api_v2_package_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_package_service_proto_rawDesc = "" + + "\n" + + ",com/daml/ledger/api/v2/package_service.proto\x12\x16com.daml.ledger.api.v2\x1a.com/daml/ledger/api/v2/package_reference.proto\"7\n" + + "\x14ListPackagesResponse\x12\x1f\n" + + "\vpackage_ids\x18\x01 \x03(\tR\n" + + "packageIds\"\x9c\x01\n" + + "\x12GetPackageResponse\x12I\n" + + "\rhash_function\x18\x01 \x01(\x0e2$.com.daml.ledger.api.v2.HashFunctionR\fhashFunction\x12'\n" + + "\x0farchive_payload\x18\x02 \x01(\fR\x0earchivePayload\x12\x12\n" + + "\x04hash\x18\x03 \x01(\tR\x04hash\"h\n" + + "\x18GetPackageStatusResponse\x12L\n" + + "\x0epackage_status\x18\x01 \x01(\x0e2%.com.daml.ledger.api.v2.PackageStatusR\rpackageStatus\"\x15\n" + + "\x13ListPackagesRequest\"2\n" + + "\x11GetPackageRequest\x12\x1d\n" + + "\n" + + "package_id\x18\x01 \x01(\tR\tpackageId\"8\n" + + "\x17GetPackageStatusRequest\x12\x1d\n" + + "\n" + + "package_id\x18\x01 \x01(\tR\tpackageId\"l\n" + + "\x15PackageMetadataFilter\x12\x1f\n" + + "\vpackage_ids\x18\x01 \x03(\tR\n" + + "packageIds\x122\n" + + "\x15package_name_prefixes\x18\x02 \x03(\tR\x13packageNamePrefixes\"i\n" + + "\x13TopologyStateFilter\x12'\n" + + "\x0fparticipant_ids\x18\x01 \x03(\tR\x0eparticipantIds\x12)\n" + + "\x10synchronizer_ids\x18\x02 \x03(\tR\x0fsynchronizerIds\"\x9f\x02\n" + + "\x19ListVettedPackagesRequest\x12e\n" + + "\x17package_metadata_filter\x18\x01 \x01(\v2-.com.daml.ledger.api.v2.PackageMetadataFilterR\x15packageMetadataFilter\x12_\n" + + "\x15topology_state_filter\x18\x02 \x01(\v2+.com.daml.ledger.api.v2.TopologyStateFilterR\x13topologyStateFilter\x12\x1d\n" + + "\n" + + "page_token\x18\x03 \x01(\tR\tpageToken\x12\x1b\n" + + "\tpage_size\x18\x04 \x01(\rR\bpageSize\"\x95\x01\n" + + "\x1aListVettedPackagesResponse\x12O\n" + + "\x0fvetted_packages\x18\x01 \x03(\v2&.com.daml.ledger.api.v2.VettedPackagesR\x0evettedPackages\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken*N\n" + + "\rPackageStatus\x12\x1e\n" + + "\x1aPACKAGE_STATUS_UNSPECIFIED\x10\x00\x12\x1d\n" + + "\x19PACKAGE_STATUS_REGISTERED\x10\x01*(\n" + + "\fHashFunction\x12\x18\n" + + "\x14HASH_FUNCTION_SHA256\x10\x002\xd4\x03\n" + + "\x0ePackageService\x12i\n" + + "\fListPackages\x12+.com.daml.ledger.api.v2.ListPackagesRequest\x1a,.com.daml.ledger.api.v2.ListPackagesResponse\x12c\n" + + "\n" + + "GetPackage\x12).com.daml.ledger.api.v2.GetPackageRequest\x1a*.com.daml.ledger.api.v2.GetPackageResponse\x12u\n" + + "\x10GetPackageStatus\x12/.com.daml.ledger.api.v2.GetPackageStatusRequest\x1a0.com.daml.ledger.api.v2.GetPackageStatusResponse\x12{\n" + + "\x12ListVettedPackages\x121.com.daml.ledger.api.v2.ListVettedPackagesRequest\x1a2.com.daml.ledger.api.v2.ListVettedPackagesResponseB\x80\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x13PackageServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_package_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_package_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_package_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_package_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_package_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_package_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_package_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_package_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_package_service_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_com_daml_ledger_api_v2_package_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_com_daml_ledger_api_v2_package_service_proto_goTypes = []any{ + (PackageStatus)(0), // 0: com.daml.ledger.api.v2.PackageStatus + (HashFunction)(0), // 1: com.daml.ledger.api.v2.HashFunction + (*ListPackagesResponse)(nil), // 2: com.daml.ledger.api.v2.ListPackagesResponse + (*GetPackageResponse)(nil), // 3: com.daml.ledger.api.v2.GetPackageResponse + (*GetPackageStatusResponse)(nil), // 4: com.daml.ledger.api.v2.GetPackageStatusResponse + (*ListPackagesRequest)(nil), // 5: com.daml.ledger.api.v2.ListPackagesRequest + (*GetPackageRequest)(nil), // 6: com.daml.ledger.api.v2.GetPackageRequest + (*GetPackageStatusRequest)(nil), // 7: com.daml.ledger.api.v2.GetPackageStatusRequest + (*PackageMetadataFilter)(nil), // 8: com.daml.ledger.api.v2.PackageMetadataFilter + (*TopologyStateFilter)(nil), // 9: com.daml.ledger.api.v2.TopologyStateFilter + (*ListVettedPackagesRequest)(nil), // 10: com.daml.ledger.api.v2.ListVettedPackagesRequest + (*ListVettedPackagesResponse)(nil), // 11: com.daml.ledger.api.v2.ListVettedPackagesResponse + (*VettedPackages)(nil), // 12: com.daml.ledger.api.v2.VettedPackages +} +var file_com_daml_ledger_api_v2_package_service_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.GetPackageResponse.hash_function:type_name -> com.daml.ledger.api.v2.HashFunction + 0, // 1: com.daml.ledger.api.v2.GetPackageStatusResponse.package_status:type_name -> com.daml.ledger.api.v2.PackageStatus + 8, // 2: com.daml.ledger.api.v2.ListVettedPackagesRequest.package_metadata_filter:type_name -> com.daml.ledger.api.v2.PackageMetadataFilter + 9, // 3: com.daml.ledger.api.v2.ListVettedPackagesRequest.topology_state_filter:type_name -> com.daml.ledger.api.v2.TopologyStateFilter + 12, // 4: com.daml.ledger.api.v2.ListVettedPackagesResponse.vetted_packages:type_name -> com.daml.ledger.api.v2.VettedPackages + 5, // 5: com.daml.ledger.api.v2.PackageService.ListPackages:input_type -> com.daml.ledger.api.v2.ListPackagesRequest + 6, // 6: com.daml.ledger.api.v2.PackageService.GetPackage:input_type -> com.daml.ledger.api.v2.GetPackageRequest + 7, // 7: com.daml.ledger.api.v2.PackageService.GetPackageStatus:input_type -> com.daml.ledger.api.v2.GetPackageStatusRequest + 10, // 8: com.daml.ledger.api.v2.PackageService.ListVettedPackages:input_type -> com.daml.ledger.api.v2.ListVettedPackagesRequest + 2, // 9: com.daml.ledger.api.v2.PackageService.ListPackages:output_type -> com.daml.ledger.api.v2.ListPackagesResponse + 3, // 10: com.daml.ledger.api.v2.PackageService.GetPackage:output_type -> com.daml.ledger.api.v2.GetPackageResponse + 4, // 11: com.daml.ledger.api.v2.PackageService.GetPackageStatus:output_type -> com.daml.ledger.api.v2.GetPackageStatusResponse + 11, // 12: com.daml.ledger.api.v2.PackageService.ListVettedPackages:output_type -> com.daml.ledger.api.v2.ListVettedPackagesResponse + 9, // [9:13] is the sub-list for method output_type + 5, // [5:9] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_package_service_proto_init() } +func file_com_daml_ledger_api_v2_package_service_proto_init() { + if File_com_daml_ledger_api_v2_package_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_package_reference_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_package_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_package_service_proto_rawDesc)), + NumEnums: 2, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_package_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_package_service_proto_depIdxs, + EnumInfos: file_com_daml_ledger_api_v2_package_service_proto_enumTypes, + MessageInfos: file_com_daml_ledger_api_v2_package_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_package_service_proto = out.File + file_com_daml_ledger_api_v2_package_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_package_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/package_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/package_service_grpc.pb.go new file mode 100644 index 00000000..2a24b5a0 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/package_service_grpc.pb.go @@ -0,0 +1,252 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/package_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + PackageService_ListPackages_FullMethodName = "/com.daml.ledger.api.v2.PackageService/ListPackages" + PackageService_GetPackage_FullMethodName = "/com.daml.ledger.api.v2.PackageService/GetPackage" + PackageService_GetPackageStatus_FullMethodName = "/com.daml.ledger.api.v2.PackageService/GetPackageStatus" + PackageService_ListVettedPackages_FullMethodName = "/com.daml.ledger.api.v2.PackageService/ListVettedPackages" +) + +// PackageServiceClient is the client API for PackageService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Allows clients to query the Daml-LF packages that are supported by the server. +type PackageServiceClient interface { + // Returns the identifiers of all supported packages. + ListPackages(ctx context.Context, in *ListPackagesRequest, opts ...grpc.CallOption) (*ListPackagesResponse, error) + // Returns the contents of a single package. + GetPackage(ctx context.Context, in *GetPackageRequest, opts ...grpc.CallOption) (*GetPackageResponse, error) + // Returns the status of a single package. + GetPackageStatus(ctx context.Context, in *GetPackageStatusRequest, opts ...grpc.CallOption) (*GetPackageStatusResponse, error) + // Lists which participant node vetted what packages on which synchronizer. + // Can be called by any authenticated user. + ListVettedPackages(ctx context.Context, in *ListVettedPackagesRequest, opts ...grpc.CallOption) (*ListVettedPackagesResponse, error) +} + +type packageServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewPackageServiceClient(cc grpc.ClientConnInterface) PackageServiceClient { + return &packageServiceClient{cc} +} + +func (c *packageServiceClient) ListPackages(ctx context.Context, in *ListPackagesRequest, opts ...grpc.CallOption) (*ListPackagesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListPackagesResponse) + err := c.cc.Invoke(ctx, PackageService_ListPackages_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *packageServiceClient) GetPackage(ctx context.Context, in *GetPackageRequest, opts ...grpc.CallOption) (*GetPackageResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetPackageResponse) + err := c.cc.Invoke(ctx, PackageService_GetPackage_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *packageServiceClient) GetPackageStatus(ctx context.Context, in *GetPackageStatusRequest, opts ...grpc.CallOption) (*GetPackageStatusResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetPackageStatusResponse) + err := c.cc.Invoke(ctx, PackageService_GetPackageStatus_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *packageServiceClient) ListVettedPackages(ctx context.Context, in *ListVettedPackagesRequest, opts ...grpc.CallOption) (*ListVettedPackagesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListVettedPackagesResponse) + err := c.cc.Invoke(ctx, PackageService_ListVettedPackages_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// PackageServiceServer is the server API for PackageService service. +// All implementations must embed UnimplementedPackageServiceServer +// for forward compatibility. +// +// Allows clients to query the Daml-LF packages that are supported by the server. +type PackageServiceServer interface { + // Returns the identifiers of all supported packages. + ListPackages(context.Context, *ListPackagesRequest) (*ListPackagesResponse, error) + // Returns the contents of a single package. + GetPackage(context.Context, *GetPackageRequest) (*GetPackageResponse, error) + // Returns the status of a single package. + GetPackageStatus(context.Context, *GetPackageStatusRequest) (*GetPackageStatusResponse, error) + // Lists which participant node vetted what packages on which synchronizer. + // Can be called by any authenticated user. + ListVettedPackages(context.Context, *ListVettedPackagesRequest) (*ListVettedPackagesResponse, error) + mustEmbedUnimplementedPackageServiceServer() +} + +// UnimplementedPackageServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedPackageServiceServer struct{} + +func (UnimplementedPackageServiceServer) ListPackages(context.Context, *ListPackagesRequest) (*ListPackagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPackages not implemented") +} +func (UnimplementedPackageServiceServer) GetPackage(context.Context, *GetPackageRequest) (*GetPackageResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPackage not implemented") +} +func (UnimplementedPackageServiceServer) GetPackageStatus(context.Context, *GetPackageStatusRequest) (*GetPackageStatusResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPackageStatus not implemented") +} +func (UnimplementedPackageServiceServer) ListVettedPackages(context.Context, *ListVettedPackagesRequest) (*ListVettedPackagesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListVettedPackages not implemented") +} +func (UnimplementedPackageServiceServer) mustEmbedUnimplementedPackageServiceServer() {} +func (UnimplementedPackageServiceServer) testEmbeddedByValue() {} + +// UnsafePackageServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to PackageServiceServer will +// result in compilation errors. +type UnsafePackageServiceServer interface { + mustEmbedUnimplementedPackageServiceServer() +} + +func RegisterPackageServiceServer(s grpc.ServiceRegistrar, srv PackageServiceServer) { + // If the following call pancis, it indicates UnimplementedPackageServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&PackageService_ServiceDesc, srv) +} + +func _PackageService_ListPackages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListPackagesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageServiceServer).ListPackages(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageService_ListPackages_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageServiceServer).ListPackages(ctx, req.(*ListPackagesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PackageService_GetPackage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPackageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageServiceServer).GetPackage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageService_GetPackage_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageServiceServer).GetPackage(ctx, req.(*GetPackageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PackageService_GetPackageStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetPackageStatusRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageServiceServer).GetPackageStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageService_GetPackageStatus_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageServiceServer).GetPackageStatus(ctx, req.(*GetPackageStatusRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _PackageService_ListVettedPackages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListVettedPackagesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(PackageServiceServer).ListVettedPackages(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: PackageService_ListVettedPackages_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(PackageServiceServer).ListVettedPackages(ctx, req.(*ListVettedPackagesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// PackageService_ServiceDesc is the grpc.ServiceDesc for PackageService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var PackageService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.PackageService", + HandlerType: (*PackageServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ListPackages", + Handler: _PackageService_ListPackages_Handler, + }, + { + MethodName: "GetPackage", + Handler: _PackageService_GetPackage_Handler, + }, + { + MethodName: "GetPackageStatus", + Handler: _PackageService_GetPackageStatus_Handler, + }, + { + MethodName: "ListVettedPackages", + Handler: _PackageService_ListVettedPackages_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/package_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/reassignment.pb.go b/chain/canton/types/com/daml/ledger/api/v2/reassignment.pb.go new file mode 100644 index 00000000..0088cc66 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/reassignment.pb.go @@ -0,0 +1,665 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/reassignment.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Complete view of an on-ledger reassignment. +type Reassignment struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Assigned by the server. Useful for correlating logs. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // The ID of the command which resulted in this reassignment. Missing for everyone except the submitting party on the submitting participant. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + // The workflow ID used in reassignment command submission. Only set if the “workflow_id“ for the command was set. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + WorkflowId string `protobuf:"bytes,3,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"` + // The participant's offset. The details of this field are described in “community/ledger-api/README.md“. + // Must be a valid absolute offset (positive integer). + // + // Required + Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` + // The collection of reassignment events. + // + // Required: must be non-empty + Events []*ReassignmentEvent `protobuf:"bytes,5,rep,name=events,proto3" json:"events,omitempty"` + // Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + TraceContext *TraceContext `protobuf:"bytes,6,opt,name=trace_context,json=traceContext,proto3" json:"trace_context,omitempty"` + // The time at which the reassignment was recorded. The record time refers to the source/target + // synchronizer for an unassign/assign event respectively. + // + // Required + RecordTime *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=record_time,json=recordTime,proto3" json:"record_time,omitempty"` + // A valid synchronizer id. + // Identifies the synchronizer that synchronized this Reassignment. + // + // Required + SynchronizerId string `protobuf:"bytes,8,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Reassignment) Reset() { + *x = Reassignment{} + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Reassignment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Reassignment) ProtoMessage() {} + +func (x *Reassignment) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Reassignment.ProtoReflect.Descriptor instead. +func (*Reassignment) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_proto_rawDescGZIP(), []int{0} +} + +func (x *Reassignment) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *Reassignment) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *Reassignment) GetWorkflowId() string { + if x != nil { + return x.WorkflowId + } + return "" +} + +func (x *Reassignment) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *Reassignment) GetEvents() []*ReassignmentEvent { + if x != nil { + return x.Events + } + return nil +} + +func (x *Reassignment) GetTraceContext() *TraceContext { + if x != nil { + return x.TraceContext + } + return nil +} + +func (x *Reassignment) GetRecordTime() *timestamppb.Timestamp { + if x != nil { + return x.RecordTime + } + return nil +} + +func (x *Reassignment) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +type ReassignmentEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Event: + // + // *ReassignmentEvent_Unassigned + // *ReassignmentEvent_Assigned + Event isReassignmentEvent_Event `protobuf_oneof:"event"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReassignmentEvent) Reset() { + *x = ReassignmentEvent{} + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReassignmentEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReassignmentEvent) ProtoMessage() {} + +func (x *ReassignmentEvent) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReassignmentEvent.ProtoReflect.Descriptor instead. +func (*ReassignmentEvent) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_proto_rawDescGZIP(), []int{1} +} + +func (x *ReassignmentEvent) GetEvent() isReassignmentEvent_Event { + if x != nil { + return x.Event + } + return nil +} + +func (x *ReassignmentEvent) GetUnassigned() *UnassignedEvent { + if x != nil { + if x, ok := x.Event.(*ReassignmentEvent_Unassigned); ok { + return x.Unassigned + } + } + return nil +} + +func (x *ReassignmentEvent) GetAssigned() *AssignedEvent { + if x != nil { + if x, ok := x.Event.(*ReassignmentEvent_Assigned); ok { + return x.Assigned + } + } + return nil +} + +type isReassignmentEvent_Event interface { + isReassignmentEvent_Event() +} + +type ReassignmentEvent_Unassigned struct { + Unassigned *UnassignedEvent `protobuf:"bytes,1,opt,name=unassigned,proto3,oneof"` +} + +type ReassignmentEvent_Assigned struct { + Assigned *AssignedEvent `protobuf:"bytes,2,opt,name=assigned,proto3,oneof"` +} + +func (*ReassignmentEvent_Unassigned) isReassignmentEvent_Event() {} + +func (*ReassignmentEvent_Assigned) isReassignmentEvent_Event() {} + +// Records that a contract has been unassigned, and it becomes unusable on the source synchronizer +type UnassignedEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the unassignment. This needs to be used as an input for a assign ReassignmentCommand. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ReassignmentId string `protobuf:"bytes,1,opt,name=reassignment_id,json=reassignmentId,proto3" json:"reassignment_id,omitempty"` + // The ID of the reassigned contract. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ContractId string `protobuf:"bytes,2,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // The template of the reassigned contract. + // The identifier uses the package-id reference format. + // + // Required + TemplateId *Identifier `protobuf:"bytes,3,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // The ID of the source synchronizer + // Must be a valid synchronizer id + // + // Required + Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` + // The ID of the target synchronizer + // Must be a valid synchronizer id + // + // Required + Target string `protobuf:"bytes,5,opt,name=target,proto3" json:"target,omitempty"` + // Party on whose behalf the unassign command was executed. + // Empty if the unassignment happened offline via the repair service. + // Must be a valid PartyIdString (as described in “value.proto“). + // + // Optional + Submitter string `protobuf:"bytes,6,opt,name=submitter,proto3" json:"submitter,omitempty"` + // Each corresponding assigned and unassigned event has the same reassignment_counter. This strictly increases + // with each unassign command for the same contract. Creation of the contract corresponds to reassignment_counter + // equals zero. + // + // Required + ReassignmentCounter uint64 `protobuf:"varint,7,opt,name=reassignment_counter,json=reassignmentCounter,proto3" json:"reassignment_counter,omitempty"` + // Assignment exclusivity + // Before this time (measured on the target synchronizer), only the submitter of the unassignment can initiate the assignment + // Defined for reassigning participants. + // + // Optional + AssignmentExclusivity *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=assignment_exclusivity,json=assignmentExclusivity,proto3" json:"assignment_exclusivity,omitempty"` + // The parties that are notified of this event. + // + // Required: must be non-empty + WitnessParties []string `protobuf:"bytes,9,rep,name=witness_parties,json=witnessParties,proto3" json:"witness_parties,omitempty"` + // The package name of the contract. + // + // Required + PackageName string `protobuf:"bytes,10,opt,name=package_name,json=packageName,proto3" json:"package_name,omitempty"` + // The offset of origin. + // Offsets are managed by the participant nodes. + // Reassignments can thus NOT be assumed to have the same offsets on different participant nodes. + // Must be a valid absolute offset (positive integer) + // + // Required + Offset int64 `protobuf:"varint,11,opt,name=offset,proto3" json:"offset,omitempty"` + // The position of this event in the originating reassignment. + // Node IDs are not necessarily equal across participants, + // as these may see different projections/parts of reassignments. + // Must be valid node ID (non-negative integer) + // + // Required + NodeId int32 `protobuf:"varint,12,opt,name=node_id,json=nodeId,proto3" json:"node_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UnassignedEvent) Reset() { + *x = UnassignedEvent{} + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UnassignedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnassignedEvent) ProtoMessage() {} + +func (x *UnassignedEvent) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnassignedEvent.ProtoReflect.Descriptor instead. +func (*UnassignedEvent) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_proto_rawDescGZIP(), []int{2} +} + +func (x *UnassignedEvent) GetReassignmentId() string { + if x != nil { + return x.ReassignmentId + } + return "" +} + +func (x *UnassignedEvent) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *UnassignedEvent) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *UnassignedEvent) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *UnassignedEvent) GetTarget() string { + if x != nil { + return x.Target + } + return "" +} + +func (x *UnassignedEvent) GetSubmitter() string { + if x != nil { + return x.Submitter + } + return "" +} + +func (x *UnassignedEvent) GetReassignmentCounter() uint64 { + if x != nil { + return x.ReassignmentCounter + } + return 0 +} + +func (x *UnassignedEvent) GetAssignmentExclusivity() *timestamppb.Timestamp { + if x != nil { + return x.AssignmentExclusivity + } + return nil +} + +func (x *UnassignedEvent) GetWitnessParties() []string { + if x != nil { + return x.WitnessParties + } + return nil +} + +func (x *UnassignedEvent) GetPackageName() string { + if x != nil { + return x.PackageName + } + return "" +} + +func (x *UnassignedEvent) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *UnassignedEvent) GetNodeId() int32 { + if x != nil { + return x.NodeId + } + return 0 +} + +// Records that a contract has been assigned, and it can be used on the target synchronizer. +type AssignedEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the source synchronizer. + // Must be a valid synchronizer id. + // + // Required + Source string `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"` + // The ID of the target synchronizer. + // Must be a valid synchronizer id. + // + // Required + Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"` + // The ID from the unassigned event. + // For correlation capabilities. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ReassignmentId string `protobuf:"bytes,3,opt,name=reassignment_id,json=reassignmentId,proto3" json:"reassignment_id,omitempty"` + // Party on whose behalf the assign command was executed. + // Empty if the assignment happened offline via the repair service. + // Must be a valid PartyIdString (as described in “value.proto“). + // + // Optional + Submitter string `protobuf:"bytes,4,opt,name=submitter,proto3" json:"submitter,omitempty"` + // Each corresponding assigned and unassigned event has the same reassignment_counter. This strictly increases + // with each unassign command for the same contract. Creation of the contract corresponds to reassignment_counter + // equals zero. + // + // Required + ReassignmentCounter uint64 `protobuf:"varint,5,opt,name=reassignment_counter,json=reassignmentCounter,proto3" json:"reassignment_counter,omitempty"` + // The offset of this event refers to the offset of the assignment, + // while the node_id is the index of within the batch. + // + // Required + CreatedEvent *CreatedEvent `protobuf:"bytes,6,opt,name=created_event,json=createdEvent,proto3" json:"created_event,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AssignedEvent) Reset() { + *x = AssignedEvent{} + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AssignedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignedEvent) ProtoMessage() {} + +func (x *AssignedEvent) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignedEvent.ProtoReflect.Descriptor instead. +func (*AssignedEvent) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_proto_rawDescGZIP(), []int{3} +} + +func (x *AssignedEvent) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *AssignedEvent) GetTarget() string { + if x != nil { + return x.Target + } + return "" +} + +func (x *AssignedEvent) GetReassignmentId() string { + if x != nil { + return x.ReassignmentId + } + return "" +} + +func (x *AssignedEvent) GetSubmitter() string { + if x != nil { + return x.Submitter + } + return "" +} + +func (x *AssignedEvent) GetReassignmentCounter() uint64 { + if x != nil { + return x.ReassignmentCounter + } + return 0 +} + +func (x *AssignedEvent) GetCreatedEvent() *CreatedEvent { + if x != nil { + return x.CreatedEvent + } + return nil +} + +var File_com_daml_ledger_api_v2_reassignment_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_reassignment_proto_rawDesc = "" + + "\n" + + ")com/daml/ledger/api/v2/reassignment.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/event.proto\x1a*com/daml/ledger/api/v2/trace_context.proto\x1a\"com/daml/ledger/api/v2/value.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xf7\x02\n" + + "\fReassignment\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12\x1d\n" + + "\n" + + "command_id\x18\x02 \x01(\tR\tcommandId\x12\x1f\n" + + "\vworkflow_id\x18\x03 \x01(\tR\n" + + "workflowId\x12\x16\n" + + "\x06offset\x18\x04 \x01(\x03R\x06offset\x12A\n" + + "\x06events\x18\x05 \x03(\v2).com.daml.ledger.api.v2.ReassignmentEventR\x06events\x12I\n" + + "\rtrace_context\x18\x06 \x01(\v2$.com.daml.ledger.api.v2.TraceContextR\ftraceContext\x12;\n" + + "\vrecord_time\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "recordTime\x12'\n" + + "\x0fsynchronizer_id\x18\b \x01(\tR\x0esynchronizerId\"\xac\x01\n" + + "\x11ReassignmentEvent\x12I\n" + + "\n" + + "unassigned\x18\x01 \x01(\v2'.com.daml.ledger.api.v2.UnassignedEventH\x00R\n" + + "unassigned\x12C\n" + + "\bassigned\x18\x02 \x01(\v2%.com.daml.ledger.api.v2.AssignedEventH\x00R\bassignedB\a\n" + + "\x05event\"\xf1\x03\n" + + "\x0fUnassignedEvent\x12'\n" + + "\x0freassignment_id\x18\x01 \x01(\tR\x0ereassignmentId\x12\x1f\n" + + "\vcontract_id\x18\x02 \x01(\tR\n" + + "contractId\x12C\n" + + "\vtemplate_id\x18\x03 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12\x16\n" + + "\x06source\x18\x04 \x01(\tR\x06source\x12\x16\n" + + "\x06target\x18\x05 \x01(\tR\x06target\x12\x1c\n" + + "\tsubmitter\x18\x06 \x01(\tR\tsubmitter\x121\n" + + "\x14reassignment_counter\x18\a \x01(\x04R\x13reassignmentCounter\x12Q\n" + + "\x16assignment_exclusivity\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\x15assignmentExclusivity\x12'\n" + + "\x0fwitness_parties\x18\t \x03(\tR\x0ewitnessParties\x12!\n" + + "\fpackage_name\x18\n" + + " \x01(\tR\vpackageName\x12\x16\n" + + "\x06offset\x18\v \x01(\x03R\x06offset\x12\x17\n" + + "\anode_id\x18\f \x01(\x05R\x06nodeId\"\x84\x02\n" + + "\rAssignedEvent\x12\x16\n" + + "\x06source\x18\x01 \x01(\tR\x06source\x12\x16\n" + + "\x06target\x18\x02 \x01(\tR\x06target\x12'\n" + + "\x0freassignment_id\x18\x03 \x01(\tR\x0ereassignmentId\x12\x1c\n" + + "\tsubmitter\x18\x04 \x01(\tR\tsubmitter\x121\n" + + "\x14reassignment_counter\x18\x05 \x01(\x04R\x13reassignmentCounter\x12I\n" + + "\rcreated_event\x18\x06 \x01(\v2$.com.daml.ledger.api.v2.CreatedEventR\fcreatedEventB\xfe\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\x11ReassignmentProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_reassignment_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_reassignment_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_reassignment_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_reassignment_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_reassignment_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_reassignment_proto_rawDesc), len(file_com_daml_ledger_api_v2_reassignment_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_reassignment_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_reassignment_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_com_daml_ledger_api_v2_reassignment_proto_goTypes = []any{ + (*Reassignment)(nil), // 0: com.daml.ledger.api.v2.Reassignment + (*ReassignmentEvent)(nil), // 1: com.daml.ledger.api.v2.ReassignmentEvent + (*UnassignedEvent)(nil), // 2: com.daml.ledger.api.v2.UnassignedEvent + (*AssignedEvent)(nil), // 3: com.daml.ledger.api.v2.AssignedEvent + (*TraceContext)(nil), // 4: com.daml.ledger.api.v2.TraceContext + (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp + (*Identifier)(nil), // 6: com.daml.ledger.api.v2.Identifier + (*CreatedEvent)(nil), // 7: com.daml.ledger.api.v2.CreatedEvent +} +var file_com_daml_ledger_api_v2_reassignment_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.Reassignment.events:type_name -> com.daml.ledger.api.v2.ReassignmentEvent + 4, // 1: com.daml.ledger.api.v2.Reassignment.trace_context:type_name -> com.daml.ledger.api.v2.TraceContext + 5, // 2: com.daml.ledger.api.v2.Reassignment.record_time:type_name -> google.protobuf.Timestamp + 2, // 3: com.daml.ledger.api.v2.ReassignmentEvent.unassigned:type_name -> com.daml.ledger.api.v2.UnassignedEvent + 3, // 4: com.daml.ledger.api.v2.ReassignmentEvent.assigned:type_name -> com.daml.ledger.api.v2.AssignedEvent + 6, // 5: com.daml.ledger.api.v2.UnassignedEvent.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 5, // 6: com.daml.ledger.api.v2.UnassignedEvent.assignment_exclusivity:type_name -> google.protobuf.Timestamp + 7, // 7: com.daml.ledger.api.v2.AssignedEvent.created_event:type_name -> com.daml.ledger.api.v2.CreatedEvent + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_reassignment_proto_init() } +func file_com_daml_ledger_api_v2_reassignment_proto_init() { + if File_com_daml_ledger_api_v2_reassignment_proto != nil { + return + } + file_com_daml_ledger_api_v2_event_proto_init() + file_com_daml_ledger_api_v2_trace_context_proto_init() + file_com_daml_ledger_api_v2_value_proto_init() + file_com_daml_ledger_api_v2_reassignment_proto_msgTypes[1].OneofWrappers = []any{ + (*ReassignmentEvent_Unassigned)(nil), + (*ReassignmentEvent_Assigned)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_reassignment_proto_rawDesc), len(file_com_daml_ledger_api_v2_reassignment_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_reassignment_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_reassignment_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_reassignment_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_reassignment_proto = out.File + file_com_daml_ledger_api_v2_reassignment_proto_goTypes = nil + file_com_daml_ledger_api_v2_reassignment_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/reassignment_commands.pb.go b/chain/canton/types/com/daml/ledger/api/v2/reassignment_commands.pb.go new file mode 100644 index 00000000..7f04c5bb --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/reassignment_commands.pb.go @@ -0,0 +1,459 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/reassignment_commands.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type ReassignmentCommands struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Identifier of the on-ledger workflow that this command is a part of. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + WorkflowId string `protobuf:"bytes,1,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"` + // Uniquely identifies the participant user that issued the command. + // Must be a valid UserIdString (as described in “value.proto“). + // Required unless authentication is used with a user token. + // In that case, the token's user-id will be used for the request's user_id. + // + // Optional + UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // Uniquely identifies the command. + // The triple (user_id, submitter, command_id) constitutes the change ID for the intended ledger change. + // The change ID can be used for matching the intended ledger changes with all their completions. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + CommandId string `protobuf:"bytes,3,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + // Party on whose behalf the command should be executed. + // If ledger API authorization is enabled, then the authorization metadata must authorize the sender of the request + // to act on behalf of the given party. + // Must be a valid PartyIdString (as described in “value.proto“). + // + // Required + Submitter string `protobuf:"bytes,4,opt,name=submitter,proto3" json:"submitter,omitempty"` + // A unique identifier to distinguish completions for different submissions with the same change ID. + // Typically a random UUID. Applications are expected to use a different UUID for each retry of a submission + // with the same change ID. + // Must be a valid LedgerString (as described in “value.proto“). + // + // If omitted, the participant or the committer may set a value of their choice. + // + // Optional + SubmissionId string `protobuf:"bytes,5,opt,name=submission_id,json=submissionId,proto3" json:"submission_id,omitempty"` + // Individual elements of this reassignment. Must be non-empty. + // + // Required: must be non-empty + Commands []*ReassignmentCommand `protobuf:"bytes,6,rep,name=commands,proto3" json:"commands,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReassignmentCommands) Reset() { + *x = ReassignmentCommands{} + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReassignmentCommands) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReassignmentCommands) ProtoMessage() {} + +func (x *ReassignmentCommands) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReassignmentCommands.ProtoReflect.Descriptor instead. +func (*ReassignmentCommands) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescGZIP(), []int{0} +} + +func (x *ReassignmentCommands) GetWorkflowId() string { + if x != nil { + return x.WorkflowId + } + return "" +} + +func (x *ReassignmentCommands) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *ReassignmentCommands) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *ReassignmentCommands) GetSubmitter() string { + if x != nil { + return x.Submitter + } + return "" +} + +func (x *ReassignmentCommands) GetSubmissionId() string { + if x != nil { + return x.SubmissionId + } + return "" +} + +func (x *ReassignmentCommands) GetCommands() []*ReassignmentCommand { + if x != nil { + return x.Commands + } + return nil +} + +type ReassignmentCommand struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Command: + // + // *ReassignmentCommand_UnassignCommand + // *ReassignmentCommand_AssignCommand + Command isReassignmentCommand_Command `protobuf_oneof:"command"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ReassignmentCommand) Reset() { + *x = ReassignmentCommand{} + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ReassignmentCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReassignmentCommand) ProtoMessage() {} + +func (x *ReassignmentCommand) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReassignmentCommand.ProtoReflect.Descriptor instead. +func (*ReassignmentCommand) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescGZIP(), []int{1} +} + +func (x *ReassignmentCommand) GetCommand() isReassignmentCommand_Command { + if x != nil { + return x.Command + } + return nil +} + +func (x *ReassignmentCommand) GetUnassignCommand() *UnassignCommand { + if x != nil { + if x, ok := x.Command.(*ReassignmentCommand_UnassignCommand); ok { + return x.UnassignCommand + } + } + return nil +} + +func (x *ReassignmentCommand) GetAssignCommand() *AssignCommand { + if x != nil { + if x, ok := x.Command.(*ReassignmentCommand_AssignCommand); ok { + return x.AssignCommand + } + } + return nil +} + +type isReassignmentCommand_Command interface { + isReassignmentCommand_Command() +} + +type ReassignmentCommand_UnassignCommand struct { + UnassignCommand *UnassignCommand `protobuf:"bytes,1,opt,name=unassign_command,json=unassignCommand,proto3,oneof"` +} + +type ReassignmentCommand_AssignCommand struct { + AssignCommand *AssignCommand `protobuf:"bytes,2,opt,name=assign_command,json=assignCommand,proto3,oneof"` +} + +func (*ReassignmentCommand_UnassignCommand) isReassignmentCommand_Command() {} + +func (*ReassignmentCommand_AssignCommand) isReassignmentCommand_Command() {} + +// Unassign a contract +type UnassignCommand struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of the contract the client wants to unassign. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ContractId string `protobuf:"bytes,1,opt,name=contract_id,json=contractId,proto3" json:"contract_id,omitempty"` + // The ID of the source synchronizer + // Must be a valid synchronizer id + // + // Required + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` + // The ID of the target synchronizer + // Must be a valid synchronizer id + // + // Required + Target string `protobuf:"bytes,3,opt,name=target,proto3" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UnassignCommand) Reset() { + *x = UnassignCommand{} + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UnassignCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnassignCommand) ProtoMessage() {} + +func (x *UnassignCommand) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UnassignCommand.ProtoReflect.Descriptor instead. +func (*UnassignCommand) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescGZIP(), []int{2} +} + +func (x *UnassignCommand) GetContractId() string { + if x != nil { + return x.ContractId + } + return "" +} + +func (x *UnassignCommand) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *UnassignCommand) GetTarget() string { + if x != nil { + return x.Target + } + return "" +} + +// Assign a contract +type AssignCommand struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID from the unassigned event to be completed by this assignment. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + ReassignmentId string `protobuf:"bytes,1,opt,name=reassignment_id,json=reassignmentId,proto3" json:"reassignment_id,omitempty"` + // The ID of the source synchronizer + // Must be a valid synchronizer id + // + // Required + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` + // The ID of the target synchronizer + // Must be a valid synchronizer id + // + // Required + Target string `protobuf:"bytes,3,opt,name=target,proto3" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AssignCommand) Reset() { + *x = AssignCommand{} + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AssignCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignCommand) ProtoMessage() {} + +func (x *AssignCommand) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignCommand.ProtoReflect.Descriptor instead. +func (*AssignCommand) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescGZIP(), []int{3} +} + +func (x *AssignCommand) GetReassignmentId() string { + if x != nil { + return x.ReassignmentId + } + return "" +} + +func (x *AssignCommand) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +func (x *AssignCommand) GetTarget() string { + if x != nil { + return x.Target + } + return "" +} + +var File_com_daml_ledger_api_v2_reassignment_commands_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDesc = "" + + "\n" + + "2com/daml/ledger/api/v2/reassignment_commands.proto\x12\x16com.daml.ledger.api.v2\"\xfb\x01\n" + + "\x14ReassignmentCommands\x12\x1f\n" + + "\vworkflow_id\x18\x01 \x01(\tR\n" + + "workflowId\x12\x17\n" + + "\auser_id\x18\x02 \x01(\tR\x06userId\x12\x1d\n" + + "\n" + + "command_id\x18\x03 \x01(\tR\tcommandId\x12\x1c\n" + + "\tsubmitter\x18\x04 \x01(\tR\tsubmitter\x12#\n" + + "\rsubmission_id\x18\x05 \x01(\tR\fsubmissionId\x12G\n" + + "\bcommands\x18\x06 \x03(\v2+.com.daml.ledger.api.v2.ReassignmentCommandR\bcommands\"\xc6\x01\n" + + "\x13ReassignmentCommand\x12T\n" + + "\x10unassign_command\x18\x01 \x01(\v2'.com.daml.ledger.api.v2.UnassignCommandH\x00R\x0funassignCommand\x12N\n" + + "\x0eassign_command\x18\x02 \x01(\v2%.com.daml.ledger.api.v2.AssignCommandH\x00R\rassignCommandB\t\n" + + "\acommand\"b\n" + + "\x0fUnassignCommand\x12\x1f\n" + + "\vcontract_id\x18\x01 \x01(\tR\n" + + "contractId\x12\x16\n" + + "\x06source\x18\x02 \x01(\tR\x06source\x12\x16\n" + + "\x06target\x18\x03 \x01(\tR\x06target\"h\n" + + "\rAssignCommand\x12'\n" + + "\x0freassignment_id\x18\x01 \x01(\tR\x0ereassignmentId\x12\x16\n" + + "\x06source\x18\x02 \x01(\tR\x06source\x12\x16\n" + + "\x06target\x18\x03 \x01(\tR\x06targetB\x86\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x19ReassignmentCommandsProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDesc), len(file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_com_daml_ledger_api_v2_reassignment_commands_proto_goTypes = []any{ + (*ReassignmentCommands)(nil), // 0: com.daml.ledger.api.v2.ReassignmentCommands + (*ReassignmentCommand)(nil), // 1: com.daml.ledger.api.v2.ReassignmentCommand + (*UnassignCommand)(nil), // 2: com.daml.ledger.api.v2.UnassignCommand + (*AssignCommand)(nil), // 3: com.daml.ledger.api.v2.AssignCommand +} +var file_com_daml_ledger_api_v2_reassignment_commands_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.ReassignmentCommands.commands:type_name -> com.daml.ledger.api.v2.ReassignmentCommand + 2, // 1: com.daml.ledger.api.v2.ReassignmentCommand.unassign_command:type_name -> com.daml.ledger.api.v2.UnassignCommand + 3, // 2: com.daml.ledger.api.v2.ReassignmentCommand.assign_command:type_name -> com.daml.ledger.api.v2.AssignCommand + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_reassignment_commands_proto_init() } +func file_com_daml_ledger_api_v2_reassignment_commands_proto_init() { + if File_com_daml_ledger_api_v2_reassignment_commands_proto != nil { + return + } + file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes[1].OneofWrappers = []any{ + (*ReassignmentCommand_UnassignCommand)(nil), + (*ReassignmentCommand_AssignCommand)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDesc), len(file_com_daml_ledger_api_v2_reassignment_commands_proto_rawDesc)), + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_reassignment_commands_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_reassignment_commands_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_reassignment_commands_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_reassignment_commands_proto = out.File + file_com_daml_ledger_api_v2_reassignment_commands_proto_goTypes = nil + file_com_daml_ledger_api_v2_reassignment_commands_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/state_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/state_service.pb.go new file mode 100644 index 00000000..bb6366b6 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/state_service.pb.go @@ -0,0 +1,1023 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/state_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Enum indicating the permission level that the participant has for the party +// whose connected synchronizers are being listed. +type ParticipantPermission int32 + +const ( + ParticipantPermission_PARTICIPANT_PERMISSION_UNSPECIFIED ParticipantPermission = 0 + ParticipantPermission_PARTICIPANT_PERMISSION_SUBMISSION ParticipantPermission = 1 + // participant can only confirm transactions + ParticipantPermission_PARTICIPANT_PERMISSION_CONFIRMATION ParticipantPermission = 2 + // participant can only observe transactions + ParticipantPermission_PARTICIPANT_PERMISSION_OBSERVATION ParticipantPermission = 3 +) + +// Enum value maps for ParticipantPermission. +var ( + ParticipantPermission_name = map[int32]string{ + 0: "PARTICIPANT_PERMISSION_UNSPECIFIED", + 1: "PARTICIPANT_PERMISSION_SUBMISSION", + 2: "PARTICIPANT_PERMISSION_CONFIRMATION", + 3: "PARTICIPANT_PERMISSION_OBSERVATION", + } + ParticipantPermission_value = map[string]int32{ + "PARTICIPANT_PERMISSION_UNSPECIFIED": 0, + "PARTICIPANT_PERMISSION_SUBMISSION": 1, + "PARTICIPANT_PERMISSION_CONFIRMATION": 2, + "PARTICIPANT_PERMISSION_OBSERVATION": 3, + } +) + +func (x ParticipantPermission) Enum() *ParticipantPermission { + p := new(ParticipantPermission) + *p = x + return p +} + +func (x ParticipantPermission) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ParticipantPermission) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_state_service_proto_enumTypes[0].Descriptor() +} + +func (ParticipantPermission) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_state_service_proto_enumTypes[0] +} + +func (x ParticipantPermission) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ParticipantPermission.Descriptor instead. +func (ParticipantPermission) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{0} +} + +// If the given offset is different than the ledger end, and there are (un)assignments in-flight at the given offset, +// the snapshot may fail with "FAILED_PRECONDITION/PARTICIPANT_PRUNED_DATA_ACCESSED". +// Note that it is ok to request acs snapshots for party migration with offsets other than ledger end, because party +// migration is not concerned with incomplete (un)assignments. +type GetActiveContractsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The offset at which the snapshot of the active contracts will be computed. + // Must be no greater than the current ledger end offset. + // Must be greater than or equal to the last pruning offset. + // Must be a valid absolute offset (positive integer) or ledger begin offset (zero). + // If zero, the empty set will be returned. + // + // Required + ActiveAtOffset int64 `protobuf:"varint,3,opt,name=active_at_offset,json=activeAtOffset,proto3" json:"active_at_offset,omitempty"` + // Format of the contract_entries in the result. In case of CreatedEvent the presentation will be of + // TRANSACTION_SHAPE_ACS_DELTA. + // + // Required + EventFormat *EventFormat `protobuf:"bytes,4,opt,name=event_format,json=eventFormat,proto3" json:"event_format,omitempty"` + // Opaque representation of a continuation token defining a position in the active contracts snapshot. + // The prefix of the active contracts snapshot will be omitted up to and including the element from which + // the continuation token was read. + // To reuse the continuation token from a `GetActiveContractsPageResponse`: + // + // - subsequent request must be executed on the same participant with the same version of canton, + // - subsequent request must have the same active_at_offset, + // - subsequent request must have the same event_format + // - and the participant must not have been pruned after the active_at_offset. + // + // If not specified, the whole active contracts snapshot will be returned. + // + // Optional: can be empty + StreamContinuationToken []byte `protobuf:"bytes,5,opt,name=stream_continuation_token,json=streamContinuationToken,proto3,oneof" json:"stream_continuation_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetActiveContractsRequest) Reset() { + *x = GetActiveContractsRequest{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetActiveContractsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetActiveContractsRequest) ProtoMessage() {} + +func (x *GetActiveContractsRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetActiveContractsRequest.ProtoReflect.Descriptor instead. +func (*GetActiveContractsRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetActiveContractsRequest) GetActiveAtOffset() int64 { + if x != nil { + return x.ActiveAtOffset + } + return 0 +} + +func (x *GetActiveContractsRequest) GetEventFormat() *EventFormat { + if x != nil { + return x.EventFormat + } + return nil +} + +func (x *GetActiveContractsRequest) GetStreamContinuationToken() []byte { + if x != nil { + return x.StreamContinuationToken + } + return nil +} + +type GetActiveContractsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The workflow ID used in command submission which corresponds to the contract_entry. Only set if + // the “workflow_id“ for the command was set. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + WorkflowId string `protobuf:"bytes,1,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"` + // For a contract there could be multiple contract_entry-s in the entire snapshot. These together define + // the state of one contract in the snapshot. + // A contract_entry is included in the result, if and only if there is at least one stakeholder party of the contract + // that is hosted on the synchronizer at the time of the event and the party satisfies the + // “TransactionFilter“ in the query. + // + // # Required + // + // Types that are valid to be assigned to ContractEntry: + // + // *GetActiveContractsResponse_ActiveContract + // *GetActiveContractsResponse_IncompleteUnassigned + // *GetActiveContractsResponse_IncompleteAssigned + ContractEntry isGetActiveContractsResponse_ContractEntry `protobuf_oneof:"contract_entry"` + // Opaque representation of a continuation token which can be used in the request to bypass the already processed part + // of the active contracts snapshot. + // Only populated for the streaming “GetActiveContracts“ rpc call. + // + // Optional: can be empty + StreamContinuationToken []byte `protobuf:"bytes,5,opt,name=stream_continuation_token,json=streamContinuationToken,proto3" json:"stream_continuation_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetActiveContractsResponse) Reset() { + *x = GetActiveContractsResponse{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetActiveContractsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetActiveContractsResponse) ProtoMessage() {} + +func (x *GetActiveContractsResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetActiveContractsResponse.ProtoReflect.Descriptor instead. +func (*GetActiveContractsResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetActiveContractsResponse) GetWorkflowId() string { + if x != nil { + return x.WorkflowId + } + return "" +} + +func (x *GetActiveContractsResponse) GetContractEntry() isGetActiveContractsResponse_ContractEntry { + if x != nil { + return x.ContractEntry + } + return nil +} + +func (x *GetActiveContractsResponse) GetActiveContract() *ActiveContract { + if x != nil { + if x, ok := x.ContractEntry.(*GetActiveContractsResponse_ActiveContract); ok { + return x.ActiveContract + } + } + return nil +} + +func (x *GetActiveContractsResponse) GetIncompleteUnassigned() *IncompleteUnassigned { + if x != nil { + if x, ok := x.ContractEntry.(*GetActiveContractsResponse_IncompleteUnassigned); ok { + return x.IncompleteUnassigned + } + } + return nil +} + +func (x *GetActiveContractsResponse) GetIncompleteAssigned() *IncompleteAssigned { + if x != nil { + if x, ok := x.ContractEntry.(*GetActiveContractsResponse_IncompleteAssigned); ok { + return x.IncompleteAssigned + } + } + return nil +} + +func (x *GetActiveContractsResponse) GetStreamContinuationToken() []byte { + if x != nil { + return x.StreamContinuationToken + } + return nil +} + +type isGetActiveContractsResponse_ContractEntry interface { + isGetActiveContractsResponse_ContractEntry() +} + +type GetActiveContractsResponse_ActiveContract struct { + // The contract is active on the assigned synchronizer, meaning: there was an activation event on the given synchronizer ( + // created, assigned), which is not followed by a deactivation event (archived, unassigned) on the same + // synchronizer, until the active_at_offset. + // Since activeness is defined as a per synchronizer concept, it is possible, that a contract is active on one + // synchronizer, but already archived on another. + // There will be one such message for each synchronizer the contract is active on. + ActiveContract *ActiveContract `protobuf:"bytes,2,opt,name=active_contract,json=activeContract,proto3,oneof"` +} + +type GetActiveContractsResponse_IncompleteUnassigned struct { + // Included iff the unassigned event was before or at the active_at_offset, but there was no corresponding + // assigned event before or at the active_at_offset. + IncompleteUnassigned *IncompleteUnassigned `protobuf:"bytes,3,opt,name=incomplete_unassigned,json=incompleteUnassigned,proto3,oneof"` +} + +type GetActiveContractsResponse_IncompleteAssigned struct { + // Important: this message is not indicating that the contract is active on the target synchronizer! + // Included iff the assigned event was before or at the active_at_offset, but there was no corresponding + // unassigned event before or at the active_at_offset. + IncompleteAssigned *IncompleteAssigned `protobuf:"bytes,4,opt,name=incomplete_assigned,json=incompleteAssigned,proto3,oneof"` +} + +func (*GetActiveContractsResponse_ActiveContract) isGetActiveContractsResponse_ContractEntry() {} + +func (*GetActiveContractsResponse_IncompleteUnassigned) isGetActiveContractsResponse_ContractEntry() { +} + +func (*GetActiveContractsResponse_IncompleteAssigned) isGetActiveContractsResponse_ContractEntry() {} + +type ActiveContract struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The event as it appeared in the context of its last update (i.e. daml transaction or + // reassignment). In particular, the last offset, node_id pair is preserved. + // The last update is the most recent update created or assigned this contract on synchronizer_id synchronizer. + // The offset of the CreatedEvent might point to an already pruned update, therefore it cannot necessarily be used + // for lookups. + // + // Required + CreatedEvent *CreatedEvent `protobuf:"bytes,1,opt,name=created_event,json=createdEvent,proto3" json:"created_event,omitempty"` + // A valid synchronizer id + // + // Required + SynchronizerId string `protobuf:"bytes,2,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // Each corresponding assigned and unassigned event has the same reassignment_counter. This strictly increases + // with each unassign command for the same contract. Creation of the contract corresponds to reassignment_counter + // equals zero. + // This field will be the reassignment_counter of the latest observable activation event on this synchronizer, which is + // before the active_at_offset. + // + // Required + ReassignmentCounter uint64 `protobuf:"varint,3,opt,name=reassignment_counter,json=reassignmentCounter,proto3" json:"reassignment_counter,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ActiveContract) Reset() { + *x = ActiveContract{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ActiveContract) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActiveContract) ProtoMessage() {} + +func (x *ActiveContract) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ActiveContract.ProtoReflect.Descriptor instead. +func (*ActiveContract) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ActiveContract) GetCreatedEvent() *CreatedEvent { + if x != nil { + return x.CreatedEvent + } + return nil +} + +func (x *ActiveContract) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *ActiveContract) GetReassignmentCounter() uint64 { + if x != nil { + return x.ReassignmentCounter + } + return 0 +} + +type IncompleteUnassigned struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The event as it appeared in the context of its last activation update (i.e. daml transaction or + // reassignment). In particular, the last activation offset, node_id pair is preserved. + // The last activation update is the most recent update created or assigned this contract on synchronizer_id synchronizer before + // the unassigned_event. + // The offset of the CreatedEvent might point to an already pruned update, therefore it cannot necessarily be used + // for lookups. + // + // Required + CreatedEvent *CreatedEvent `protobuf:"bytes,1,opt,name=created_event,json=createdEvent,proto3" json:"created_event,omitempty"` + // Required + UnassignedEvent *UnassignedEvent `protobuf:"bytes,2,opt,name=unassigned_event,json=unassignedEvent,proto3" json:"unassigned_event,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IncompleteUnassigned) Reset() { + *x = IncompleteUnassigned{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IncompleteUnassigned) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IncompleteUnassigned) ProtoMessage() {} + +func (x *IncompleteUnassigned) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IncompleteUnassigned.ProtoReflect.Descriptor instead. +func (*IncompleteUnassigned) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{3} +} + +func (x *IncompleteUnassigned) GetCreatedEvent() *CreatedEvent { + if x != nil { + return x.CreatedEvent + } + return nil +} + +func (x *IncompleteUnassigned) GetUnassignedEvent() *UnassignedEvent { + if x != nil { + return x.UnassignedEvent + } + return nil +} + +type IncompleteAssigned struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + AssignedEvent *AssignedEvent `protobuf:"bytes,1,opt,name=assigned_event,json=assignedEvent,proto3" json:"assigned_event,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *IncompleteAssigned) Reset() { + *x = IncompleteAssigned{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *IncompleteAssigned) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IncompleteAssigned) ProtoMessage() {} + +func (x *IncompleteAssigned) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IncompleteAssigned.ProtoReflect.Descriptor instead. +func (*IncompleteAssigned) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{4} +} + +func (x *IncompleteAssigned) GetAssignedEvent() *AssignedEvent { + if x != nil { + return x.AssignedEvent + } + return nil +} + +type GetConnectedSynchronizersRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The party of interest + // Must be a valid PartyIdString (as described in “value.proto“). + // If empty, all synchronizers this node is connected to will be returned + // + // Optional + Party string `protobuf:"bytes,1,opt,name=party,proto3" json:"party,omitempty"` + // The id of a participant whose mapping of a party to connected synchronizers is requested. + // Must be a valid participant-id retrieved through a prior call to getParticipantId. + // Defaults to the participant id of the host participant. + // + // Optional + ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + // The ID of the identity provider configured by “Identity Provider Config“ + // If not set, it's assumed the user is managed by the default identity provider. + // + // Optional + IdentityProviderId string `protobuf:"bytes,3,opt,name=identity_provider_id,json=identityProviderId,proto3" json:"identity_provider_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetConnectedSynchronizersRequest) Reset() { + *x = GetConnectedSynchronizersRequest{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetConnectedSynchronizersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConnectedSynchronizersRequest) ProtoMessage() {} + +func (x *GetConnectedSynchronizersRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConnectedSynchronizersRequest.ProtoReflect.Descriptor instead. +func (*GetConnectedSynchronizersRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{5} +} + +func (x *GetConnectedSynchronizersRequest) GetParty() string { + if x != nil { + return x.Party + } + return "" +} + +func (x *GetConnectedSynchronizersRequest) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +func (x *GetConnectedSynchronizersRequest) GetIdentityProviderId() string { + if x != nil { + return x.IdentityProviderId + } + return "" +} + +type GetConnectedSynchronizersResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional: can be empty + ConnectedSynchronizers []*GetConnectedSynchronizersResponse_ConnectedSynchronizer `protobuf:"bytes,1,rep,name=connected_synchronizers,json=connectedSynchronizers,proto3" json:"connected_synchronizers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetConnectedSynchronizersResponse) Reset() { + *x = GetConnectedSynchronizersResponse{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetConnectedSynchronizersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConnectedSynchronizersResponse) ProtoMessage() {} + +func (x *GetConnectedSynchronizersResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConnectedSynchronizersResponse.ProtoReflect.Descriptor instead. +func (*GetConnectedSynchronizersResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{6} +} + +func (x *GetConnectedSynchronizersResponse) GetConnectedSynchronizers() []*GetConnectedSynchronizersResponse_ConnectedSynchronizer { + if x != nil { + return x.ConnectedSynchronizers + } + return nil +} + +type GetLedgerEndRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLedgerEndRequest) Reset() { + *x = GetLedgerEndRequest{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLedgerEndRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLedgerEndRequest) ProtoMessage() {} + +func (x *GetLedgerEndRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLedgerEndRequest.ProtoReflect.Descriptor instead. +func (*GetLedgerEndRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{7} +} + +type GetLedgerEndResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // It will always be a non-negative integer. + // If zero, the participant view of the ledger is empty. + // If positive, the absolute offset of the ledger as viewed by the participant. + // + // Optional + Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLedgerEndResponse) Reset() { + *x = GetLedgerEndResponse{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLedgerEndResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLedgerEndResponse) ProtoMessage() {} + +func (x *GetLedgerEndResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLedgerEndResponse.ProtoReflect.Descriptor instead. +func (*GetLedgerEndResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{8} +} + +func (x *GetLedgerEndResponse) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +type GetLatestPrunedOffsetsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLatestPrunedOffsetsRequest) Reset() { + *x = GetLatestPrunedOffsetsRequest{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLatestPrunedOffsetsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLatestPrunedOffsetsRequest) ProtoMessage() {} + +func (x *GetLatestPrunedOffsetsRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLatestPrunedOffsetsRequest.ProtoReflect.Descriptor instead. +func (*GetLatestPrunedOffsetsRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{9} +} + +type GetLatestPrunedOffsetsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // It will always be a non-negative integer. + // If positive, the absolute offset up to which the ledger has been pruned, + // disregarding the state of all divulged contracts pruning. + // If zero, the ledger has not been pruned yet. + // + // Optional + ParticipantPrunedUpToInclusive int64 `protobuf:"varint,1,opt,name=participant_pruned_up_to_inclusive,json=participantPrunedUpToInclusive,proto3" json:"participant_pruned_up_to_inclusive,omitempty"` + // It will always be a non-negative integer. + // If positive, the absolute offset up to which all divulged events have been pruned on the ledger. + // It can be at or before the “participant_pruned_up_to_inclusive“ offset. + // For more details about all divulged events pruning, + // see “PruneRequest.prune_all_divulged_contracts“ in “participant_pruning_service.proto“. + // If zero, the divulged events have not been pruned yet. + // + // Optional + AllDivulgedContractsPrunedUpToInclusive int64 `protobuf:"varint,2,opt,name=all_divulged_contracts_pruned_up_to_inclusive,json=allDivulgedContractsPrunedUpToInclusive,proto3" json:"all_divulged_contracts_pruned_up_to_inclusive,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLatestPrunedOffsetsResponse) Reset() { + *x = GetLatestPrunedOffsetsResponse{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLatestPrunedOffsetsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLatestPrunedOffsetsResponse) ProtoMessage() {} + +func (x *GetLatestPrunedOffsetsResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLatestPrunedOffsetsResponse.ProtoReflect.Descriptor instead. +func (*GetLatestPrunedOffsetsResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{10} +} + +func (x *GetLatestPrunedOffsetsResponse) GetParticipantPrunedUpToInclusive() int64 { + if x != nil { + return x.ParticipantPrunedUpToInclusive + } + return 0 +} + +func (x *GetLatestPrunedOffsetsResponse) GetAllDivulgedContractsPrunedUpToInclusive() int64 { + if x != nil { + return x.AllDivulgedContractsPrunedUpToInclusive + } + return 0 +} + +type GetConnectedSynchronizersResponse_ConnectedSynchronizer struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The alias of the synchronizer + // + // Required + SynchronizerAlias string `protobuf:"bytes,1,opt,name=synchronizer_alias,json=synchronizerAlias,proto3" json:"synchronizer_alias,omitempty"` + // The ID of the synchronizer + // + // Required + SynchronizerId string `protobuf:"bytes,2,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The permission on the synchronizer + // Set if a party was used in the request, otherwise unspecified. + // + // Optional + Permission ParticipantPermission `protobuf:"varint,3,opt,name=permission,proto3,enum=com.daml.ledger.api.v2.ParticipantPermission" json:"permission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetConnectedSynchronizersResponse_ConnectedSynchronizer) Reset() { + *x = GetConnectedSynchronizersResponse_ConnectedSynchronizer{} + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetConnectedSynchronizersResponse_ConnectedSynchronizer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetConnectedSynchronizersResponse_ConnectedSynchronizer) ProtoMessage() {} + +func (x *GetConnectedSynchronizersResponse_ConnectedSynchronizer) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_state_service_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetConnectedSynchronizersResponse_ConnectedSynchronizer.ProtoReflect.Descriptor instead. +func (*GetConnectedSynchronizersResponse_ConnectedSynchronizer) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP(), []int{6, 0} +} + +func (x *GetConnectedSynchronizersResponse_ConnectedSynchronizer) GetSynchronizerAlias() string { + if x != nil { + return x.SynchronizerAlias + } + return "" +} + +func (x *GetConnectedSynchronizersResponse_ConnectedSynchronizer) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *GetConnectedSynchronizersResponse_ConnectedSynchronizer) GetPermission() ParticipantPermission { + if x != nil { + return x.Permission + } + return ParticipantPermission_PARTICIPANT_PERMISSION_UNSPECIFIED +} + +var File_com_daml_ledger_api_v2_state_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_state_service_proto_rawDesc = "" + + "\n" + + "*com/daml/ledger/api/v2/state_service.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/event.proto\x1a)com/daml/ledger/api/v2/reassignment.proto\x1a/com/daml/ledger/api/v2/transaction_filter.proto\"\x89\x02\n" + + "\x19GetActiveContractsRequest\x12(\n" + + "\x10active_at_offset\x18\x03 \x01(\x03R\x0eactiveAtOffset\x12F\n" + + "\fevent_format\x18\x04 \x01(\v2#.com.daml.ledger.api.v2.EventFormatR\veventFormat\x12?\n" + + "\x19stream_continuation_token\x18\x05 \x01(\fH\x00R\x17streamContinuationToken\x88\x01\x01B\x1c\n" + + "\x1a_stream_continuation_tokenJ\x04\b\x01\x10\x02J\x04\b\x02\x10\x03R\x06filterR\averbose\"\xa2\x03\n" + + "\x1aGetActiveContractsResponse\x12\x1f\n" + + "\vworkflow_id\x18\x01 \x01(\tR\n" + + "workflowId\x12Q\n" + + "\x0factive_contract\x18\x02 \x01(\v2&.com.daml.ledger.api.v2.ActiveContractH\x00R\x0eactiveContract\x12c\n" + + "\x15incomplete_unassigned\x18\x03 \x01(\v2,.com.daml.ledger.api.v2.IncompleteUnassignedH\x00R\x14incompleteUnassigned\x12]\n" + + "\x13incomplete_assigned\x18\x04 \x01(\v2*.com.daml.ledger.api.v2.IncompleteAssignedH\x00R\x12incompleteAssigned\x12:\n" + + "\x19stream_continuation_token\x18\x05 \x01(\fR\x17streamContinuationTokenB\x10\n" + + "\x0econtract_entry\"\xb7\x01\n" + + "\x0eActiveContract\x12I\n" + + "\rcreated_event\x18\x01 \x01(\v2$.com.daml.ledger.api.v2.CreatedEventR\fcreatedEvent\x12'\n" + + "\x0fsynchronizer_id\x18\x02 \x01(\tR\x0esynchronizerId\x121\n" + + "\x14reassignment_counter\x18\x03 \x01(\x04R\x13reassignmentCounter\"\xb5\x01\n" + + "\x14IncompleteUnassigned\x12I\n" + + "\rcreated_event\x18\x01 \x01(\v2$.com.daml.ledger.api.v2.CreatedEventR\fcreatedEvent\x12R\n" + + "\x10unassigned_event\x18\x02 \x01(\v2'.com.daml.ledger.api.v2.UnassignedEventR\x0funassignedEvent\"b\n" + + "\x12IncompleteAssigned\x12L\n" + + "\x0eassigned_event\x18\x01 \x01(\v2%.com.daml.ledger.api.v2.AssignedEventR\rassignedEvent\"\x91\x01\n" + + " GetConnectedSynchronizersRequest\x12\x14\n" + + "\x05party\x18\x01 \x01(\tR\x05party\x12%\n" + + "\x0eparticipant_id\x18\x02 \x01(\tR\rparticipantId\x120\n" + + "\x14identity_provider_id\x18\x03 \x01(\tR\x12identityProviderId\"\xef\x02\n" + + "!GetConnectedSynchronizersResponse\x12\x88\x01\n" + + "\x17connected_synchronizers\x18\x01 \x03(\v2O.com.daml.ledger.api.v2.GetConnectedSynchronizersResponse.ConnectedSynchronizerR\x16connectedSynchronizers\x1a\xbe\x01\n" + + "\x15ConnectedSynchronizer\x12-\n" + + "\x12synchronizer_alias\x18\x01 \x01(\tR\x11synchronizerAlias\x12'\n" + + "\x0fsynchronizer_id\x18\x02 \x01(\tR\x0esynchronizerId\x12M\n" + + "\n" + + "permission\x18\x03 \x01(\x0e2-.com.daml.ledger.api.v2.ParticipantPermissionR\n" + + "permission\"\x15\n" + + "\x13GetLedgerEndRequest\".\n" + + "\x14GetLedgerEndResponse\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x03R\x06offset\"\x1f\n" + + "\x1dGetLatestPrunedOffsetsRequest\"\xcc\x01\n" + + "\x1eGetLatestPrunedOffsetsResponse\x12J\n" + + "\"participant_pruned_up_to_inclusive\x18\x01 \x01(\x03R\x1eparticipantPrunedUpToInclusive\x12^\n" + + "-all_divulged_contracts_pruned_up_to_inclusive\x18\x02 \x01(\x03R'allDivulgedContractsPrunedUpToInclusive*\xb7\x01\n" + + "\x15ParticipantPermission\x12&\n" + + "\"PARTICIPANT_PERMISSION_UNSPECIFIED\x10\x00\x12%\n" + + "!PARTICIPANT_PERMISSION_SUBMISSION\x10\x01\x12'\n" + + "#PARTICIPANT_PERMISSION_CONFIRMATION\x10\x02\x12&\n" + + "\"PARTICIPANT_PERMISSION_OBSERVATION\x10\x032\x95\x04\n" + + "\fStateService\x12}\n" + + "\x12GetActiveContracts\x121.com.daml.ledger.api.v2.GetActiveContractsRequest\x1a2.com.daml.ledger.api.v2.GetActiveContractsResponse0\x01\x12\x90\x01\n" + + "\x19GetConnectedSynchronizers\x128.com.daml.ledger.api.v2.GetConnectedSynchronizersRequest\x1a9.com.daml.ledger.api.v2.GetConnectedSynchronizersResponse\x12i\n" + + "\fGetLedgerEnd\x12+.com.daml.ledger.api.v2.GetLedgerEndRequest\x1a,.com.daml.ledger.api.v2.GetLedgerEndResponse\x12\x87\x01\n" + + "\x16GetLatestPrunedOffsets\x125.com.daml.ledger.api.v2.GetLatestPrunedOffsetsRequest\x1a6.com.daml.ledger.api.v2.GetLatestPrunedOffsetsResponseB\xfe\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\x11StateServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_state_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_state_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_state_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_state_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_state_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_state_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_state_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_state_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_state_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_com_daml_ledger_api_v2_state_service_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_com_daml_ledger_api_v2_state_service_proto_goTypes = []any{ + (ParticipantPermission)(0), // 0: com.daml.ledger.api.v2.ParticipantPermission + (*GetActiveContractsRequest)(nil), // 1: com.daml.ledger.api.v2.GetActiveContractsRequest + (*GetActiveContractsResponse)(nil), // 2: com.daml.ledger.api.v2.GetActiveContractsResponse + (*ActiveContract)(nil), // 3: com.daml.ledger.api.v2.ActiveContract + (*IncompleteUnassigned)(nil), // 4: com.daml.ledger.api.v2.IncompleteUnassigned + (*IncompleteAssigned)(nil), // 5: com.daml.ledger.api.v2.IncompleteAssigned + (*GetConnectedSynchronizersRequest)(nil), // 6: com.daml.ledger.api.v2.GetConnectedSynchronizersRequest + (*GetConnectedSynchronizersResponse)(nil), // 7: com.daml.ledger.api.v2.GetConnectedSynchronizersResponse + (*GetLedgerEndRequest)(nil), // 8: com.daml.ledger.api.v2.GetLedgerEndRequest + (*GetLedgerEndResponse)(nil), // 9: com.daml.ledger.api.v2.GetLedgerEndResponse + (*GetLatestPrunedOffsetsRequest)(nil), // 10: com.daml.ledger.api.v2.GetLatestPrunedOffsetsRequest + (*GetLatestPrunedOffsetsResponse)(nil), // 11: com.daml.ledger.api.v2.GetLatestPrunedOffsetsResponse + (*GetConnectedSynchronizersResponse_ConnectedSynchronizer)(nil), // 12: com.daml.ledger.api.v2.GetConnectedSynchronizersResponse.ConnectedSynchronizer + (*EventFormat)(nil), // 13: com.daml.ledger.api.v2.EventFormat + (*CreatedEvent)(nil), // 14: com.daml.ledger.api.v2.CreatedEvent + (*UnassignedEvent)(nil), // 15: com.daml.ledger.api.v2.UnassignedEvent + (*AssignedEvent)(nil), // 16: com.daml.ledger.api.v2.AssignedEvent +} +var file_com_daml_ledger_api_v2_state_service_proto_depIdxs = []int32{ + 13, // 0: com.daml.ledger.api.v2.GetActiveContractsRequest.event_format:type_name -> com.daml.ledger.api.v2.EventFormat + 3, // 1: com.daml.ledger.api.v2.GetActiveContractsResponse.active_contract:type_name -> com.daml.ledger.api.v2.ActiveContract + 4, // 2: com.daml.ledger.api.v2.GetActiveContractsResponse.incomplete_unassigned:type_name -> com.daml.ledger.api.v2.IncompleteUnassigned + 5, // 3: com.daml.ledger.api.v2.GetActiveContractsResponse.incomplete_assigned:type_name -> com.daml.ledger.api.v2.IncompleteAssigned + 14, // 4: com.daml.ledger.api.v2.ActiveContract.created_event:type_name -> com.daml.ledger.api.v2.CreatedEvent + 14, // 5: com.daml.ledger.api.v2.IncompleteUnassigned.created_event:type_name -> com.daml.ledger.api.v2.CreatedEvent + 15, // 6: com.daml.ledger.api.v2.IncompleteUnassigned.unassigned_event:type_name -> com.daml.ledger.api.v2.UnassignedEvent + 16, // 7: com.daml.ledger.api.v2.IncompleteAssigned.assigned_event:type_name -> com.daml.ledger.api.v2.AssignedEvent + 12, // 8: com.daml.ledger.api.v2.GetConnectedSynchronizersResponse.connected_synchronizers:type_name -> com.daml.ledger.api.v2.GetConnectedSynchronizersResponse.ConnectedSynchronizer + 0, // 9: com.daml.ledger.api.v2.GetConnectedSynchronizersResponse.ConnectedSynchronizer.permission:type_name -> com.daml.ledger.api.v2.ParticipantPermission + 1, // 10: com.daml.ledger.api.v2.StateService.GetActiveContracts:input_type -> com.daml.ledger.api.v2.GetActiveContractsRequest + 6, // 11: com.daml.ledger.api.v2.StateService.GetConnectedSynchronizers:input_type -> com.daml.ledger.api.v2.GetConnectedSynchronizersRequest + 8, // 12: com.daml.ledger.api.v2.StateService.GetLedgerEnd:input_type -> com.daml.ledger.api.v2.GetLedgerEndRequest + 10, // 13: com.daml.ledger.api.v2.StateService.GetLatestPrunedOffsets:input_type -> com.daml.ledger.api.v2.GetLatestPrunedOffsetsRequest + 2, // 14: com.daml.ledger.api.v2.StateService.GetActiveContracts:output_type -> com.daml.ledger.api.v2.GetActiveContractsResponse + 7, // 15: com.daml.ledger.api.v2.StateService.GetConnectedSynchronizers:output_type -> com.daml.ledger.api.v2.GetConnectedSynchronizersResponse + 9, // 16: com.daml.ledger.api.v2.StateService.GetLedgerEnd:output_type -> com.daml.ledger.api.v2.GetLedgerEndResponse + 11, // 17: com.daml.ledger.api.v2.StateService.GetLatestPrunedOffsets:output_type -> com.daml.ledger.api.v2.GetLatestPrunedOffsetsResponse + 14, // [14:18] is the sub-list for method output_type + 10, // [10:14] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_state_service_proto_init() } +func file_com_daml_ledger_api_v2_state_service_proto_init() { + if File_com_daml_ledger_api_v2_state_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_event_proto_init() + file_com_daml_ledger_api_v2_reassignment_proto_init() + file_com_daml_ledger_api_v2_transaction_filter_proto_init() + file_com_daml_ledger_api_v2_state_service_proto_msgTypes[0].OneofWrappers = []any{} + file_com_daml_ledger_api_v2_state_service_proto_msgTypes[1].OneofWrappers = []any{ + (*GetActiveContractsResponse_ActiveContract)(nil), + (*GetActiveContractsResponse_IncompleteUnassigned)(nil), + (*GetActiveContractsResponse_IncompleteAssigned)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_state_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_state_service_proto_rawDesc)), + NumEnums: 1, + NumMessages: 12, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_state_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_state_service_proto_depIdxs, + EnumInfos: file_com_daml_ledger_api_v2_state_service_proto_enumTypes, + MessageInfos: file_com_daml_ledger_api_v2_state_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_state_service_proto = out.File + file_com_daml_ledger_api_v2_state_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_state_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/state_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/state_service_grpc.pb.go new file mode 100644 index 00000000..d8bd76e2 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/state_service_grpc.pb.go @@ -0,0 +1,264 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/state_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + StateService_GetActiveContracts_FullMethodName = "/com.daml.ledger.api.v2.StateService/GetActiveContracts" + StateService_GetConnectedSynchronizers_FullMethodName = "/com.daml.ledger.api.v2.StateService/GetConnectedSynchronizers" + StateService_GetLedgerEnd_FullMethodName = "/com.daml.ledger.api.v2.StateService/GetLedgerEnd" + StateService_GetLatestPrunedOffsets_FullMethodName = "/com.daml.ledger.api.v2.StateService/GetLatestPrunedOffsets" +) + +// StateServiceClient is the client API for StateService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Allows clients to get state from the ledger. +type StateServiceClient interface { + // Returns a stream of the snapshot of the active contracts and incomplete (un)assignments at a ledger offset. + // Once the stream of GetActiveContractsResponses completes, + // the client SHOULD begin streaming updates from the update service, + // starting at the GetActiveContractsRequest.active_at_offset specified in this request. + // Clients SHOULD NOT assume that the set of active contracts they receive reflects the state at the ledger end. + GetActiveContracts(ctx context.Context, in *GetActiveContractsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetActiveContractsResponse], error) + // Get the list of connected synchronizers at the time of the query. + GetConnectedSynchronizers(ctx context.Context, in *GetConnectedSynchronizersRequest, opts ...grpc.CallOption) (*GetConnectedSynchronizersResponse, error) + // Get the current ledger end. + // Subscriptions started with the returned offset will serve events after this RPC was called. + GetLedgerEnd(ctx context.Context, in *GetLedgerEndRequest, opts ...grpc.CallOption) (*GetLedgerEndResponse, error) + // Get the latest successfully pruned ledger offsets + GetLatestPrunedOffsets(ctx context.Context, in *GetLatestPrunedOffsetsRequest, opts ...grpc.CallOption) (*GetLatestPrunedOffsetsResponse, error) +} + +type stateServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewStateServiceClient(cc grpc.ClientConnInterface) StateServiceClient { + return &stateServiceClient{cc} +} + +func (c *stateServiceClient) GetActiveContracts(ctx context.Context, in *GetActiveContractsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetActiveContractsResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &StateService_ServiceDesc.Streams[0], StateService_GetActiveContracts_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[GetActiveContractsRequest, GetActiveContractsResponse]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StateService_GetActiveContractsClient = grpc.ServerStreamingClient[GetActiveContractsResponse] + +func (c *stateServiceClient) GetConnectedSynchronizers(ctx context.Context, in *GetConnectedSynchronizersRequest, opts ...grpc.CallOption) (*GetConnectedSynchronizersResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetConnectedSynchronizersResponse) + err := c.cc.Invoke(ctx, StateService_GetConnectedSynchronizers_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateServiceClient) GetLedgerEnd(ctx context.Context, in *GetLedgerEndRequest, opts ...grpc.CallOption) (*GetLedgerEndResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetLedgerEndResponse) + err := c.cc.Invoke(ctx, StateService_GetLedgerEnd_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateServiceClient) GetLatestPrunedOffsets(ctx context.Context, in *GetLatestPrunedOffsetsRequest, opts ...grpc.CallOption) (*GetLatestPrunedOffsetsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetLatestPrunedOffsetsResponse) + err := c.cc.Invoke(ctx, StateService_GetLatestPrunedOffsets_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StateServiceServer is the server API for StateService service. +// All implementations must embed UnimplementedStateServiceServer +// for forward compatibility. +// +// Allows clients to get state from the ledger. +type StateServiceServer interface { + // Returns a stream of the snapshot of the active contracts and incomplete (un)assignments at a ledger offset. + // Once the stream of GetActiveContractsResponses completes, + // the client SHOULD begin streaming updates from the update service, + // starting at the GetActiveContractsRequest.active_at_offset specified in this request. + // Clients SHOULD NOT assume that the set of active contracts they receive reflects the state at the ledger end. + GetActiveContracts(*GetActiveContractsRequest, grpc.ServerStreamingServer[GetActiveContractsResponse]) error + // Get the list of connected synchronizers at the time of the query. + GetConnectedSynchronizers(context.Context, *GetConnectedSynchronizersRequest) (*GetConnectedSynchronizersResponse, error) + // Get the current ledger end. + // Subscriptions started with the returned offset will serve events after this RPC was called. + GetLedgerEnd(context.Context, *GetLedgerEndRequest) (*GetLedgerEndResponse, error) + // Get the latest successfully pruned ledger offsets + GetLatestPrunedOffsets(context.Context, *GetLatestPrunedOffsetsRequest) (*GetLatestPrunedOffsetsResponse, error) + mustEmbedUnimplementedStateServiceServer() +} + +// UnimplementedStateServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedStateServiceServer struct{} + +func (UnimplementedStateServiceServer) GetActiveContracts(*GetActiveContractsRequest, grpc.ServerStreamingServer[GetActiveContractsResponse]) error { + return status.Errorf(codes.Unimplemented, "method GetActiveContracts not implemented") +} +func (UnimplementedStateServiceServer) GetConnectedSynchronizers(context.Context, *GetConnectedSynchronizersRequest) (*GetConnectedSynchronizersResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetConnectedSynchronizers not implemented") +} +func (UnimplementedStateServiceServer) GetLedgerEnd(context.Context, *GetLedgerEndRequest) (*GetLedgerEndResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetLedgerEnd not implemented") +} +func (UnimplementedStateServiceServer) GetLatestPrunedOffsets(context.Context, *GetLatestPrunedOffsetsRequest) (*GetLatestPrunedOffsetsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetLatestPrunedOffsets not implemented") +} +func (UnimplementedStateServiceServer) mustEmbedUnimplementedStateServiceServer() {} +func (UnimplementedStateServiceServer) testEmbeddedByValue() {} + +// UnsafeStateServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StateServiceServer will +// result in compilation errors. +type UnsafeStateServiceServer interface { + mustEmbedUnimplementedStateServiceServer() +} + +func RegisterStateServiceServer(s grpc.ServiceRegistrar, srv StateServiceServer) { + // If the following call pancis, it indicates UnimplementedStateServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&StateService_ServiceDesc, srv) +} + +func _StateService_GetActiveContracts_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(GetActiveContractsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StateServiceServer).GetActiveContracts(m, &grpc.GenericServerStream[GetActiveContractsRequest, GetActiveContractsResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StateService_GetActiveContractsServer = grpc.ServerStreamingServer[GetActiveContractsResponse] + +func _StateService_GetConnectedSynchronizers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetConnectedSynchronizersRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateServiceServer).GetConnectedSynchronizers(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateService_GetConnectedSynchronizers_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateServiceServer).GetConnectedSynchronizers(ctx, req.(*GetConnectedSynchronizersRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StateService_GetLedgerEnd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetLedgerEndRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateServiceServer).GetLedgerEnd(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateService_GetLedgerEnd_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateServiceServer).GetLedgerEnd(ctx, req.(*GetLedgerEndRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StateService_GetLatestPrunedOffsets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetLatestPrunedOffsetsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateServiceServer).GetLatestPrunedOffsets(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StateService_GetLatestPrunedOffsets_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateServiceServer).GetLatestPrunedOffsets(ctx, req.(*GetLatestPrunedOffsetsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// StateService_ServiceDesc is the grpc.ServiceDesc for StateService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StateService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.StateService", + HandlerType: (*StateServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetConnectedSynchronizers", + Handler: _StateService_GetConnectedSynchronizers_Handler, + }, + { + MethodName: "GetLedgerEnd", + Handler: _StateService_GetLedgerEnd_Handler, + }, + { + MethodName: "GetLatestPrunedOffsets", + Handler: _StateService_GetLatestPrunedOffsets_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "GetActiveContracts", + Handler: _StateService_GetActiveContracts_Handler, + ServerStreams: true, + }, + }, + Metadata: "com/daml/ledger/api/v2/state_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/testing/time_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/testing/time_service.pb.go new file mode 100644 index 00000000..94c8c338 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/testing/time_service.pb.go @@ -0,0 +1,244 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/testing/time_service.proto + +package testing + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetTimeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTimeRequest) Reset() { + *x = GetTimeRequest{} + mi := &file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTimeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTimeRequest) ProtoMessage() {} + +func (x *GetTimeRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTimeRequest.ProtoReflect.Descriptor instead. +func (*GetTimeRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescGZIP(), []int{0} +} + +type GetTimeResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The current time according to the ledger server. + // + // Required + CurrentTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=current_time,json=currentTime,proto3" json:"current_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetTimeResponse) Reset() { + *x = GetTimeResponse{} + mi := &file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetTimeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTimeResponse) ProtoMessage() {} + +func (x *GetTimeResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTimeResponse.ProtoReflect.Descriptor instead. +func (*GetTimeResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetTimeResponse) GetCurrentTime() *timestamppb.Timestamp { + if x != nil { + return x.CurrentTime + } + return nil +} + +type SetTimeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // MUST precisely match the current time as it's known to the ledger server. + // + // Required + CurrentTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=current_time,json=currentTime,proto3" json:"current_time,omitempty"` + // The time the client wants to set on the ledger. + // MUST be a point int time after “current_time“. + // + // Required + NewTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=new_time,json=newTime,proto3" json:"new_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetTimeRequest) Reset() { + *x = SetTimeRequest{} + mi := &file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetTimeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetTimeRequest) ProtoMessage() {} + +func (x *SetTimeRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetTimeRequest.ProtoReflect.Descriptor instead. +func (*SetTimeRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescGZIP(), []int{2} +} + +func (x *SetTimeRequest) GetCurrentTime() *timestamppb.Timestamp { + if x != nil { + return x.CurrentTime + } + return nil +} + +func (x *SetTimeRequest) GetNewTime() *timestamppb.Timestamp { + if x != nil { + return x.NewTime + } + return nil +} + +var File_com_daml_ledger_api_v2_testing_time_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_testing_time_service_proto_rawDesc = "" + + "\n" + + "1com/daml/ledger/api/v2/testing/time_service.proto\x12\x1ecom.daml.ledger.api.v2.testing\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x10\n" + + "\x0eGetTimeRequest\"P\n" + + "\x0fGetTimeResponse\x12=\n" + + "\fcurrent_time\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\vcurrentTime\"\x86\x01\n" + + "\x0eSetTimeRequest\x12=\n" + + "\fcurrent_time\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\vcurrentTime\x125\n" + + "\bnew_time\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\anewTime2\xcc\x01\n" + + "\vTimeService\x12j\n" + + "\aGetTime\x12..com.daml.ledger.api.v2.testing.GetTimeRequest\x1a/.com.daml.ledger.api.v2.testing.GetTimeResponse\x12Q\n" + + "\aSetTime\x12..com.daml.ledger.api.v2.testing.SetTimeRequest\x1a\x16.google.protobuf.EmptyB\xaa\x02\n" + + "\"com.com.daml.ledger.api.v2.testingB\x10TimeServiceProtoP\x01ZRgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/testing\xa2\x02\x06CDLAVT\xaa\x02\x1eCom.Daml.Ledger.Api.V2.Testing\xca\x02\x1eCom\\Daml\\Ledger\\Api\\V2\\Testing\xe2\x02*Com\\Daml\\Ledger\\Api\\V2\\Testing\\GPBMetadata\xea\x02#Com::Daml::Ledger::Api::V2::Testingb\x06proto3" + +var ( + file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_testing_time_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_testing_time_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_testing_time_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_com_daml_ledger_api_v2_testing_time_service_proto_goTypes = []any{ + (*GetTimeRequest)(nil), // 0: com.daml.ledger.api.v2.testing.GetTimeRequest + (*GetTimeResponse)(nil), // 1: com.daml.ledger.api.v2.testing.GetTimeResponse + (*SetTimeRequest)(nil), // 2: com.daml.ledger.api.v2.testing.SetTimeRequest + (*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 4: google.protobuf.Empty +} +var file_com_daml_ledger_api_v2_testing_time_service_proto_depIdxs = []int32{ + 3, // 0: com.daml.ledger.api.v2.testing.GetTimeResponse.current_time:type_name -> google.protobuf.Timestamp + 3, // 1: com.daml.ledger.api.v2.testing.SetTimeRequest.current_time:type_name -> google.protobuf.Timestamp + 3, // 2: com.daml.ledger.api.v2.testing.SetTimeRequest.new_time:type_name -> google.protobuf.Timestamp + 0, // 3: com.daml.ledger.api.v2.testing.TimeService.GetTime:input_type -> com.daml.ledger.api.v2.testing.GetTimeRequest + 2, // 4: com.daml.ledger.api.v2.testing.TimeService.SetTime:input_type -> com.daml.ledger.api.v2.testing.SetTimeRequest + 1, // 5: com.daml.ledger.api.v2.testing.TimeService.GetTime:output_type -> com.daml.ledger.api.v2.testing.GetTimeResponse + 4, // 6: com.daml.ledger.api.v2.testing.TimeService.SetTime:output_type -> google.protobuf.Empty + 5, // [5:7] is the sub-list for method output_type + 3, // [3:5] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_testing_time_service_proto_init() } +func file_com_daml_ledger_api_v2_testing_time_service_proto_init() { + if File_com_daml_ledger_api_v2_testing_time_service_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_testing_time_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_testing_time_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_testing_time_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_testing_time_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_testing_time_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_testing_time_service_proto = out.File + file_com_daml_ledger_api_v2_testing_time_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_testing_time_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/testing/time_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/testing/time_service_grpc.pb.go new file mode 100644 index 00000000..65c0e2b5 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/testing/time_service_grpc.pb.go @@ -0,0 +1,171 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/testing/time_service.proto + +package testing + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + TimeService_GetTime_FullMethodName = "/com.daml.ledger.api.v2.testing.TimeService/GetTime" + TimeService_SetTime_FullMethodName = "/com.daml.ledger.api.v2.testing.TimeService/SetTime" +) + +// TimeServiceClient is the client API for TimeService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Optional service, exposed for testing static time scenarios. +type TimeServiceClient interface { + // Returns the current time according to the ledger server. + GetTime(ctx context.Context, in *GetTimeRequest, opts ...grpc.CallOption) (*GetTimeResponse, error) + // Allows clients to change the ledger's clock in an atomic get-and-set operation. + SetTime(ctx context.Context, in *SetTimeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) +} + +type timeServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewTimeServiceClient(cc grpc.ClientConnInterface) TimeServiceClient { + return &timeServiceClient{cc} +} + +func (c *timeServiceClient) GetTime(ctx context.Context, in *GetTimeRequest, opts ...grpc.CallOption) (*GetTimeResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetTimeResponse) + err := c.cc.Invoke(ctx, TimeService_GetTime_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *timeServiceClient) SetTime(ctx context.Context, in *SetTimeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, TimeService_SetTime_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// TimeServiceServer is the server API for TimeService service. +// All implementations must embed UnimplementedTimeServiceServer +// for forward compatibility. +// +// Optional service, exposed for testing static time scenarios. +type TimeServiceServer interface { + // Returns the current time according to the ledger server. + GetTime(context.Context, *GetTimeRequest) (*GetTimeResponse, error) + // Allows clients to change the ledger's clock in an atomic get-and-set operation. + SetTime(context.Context, *SetTimeRequest) (*emptypb.Empty, error) + mustEmbedUnimplementedTimeServiceServer() +} + +// UnimplementedTimeServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedTimeServiceServer struct{} + +func (UnimplementedTimeServiceServer) GetTime(context.Context, *GetTimeRequest) (*GetTimeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTime not implemented") +} +func (UnimplementedTimeServiceServer) SetTime(context.Context, *SetTimeRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetTime not implemented") +} +func (UnimplementedTimeServiceServer) mustEmbedUnimplementedTimeServiceServer() {} +func (UnimplementedTimeServiceServer) testEmbeddedByValue() {} + +// UnsafeTimeServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to TimeServiceServer will +// result in compilation errors. +type UnsafeTimeServiceServer interface { + mustEmbedUnimplementedTimeServiceServer() +} + +func RegisterTimeServiceServer(s grpc.ServiceRegistrar, srv TimeServiceServer) { + // If the following call pancis, it indicates UnimplementedTimeServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&TimeService_ServiceDesc, srv) +} + +func _TimeService_GetTime_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTimeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TimeServiceServer).GetTime(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TimeService_GetTime_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TimeServiceServer).GetTime(ctx, req.(*GetTimeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TimeService_SetTime_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SetTimeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TimeServiceServer).SetTime(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TimeService_SetTime_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TimeServiceServer).SetTime(ctx, req.(*SetTimeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// TimeService_ServiceDesc is the grpc.ServiceDesc for TimeService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var TimeService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.testing.TimeService", + HandlerType: (*TimeServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetTime", + Handler: _TimeService_GetTime_Handler, + }, + { + MethodName: "SetTime", + Handler: _TimeService_SetTime_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/testing/time_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/topology_transaction.pb.go b/chain/canton/types/com/daml/ledger/api/v2/topology_transaction.pb.go new file mode 100644 index 00000000..90717e89 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/topology_transaction.pb.go @@ -0,0 +1,610 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/topology_transaction.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type TopologyTransaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Assigned by the server. Useful for correlating logs. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // The absolute offset. The details of this field are described in “community/ledger-api/README.md“. + // It is a valid absolute offset (positive integer). + // + // Required + Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` + // A valid synchronizer id. + // Identifies the synchronizer that synchronized the topology transaction. + // + // Required + SynchronizerId string `protobuf:"bytes,3,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // The time at which the changes in the topology transaction become effective. There is a small delay between a + // topology transaction being sequenced and the changes it contains becoming effective. Topology transactions appear + // in order relative to a synchronizer based on their effective time rather than their sequencing time. + // + // Required + RecordTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=record_time,json=recordTime,proto3" json:"record_time,omitempty"` + // A non-empty list of topology events. + // + // Required: must be non-empty + Events []*TopologyEvent `protobuf:"bytes,5,rep,name=events,proto3" json:"events,omitempty"` + // Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + TraceContext *TraceContext `protobuf:"bytes,6,opt,name=trace_context,json=traceContext,proto3" json:"trace_context,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyTransaction) Reset() { + *x = TopologyTransaction{} + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyTransaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyTransaction) ProtoMessage() {} + +func (x *TopologyTransaction) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyTransaction.ProtoReflect.Descriptor instead. +func (*TopologyTransaction) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescGZIP(), []int{0} +} + +func (x *TopologyTransaction) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *TopologyTransaction) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *TopologyTransaction) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *TopologyTransaction) GetRecordTime() *timestamppb.Timestamp { + if x != nil { + return x.RecordTime + } + return nil +} + +func (x *TopologyTransaction) GetEvents() []*TopologyEvent { + if x != nil { + return x.Events + } + return nil +} + +func (x *TopologyTransaction) GetTraceContext() *TraceContext { + if x != nil { + return x.TraceContext + } + return nil +} + +type TopologyEvent struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to Event: + // + // *TopologyEvent_ParticipantAuthorizationChanged + // *TopologyEvent_ParticipantAuthorizationRevoked + // *TopologyEvent_ParticipantAuthorizationAdded + // *TopologyEvent_ParticipantAuthorizationOnboarding + Event isTopologyEvent_Event `protobuf_oneof:"event"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyEvent) Reset() { + *x = TopologyEvent{} + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyEvent) ProtoMessage() {} + +func (x *TopologyEvent) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyEvent.ProtoReflect.Descriptor instead. +func (*TopologyEvent) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescGZIP(), []int{1} +} + +func (x *TopologyEvent) GetEvent() isTopologyEvent_Event { + if x != nil { + return x.Event + } + return nil +} + +func (x *TopologyEvent) GetParticipantAuthorizationChanged() *ParticipantAuthorizationChanged { + if x != nil { + if x, ok := x.Event.(*TopologyEvent_ParticipantAuthorizationChanged); ok { + return x.ParticipantAuthorizationChanged + } + } + return nil +} + +func (x *TopologyEvent) GetParticipantAuthorizationRevoked() *ParticipantAuthorizationRevoked { + if x != nil { + if x, ok := x.Event.(*TopologyEvent_ParticipantAuthorizationRevoked); ok { + return x.ParticipantAuthorizationRevoked + } + } + return nil +} + +func (x *TopologyEvent) GetParticipantAuthorizationAdded() *ParticipantAuthorizationAdded { + if x != nil { + if x, ok := x.Event.(*TopologyEvent_ParticipantAuthorizationAdded); ok { + return x.ParticipantAuthorizationAdded + } + } + return nil +} + +func (x *TopologyEvent) GetParticipantAuthorizationOnboarding() *ParticipantAuthorizationOnboarding { + if x != nil { + if x, ok := x.Event.(*TopologyEvent_ParticipantAuthorizationOnboarding); ok { + return x.ParticipantAuthorizationOnboarding + } + } + return nil +} + +type isTopologyEvent_Event interface { + isTopologyEvent_Event() +} + +type TopologyEvent_ParticipantAuthorizationChanged struct { + ParticipantAuthorizationChanged *ParticipantAuthorizationChanged `protobuf:"bytes,1,opt,name=participant_authorization_changed,json=participantAuthorizationChanged,proto3,oneof"` +} + +type TopologyEvent_ParticipantAuthorizationRevoked struct { + ParticipantAuthorizationRevoked *ParticipantAuthorizationRevoked `protobuf:"bytes,2,opt,name=participant_authorization_revoked,json=participantAuthorizationRevoked,proto3,oneof"` +} + +type TopologyEvent_ParticipantAuthorizationAdded struct { + ParticipantAuthorizationAdded *ParticipantAuthorizationAdded `protobuf:"bytes,3,opt,name=participant_authorization_added,json=participantAuthorizationAdded,proto3,oneof"` +} + +type TopologyEvent_ParticipantAuthorizationOnboarding struct { + ParticipantAuthorizationOnboarding *ParticipantAuthorizationOnboarding `protobuf:"bytes,4,opt,name=participant_authorization_onboarding,json=participantAuthorizationOnboarding,proto3,oneof"` +} + +func (*TopologyEvent_ParticipantAuthorizationChanged) isTopologyEvent_Event() {} + +func (*TopologyEvent_ParticipantAuthorizationRevoked) isTopologyEvent_Event() {} + +func (*TopologyEvent_ParticipantAuthorizationAdded) isTopologyEvent_Event() {} + +func (*TopologyEvent_ParticipantAuthorizationOnboarding) isTopologyEvent_Event() {} + +type ParticipantAuthorizationAdded struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + PartyId string `protobuf:"bytes,1,opt,name=party_id,json=partyId,proto3" json:"party_id,omitempty"` + // Required + ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + // Required + ParticipantPermission ParticipantPermission `protobuf:"varint,3,opt,name=participant_permission,json=participantPermission,proto3,enum=com.daml.ledger.api.v2.ParticipantPermission" json:"participant_permission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParticipantAuthorizationAdded) Reset() { + *x = ParticipantAuthorizationAdded{} + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParticipantAuthorizationAdded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParticipantAuthorizationAdded) ProtoMessage() {} + +func (x *ParticipantAuthorizationAdded) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParticipantAuthorizationAdded.ProtoReflect.Descriptor instead. +func (*ParticipantAuthorizationAdded) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescGZIP(), []int{2} +} + +func (x *ParticipantAuthorizationAdded) GetPartyId() string { + if x != nil { + return x.PartyId + } + return "" +} + +func (x *ParticipantAuthorizationAdded) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +func (x *ParticipantAuthorizationAdded) GetParticipantPermission() ParticipantPermission { + if x != nil { + return x.ParticipantPermission + } + return ParticipantPermission_PARTICIPANT_PERMISSION_UNSPECIFIED +} + +type ParticipantAuthorizationChanged struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + PartyId string `protobuf:"bytes,1,opt,name=party_id,json=partyId,proto3" json:"party_id,omitempty"` + // Required + ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + // Required + ParticipantPermission ParticipantPermission `protobuf:"varint,3,opt,name=participant_permission,json=participantPermission,proto3,enum=com.daml.ledger.api.v2.ParticipantPermission" json:"participant_permission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParticipantAuthorizationChanged) Reset() { + *x = ParticipantAuthorizationChanged{} + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParticipantAuthorizationChanged) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParticipantAuthorizationChanged) ProtoMessage() {} + +func (x *ParticipantAuthorizationChanged) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParticipantAuthorizationChanged.ProtoReflect.Descriptor instead. +func (*ParticipantAuthorizationChanged) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescGZIP(), []int{3} +} + +func (x *ParticipantAuthorizationChanged) GetPartyId() string { + if x != nil { + return x.PartyId + } + return "" +} + +func (x *ParticipantAuthorizationChanged) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +func (x *ParticipantAuthorizationChanged) GetParticipantPermission() ParticipantPermission { + if x != nil { + return x.ParticipantPermission + } + return ParticipantPermission_PARTICIPANT_PERMISSION_UNSPECIFIED +} + +type ParticipantAuthorizationRevoked struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + PartyId string `protobuf:"bytes,1,opt,name=party_id,json=partyId,proto3" json:"party_id,omitempty"` + // Required + ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParticipantAuthorizationRevoked) Reset() { + *x = ParticipantAuthorizationRevoked{} + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParticipantAuthorizationRevoked) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParticipantAuthorizationRevoked) ProtoMessage() {} + +func (x *ParticipantAuthorizationRevoked) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParticipantAuthorizationRevoked.ProtoReflect.Descriptor instead. +func (*ParticipantAuthorizationRevoked) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescGZIP(), []int{4} +} + +func (x *ParticipantAuthorizationRevoked) GetPartyId() string { + if x != nil { + return x.PartyId + } + return "" +} + +func (x *ParticipantAuthorizationRevoked) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +type ParticipantAuthorizationOnboarding struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + PartyId string `protobuf:"bytes,1,opt,name=party_id,json=partyId,proto3" json:"party_id,omitempty"` + // Required + ParticipantId string `protobuf:"bytes,2,opt,name=participant_id,json=participantId,proto3" json:"participant_id,omitempty"` + // Required + ParticipantPermission ParticipantPermission `protobuf:"varint,3,opt,name=participant_permission,json=participantPermission,proto3,enum=com.daml.ledger.api.v2.ParticipantPermission" json:"participant_permission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParticipantAuthorizationOnboarding) Reset() { + *x = ParticipantAuthorizationOnboarding{} + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParticipantAuthorizationOnboarding) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParticipantAuthorizationOnboarding) ProtoMessage() {} + +func (x *ParticipantAuthorizationOnboarding) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParticipantAuthorizationOnboarding.ProtoReflect.Descriptor instead. +func (*ParticipantAuthorizationOnboarding) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescGZIP(), []int{5} +} + +func (x *ParticipantAuthorizationOnboarding) GetPartyId() string { + if x != nil { + return x.PartyId + } + return "" +} + +func (x *ParticipantAuthorizationOnboarding) GetParticipantId() string { + if x != nil { + return x.ParticipantId + } + return "" +} + +func (x *ParticipantAuthorizationOnboarding) GetParticipantPermission() ParticipantPermission { + if x != nil { + return x.ParticipantPermission + } + return ParticipantPermission_PARTICIPANT_PERMISSION_UNSPECIFIED +} + +var File_com_daml_ledger_api_v2_topology_transaction_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_topology_transaction_proto_rawDesc = "" + + "\n" + + "1com/daml/ledger/api/v2/topology_transaction.proto\x12\x16com.daml.ledger.api.v2\x1a*com/daml/ledger/api/v2/state_service.proto\x1a*com/daml/ledger/api/v2/trace_context.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xba\x02\n" + + "\x13TopologyTransaction\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12\x16\n" + + "\x06offset\x18\x02 \x01(\x03R\x06offset\x12'\n" + + "\x0fsynchronizer_id\x18\x03 \x01(\tR\x0esynchronizerId\x12;\n" + + "\vrecord_time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "recordTime\x12=\n" + + "\x06events\x18\x05 \x03(\v2%.com.daml.ledger.api.v2.TopologyEventR\x06events\x12I\n" + + "\rtrace_context\x18\x06 \x01(\v2$.com.daml.ledger.api.v2.TraceContextR\ftraceContext\"\xba\x04\n" + + "\rTopologyEvent\x12\x85\x01\n" + + "!participant_authorization_changed\x18\x01 \x01(\v27.com.daml.ledger.api.v2.ParticipantAuthorizationChangedH\x00R\x1fparticipantAuthorizationChanged\x12\x85\x01\n" + + "!participant_authorization_revoked\x18\x02 \x01(\v27.com.daml.ledger.api.v2.ParticipantAuthorizationRevokedH\x00R\x1fparticipantAuthorizationRevoked\x12\x7f\n" + + "\x1fparticipant_authorization_added\x18\x03 \x01(\v25.com.daml.ledger.api.v2.ParticipantAuthorizationAddedH\x00R\x1dparticipantAuthorizationAdded\x12\x8e\x01\n" + + "$participant_authorization_onboarding\x18\x04 \x01(\v2:.com.daml.ledger.api.v2.ParticipantAuthorizationOnboardingH\x00R\"participantAuthorizationOnboardingB\a\n" + + "\x05event\"\xc7\x01\n" + + "\x1dParticipantAuthorizationAdded\x12\x19\n" + + "\bparty_id\x18\x01 \x01(\tR\apartyId\x12%\n" + + "\x0eparticipant_id\x18\x02 \x01(\tR\rparticipantId\x12d\n" + + "\x16participant_permission\x18\x03 \x01(\x0e2-.com.daml.ledger.api.v2.ParticipantPermissionR\x15participantPermission\"\xc9\x01\n" + + "\x1fParticipantAuthorizationChanged\x12\x19\n" + + "\bparty_id\x18\x01 \x01(\tR\apartyId\x12%\n" + + "\x0eparticipant_id\x18\x02 \x01(\tR\rparticipantId\x12d\n" + + "\x16participant_permission\x18\x03 \x01(\x0e2-.com.daml.ledger.api.v2.ParticipantPermissionR\x15participantPermission\"c\n" + + "\x1fParticipantAuthorizationRevoked\x12\x19\n" + + "\bparty_id\x18\x01 \x01(\tR\apartyId\x12%\n" + + "\x0eparticipant_id\x18\x02 \x01(\tR\rparticipantId\"\xcc\x01\n" + + "\"ParticipantAuthorizationOnboarding\x12\x19\n" + + "\bparty_id\x18\x01 \x01(\tR\apartyId\x12%\n" + + "\x0eparticipant_id\x18\x02 \x01(\tR\rparticipantId\x12d\n" + + "\x16participant_permission\x18\x03 \x01(\x0e2-.com.daml.ledger.api.v2.ParticipantPermissionR\x15participantPermissionB\x85\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x18TopologyTransactionProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_topology_transaction_proto_rawDesc), len(file_com_daml_ledger_api_v2_topology_transaction_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_topology_transaction_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_com_daml_ledger_api_v2_topology_transaction_proto_goTypes = []any{ + (*TopologyTransaction)(nil), // 0: com.daml.ledger.api.v2.TopologyTransaction + (*TopologyEvent)(nil), // 1: com.daml.ledger.api.v2.TopologyEvent + (*ParticipantAuthorizationAdded)(nil), // 2: com.daml.ledger.api.v2.ParticipantAuthorizationAdded + (*ParticipantAuthorizationChanged)(nil), // 3: com.daml.ledger.api.v2.ParticipantAuthorizationChanged + (*ParticipantAuthorizationRevoked)(nil), // 4: com.daml.ledger.api.v2.ParticipantAuthorizationRevoked + (*ParticipantAuthorizationOnboarding)(nil), // 5: com.daml.ledger.api.v2.ParticipantAuthorizationOnboarding + (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp + (*TraceContext)(nil), // 7: com.daml.ledger.api.v2.TraceContext + (ParticipantPermission)(0), // 8: com.daml.ledger.api.v2.ParticipantPermission +} +var file_com_daml_ledger_api_v2_topology_transaction_proto_depIdxs = []int32{ + 6, // 0: com.daml.ledger.api.v2.TopologyTransaction.record_time:type_name -> google.protobuf.Timestamp + 1, // 1: com.daml.ledger.api.v2.TopologyTransaction.events:type_name -> com.daml.ledger.api.v2.TopologyEvent + 7, // 2: com.daml.ledger.api.v2.TopologyTransaction.trace_context:type_name -> com.daml.ledger.api.v2.TraceContext + 3, // 3: com.daml.ledger.api.v2.TopologyEvent.participant_authorization_changed:type_name -> com.daml.ledger.api.v2.ParticipantAuthorizationChanged + 4, // 4: com.daml.ledger.api.v2.TopologyEvent.participant_authorization_revoked:type_name -> com.daml.ledger.api.v2.ParticipantAuthorizationRevoked + 2, // 5: com.daml.ledger.api.v2.TopologyEvent.participant_authorization_added:type_name -> com.daml.ledger.api.v2.ParticipantAuthorizationAdded + 5, // 6: com.daml.ledger.api.v2.TopologyEvent.participant_authorization_onboarding:type_name -> com.daml.ledger.api.v2.ParticipantAuthorizationOnboarding + 8, // 7: com.daml.ledger.api.v2.ParticipantAuthorizationAdded.participant_permission:type_name -> com.daml.ledger.api.v2.ParticipantPermission + 8, // 8: com.daml.ledger.api.v2.ParticipantAuthorizationChanged.participant_permission:type_name -> com.daml.ledger.api.v2.ParticipantPermission + 8, // 9: com.daml.ledger.api.v2.ParticipantAuthorizationOnboarding.participant_permission:type_name -> com.daml.ledger.api.v2.ParticipantPermission + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_topology_transaction_proto_init() } +func file_com_daml_ledger_api_v2_topology_transaction_proto_init() { + if File_com_daml_ledger_api_v2_topology_transaction_proto != nil { + return + } + file_com_daml_ledger_api_v2_state_service_proto_init() + file_com_daml_ledger_api_v2_trace_context_proto_init() + file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes[1].OneofWrappers = []any{ + (*TopologyEvent_ParticipantAuthorizationChanged)(nil), + (*TopologyEvent_ParticipantAuthorizationRevoked)(nil), + (*TopologyEvent_ParticipantAuthorizationAdded)(nil), + (*TopologyEvent_ParticipantAuthorizationOnboarding)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_topology_transaction_proto_rawDesc), len(file_com_daml_ledger_api_v2_topology_transaction_proto_rawDesc)), + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_topology_transaction_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_topology_transaction_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_topology_transaction_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_topology_transaction_proto = out.File + file_com_daml_ledger_api_v2_topology_transaction_proto_goTypes = nil + file_com_daml_ledger_api_v2_topology_transaction_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/trace_context.pb.go b/chain/canton/types/com/daml/ledger/api/v2/trace_context.pb.go new file mode 100644 index 00000000..951c1d9f --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/trace_context.pb.go @@ -0,0 +1,144 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/trace_context.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type TraceContext struct { + state protoimpl.MessageState `protogen:"open.v1"` + // https://www.w3.org/TR/trace-context/ + // + // Optional + Traceparent *string `protobuf:"bytes,1,opt,name=traceparent,proto3,oneof" json:"traceparent,omitempty"` + // Optional + Tracestate *string `protobuf:"bytes,2,opt,name=tracestate,proto3,oneof" json:"tracestate,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TraceContext) Reset() { + *x = TraceContext{} + mi := &file_com_daml_ledger_api_v2_trace_context_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TraceContext) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TraceContext) ProtoMessage() {} + +func (x *TraceContext) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_trace_context_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TraceContext.ProtoReflect.Descriptor instead. +func (*TraceContext) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_trace_context_proto_rawDescGZIP(), []int{0} +} + +func (x *TraceContext) GetTraceparent() string { + if x != nil && x.Traceparent != nil { + return *x.Traceparent + } + return "" +} + +func (x *TraceContext) GetTracestate() string { + if x != nil && x.Tracestate != nil { + return *x.Tracestate + } + return "" +} + +var File_com_daml_ledger_api_v2_trace_context_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_trace_context_proto_rawDesc = "" + + "\n" + + "*com/daml/ledger/api/v2/trace_context.proto\x12\x16com.daml.ledger.api.v2\"y\n" + + "\fTraceContext\x12%\n" + + "\vtraceparent\x18\x01 \x01(\tH\x00R\vtraceparent\x88\x01\x01\x12#\n" + + "\n" + + "tracestate\x18\x02 \x01(\tH\x01R\n" + + "tracestate\x88\x01\x01B\x0e\n" + + "\f_traceparentB\r\n" + + "\v_tracestateB\xfe\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\x11TraceContextProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_trace_context_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_trace_context_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_trace_context_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_trace_context_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_trace_context_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_trace_context_proto_rawDesc), len(file_com_daml_ledger_api_v2_trace_context_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_trace_context_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_trace_context_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_com_daml_ledger_api_v2_trace_context_proto_goTypes = []any{ + (*TraceContext)(nil), // 0: com.daml.ledger.api.v2.TraceContext +} +var file_com_daml_ledger_api_v2_trace_context_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_trace_context_proto_init() } +func file_com_daml_ledger_api_v2_trace_context_proto_init() { + if File_com_daml_ledger_api_v2_trace_context_proto != nil { + return + } + file_com_daml_ledger_api_v2_trace_context_proto_msgTypes[0].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_trace_context_proto_rawDesc), len(file_com_daml_ledger_api_v2_trace_context_proto_rawDesc)), + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_trace_context_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_trace_context_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_trace_context_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_trace_context_proto = out.File + file_com_daml_ledger_api_v2_trace_context_proto_goTypes = nil + file_com_daml_ledger_api_v2_trace_context_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/transaction.pb.go b/chain/canton/types/com/daml/ledger/api/v2/transaction.pb.go new file mode 100644 index 00000000..53a54587 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/transaction.pb.go @@ -0,0 +1,273 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/transaction.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Filtered view of an on-ledger transaction's create and archive events. +type Transaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Assigned by the server. Useful for correlating logs. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // The ID of the command which resulted in this transaction. Missing for everyone except the submitting party. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + // The workflow ID used in command submission. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Optional + WorkflowId string `protobuf:"bytes,3,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"` + // Ledger effective time. + // + // Required + EffectiveAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=effective_at,json=effectiveAt,proto3" json:"effective_at,omitempty"` + // The collection of events. + // Contains: + // + // - “CreatedEvent“ or “ArchivedEvent“ in case of ACS_DELTA transaction shape + // - “CreatedEvent“ or “ExercisedEvent“ in case of LEDGER_EFFECTS transaction shape + // + // Required: must be non-empty + Events []*Event `protobuf:"bytes,5,rep,name=events,proto3" json:"events,omitempty"` + // The absolute offset. The details of this field are described in “community/ledger-api/README.md“. + // It is a valid absolute offset (positive integer). + // + // Required + Offset int64 `protobuf:"varint,6,opt,name=offset,proto3" json:"offset,omitempty"` + // A valid synchronizer id. + // Identifies the synchronizer that synchronized the transaction. + // + // Required + SynchronizerId string `protobuf:"bytes,7,opt,name=synchronizer_id,json=synchronizerId,proto3" json:"synchronizer_id,omitempty"` + // Ledger API trace context + // + // The trace context transported in this message corresponds to the trace context supplied + // by the client application in a HTTP2 header of the original command submission. + // We typically use a header to transfer this type of information. Here we use message + // body, because it is used in gRPC streams which do not support per message headers. + // This field will be populated with the trace context contained in the original submission. + // If that was not provided, a unique ledger-api-server generated trace context will be used + // instead. + // + // Optional + TraceContext *TraceContext `protobuf:"bytes,8,opt,name=trace_context,json=traceContext,proto3" json:"trace_context,omitempty"` + // The time at which the transaction was recorded. The record time refers to the synchronizer + // which synchronized the transaction. + // + // Required + RecordTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=record_time,json=recordTime,proto3" json:"record_time,omitempty"` + // For transaction externally signed, contains the external transaction hash + // signed by the external party. Can be used to correlate an external submission with a committed transaction. + // + // Optional: can be empty + ExternalTransactionHash []byte `protobuf:"bytes,10,opt,name=external_transaction_hash,json=externalTransactionHash,proto3,oneof" json:"external_transaction_hash,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Transaction) Reset() { + *x = Transaction{} + mi := &file_com_daml_ledger_api_v2_transaction_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Transaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Transaction) ProtoMessage() {} + +func (x *Transaction) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Transaction.ProtoReflect.Descriptor instead. +func (*Transaction) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_proto_rawDescGZIP(), []int{0} +} + +func (x *Transaction) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *Transaction) GetCommandId() string { + if x != nil { + return x.CommandId + } + return "" +} + +func (x *Transaction) GetWorkflowId() string { + if x != nil { + return x.WorkflowId + } + return "" +} + +func (x *Transaction) GetEffectiveAt() *timestamppb.Timestamp { + if x != nil { + return x.EffectiveAt + } + return nil +} + +func (x *Transaction) GetEvents() []*Event { + if x != nil { + return x.Events + } + return nil +} + +func (x *Transaction) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *Transaction) GetSynchronizerId() string { + if x != nil { + return x.SynchronizerId + } + return "" +} + +func (x *Transaction) GetTraceContext() *TraceContext { + if x != nil { + return x.TraceContext + } + return nil +} + +func (x *Transaction) GetRecordTime() *timestamppb.Timestamp { + if x != nil { + return x.RecordTime + } + return nil +} + +func (x *Transaction) GetExternalTransactionHash() []byte { + if x != nil { + return x.ExternalTransactionHash + } + return nil +} + +var File_com_daml_ledger_api_v2_transaction_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_transaction_proto_rawDesc = "" + + "\n" + + "(com/daml/ledger/api/v2/transaction.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/event.proto\x1a*com/daml/ledger/api/v2/trace_context.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x88\x04\n" + + "\vTransaction\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12\x1d\n" + + "\n" + + "command_id\x18\x02 \x01(\tR\tcommandId\x12\x1f\n" + + "\vworkflow_id\x18\x03 \x01(\tR\n" + + "workflowId\x12=\n" + + "\feffective_at\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\veffectiveAt\x125\n" + + "\x06events\x18\x05 \x03(\v2\x1d.com.daml.ledger.api.v2.EventR\x06events\x12\x16\n" + + "\x06offset\x18\x06 \x01(\x03R\x06offset\x12'\n" + + "\x0fsynchronizer_id\x18\a \x01(\tR\x0esynchronizerId\x12I\n" + + "\rtrace_context\x18\b \x01(\v2$.com.daml.ledger.api.v2.TraceContextR\ftraceContext\x12;\n" + + "\vrecord_time\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "recordTime\x12?\n" + + "\x19external_transaction_hash\x18\n" + + " \x01(\fH\x00R\x17externalTransactionHash\x88\x01\x01B\x1c\n" + + "\x1a_external_transaction_hashB\xfd\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\x10TransactionProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_transaction_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_transaction_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_transaction_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_transaction_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_transaction_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_transaction_proto_rawDesc), len(file_com_daml_ledger_api_v2_transaction_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_transaction_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_transaction_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_com_daml_ledger_api_v2_transaction_proto_goTypes = []any{ + (*Transaction)(nil), // 0: com.daml.ledger.api.v2.Transaction + (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp + (*Event)(nil), // 2: com.daml.ledger.api.v2.Event + (*TraceContext)(nil), // 3: com.daml.ledger.api.v2.TraceContext +} +var file_com_daml_ledger_api_v2_transaction_proto_depIdxs = []int32{ + 1, // 0: com.daml.ledger.api.v2.Transaction.effective_at:type_name -> google.protobuf.Timestamp + 2, // 1: com.daml.ledger.api.v2.Transaction.events:type_name -> com.daml.ledger.api.v2.Event + 3, // 2: com.daml.ledger.api.v2.Transaction.trace_context:type_name -> com.daml.ledger.api.v2.TraceContext + 1, // 3: com.daml.ledger.api.v2.Transaction.record_time:type_name -> google.protobuf.Timestamp + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_transaction_proto_init() } +func file_com_daml_ledger_api_v2_transaction_proto_init() { + if File_com_daml_ledger_api_v2_transaction_proto != nil { + return + } + file_com_daml_ledger_api_v2_event_proto_init() + file_com_daml_ledger_api_v2_trace_context_proto_init() + file_com_daml_ledger_api_v2_transaction_proto_msgTypes[0].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_transaction_proto_rawDesc), len(file_com_daml_ledger_api_v2_transaction_proto_rawDesc)), + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_transaction_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_transaction_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_transaction_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_transaction_proto = out.File + file_com_daml_ledger_api_v2_transaction_proto_goTypes = nil + file_com_daml_ledger_api_v2_transaction_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/transaction_filter.pb.go b/chain/canton/types/com/daml/ledger/api/v2/transaction_filter.pb.go new file mode 100644 index 00000000..6c49790c --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/transaction_filter.pb.go @@ -0,0 +1,889 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/transaction_filter.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Event shape for Transactions. +// Shapes are exclusive and only one of them can be defined in queries. +type TransactionShape int32 + +const ( + // Following official proto3 convention, not intended for actual use. + TransactionShape_TRANSACTION_SHAPE_UNSPECIFIED TransactionShape = 0 + // Transaction shape that is sufficient to maintain an accurate ACS view. + // The field witness_parties in events are populated as stakeholders, transaction filter will apply accordingly. + // This translates to create and archive events. + TransactionShape_TRANSACTION_SHAPE_ACS_DELTA TransactionShape = 1 + // Transaction shape that allows maintaining an ACS and also conveys detailed information about + // all exercises. + // The field witness_parties in events are populated as cumulative informees, transaction filter will apply accordingly. + // This translates to create, consuming exercise and non-consuming exercise. + TransactionShape_TRANSACTION_SHAPE_LEDGER_EFFECTS TransactionShape = 2 +) + +// Enum value maps for TransactionShape. +var ( + TransactionShape_name = map[int32]string{ + 0: "TRANSACTION_SHAPE_UNSPECIFIED", + 1: "TRANSACTION_SHAPE_ACS_DELTA", + 2: "TRANSACTION_SHAPE_LEDGER_EFFECTS", + } + TransactionShape_value = map[string]int32{ + "TRANSACTION_SHAPE_UNSPECIFIED": 0, + "TRANSACTION_SHAPE_ACS_DELTA": 1, + "TRANSACTION_SHAPE_LEDGER_EFFECTS": 2, + } +) + +func (x TransactionShape) Enum() *TransactionShape { + p := new(TransactionShape) + *p = x + return p +} + +func (x TransactionShape) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TransactionShape) Descriptor() protoreflect.EnumDescriptor { + return file_com_daml_ledger_api_v2_transaction_filter_proto_enumTypes[0].Descriptor() +} + +func (TransactionShape) Type() protoreflect.EnumType { + return &file_com_daml_ledger_api_v2_transaction_filter_proto_enumTypes[0] +} + +func (x TransactionShape) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TransactionShape.Descriptor instead. +func (TransactionShape) EnumDescriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{0} +} + +// The union of a set of template filters, interface filters, or a wildcard. +type Filters struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Every filter in the cumulative list expands the scope of the resulting stream. Each interface, + // template or wildcard filter means additional events that will match the query. + // The impact of include_interface_view and include_created_event_blob fields in the filters will + // also be accumulated. + // A template or an interface SHOULD NOT appear twice in the accumulative field. + // A wildcard filter SHOULD NOT be defined more than once in the accumulative field. + // If no “CumulativeFilter“ defined, the default of a single “WildcardFilter“ with + // include_created_event_blob unset is used. + // + // Optional: can be empty + Cumulative []*CumulativeFilter `protobuf:"bytes,1,rep,name=cumulative,proto3" json:"cumulative,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Filters) Reset() { + *x = Filters{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Filters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Filters) ProtoMessage() {} + +func (x *Filters) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Filters.ProtoReflect.Descriptor instead. +func (*Filters) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{0} +} + +func (x *Filters) GetCumulative() []*CumulativeFilter { + if x != nil { + return x.Cumulative + } + return nil +} + +// A filter that matches all contracts that are either an instance of one of +// the “template_filters“ or that match one of the “interface_filters“. +type CumulativeFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + // + // Types that are valid to be assigned to IdentifierFilter: + // + // *CumulativeFilter_WildcardFilter + // *CumulativeFilter_InterfaceFilter + // *CumulativeFilter_TemplateFilter + IdentifierFilter isCumulativeFilter_IdentifierFilter `protobuf_oneof:"identifier_filter"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CumulativeFilter) Reset() { + *x = CumulativeFilter{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CumulativeFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CumulativeFilter) ProtoMessage() {} + +func (x *CumulativeFilter) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CumulativeFilter.ProtoReflect.Descriptor instead. +func (*CumulativeFilter) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{1} +} + +func (x *CumulativeFilter) GetIdentifierFilter() isCumulativeFilter_IdentifierFilter { + if x != nil { + return x.IdentifierFilter + } + return nil +} + +func (x *CumulativeFilter) GetWildcardFilter() *WildcardFilter { + if x != nil { + if x, ok := x.IdentifierFilter.(*CumulativeFilter_WildcardFilter); ok { + return x.WildcardFilter + } + } + return nil +} + +func (x *CumulativeFilter) GetInterfaceFilter() *InterfaceFilter { + if x != nil { + if x, ok := x.IdentifierFilter.(*CumulativeFilter_InterfaceFilter); ok { + return x.InterfaceFilter + } + } + return nil +} + +func (x *CumulativeFilter) GetTemplateFilter() *TemplateFilter { + if x != nil { + if x, ok := x.IdentifierFilter.(*CumulativeFilter_TemplateFilter); ok { + return x.TemplateFilter + } + } + return nil +} + +type isCumulativeFilter_IdentifierFilter interface { + isCumulativeFilter_IdentifierFilter() +} + +type CumulativeFilter_WildcardFilter struct { + // A wildcard filter that matches all templates + // + // Optional + WildcardFilter *WildcardFilter `protobuf:"bytes,1,opt,name=wildcard_filter,json=wildcardFilter,proto3,oneof"` +} + +type CumulativeFilter_InterfaceFilter struct { + // Include an “InterfaceView“ for every “InterfaceFilter“ matching a contract. + // The “InterfaceFilter“ instances MUST each use a unique “interface_id“. + // + // Optional + InterfaceFilter *InterfaceFilter `protobuf:"bytes,2,opt,name=interface_filter,json=interfaceFilter,proto3,oneof"` +} + +type CumulativeFilter_TemplateFilter struct { + // A template for which the data will be included in the + // “create_arguments“ of a matching “CreatedEvent“. + // If a contract is simultaneously selected by a template filter and one or more interface filters, + // the corresponding “include_created_event_blob“ are consolidated using an OR operation. + // + // Optional + TemplateFilter *TemplateFilter `protobuf:"bytes,3,opt,name=template_filter,json=templateFilter,proto3,oneof"` +} + +func (*CumulativeFilter_WildcardFilter) isCumulativeFilter_IdentifierFilter() {} + +func (*CumulativeFilter_InterfaceFilter) isCumulativeFilter_IdentifierFilter() {} + +func (*CumulativeFilter_TemplateFilter) isCumulativeFilter_IdentifierFilter() {} + +// This filter matches all templates. +type WildcardFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Whether to include a “created_event_blob“ in the returned “CreatedEvent“. + // Use this to access the contract create event payload in your API client + // for submitting it as a disclosed contract with future commands. + // + // Optional + IncludeCreatedEventBlob bool `protobuf:"varint,1,opt,name=include_created_event_blob,json=includeCreatedEventBlob,proto3" json:"include_created_event_blob,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WildcardFilter) Reset() { + *x = WildcardFilter{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WildcardFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WildcardFilter) ProtoMessage() {} + +func (x *WildcardFilter) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WildcardFilter.ProtoReflect.Descriptor instead. +func (*WildcardFilter) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{2} +} + +func (x *WildcardFilter) GetIncludeCreatedEventBlob() bool { + if x != nil { + return x.IncludeCreatedEventBlob + } + return false +} + +// This filter matches contracts that implement a specific interface. +type InterfaceFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The interface that a matching contract must implement. + // The “interface_id“ needs to be valid: corresponding interface should be defined in + // one of the available packages at the time of the query. + // Both package-name and package-id reference formats for the identifier are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + InterfaceId *Identifier `protobuf:"bytes,1,opt,name=interface_id,json=interfaceId,proto3" json:"interface_id,omitempty"` + // Whether to include the interface view on the contract in the returned “CreatedEvent“. + // Use this to access contract data in a uniform manner in your API client. + // + // Optional + IncludeInterfaceView bool `protobuf:"varint,2,opt,name=include_interface_view,json=includeInterfaceView,proto3" json:"include_interface_view,omitempty"` + // Whether to include a “created_event_blob“ in the returned “CreatedEvent“. + // Use this to access the contract create event payload in your API client + // for submitting it as a disclosed contract with future commands. + // + // Optional + IncludeCreatedEventBlob bool `protobuf:"varint,3,opt,name=include_created_event_blob,json=includeCreatedEventBlob,proto3" json:"include_created_event_blob,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InterfaceFilter) Reset() { + *x = InterfaceFilter{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InterfaceFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InterfaceFilter) ProtoMessage() {} + +func (x *InterfaceFilter) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InterfaceFilter.ProtoReflect.Descriptor instead. +func (*InterfaceFilter) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{3} +} + +func (x *InterfaceFilter) GetInterfaceId() *Identifier { + if x != nil { + return x.InterfaceId + } + return nil +} + +func (x *InterfaceFilter) GetIncludeInterfaceView() bool { + if x != nil { + return x.IncludeInterfaceView + } + return false +} + +func (x *InterfaceFilter) GetIncludeCreatedEventBlob() bool { + if x != nil { + return x.IncludeCreatedEventBlob + } + return false +} + +// This filter matches contracts of a specific template. +type TemplateFilter struct { + state protoimpl.MessageState `protogen:"open.v1"` + // A template for which the payload should be included in the response. + // The “template_id“ needs to be valid: corresponding template should be defined in + // one of the available packages at the time of the query. + // Both package-name and package-id reference formats for the identifier are supported. + // Note: The package-id reference identifier format is deprecated. We plan to end support for this format in version 3.4. + // + // Required + TemplateId *Identifier `protobuf:"bytes,1,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` + // Whether to include a “created_event_blob“ in the returned “CreatedEvent“. + // Use this to access the contract event payload in your API client + // for submitting it as a disclosed contract with future commands. + // + // Optional + IncludeCreatedEventBlob bool `protobuf:"varint,2,opt,name=include_created_event_blob,json=includeCreatedEventBlob,proto3" json:"include_created_event_blob,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TemplateFilter) Reset() { + *x = TemplateFilter{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TemplateFilter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TemplateFilter) ProtoMessage() {} + +func (x *TemplateFilter) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TemplateFilter.ProtoReflect.Descriptor instead. +func (*TemplateFilter) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{4} +} + +func (x *TemplateFilter) GetTemplateId() *Identifier { + if x != nil { + return x.TemplateId + } + return nil +} + +func (x *TemplateFilter) GetIncludeCreatedEventBlob() bool { + if x != nil { + return x.IncludeCreatedEventBlob + } + return false +} + +// A format for events which defines both which events should be included +// and what data should be computed and included for them. +// +// Note that some of the filtering behavior depends on the `TransactionShape`, +// which is expected to be specified alongside usages of `EventFormat`. +type EventFormat struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Each key must be a valid PartyIdString (as described in “value.proto“). + // The interpretation of the filter depends on the transaction-shape being filtered: + // + // 1. For **ledger-effects** create and exercise events are returned, for which the witnesses include at least one of + // the listed parties and match the per-party filter. + // 2. For **transaction and active-contract-set streams** create and archive events are returned for all contracts whose + // stakeholders include at least one of the listed parties and match the per-party filter. + // + // Optional: can be empty + FiltersByParty map[string]*Filters `protobuf:"bytes,1,rep,name=filters_by_party,json=filtersByParty,proto3" json:"filters_by_party,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // Wildcard filters that apply to all the parties existing on the participant. The interpretation of the filters is the same + // with the per-party filter as described above. + // + // Optional + FiltersForAnyParty *Filters `protobuf:"bytes,2,opt,name=filters_for_any_party,json=filtersForAnyParty,proto3" json:"filters_for_any_party,omitempty"` + // If enabled, values served over the API will contain more information than strictly necessary to interpret the data. + // In particular, setting the verbose flag to true triggers the ledger to include labels for record fields. + // + // Optional + Verbose bool `protobuf:"varint,3,opt,name=verbose,proto3" json:"verbose,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EventFormat) Reset() { + *x = EventFormat{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EventFormat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventFormat) ProtoMessage() {} + +func (x *EventFormat) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventFormat.ProtoReflect.Descriptor instead. +func (*EventFormat) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{5} +} + +func (x *EventFormat) GetFiltersByParty() map[string]*Filters { + if x != nil { + return x.FiltersByParty + } + return nil +} + +func (x *EventFormat) GetFiltersForAnyParty() *Filters { + if x != nil { + return x.FiltersForAnyParty + } + return nil +} + +func (x *EventFormat) GetVerbose() bool { + if x != nil { + return x.Verbose + } + return false +} + +// A format that specifies what events to include in Daml transactions +// and what data to compute and include for them. +type TransactionFormat struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + EventFormat *EventFormat `protobuf:"bytes,1,opt,name=event_format,json=eventFormat,proto3" json:"event_format,omitempty"` + // What transaction shape to use for interpreting the filters of the event format. + // + // Required + TransactionShape TransactionShape `protobuf:"varint,2,opt,name=transaction_shape,json=transactionShape,proto3,enum=com.daml.ledger.api.v2.TransactionShape" json:"transaction_shape,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TransactionFormat) Reset() { + *x = TransactionFormat{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TransactionFormat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionFormat) ProtoMessage() {} + +func (x *TransactionFormat) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionFormat.ProtoReflect.Descriptor instead. +func (*TransactionFormat) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{6} +} + +func (x *TransactionFormat) GetEventFormat() *EventFormat { + if x != nil { + return x.EventFormat + } + return nil +} + +func (x *TransactionFormat) GetTransactionShape() TransactionShape { + if x != nil { + return x.TransactionShape + } + return TransactionShape_TRANSACTION_SHAPE_UNSPECIFIED +} + +// A format specifying which topology transactions to include and how to render them. +type TopologyFormat struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Include participant authorization topology events in streams. + // If unset, no participant authorization topology events are emitted in the stream. + // + // Optional + IncludeParticipantAuthorizationEvents *ParticipantAuthorizationTopologyFormat `protobuf:"bytes,1,opt,name=include_participant_authorization_events,json=includeParticipantAuthorizationEvents,proto3" json:"include_participant_authorization_events,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopologyFormat) Reset() { + *x = TopologyFormat{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopologyFormat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyFormat) ProtoMessage() {} + +func (x *TopologyFormat) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyFormat.ProtoReflect.Descriptor instead. +func (*TopologyFormat) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{7} +} + +func (x *TopologyFormat) GetIncludeParticipantAuthorizationEvents() *ParticipantAuthorizationTopologyFormat { + if x != nil { + return x.IncludeParticipantAuthorizationEvents + } + return nil +} + +// A format specifying which participant authorization topology transactions to include and how to render them. +type ParticipantAuthorizationTopologyFormat struct { + state protoimpl.MessageState `protogen:"open.v1"` + // List of parties for which the topology transactions should be sent. + // Empty means: for all parties. + // + // Optional: can be empty + Parties []string `protobuf:"bytes,1,rep,name=parties,proto3" json:"parties,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ParticipantAuthorizationTopologyFormat) Reset() { + *x = ParticipantAuthorizationTopologyFormat{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ParticipantAuthorizationTopologyFormat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParticipantAuthorizationTopologyFormat) ProtoMessage() {} + +func (x *ParticipantAuthorizationTopologyFormat) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ParticipantAuthorizationTopologyFormat.ProtoReflect.Descriptor instead. +func (*ParticipantAuthorizationTopologyFormat) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{8} +} + +func (x *ParticipantAuthorizationTopologyFormat) GetParties() []string { + if x != nil { + return x.Parties + } + return nil +} + +// A format specifying what updates to include and how to render them. +type UpdateFormat struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Include Daml transactions in streams. + // If unset, no transactions are emitted in the stream. + // + // Optional + IncludeTransactions *TransactionFormat `protobuf:"bytes,1,opt,name=include_transactions,json=includeTransactions,proto3" json:"include_transactions,omitempty"` + // Include (un)assignments in the stream. + // The events in the result take the shape TRANSACTION_SHAPE_ACS_DELTA. + // If unset, no (un)assignments are emitted in the stream. + // + // Optional + IncludeReassignments *EventFormat `protobuf:"bytes,2,opt,name=include_reassignments,json=includeReassignments,proto3" json:"include_reassignments,omitempty"` + // Include topology events in streams. + // If unset no topology events are emitted in the stream. + // + // Optional + IncludeTopologyEvents *TopologyFormat `protobuf:"bytes,3,opt,name=include_topology_events,json=includeTopologyEvents,proto3" json:"include_topology_events,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateFormat) Reset() { + *x = UpdateFormat{} + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateFormat) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateFormat) ProtoMessage() {} + +func (x *UpdateFormat) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateFormat.ProtoReflect.Descriptor instead. +func (*UpdateFormat) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP(), []int{9} +} + +func (x *UpdateFormat) GetIncludeTransactions() *TransactionFormat { + if x != nil { + return x.IncludeTransactions + } + return nil +} + +func (x *UpdateFormat) GetIncludeReassignments() *EventFormat { + if x != nil { + return x.IncludeReassignments + } + return nil +} + +func (x *UpdateFormat) GetIncludeTopologyEvents() *TopologyFormat { + if x != nil { + return x.IncludeTopologyEvents + } + return nil +} + +var File_com_daml_ledger_api_v2_transaction_filter_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_transaction_filter_proto_rawDesc = "" + + "\n" + + "/com/daml/ledger/api/v2/transaction_filter.proto\x12\x16com.daml.ledger.api.v2\x1a\"com/daml/ledger/api/v2/value.proto\"S\n" + + "\aFilters\x12H\n" + + "\n" + + "cumulative\x18\x01 \x03(\v2(.com.daml.ledger.api.v2.CumulativeFilterR\n" + + "cumulative\"\xa3\x02\n" + + "\x10CumulativeFilter\x12Q\n" + + "\x0fwildcard_filter\x18\x01 \x01(\v2&.com.daml.ledger.api.v2.WildcardFilterH\x00R\x0ewildcardFilter\x12T\n" + + "\x10interface_filter\x18\x02 \x01(\v2'.com.daml.ledger.api.v2.InterfaceFilterH\x00R\x0finterfaceFilter\x12Q\n" + + "\x0ftemplate_filter\x18\x03 \x01(\v2&.com.daml.ledger.api.v2.TemplateFilterH\x00R\x0etemplateFilterB\x13\n" + + "\x11identifier_filter\"M\n" + + "\x0eWildcardFilter\x12;\n" + + "\x1ainclude_created_event_blob\x18\x01 \x01(\bR\x17includeCreatedEventBlob\"\xcb\x01\n" + + "\x0fInterfaceFilter\x12E\n" + + "\finterface_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\vinterfaceId\x124\n" + + "\x16include_interface_view\x18\x02 \x01(\bR\x14includeInterfaceView\x12;\n" + + "\x1ainclude_created_event_blob\x18\x03 \x01(\bR\x17includeCreatedEventBlob\"\x92\x01\n" + + "\x0eTemplateFilter\x12C\n" + + "\vtemplate_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\n" + + "templateId\x12;\n" + + "\x1ainclude_created_event_blob\x18\x02 \x01(\bR\x17includeCreatedEventBlob\"\xc2\x02\n" + + "\vEventFormat\x12a\n" + + "\x10filters_by_party\x18\x01 \x03(\v27.com.daml.ledger.api.v2.EventFormat.FiltersByPartyEntryR\x0efiltersByParty\x12R\n" + + "\x15filters_for_any_party\x18\x02 \x01(\v2\x1f.com.daml.ledger.api.v2.FiltersR\x12filtersForAnyParty\x12\x18\n" + + "\averbose\x18\x03 \x01(\bR\averbose\x1ab\n" + + "\x13FiltersByPartyEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x125\n" + + "\x05value\x18\x02 \x01(\v2\x1f.com.daml.ledger.api.v2.FiltersR\x05value:\x028\x01\"\xb2\x01\n" + + "\x11TransactionFormat\x12F\n" + + "\fevent_format\x18\x01 \x01(\v2#.com.daml.ledger.api.v2.EventFormatR\veventFormat\x12U\n" + + "\x11transaction_shape\x18\x02 \x01(\x0e2(.com.daml.ledger.api.v2.TransactionShapeR\x10transactionShape\"\xaa\x01\n" + + "\x0eTopologyFormat\x12\x97\x01\n" + + "(include_participant_authorization_events\x18\x01 \x01(\v2>.com.daml.ledger.api.v2.ParticipantAuthorizationTopologyFormatR%includeParticipantAuthorizationEvents\"B\n" + + "&ParticipantAuthorizationTopologyFormat\x12\x18\n" + + "\aparties\x18\x01 \x03(\tR\aparties\"\xa6\x02\n" + + "\fUpdateFormat\x12\\\n" + + "\x14include_transactions\x18\x01 \x01(\v2).com.daml.ledger.api.v2.TransactionFormatR\x13includeTransactions\x12X\n" + + "\x15include_reassignments\x18\x02 \x01(\v2#.com.daml.ledger.api.v2.EventFormatR\x14includeReassignments\x12^\n" + + "\x17include_topology_events\x18\x03 \x01(\v2&.com.daml.ledger.api.v2.TopologyFormatR\x15includeTopologyEvents*|\n" + + "\x10TransactionShape\x12!\n" + + "\x1dTRANSACTION_SHAPE_UNSPECIFIED\x10\x00\x12\x1f\n" + + "\x1bTRANSACTION_SHAPE_ACS_DELTA\x10\x01\x12$\n" + + " TRANSACTION_SHAPE_LEDGER_EFFECTS\x10\x02B\x83\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x16TransactionFilterProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_transaction_filter_proto_rawDesc), len(file_com_daml_ledger_api_v2_transaction_filter_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_transaction_filter_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_transaction_filter_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_com_daml_ledger_api_v2_transaction_filter_proto_goTypes = []any{ + (TransactionShape)(0), // 0: com.daml.ledger.api.v2.TransactionShape + (*Filters)(nil), // 1: com.daml.ledger.api.v2.Filters + (*CumulativeFilter)(nil), // 2: com.daml.ledger.api.v2.CumulativeFilter + (*WildcardFilter)(nil), // 3: com.daml.ledger.api.v2.WildcardFilter + (*InterfaceFilter)(nil), // 4: com.daml.ledger.api.v2.InterfaceFilter + (*TemplateFilter)(nil), // 5: com.daml.ledger.api.v2.TemplateFilter + (*EventFormat)(nil), // 6: com.daml.ledger.api.v2.EventFormat + (*TransactionFormat)(nil), // 7: com.daml.ledger.api.v2.TransactionFormat + (*TopologyFormat)(nil), // 8: com.daml.ledger.api.v2.TopologyFormat + (*ParticipantAuthorizationTopologyFormat)(nil), // 9: com.daml.ledger.api.v2.ParticipantAuthorizationTopologyFormat + (*UpdateFormat)(nil), // 10: com.daml.ledger.api.v2.UpdateFormat + nil, // 11: com.daml.ledger.api.v2.EventFormat.FiltersByPartyEntry + (*Identifier)(nil), // 12: com.daml.ledger.api.v2.Identifier +} +var file_com_daml_ledger_api_v2_transaction_filter_proto_depIdxs = []int32{ + 2, // 0: com.daml.ledger.api.v2.Filters.cumulative:type_name -> com.daml.ledger.api.v2.CumulativeFilter + 3, // 1: com.daml.ledger.api.v2.CumulativeFilter.wildcard_filter:type_name -> com.daml.ledger.api.v2.WildcardFilter + 4, // 2: com.daml.ledger.api.v2.CumulativeFilter.interface_filter:type_name -> com.daml.ledger.api.v2.InterfaceFilter + 5, // 3: com.daml.ledger.api.v2.CumulativeFilter.template_filter:type_name -> com.daml.ledger.api.v2.TemplateFilter + 12, // 4: com.daml.ledger.api.v2.InterfaceFilter.interface_id:type_name -> com.daml.ledger.api.v2.Identifier + 12, // 5: com.daml.ledger.api.v2.TemplateFilter.template_id:type_name -> com.daml.ledger.api.v2.Identifier + 11, // 6: com.daml.ledger.api.v2.EventFormat.filters_by_party:type_name -> com.daml.ledger.api.v2.EventFormat.FiltersByPartyEntry + 1, // 7: com.daml.ledger.api.v2.EventFormat.filters_for_any_party:type_name -> com.daml.ledger.api.v2.Filters + 6, // 8: com.daml.ledger.api.v2.TransactionFormat.event_format:type_name -> com.daml.ledger.api.v2.EventFormat + 0, // 9: com.daml.ledger.api.v2.TransactionFormat.transaction_shape:type_name -> com.daml.ledger.api.v2.TransactionShape + 9, // 10: com.daml.ledger.api.v2.TopologyFormat.include_participant_authorization_events:type_name -> com.daml.ledger.api.v2.ParticipantAuthorizationTopologyFormat + 7, // 11: com.daml.ledger.api.v2.UpdateFormat.include_transactions:type_name -> com.daml.ledger.api.v2.TransactionFormat + 6, // 12: com.daml.ledger.api.v2.UpdateFormat.include_reassignments:type_name -> com.daml.ledger.api.v2.EventFormat + 8, // 13: com.daml.ledger.api.v2.UpdateFormat.include_topology_events:type_name -> com.daml.ledger.api.v2.TopologyFormat + 1, // 14: com.daml.ledger.api.v2.EventFormat.FiltersByPartyEntry.value:type_name -> com.daml.ledger.api.v2.Filters + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_transaction_filter_proto_init() } +func file_com_daml_ledger_api_v2_transaction_filter_proto_init() { + if File_com_daml_ledger_api_v2_transaction_filter_proto != nil { + return + } + file_com_daml_ledger_api_v2_value_proto_init() + file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes[1].OneofWrappers = []any{ + (*CumulativeFilter_WildcardFilter)(nil), + (*CumulativeFilter_InterfaceFilter)(nil), + (*CumulativeFilter_TemplateFilter)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_transaction_filter_proto_rawDesc), len(file_com_daml_ledger_api_v2_transaction_filter_proto_rawDesc)), + NumEnums: 1, + NumMessages: 11, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_transaction_filter_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_transaction_filter_proto_depIdxs, + EnumInfos: file_com_daml_ledger_api_v2_transaction_filter_proto_enumTypes, + MessageInfos: file_com_daml_ledger_api_v2_transaction_filter_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_transaction_filter_proto = out.File + file_com_daml_ledger_api_v2_transaction_filter_proto_goTypes = nil + file_com_daml_ledger_api_v2_transaction_filter_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/update_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/update_service.pb.go new file mode 100644 index 00000000..1bfe0b43 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/update_service.pb.go @@ -0,0 +1,571 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/update_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetUpdatesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Required + BeginExclusive int64 `protobuf:"varint,1,opt,name=begin_exclusive,json=beginExclusive,proto3" json:"begin_exclusive,omitempty"` + // Inclusive higher bound offset of the requested ledger section. + // If specified the response will only contain transactions whose offset is less than or equal to this. + // If not specified, + // + // - the descending_order must not be selected, + // - the stream will not terminate. + // + // Optional + EndInclusive *int64 `protobuf:"varint,2,opt,name=end_inclusive,json=endInclusive,proto3,oneof" json:"end_inclusive,omitempty"` + // The update format for this request + // + // Required + UpdateFormat *UpdateFormat `protobuf:"bytes,5,opt,name=update_format,json=updateFormat,proto3" json:"update_format,omitempty"` + // If set, the stream will populate the elements in descending order. + // + // Optional + DescendingOrder bool `protobuf:"varint,6,opt,name=descending_order,json=descendingOrder,proto3" json:"descending_order,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUpdatesRequest) Reset() { + *x = GetUpdatesRequest{} + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUpdatesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUpdatesRequest) ProtoMessage() {} + +func (x *GetUpdatesRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUpdatesRequest.ProtoReflect.Descriptor instead. +func (*GetUpdatesRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_update_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetUpdatesRequest) GetBeginExclusive() int64 { + if x != nil { + return x.BeginExclusive + } + return 0 +} + +func (x *GetUpdatesRequest) GetEndInclusive() int64 { + if x != nil && x.EndInclusive != nil { + return *x.EndInclusive + } + return 0 +} + +func (x *GetUpdatesRequest) GetUpdateFormat() *UpdateFormat { + if x != nil { + return x.UpdateFormat + } + return nil +} + +func (x *GetUpdatesRequest) GetDescendingOrder() bool { + if x != nil { + return x.DescendingOrder + } + return false +} + +type GetUpdatesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The update that matches the filter in the request. + // + // # Required + // + // Types that are valid to be assigned to Update: + // + // *GetUpdatesResponse_Transaction + // *GetUpdatesResponse_Reassignment + // *GetUpdatesResponse_OffsetCheckpoint + // *GetUpdatesResponse_TopologyTransaction + Update isGetUpdatesResponse_Update `protobuf_oneof:"update"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUpdatesResponse) Reset() { + *x = GetUpdatesResponse{} + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUpdatesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUpdatesResponse) ProtoMessage() {} + +func (x *GetUpdatesResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUpdatesResponse.ProtoReflect.Descriptor instead. +func (*GetUpdatesResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_update_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetUpdatesResponse) GetUpdate() isGetUpdatesResponse_Update { + if x != nil { + return x.Update + } + return nil +} + +func (x *GetUpdatesResponse) GetTransaction() *Transaction { + if x != nil { + if x, ok := x.Update.(*GetUpdatesResponse_Transaction); ok { + return x.Transaction + } + } + return nil +} + +func (x *GetUpdatesResponse) GetReassignment() *Reassignment { + if x != nil { + if x, ok := x.Update.(*GetUpdatesResponse_Reassignment); ok { + return x.Reassignment + } + } + return nil +} + +func (x *GetUpdatesResponse) GetOffsetCheckpoint() *OffsetCheckpoint { + if x != nil { + if x, ok := x.Update.(*GetUpdatesResponse_OffsetCheckpoint); ok { + return x.OffsetCheckpoint + } + } + return nil +} + +func (x *GetUpdatesResponse) GetTopologyTransaction() *TopologyTransaction { + if x != nil { + if x, ok := x.Update.(*GetUpdatesResponse_TopologyTransaction); ok { + return x.TopologyTransaction + } + } + return nil +} + +type isGetUpdatesResponse_Update interface { + isGetUpdatesResponse_Update() +} + +type GetUpdatesResponse_Transaction struct { + Transaction *Transaction `protobuf:"bytes,1,opt,name=transaction,proto3,oneof"` +} + +type GetUpdatesResponse_Reassignment struct { + Reassignment *Reassignment `protobuf:"bytes,2,opt,name=reassignment,proto3,oneof"` +} + +type GetUpdatesResponse_OffsetCheckpoint struct { + OffsetCheckpoint *OffsetCheckpoint `protobuf:"bytes,3,opt,name=offset_checkpoint,json=offsetCheckpoint,proto3,oneof"` +} + +type GetUpdatesResponse_TopologyTransaction struct { + TopologyTransaction *TopologyTransaction `protobuf:"bytes,4,opt,name=topology_transaction,json=topologyTransaction,proto3,oneof"` +} + +func (*GetUpdatesResponse_Transaction) isGetUpdatesResponse_Update() {} + +func (*GetUpdatesResponse_Reassignment) isGetUpdatesResponse_Update() {} + +func (*GetUpdatesResponse_OffsetCheckpoint) isGetUpdatesResponse_Update() {} + +func (*GetUpdatesResponse_TopologyTransaction) isGetUpdatesResponse_Update() {} + +type GetUpdateByOffsetRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The offset of the update being looked up. + // Must be a valid absolute offset (positive integer). + // + // Required + Offset int64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + // The format for the update. + // + // Required + UpdateFormat *UpdateFormat `protobuf:"bytes,2,opt,name=update_format,json=updateFormat,proto3" json:"update_format,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUpdateByOffsetRequest) Reset() { + *x = GetUpdateByOffsetRequest{} + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUpdateByOffsetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUpdateByOffsetRequest) ProtoMessage() {} + +func (x *GetUpdateByOffsetRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUpdateByOffsetRequest.ProtoReflect.Descriptor instead. +func (*GetUpdateByOffsetRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_update_service_proto_rawDescGZIP(), []int{2} +} + +func (x *GetUpdateByOffsetRequest) GetOffset() int64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *GetUpdateByOffsetRequest) GetUpdateFormat() *UpdateFormat { + if x != nil { + return x.UpdateFormat + } + return nil +} + +type GetUpdateByIdRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The ID of a particular update. + // Must be a valid LedgerString (as described in “value.proto“). + // + // Required + UpdateId string `protobuf:"bytes,1,opt,name=update_id,json=updateId,proto3" json:"update_id,omitempty"` + // The format for the update. + // + // Required + UpdateFormat *UpdateFormat `protobuf:"bytes,2,opt,name=update_format,json=updateFormat,proto3" json:"update_format,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUpdateByIdRequest) Reset() { + *x = GetUpdateByIdRequest{} + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUpdateByIdRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUpdateByIdRequest) ProtoMessage() {} + +func (x *GetUpdateByIdRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUpdateByIdRequest.ProtoReflect.Descriptor instead. +func (*GetUpdateByIdRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_update_service_proto_rawDescGZIP(), []int{3} +} + +func (x *GetUpdateByIdRequest) GetUpdateId() string { + if x != nil { + return x.UpdateId + } + return "" +} + +func (x *GetUpdateByIdRequest) GetUpdateFormat() *UpdateFormat { + if x != nil { + return x.UpdateFormat + } + return nil +} + +type GetUpdateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The update that matches the filter in the request. + // + // # Required + // + // Types that are valid to be assigned to Update: + // + // *GetUpdateResponse_Transaction + // *GetUpdateResponse_Reassignment + // *GetUpdateResponse_TopologyTransaction + Update isGetUpdateResponse_Update `protobuf_oneof:"update"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetUpdateResponse) Reset() { + *x = GetUpdateResponse{} + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetUpdateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUpdateResponse) ProtoMessage() {} + +func (x *GetUpdateResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_update_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUpdateResponse.ProtoReflect.Descriptor instead. +func (*GetUpdateResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_update_service_proto_rawDescGZIP(), []int{4} +} + +func (x *GetUpdateResponse) GetUpdate() isGetUpdateResponse_Update { + if x != nil { + return x.Update + } + return nil +} + +func (x *GetUpdateResponse) GetTransaction() *Transaction { + if x != nil { + if x, ok := x.Update.(*GetUpdateResponse_Transaction); ok { + return x.Transaction + } + } + return nil +} + +func (x *GetUpdateResponse) GetReassignment() *Reassignment { + if x != nil { + if x, ok := x.Update.(*GetUpdateResponse_Reassignment); ok { + return x.Reassignment + } + } + return nil +} + +func (x *GetUpdateResponse) GetTopologyTransaction() *TopologyTransaction { + if x != nil { + if x, ok := x.Update.(*GetUpdateResponse_TopologyTransaction); ok { + return x.TopologyTransaction + } + } + return nil +} + +type isGetUpdateResponse_Update interface { + isGetUpdateResponse_Update() +} + +type GetUpdateResponse_Transaction struct { + Transaction *Transaction `protobuf:"bytes,1,opt,name=transaction,proto3,oneof"` +} + +type GetUpdateResponse_Reassignment struct { + Reassignment *Reassignment `protobuf:"bytes,2,opt,name=reassignment,proto3,oneof"` +} + +type GetUpdateResponse_TopologyTransaction struct { + TopologyTransaction *TopologyTransaction `protobuf:"bytes,3,opt,name=topology_transaction,json=topologyTransaction,proto3,oneof"` +} + +func (*GetUpdateResponse_Transaction) isGetUpdateResponse_Update() {} + +func (*GetUpdateResponse_Reassignment) isGetUpdateResponse_Update() {} + +func (*GetUpdateResponse_TopologyTransaction) isGetUpdateResponse_Update() {} + +var File_com_daml_ledger_api_v2_update_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_update_service_proto_rawDesc = "" + + "\n" + + "+com/daml/ledger/api/v2/update_service.proto\x12\x16com.daml.ledger.api.v2\x1a.com/daml/ledger/api/v2/offset_checkpoint.proto\x1a)com/daml/ledger/api/v2/reassignment.proto\x1a1com/daml/ledger/api/v2/topology_transaction.proto\x1a(com/daml/ledger/api/v2/transaction.proto\x1a/com/daml/ledger/api/v2/transaction_filter.proto\"\x8b\x02\n" + + "\x11GetUpdatesRequest\x12'\n" + + "\x0fbegin_exclusive\x18\x01 \x01(\x03R\x0ebeginExclusive\x12(\n" + + "\rend_inclusive\x18\x02 \x01(\x03H\x00R\fendInclusive\x88\x01\x01\x12I\n" + + "\rupdate_format\x18\x05 \x01(\v2$.com.daml.ledger.api.v2.UpdateFormatR\fupdateFormat\x12)\n" + + "\x10descending_order\x18\x06 \x01(\bR\x0fdescendingOrderB\x10\n" + + "\x0e_end_inclusiveJ\x04\b\x03\x10\x04J\x04\b\x04\x10\x05R\x06filterR\averbose\"\xee\x02\n" + + "\x12GetUpdatesResponse\x12G\n" + + "\vtransaction\x18\x01 \x01(\v2#.com.daml.ledger.api.v2.TransactionH\x00R\vtransaction\x12J\n" + + "\freassignment\x18\x02 \x01(\v2$.com.daml.ledger.api.v2.ReassignmentH\x00R\freassignment\x12W\n" + + "\x11offset_checkpoint\x18\x03 \x01(\v2(.com.daml.ledger.api.v2.OffsetCheckpointH\x00R\x10offsetCheckpoint\x12`\n" + + "\x14topology_transaction\x18\x04 \x01(\v2+.com.daml.ledger.api.v2.TopologyTransactionH\x00R\x13topologyTransactionB\b\n" + + "\x06update\"}\n" + + "\x18GetUpdateByOffsetRequest\x12\x16\n" + + "\x06offset\x18\x01 \x01(\x03R\x06offset\x12I\n" + + "\rupdate_format\x18\x02 \x01(\v2$.com.daml.ledger.api.v2.UpdateFormatR\fupdateFormat\"~\n" + + "\x14GetUpdateByIdRequest\x12\x1b\n" + + "\tupdate_id\x18\x01 \x01(\tR\bupdateId\x12I\n" + + "\rupdate_format\x18\x02 \x01(\v2$.com.daml.ledger.api.v2.UpdateFormatR\fupdateFormat\"\x94\x02\n" + + "\x11GetUpdateResponse\x12G\n" + + "\vtransaction\x18\x01 \x01(\v2#.com.daml.ledger.api.v2.TransactionH\x00R\vtransaction\x12J\n" + + "\freassignment\x18\x02 \x01(\v2$.com.daml.ledger.api.v2.ReassignmentH\x00R\freassignment\x12`\n" + + "\x14topology_transaction\x18\x03 \x01(\v2+.com.daml.ledger.api.v2.TopologyTransactionH\x00R\x13topologyTransactionB\b\n" + + "\x06update2\xd2\x02\n" + + "\rUpdateService\x12e\n" + + "\n" + + "GetUpdates\x12).com.daml.ledger.api.v2.GetUpdatesRequest\x1a*.com.daml.ledger.api.v2.GetUpdatesResponse0\x01\x12p\n" + + "\x11GetUpdateByOffset\x120.com.daml.ledger.api.v2.GetUpdateByOffsetRequest\x1a).com.daml.ledger.api.v2.GetUpdateResponse\x12h\n" + + "\rGetUpdateById\x12,.com.daml.ledger.api.v2.GetUpdateByIdRequest\x1a).com.daml.ledger.api.v2.GetUpdateResponseB\xff\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\x12UpdateServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_update_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_update_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_update_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_update_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_update_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_update_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_update_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_update_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_update_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_com_daml_ledger_api_v2_update_service_proto_goTypes = []any{ + (*GetUpdatesRequest)(nil), // 0: com.daml.ledger.api.v2.GetUpdatesRequest + (*GetUpdatesResponse)(nil), // 1: com.daml.ledger.api.v2.GetUpdatesResponse + (*GetUpdateByOffsetRequest)(nil), // 2: com.daml.ledger.api.v2.GetUpdateByOffsetRequest + (*GetUpdateByIdRequest)(nil), // 3: com.daml.ledger.api.v2.GetUpdateByIdRequest + (*GetUpdateResponse)(nil), // 4: com.daml.ledger.api.v2.GetUpdateResponse + (*UpdateFormat)(nil), // 5: com.daml.ledger.api.v2.UpdateFormat + (*Transaction)(nil), // 6: com.daml.ledger.api.v2.Transaction + (*Reassignment)(nil), // 7: com.daml.ledger.api.v2.Reassignment + (*OffsetCheckpoint)(nil), // 8: com.daml.ledger.api.v2.OffsetCheckpoint + (*TopologyTransaction)(nil), // 9: com.daml.ledger.api.v2.TopologyTransaction +} +var file_com_daml_ledger_api_v2_update_service_proto_depIdxs = []int32{ + 5, // 0: com.daml.ledger.api.v2.GetUpdatesRequest.update_format:type_name -> com.daml.ledger.api.v2.UpdateFormat + 6, // 1: com.daml.ledger.api.v2.GetUpdatesResponse.transaction:type_name -> com.daml.ledger.api.v2.Transaction + 7, // 2: com.daml.ledger.api.v2.GetUpdatesResponse.reassignment:type_name -> com.daml.ledger.api.v2.Reassignment + 8, // 3: com.daml.ledger.api.v2.GetUpdatesResponse.offset_checkpoint:type_name -> com.daml.ledger.api.v2.OffsetCheckpoint + 9, // 4: com.daml.ledger.api.v2.GetUpdatesResponse.topology_transaction:type_name -> com.daml.ledger.api.v2.TopologyTransaction + 5, // 5: com.daml.ledger.api.v2.GetUpdateByOffsetRequest.update_format:type_name -> com.daml.ledger.api.v2.UpdateFormat + 5, // 6: com.daml.ledger.api.v2.GetUpdateByIdRequest.update_format:type_name -> com.daml.ledger.api.v2.UpdateFormat + 6, // 7: com.daml.ledger.api.v2.GetUpdateResponse.transaction:type_name -> com.daml.ledger.api.v2.Transaction + 7, // 8: com.daml.ledger.api.v2.GetUpdateResponse.reassignment:type_name -> com.daml.ledger.api.v2.Reassignment + 9, // 9: com.daml.ledger.api.v2.GetUpdateResponse.topology_transaction:type_name -> com.daml.ledger.api.v2.TopologyTransaction + 0, // 10: com.daml.ledger.api.v2.UpdateService.GetUpdates:input_type -> com.daml.ledger.api.v2.GetUpdatesRequest + 2, // 11: com.daml.ledger.api.v2.UpdateService.GetUpdateByOffset:input_type -> com.daml.ledger.api.v2.GetUpdateByOffsetRequest + 3, // 12: com.daml.ledger.api.v2.UpdateService.GetUpdateById:input_type -> com.daml.ledger.api.v2.GetUpdateByIdRequest + 1, // 13: com.daml.ledger.api.v2.UpdateService.GetUpdates:output_type -> com.daml.ledger.api.v2.GetUpdatesResponse + 4, // 14: com.daml.ledger.api.v2.UpdateService.GetUpdateByOffset:output_type -> com.daml.ledger.api.v2.GetUpdateResponse + 4, // 15: com.daml.ledger.api.v2.UpdateService.GetUpdateById:output_type -> com.daml.ledger.api.v2.GetUpdateResponse + 13, // [13:16] is the sub-list for method output_type + 10, // [10:13] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_update_service_proto_init() } +func file_com_daml_ledger_api_v2_update_service_proto_init() { + if File_com_daml_ledger_api_v2_update_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_offset_checkpoint_proto_init() + file_com_daml_ledger_api_v2_reassignment_proto_init() + file_com_daml_ledger_api_v2_topology_transaction_proto_init() + file_com_daml_ledger_api_v2_transaction_proto_init() + file_com_daml_ledger_api_v2_transaction_filter_proto_init() + file_com_daml_ledger_api_v2_update_service_proto_msgTypes[0].OneofWrappers = []any{} + file_com_daml_ledger_api_v2_update_service_proto_msgTypes[1].OneofWrappers = []any{ + (*GetUpdatesResponse_Transaction)(nil), + (*GetUpdatesResponse_Reassignment)(nil), + (*GetUpdatesResponse_OffsetCheckpoint)(nil), + (*GetUpdatesResponse_TopologyTransaction)(nil), + } + file_com_daml_ledger_api_v2_update_service_proto_msgTypes[4].OneofWrappers = []any{ + (*GetUpdateResponse_Transaction)(nil), + (*GetUpdateResponse_Reassignment)(nil), + (*GetUpdateResponse_TopologyTransaction)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_update_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_update_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_update_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_update_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_update_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_update_service_proto = out.File + file_com_daml_ledger_api_v2_update_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_update_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/update_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/update_service_grpc.pb.go new file mode 100644 index 00000000..8d8d1e56 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/update_service_grpc.pb.go @@ -0,0 +1,250 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/update_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + UpdateService_GetUpdates_FullMethodName = "/com.daml.ledger.api.v2.UpdateService/GetUpdates" + UpdateService_GetUpdateByOffset_FullMethodName = "/com.daml.ledger.api.v2.UpdateService/GetUpdateByOffset" + UpdateService_GetUpdateById_FullMethodName = "/com.daml.ledger.api.v2.UpdateService/GetUpdateById" +) + +// UpdateServiceClient is the client API for UpdateService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Allows clients to read updates (transactions, (un)assignments, topology events) from the ledger. +// +// “GetUpdates“ provides a comprehensive stream of updates/changes +// which happened on the virtual shared ledger. These streams are indexed with ledger +// offsets, which are strictly increasing. +// The virtual shared ledger consist of changes happening on multiple synchronizers which are +// connected to the serving participant. Each update belongs to one synchronizer, this is +// provided in the result (the “synchronizer_id“ field in “Transaction“ +// for transactions, the “source“ field in “UnassignedEvent“ and the “target“ field in “AssignedEvent“). +// Consumers can rely on strong causal guarantees on the virtual shared ledger for a single +// synchronizer: updates which have greater offsets are happened after than updates with smaller +// offsets for the same synchronizer. Across different synchronizers this is not guaranteed. +type UpdateServiceClient interface { + // Read the ledger's filtered update stream for the specified contents and filters. + // It returns the event types in accordance with the stream contents selected. Also the selection criteria + // for individual events depends on the transaction shape chosen. + // + // - ACS delta: a requesting party must be a stakeholder of an event for it to be included. + // - ledger effects: a requesting party must be a witness of an event for it to be included. + GetUpdates(ctx context.Context, in *GetUpdatesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetUpdatesResponse], error) + // Lookup an update by its offset. + // If there is no update with this offset, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + GetUpdateByOffset(ctx context.Context, in *GetUpdateByOffsetRequest, opts ...grpc.CallOption) (*GetUpdateResponse, error) + // Lookup an update by its ID. + // If there is no update with this ID, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + GetUpdateById(ctx context.Context, in *GetUpdateByIdRequest, opts ...grpc.CallOption) (*GetUpdateResponse, error) +} + +type updateServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewUpdateServiceClient(cc grpc.ClientConnInterface) UpdateServiceClient { + return &updateServiceClient{cc} +} + +func (c *updateServiceClient) GetUpdates(ctx context.Context, in *GetUpdatesRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetUpdatesResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &UpdateService_ServiceDesc.Streams[0], UpdateService_GetUpdates_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[GetUpdatesRequest, GetUpdatesResponse]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type UpdateService_GetUpdatesClient = grpc.ServerStreamingClient[GetUpdatesResponse] + +func (c *updateServiceClient) GetUpdateByOffset(ctx context.Context, in *GetUpdateByOffsetRequest, opts ...grpc.CallOption) (*GetUpdateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUpdateResponse) + err := c.cc.Invoke(ctx, UpdateService_GetUpdateByOffset_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *updateServiceClient) GetUpdateById(ctx context.Context, in *GetUpdateByIdRequest, opts ...grpc.CallOption) (*GetUpdateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetUpdateResponse) + err := c.cc.Invoke(ctx, UpdateService_GetUpdateById_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UpdateServiceServer is the server API for UpdateService service. +// All implementations must embed UnimplementedUpdateServiceServer +// for forward compatibility. +// +// Allows clients to read updates (transactions, (un)assignments, topology events) from the ledger. +// +// “GetUpdates“ provides a comprehensive stream of updates/changes +// which happened on the virtual shared ledger. These streams are indexed with ledger +// offsets, which are strictly increasing. +// The virtual shared ledger consist of changes happening on multiple synchronizers which are +// connected to the serving participant. Each update belongs to one synchronizer, this is +// provided in the result (the “synchronizer_id“ field in “Transaction“ +// for transactions, the “source“ field in “UnassignedEvent“ and the “target“ field in “AssignedEvent“). +// Consumers can rely on strong causal guarantees on the virtual shared ledger for a single +// synchronizer: updates which have greater offsets are happened after than updates with smaller +// offsets for the same synchronizer. Across different synchronizers this is not guaranteed. +type UpdateServiceServer interface { + // Read the ledger's filtered update stream for the specified contents and filters. + // It returns the event types in accordance with the stream contents selected. Also the selection criteria + // for individual events depends on the transaction shape chosen. + // + // - ACS delta: a requesting party must be a stakeholder of an event for it to be included. + // - ledger effects: a requesting party must be a witness of an event for it to be included. + GetUpdates(*GetUpdatesRequest, grpc.ServerStreamingServer[GetUpdatesResponse]) error + // Lookup an update by its offset. + // If there is no update with this offset, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + GetUpdateByOffset(context.Context, *GetUpdateByOffsetRequest) (*GetUpdateResponse, error) + // Lookup an update by its ID. + // If there is no update with this ID, or all the events are filtered, an UPDATE_NOT_FOUND error will be raised. + GetUpdateById(context.Context, *GetUpdateByIdRequest) (*GetUpdateResponse, error) + mustEmbedUnimplementedUpdateServiceServer() +} + +// UnimplementedUpdateServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedUpdateServiceServer struct{} + +func (UnimplementedUpdateServiceServer) GetUpdates(*GetUpdatesRequest, grpc.ServerStreamingServer[GetUpdatesResponse]) error { + return status.Errorf(codes.Unimplemented, "method GetUpdates not implemented") +} +func (UnimplementedUpdateServiceServer) GetUpdateByOffset(context.Context, *GetUpdateByOffsetRequest) (*GetUpdateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUpdateByOffset not implemented") +} +func (UnimplementedUpdateServiceServer) GetUpdateById(context.Context, *GetUpdateByIdRequest) (*GetUpdateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUpdateById not implemented") +} +func (UnimplementedUpdateServiceServer) mustEmbedUnimplementedUpdateServiceServer() {} +func (UnimplementedUpdateServiceServer) testEmbeddedByValue() {} + +// UnsafeUpdateServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UpdateServiceServer will +// result in compilation errors. +type UnsafeUpdateServiceServer interface { + mustEmbedUnimplementedUpdateServiceServer() +} + +func RegisterUpdateServiceServer(s grpc.ServiceRegistrar, srv UpdateServiceServer) { + // If the following call pancis, it indicates UnimplementedUpdateServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&UpdateService_ServiceDesc, srv) +} + +func _UpdateService_GetUpdates_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(GetUpdatesRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(UpdateServiceServer).GetUpdates(m, &grpc.GenericServerStream[GetUpdatesRequest, GetUpdatesResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type UpdateService_GetUpdatesServer = grpc.ServerStreamingServer[GetUpdatesResponse] + +func _UpdateService_GetUpdateByOffset_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUpdateByOffsetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UpdateServiceServer).GetUpdateByOffset(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UpdateService_GetUpdateByOffset_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UpdateServiceServer).GetUpdateByOffset(ctx, req.(*GetUpdateByOffsetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _UpdateService_GetUpdateById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUpdateByIdRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UpdateServiceServer).GetUpdateById(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: UpdateService_GetUpdateById_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UpdateServiceServer).GetUpdateById(ctx, req.(*GetUpdateByIdRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// UpdateService_ServiceDesc is the grpc.ServiceDesc for UpdateService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var UpdateService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.UpdateService", + HandlerType: (*UpdateServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetUpdateByOffset", + Handler: _UpdateService_GetUpdateByOffset_Handler, + }, + { + MethodName: "GetUpdateById", + Handler: _UpdateService_GetUpdateById_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "GetUpdates", + Handler: _UpdateService_GetUpdates_Handler, + ServerStreams: true, + }, + }, + Metadata: "com/daml/ledger/api/v2/update_service.proto", +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/value.pb.go b/chain/canton/types/com/daml/ledger/api/v2/value.pb.go new file mode 100644 index 00000000..c90204b8 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/value.pb.go @@ -0,0 +1,1148 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// IMPORTANT: The comments for the messages and fields are used to produce Sphinx documentation in Canton. +// Make sure to check if they're valid and the output is as expected. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/value.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Encodes values that the ledger accepts as command arguments and emits as contract arguments. +// +// The values encoding use different classes of non-empty strings as identifiers. Those classes are +// defined as follows: +// +// - NameStrings are strings with length <= 1000 that match the regexp “[A-Za-z\$_][A-Za-z0-9\$_]*“. +// - PackageIdStrings are strings with length <= 64 that match the regexp “[A-Za-z0-9\-_ ]+“. +// - PartyIdStrings are strings with length <= 255 that match the regexp “[A-Za-z0-9:\-_ ]+“. +// - LedgerStrings are strings with length <= 255 that match the regexp “[A-Za-z0-9#:\-_/ ]+“. +// - UserIdStrings are strings with length <= 128 that match the regexp “[a-zA-Z0-9@^$.!`\-#+'~_|:]+“. +type Value struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Sum: + // + // *Value_Unit + // *Value_Bool + // *Value_Int64 + // *Value_Date + // *Value_Timestamp + // *Value_Numeric + // *Value_Party + // *Value_Text + // *Value_ContractId + // *Value_Optional + // *Value_List + // *Value_TextMap + // *Value_GenMap + // *Value_Record + // *Value_Variant + // *Value_Enum + Sum isValue_Sum `protobuf_oneof:"sum"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Value) Reset() { + *x = Value{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Value) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Value) ProtoMessage() {} + +func (x *Value) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Value.ProtoReflect.Descriptor instead. +func (*Value) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{0} +} + +func (x *Value) GetSum() isValue_Sum { + if x != nil { + return x.Sum + } + return nil +} + +func (x *Value) GetUnit() *emptypb.Empty { + if x != nil { + if x, ok := x.Sum.(*Value_Unit); ok { + return x.Unit + } + } + return nil +} + +func (x *Value) GetBool() bool { + if x != nil { + if x, ok := x.Sum.(*Value_Bool); ok { + return x.Bool + } + } + return false +} + +func (x *Value) GetInt64() int64 { + if x != nil { + if x, ok := x.Sum.(*Value_Int64); ok { + return x.Int64 + } + } + return 0 +} + +func (x *Value) GetDate() int32 { + if x != nil { + if x, ok := x.Sum.(*Value_Date); ok { + return x.Date + } + } + return 0 +} + +func (x *Value) GetTimestamp() int64 { + if x != nil { + if x, ok := x.Sum.(*Value_Timestamp); ok { + return x.Timestamp + } + } + return 0 +} + +func (x *Value) GetNumeric() string { + if x != nil { + if x, ok := x.Sum.(*Value_Numeric); ok { + return x.Numeric + } + } + return "" +} + +func (x *Value) GetParty() string { + if x != nil { + if x, ok := x.Sum.(*Value_Party); ok { + return x.Party + } + } + return "" +} + +func (x *Value) GetText() string { + if x != nil { + if x, ok := x.Sum.(*Value_Text); ok { + return x.Text + } + } + return "" +} + +func (x *Value) GetContractId() string { + if x != nil { + if x, ok := x.Sum.(*Value_ContractId); ok { + return x.ContractId + } + } + return "" +} + +func (x *Value) GetOptional() *Optional { + if x != nil { + if x, ok := x.Sum.(*Value_Optional); ok { + return x.Optional + } + } + return nil +} + +func (x *Value) GetList() *List { + if x != nil { + if x, ok := x.Sum.(*Value_List); ok { + return x.List + } + } + return nil +} + +func (x *Value) GetTextMap() *TextMap { + if x != nil { + if x, ok := x.Sum.(*Value_TextMap); ok { + return x.TextMap + } + } + return nil +} + +func (x *Value) GetGenMap() *GenMap { + if x != nil { + if x, ok := x.Sum.(*Value_GenMap); ok { + return x.GenMap + } + } + return nil +} + +func (x *Value) GetRecord() *Record { + if x != nil { + if x, ok := x.Sum.(*Value_Record); ok { + return x.Record + } + } + return nil +} + +func (x *Value) GetVariant() *Variant { + if x != nil { + if x, ok := x.Sum.(*Value_Variant); ok { + return x.Variant + } + } + return nil +} + +func (x *Value) GetEnum() *Enum { + if x != nil { + if x, ok := x.Sum.(*Value_Enum); ok { + return x.Enum + } + } + return nil +} + +type isValue_Sum interface { + isValue_Sum() +} + +type Value_Unit struct { + // This value is used for example for choices that don't take any arguments. + Unit *emptypb.Empty `protobuf:"bytes,1,opt,name=unit,proto3,oneof"` +} + +type Value_Bool struct { + // True or false. + Bool bool `protobuf:"varint,2,opt,name=bool,proto3,oneof"` +} + +type Value_Int64 struct { + Int64 int64 `protobuf:"zigzag64,3,opt,name=int64,proto3,oneof"` +} + +type Value_Date struct { + // Days since the unix epoch. Can go backwards. Limited from + // 0001-01-01 to 9999-12-31, also to be compatible with + // https://www.ietf.org/rfc/rfc3339.txt + Date int32 `protobuf:"varint,4,opt,name=date,proto3,oneof"` +} + +type Value_Timestamp struct { + // Microseconds since the UNIX epoch. Can go backwards. Fixed + // since the vast majority of values will be greater than + // 2^28, since currently the number of microseconds since the + // epoch is greater than that. Range: 0001-01-01T00:00:00Z to + // 9999-12-31T23:59:59.999999Z, so that we can convert to/from + // https://www.ietf.org/rfc/rfc3339.txt + Timestamp int64 `protobuf:"fixed64,5,opt,name=timestamp,proto3,oneof"` +} + +type Value_Numeric struct { + // A Numeric, that is a decimal value with precision 38 (at most 38 significant digits) and a + // scale between 0 and 37 (significant digits on the right of the decimal point). + // The field has to match the regex + // + // .. code-block:: none + // + // [+-]?\d{1,38}(.\d{0,37})? + // + // and should be representable by a Numeric without loss of precision. + Numeric string `protobuf:"bytes,6,opt,name=numeric,proto3,oneof"` +} + +type Value_Party struct { + // An agent operating on the ledger. + // Must be a valid PartyIdString. + Party string `protobuf:"bytes,7,opt,name=party,proto3,oneof"` +} + +type Value_Text struct { + // A string. + Text string `protobuf:"bytes,8,opt,name=text,proto3,oneof"` +} + +type Value_ContractId struct { + // Identifier of an on-ledger contract. Commands which reference an unknown or already archived contract ID will fail. + // Must be a valid LedgerString. + ContractId string `protobuf:"bytes,9,opt,name=contract_id,json=contractId,proto3,oneof"` +} + +type Value_Optional struct { + // The Optional type, None or Some + Optional *Optional `protobuf:"bytes,10,opt,name=optional,proto3,oneof"` +} + +type Value_List struct { + // Represents a homogeneous list of values. + List *List `protobuf:"bytes,11,opt,name=list,proto3,oneof"` +} + +type Value_TextMap struct { + // The TextMap type + TextMap *TextMap `protobuf:"bytes,12,opt,name=text_map,json=textMap,proto3,oneof"` +} + +type Value_GenMap struct { + // The GenMap type + GenMap *GenMap `protobuf:"bytes,13,opt,name=gen_map,json=genMap,proto3,oneof"` +} + +type Value_Record struct { + Record *Record `protobuf:"bytes,14,opt,name=record,proto3,oneof"` +} + +type Value_Variant struct { + Variant *Variant `protobuf:"bytes,15,opt,name=variant,proto3,oneof"` +} + +type Value_Enum struct { + // The Enum type + Enum *Enum `protobuf:"bytes,16,opt,name=enum,proto3,oneof"` +} + +func (*Value_Unit) isValue_Sum() {} + +func (*Value_Bool) isValue_Sum() {} + +func (*Value_Int64) isValue_Sum() {} + +func (*Value_Date) isValue_Sum() {} + +func (*Value_Timestamp) isValue_Sum() {} + +func (*Value_Numeric) isValue_Sum() {} + +func (*Value_Party) isValue_Sum() {} + +func (*Value_Text) isValue_Sum() {} + +func (*Value_ContractId) isValue_Sum() {} + +func (*Value_Optional) isValue_Sum() {} + +func (*Value_List) isValue_Sum() {} + +func (*Value_TextMap) isValue_Sum() {} + +func (*Value_GenMap) isValue_Sum() {} + +func (*Value_Record) isValue_Sum() {} + +func (*Value_Variant) isValue_Sum() {} + +func (*Value_Enum) isValue_Sum() {} + +// Contains nested values. +type Record struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Omitted from the transaction stream when verbose streaming is not enabled. + // Optional when submitting commands. + RecordId *Identifier `protobuf:"bytes,1,opt,name=record_id,json=recordId,proto3" json:"record_id,omitempty"` + // The nested values of the record. + // Required + Fields []*RecordField `protobuf:"bytes,2,rep,name=fields,proto3" json:"fields,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Record) Reset() { + *x = Record{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Record) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Record) ProtoMessage() {} + +func (x *Record) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Record.ProtoReflect.Descriptor instead. +func (*Record) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{1} +} + +func (x *Record) GetRecordId() *Identifier { + if x != nil { + return x.RecordId + } + return nil +} + +func (x *Record) GetFields() []*RecordField { + if x != nil { + return x.Fields + } + return nil +} + +// A named nested value within a record. +type RecordField struct { + state protoimpl.MessageState `protogen:"open.v1"` + // When reading a transaction stream, it's omitted if verbose streaming is not enabled. + // When submitting a command, it's optional: + // + // - if all keys within a single record are present, the order in which fields appear does not matter. however, each key must appear exactly once. + // - if any of the keys within a single record are omitted, the order of fields MUST match the order of declaration in the Daml template. + // + // Must be a valid NameString + Label string `protobuf:"bytes,1,opt,name=label,proto3" json:"label,omitempty"` + // A nested value of a record. + // Required + Value *Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RecordField) Reset() { + *x = RecordField{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RecordField) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RecordField) ProtoMessage() {} + +func (x *RecordField) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RecordField.ProtoReflect.Descriptor instead. +func (*RecordField) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{2} +} + +func (x *RecordField) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *RecordField) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +// Unique identifier of an entity. +// Throughout this API, the following terminology is being used: +// +// - if a Daml package-id is encoded in the package_id field, it is referred to as using a "package-id reference format" +// - if a Daml package-name is encoded in the package_id field, it is referred to as using a "package-name reference format" +type Identifier struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Generally, the identifier of the Daml package that contains the entity. + // When encoding a package-id, it must be a valid PackageIdString. + // + // The field is overloaded to also be able to contain the package-name of the Daml package. + // This is supported if the entity referenced is either an interface or template. + // When representing the Daml package-name, the encoding is of form `#` + // where `#` (not a valid package-id character) + // is used as a discriminator for signalling a package-name encoding. + // + // Required + PackageId string `protobuf:"bytes,1,opt,name=package_id,json=packageId,proto3" json:"package_id,omitempty"` + // The dot-separated module name of the identifier. + // Required + ModuleName string `protobuf:"bytes,2,opt,name=module_name,json=moduleName,proto3" json:"module_name,omitempty"` + // The dot-separated name of the entity (e.g. record, template, ...) within the module. + // Required + EntityName string `protobuf:"bytes,3,opt,name=entity_name,json=entityName,proto3" json:"entity_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Identifier) Reset() { + *x = Identifier{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Identifier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Identifier) ProtoMessage() {} + +func (x *Identifier) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Identifier.ProtoReflect.Descriptor instead. +func (*Identifier) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{3} +} + +func (x *Identifier) GetPackageId() string { + if x != nil { + return x.PackageId + } + return "" +} + +func (x *Identifier) GetModuleName() string { + if x != nil { + return x.ModuleName + } + return "" +} + +func (x *Identifier) GetEntityName() string { + if x != nil { + return x.EntityName + } + return "" +} + +// A value with alternative representations. +type Variant struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Omitted from the transaction stream when verbose streaming is not enabled. + // Optional when submitting commands. + VariantId *Identifier `protobuf:"bytes,1,opt,name=variant_id,json=variantId,proto3" json:"variant_id,omitempty"` + // Determines which of the Variant's alternatives is encoded in this message. + // Must be a valid NameString. + // Required + Constructor string `protobuf:"bytes,2,opt,name=constructor,proto3" json:"constructor,omitempty"` + // The value encoded within the Variant. + // Required + Value *Value `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Variant) Reset() { + *x = Variant{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Variant) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Variant) ProtoMessage() {} + +func (x *Variant) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Variant.ProtoReflect.Descriptor instead. +func (*Variant) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{4} +} + +func (x *Variant) GetVariantId() *Identifier { + if x != nil { + return x.VariantId + } + return nil +} + +func (x *Variant) GetConstructor() string { + if x != nil { + return x.Constructor + } + return "" +} + +func (x *Variant) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +// A value with finite set of alternative representations. +type Enum struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Omitted from the transaction stream when verbose streaming is not enabled. + // Optional when submitting commands. + EnumId *Identifier `protobuf:"bytes,1,opt,name=enum_id,json=enumId,proto3" json:"enum_id,omitempty"` + // Determines which of the Variant's alternatives is encoded in this message. + // Must be a valid NameString. + // Required + Constructor string `protobuf:"bytes,2,opt,name=constructor,proto3" json:"constructor,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Enum) Reset() { + *x = Enum{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Enum) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Enum) ProtoMessage() {} + +func (x *Enum) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Enum.ProtoReflect.Descriptor instead. +func (*Enum) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{5} +} + +func (x *Enum) GetEnumId() *Identifier { + if x != nil { + return x.EnumId + } + return nil +} + +func (x *Enum) GetConstructor() string { + if x != nil { + return x.Constructor + } + return "" +} + +// A homogenous collection of values. +type List struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The elements must all be of the same concrete value type. + // Optional + Elements []*Value `protobuf:"bytes,1,rep,name=elements,proto3" json:"elements,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *List) Reset() { + *x = List{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *List) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*List) ProtoMessage() {} + +func (x *List) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use List.ProtoReflect.Descriptor instead. +func (*List) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{6} +} + +func (x *List) GetElements() []*Value { + if x != nil { + return x.Elements + } + return nil +} + +// Corresponds to Java's Optional type, Scala's Option, and Haskell's Maybe. +// The reason why we need to wrap this in an additional “message“ is that we +// need to be able to encode the “None“ case in the “Value“ oneof. +type Optional struct { + state protoimpl.MessageState `protogen:"open.v1"` + Value *Value `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // optional + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Optional) Reset() { + *x = Optional{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Optional) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Optional) ProtoMessage() {} + +func (x *Optional) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Optional.ProtoReflect.Descriptor instead. +func (*Optional) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{7} +} + +func (x *Optional) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +type TextMap struct { + state protoimpl.MessageState `protogen:"open.v1"` + Entries []*TextMap_Entry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TextMap) Reset() { + *x = TextMap{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TextMap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TextMap) ProtoMessage() {} + +func (x *TextMap) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TextMap.ProtoReflect.Descriptor instead. +func (*TextMap) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{8} +} + +func (x *TextMap) GetEntries() []*TextMap_Entry { + if x != nil { + return x.Entries + } + return nil +} + +type GenMap struct { + state protoimpl.MessageState `protogen:"open.v1"` + Entries []*GenMap_Entry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GenMap) Reset() { + *x = GenMap{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenMap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenMap) ProtoMessage() {} + +func (x *GenMap) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenMap.ProtoReflect.Descriptor instead. +func (*GenMap) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{9} +} + +func (x *GenMap) GetEntries() []*GenMap_Entry { + if x != nil { + return x.Entries + } + return nil +} + +type TextMap_Entry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value *Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TextMap_Entry) Reset() { + *x = TextMap_Entry{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TextMap_Entry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TextMap_Entry) ProtoMessage() {} + +func (x *TextMap_Entry) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TextMap_Entry.ProtoReflect.Descriptor instead. +func (*TextMap_Entry) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{8, 0} +} + +func (x *TextMap_Entry) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *TextMap_Entry) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +type GenMap_Entry struct { + state protoimpl.MessageState `protogen:"open.v1"` + Key *Value `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value *Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GenMap_Entry) Reset() { + *x = GenMap_Entry{} + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GenMap_Entry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenMap_Entry) ProtoMessage() {} + +func (x *GenMap_Entry) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_value_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenMap_Entry.ProtoReflect.Descriptor instead. +func (*GenMap_Entry) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_value_proto_rawDescGZIP(), []int{9, 0} +} + +func (x *GenMap_Entry) GetKey() *Value { + if x != nil { + return x.Key + } + return nil +} + +func (x *GenMap_Entry) GetValue() *Value { + if x != nil { + return x.Value + } + return nil +} + +var File_com_daml_ledger_api_v2_value_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_value_proto_rawDesc = "" + + "\n" + + "\"com/daml/ledger/api/v2/value.proto\x12\x16com.daml.ledger.api.v2\x1a\x1bgoogle/protobuf/empty.proto\"\xad\x05\n" + + "\x05Value\x12,\n" + + "\x04unit\x18\x01 \x01(\v2\x16.google.protobuf.EmptyH\x00R\x04unit\x12\x14\n" + + "\x04bool\x18\x02 \x01(\bH\x00R\x04bool\x12\x1a\n" + + "\x05int64\x18\x03 \x01(\x12B\x020\x01H\x00R\x05int64\x12\x14\n" + + "\x04date\x18\x04 \x01(\x05H\x00R\x04date\x12\"\n" + + "\ttimestamp\x18\x05 \x01(\x10B\x020\x01H\x00R\ttimestamp\x12\x1a\n" + + "\anumeric\x18\x06 \x01(\tH\x00R\anumeric\x12\x16\n" + + "\x05party\x18\a \x01(\tH\x00R\x05party\x12\x14\n" + + "\x04text\x18\b \x01(\tH\x00R\x04text\x12!\n" + + "\vcontract_id\x18\t \x01(\tH\x00R\n" + + "contractId\x12>\n" + + "\boptional\x18\n" + + " \x01(\v2 .com.daml.ledger.api.v2.OptionalH\x00R\boptional\x122\n" + + "\x04list\x18\v \x01(\v2\x1c.com.daml.ledger.api.v2.ListH\x00R\x04list\x12<\n" + + "\btext_map\x18\f \x01(\v2\x1f.com.daml.ledger.api.v2.TextMapH\x00R\atextMap\x129\n" + + "\agen_map\x18\r \x01(\v2\x1e.com.daml.ledger.api.v2.GenMapH\x00R\x06genMap\x128\n" + + "\x06record\x18\x0e \x01(\v2\x1e.com.daml.ledger.api.v2.RecordH\x00R\x06record\x12;\n" + + "\avariant\x18\x0f \x01(\v2\x1f.com.daml.ledger.api.v2.VariantH\x00R\avariant\x122\n" + + "\x04enum\x18\x10 \x01(\v2\x1c.com.daml.ledger.api.v2.EnumH\x00R\x04enumB\x05\n" + + "\x03sum\"\x86\x01\n" + + "\x06Record\x12?\n" + + "\trecord_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\brecordId\x12;\n" + + "\x06fields\x18\x02 \x03(\v2#.com.daml.ledger.api.v2.RecordFieldR\x06fields\"X\n" + + "\vRecordField\x12\x14\n" + + "\x05label\x18\x01 \x01(\tR\x05label\x123\n" + + "\x05value\x18\x02 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x05value\"m\n" + + "\n" + + "Identifier\x12\x1d\n" + + "\n" + + "package_id\x18\x01 \x01(\tR\tpackageId\x12\x1f\n" + + "\vmodule_name\x18\x02 \x01(\tR\n" + + "moduleName\x12\x1f\n" + + "\ventity_name\x18\x03 \x01(\tR\n" + + "entityName\"\xa3\x01\n" + + "\aVariant\x12A\n" + + "\n" + + "variant_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\tvariantId\x12 \n" + + "\vconstructor\x18\x02 \x01(\tR\vconstructor\x123\n" + + "\x05value\x18\x03 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x05value\"e\n" + + "\x04Enum\x12;\n" + + "\aenum_id\x18\x01 \x01(\v2\".com.daml.ledger.api.v2.IdentifierR\x06enumId\x12 \n" + + "\vconstructor\x18\x02 \x01(\tR\vconstructor\"A\n" + + "\x04List\x129\n" + + "\belements\x18\x01 \x03(\v2\x1d.com.daml.ledger.api.v2.ValueR\belements\"?\n" + + "\bOptional\x123\n" + + "\x05value\x18\x01 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x05value\"\x9a\x01\n" + + "\aTextMap\x12?\n" + + "\aentries\x18\x01 \x03(\v2%.com.daml.ledger.api.v2.TextMap.EntryR\aentries\x1aN\n" + + "\x05Entry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x123\n" + + "\x05value\x18\x02 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x05value\"\xb7\x01\n" + + "\x06GenMap\x12>\n" + + "\aentries\x18\x01 \x03(\v2$.com.daml.ledger.api.v2.GenMap.EntryR\aentries\x1am\n" + + "\x05Entry\x12/\n" + + "\x03key\x18\x01 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x03key\x123\n" + + "\x05value\x18\x02 \x01(\v2\x1d.com.daml.ledger.api.v2.ValueR\x05valueB\xf7\x01\n" + + "\x1acom.com.daml.ledger.api.v2B\n" + + "ValueProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_value_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_value_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_value_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_value_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_value_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_value_proto_rawDesc), len(file_com_daml_ledger_api_v2_value_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_value_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_value_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_com_daml_ledger_api_v2_value_proto_goTypes = []any{ + (*Value)(nil), // 0: com.daml.ledger.api.v2.Value + (*Record)(nil), // 1: com.daml.ledger.api.v2.Record + (*RecordField)(nil), // 2: com.daml.ledger.api.v2.RecordField + (*Identifier)(nil), // 3: com.daml.ledger.api.v2.Identifier + (*Variant)(nil), // 4: com.daml.ledger.api.v2.Variant + (*Enum)(nil), // 5: com.daml.ledger.api.v2.Enum + (*List)(nil), // 6: com.daml.ledger.api.v2.List + (*Optional)(nil), // 7: com.daml.ledger.api.v2.Optional + (*TextMap)(nil), // 8: com.daml.ledger.api.v2.TextMap + (*GenMap)(nil), // 9: com.daml.ledger.api.v2.GenMap + (*TextMap_Entry)(nil), // 10: com.daml.ledger.api.v2.TextMap.Entry + (*GenMap_Entry)(nil), // 11: com.daml.ledger.api.v2.GenMap.Entry + (*emptypb.Empty)(nil), // 12: google.protobuf.Empty +} +var file_com_daml_ledger_api_v2_value_proto_depIdxs = []int32{ + 12, // 0: com.daml.ledger.api.v2.Value.unit:type_name -> google.protobuf.Empty + 7, // 1: com.daml.ledger.api.v2.Value.optional:type_name -> com.daml.ledger.api.v2.Optional + 6, // 2: com.daml.ledger.api.v2.Value.list:type_name -> com.daml.ledger.api.v2.List + 8, // 3: com.daml.ledger.api.v2.Value.text_map:type_name -> com.daml.ledger.api.v2.TextMap + 9, // 4: com.daml.ledger.api.v2.Value.gen_map:type_name -> com.daml.ledger.api.v2.GenMap + 1, // 5: com.daml.ledger.api.v2.Value.record:type_name -> com.daml.ledger.api.v2.Record + 4, // 6: com.daml.ledger.api.v2.Value.variant:type_name -> com.daml.ledger.api.v2.Variant + 5, // 7: com.daml.ledger.api.v2.Value.enum:type_name -> com.daml.ledger.api.v2.Enum + 3, // 8: com.daml.ledger.api.v2.Record.record_id:type_name -> com.daml.ledger.api.v2.Identifier + 2, // 9: com.daml.ledger.api.v2.Record.fields:type_name -> com.daml.ledger.api.v2.RecordField + 0, // 10: com.daml.ledger.api.v2.RecordField.value:type_name -> com.daml.ledger.api.v2.Value + 3, // 11: com.daml.ledger.api.v2.Variant.variant_id:type_name -> com.daml.ledger.api.v2.Identifier + 0, // 12: com.daml.ledger.api.v2.Variant.value:type_name -> com.daml.ledger.api.v2.Value + 3, // 13: com.daml.ledger.api.v2.Enum.enum_id:type_name -> com.daml.ledger.api.v2.Identifier + 0, // 14: com.daml.ledger.api.v2.List.elements:type_name -> com.daml.ledger.api.v2.Value + 0, // 15: com.daml.ledger.api.v2.Optional.value:type_name -> com.daml.ledger.api.v2.Value + 10, // 16: com.daml.ledger.api.v2.TextMap.entries:type_name -> com.daml.ledger.api.v2.TextMap.Entry + 11, // 17: com.daml.ledger.api.v2.GenMap.entries:type_name -> com.daml.ledger.api.v2.GenMap.Entry + 0, // 18: com.daml.ledger.api.v2.TextMap.Entry.value:type_name -> com.daml.ledger.api.v2.Value + 0, // 19: com.daml.ledger.api.v2.GenMap.Entry.key:type_name -> com.daml.ledger.api.v2.Value + 0, // 20: com.daml.ledger.api.v2.GenMap.Entry.value:type_name -> com.daml.ledger.api.v2.Value + 21, // [21:21] is the sub-list for method output_type + 21, // [21:21] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_value_proto_init() } +func file_com_daml_ledger_api_v2_value_proto_init() { + if File_com_daml_ledger_api_v2_value_proto != nil { + return + } + file_com_daml_ledger_api_v2_value_proto_msgTypes[0].OneofWrappers = []any{ + (*Value_Unit)(nil), + (*Value_Bool)(nil), + (*Value_Int64)(nil), + (*Value_Date)(nil), + (*Value_Timestamp)(nil), + (*Value_Numeric)(nil), + (*Value_Party)(nil), + (*Value_Text)(nil), + (*Value_ContractId)(nil), + (*Value_Optional)(nil), + (*Value_List)(nil), + (*Value_TextMap)(nil), + (*Value_GenMap)(nil), + (*Value_Record)(nil), + (*Value_Variant)(nil), + (*Value_Enum)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_value_proto_rawDesc), len(file_com_daml_ledger_api_v2_value_proto_rawDesc)), + NumEnums: 0, + NumMessages: 12, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_com_daml_ledger_api_v2_value_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_value_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_value_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_value_proto = out.File + file_com_daml_ledger_api_v2_value_proto_goTypes = nil + file_com_daml_ledger_api_v2_value_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/version_service.pb.go b/chain/canton/types/com/daml/ledger/api/v2/version_service.pb.go new file mode 100644 index 00000000..913785a5 --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/version_service.pb.go @@ -0,0 +1,538 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc (unknown) +// source: com/daml/ledger/api/v2/version_service.proto + +package apiv2 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetLedgerApiVersionRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLedgerApiVersionRequest) Reset() { + *x = GetLedgerApiVersionRequest{} + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLedgerApiVersionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLedgerApiVersionRequest) ProtoMessage() {} + +func (x *GetLedgerApiVersionRequest) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLedgerApiVersionRequest.ProtoReflect.Descriptor instead. +func (*GetLedgerApiVersionRequest) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP(), []int{0} +} + +type GetLedgerApiVersionResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The version of the ledger API. + // + // Required + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + // The features supported by this Ledger API endpoint. + // + // Daml applications CAN use the feature descriptor on top of + // version constraints on the Ledger API version to determine + // whether a given Ledger API endpoint supports the features + // required to run the application. + // + // See the feature descriptions themselves for the relation between + // Ledger API versions and feature presence. + // + // Required + Features *FeaturesDescriptor `protobuf:"bytes,2,opt,name=features,proto3" json:"features,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetLedgerApiVersionResponse) Reset() { + *x = GetLedgerApiVersionResponse{} + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetLedgerApiVersionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetLedgerApiVersionResponse) ProtoMessage() {} + +func (x *GetLedgerApiVersionResponse) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetLedgerApiVersionResponse.ProtoReflect.Descriptor instead. +func (*GetLedgerApiVersionResponse) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetLedgerApiVersionResponse) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *GetLedgerApiVersionResponse) GetFeatures() *FeaturesDescriptor { + if x != nil { + return x.Features + } + return nil +} + +type FeaturesDescriptor struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Features under development or features that are used + // for ledger implementation testing purposes only. + // + // Daml applications SHOULD not depend on these in production. + // + // Required + Experimental *ExperimentalFeatures `protobuf:"bytes,1,opt,name=experimental,proto3" json:"experimental,omitempty"` + // If set, then the Ledger API server supports user management. + // It is recommended that clients query this field to gracefully adjust their behavior for + // ledgers that do not support user management. + // + // Required + UserManagement *UserManagementFeature `protobuf:"bytes,2,opt,name=user_management,json=userManagement,proto3" json:"user_management,omitempty"` + // If set, then the Ledger API server supports party management configurability. + // It is recommended that clients query this field to gracefully adjust their behavior to + // maximum party page size. + // + // Required + PartyManagement *PartyManagementFeature `protobuf:"bytes,3,opt,name=party_management,json=partyManagement,proto3" json:"party_management,omitempty"` + // It contains the timeouts related to the periodic offset checkpoint emission + // + // Required + OffsetCheckpoint *OffsetCheckpointFeature `protobuf:"bytes,4,opt,name=offset_checkpoint,json=offsetCheckpoint,proto3" json:"offset_checkpoint,omitempty"` + // If set, then the Ledger API server supports package listing + // configurability. It is recommended that clients query this field to + // gracefully adjust their behavior to maximum package listing page size. + // + // Required + PackageFeature *PackageFeature `protobuf:"bytes,5,opt,name=package_feature,json=packageFeature,proto3" json:"package_feature,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FeaturesDescriptor) Reset() { + *x = FeaturesDescriptor{} + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FeaturesDescriptor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FeaturesDescriptor) ProtoMessage() {} + +func (x *FeaturesDescriptor) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FeaturesDescriptor.ProtoReflect.Descriptor instead. +func (*FeaturesDescriptor) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP(), []int{2} +} + +func (x *FeaturesDescriptor) GetExperimental() *ExperimentalFeatures { + if x != nil { + return x.Experimental + } + return nil +} + +func (x *FeaturesDescriptor) GetUserManagement() *UserManagementFeature { + if x != nil { + return x.UserManagement + } + return nil +} + +func (x *FeaturesDescriptor) GetPartyManagement() *PartyManagementFeature { + if x != nil { + return x.PartyManagement + } + return nil +} + +func (x *FeaturesDescriptor) GetOffsetCheckpoint() *OffsetCheckpointFeature { + if x != nil { + return x.OffsetCheckpoint + } + return nil +} + +func (x *FeaturesDescriptor) GetPackageFeature() *PackageFeature { + if x != nil { + return x.PackageFeature + } + return nil +} + +type UserManagementFeature struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Whether the Ledger API server provides the user management service. + // + // Required + Supported bool `protobuf:"varint,1,opt,name=supported,proto3" json:"supported,omitempty"` + // The maximum number of rights that can be assigned to a single user. + // Servers MUST support at least 100 rights per user. + // A value of 0 means that the server enforces no rights per user limit. + // + // Required + MaxRightsPerUser int32 `protobuf:"varint,2,opt,name=max_rights_per_user,json=maxRightsPerUser,proto3" json:"max_rights_per_user,omitempty"` + // The maximum number of users the server can return in a single response (page). + // Servers MUST support at least a 100 users per page. + // A value of 0 means that the server enforces no page size limit. + // + // Required + MaxUsersPageSize int32 `protobuf:"varint,3,opt,name=max_users_page_size,json=maxUsersPageSize,proto3" json:"max_users_page_size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UserManagementFeature) Reset() { + *x = UserManagementFeature{} + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UserManagementFeature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserManagementFeature) ProtoMessage() {} + +func (x *UserManagementFeature) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserManagementFeature.ProtoReflect.Descriptor instead. +func (*UserManagementFeature) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP(), []int{3} +} + +func (x *UserManagementFeature) GetSupported() bool { + if x != nil { + return x.Supported + } + return false +} + +func (x *UserManagementFeature) GetMaxRightsPerUser() int32 { + if x != nil { + return x.MaxRightsPerUser + } + return 0 +} + +func (x *UserManagementFeature) GetMaxUsersPageSize() int32 { + if x != nil { + return x.MaxUsersPageSize + } + return 0 +} + +type PartyManagementFeature struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The maximum number of parties the server can return in a single response (page). + // + // Required + MaxPartiesPageSize int32 `protobuf:"varint,1,opt,name=max_parties_page_size,json=maxPartiesPageSize,proto3" json:"max_parties_page_size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PartyManagementFeature) Reset() { + *x = PartyManagementFeature{} + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PartyManagementFeature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PartyManagementFeature) ProtoMessage() {} + +func (x *PartyManagementFeature) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PartyManagementFeature.ProtoReflect.Descriptor instead. +func (*PartyManagementFeature) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP(), []int{4} +} + +func (x *PartyManagementFeature) GetMaxPartiesPageSize() int32 { + if x != nil { + return x.MaxPartiesPageSize + } + return 0 +} + +type PackageFeature struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The maximum number of vetted packages the server can return in a single + // response (page) when listing them. + // + // Required + MaxVettedPackagesPageSize int32 `protobuf:"varint,1,opt,name=max_vetted_packages_page_size,json=maxVettedPackagesPageSize,proto3" json:"max_vetted_packages_page_size,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PackageFeature) Reset() { + *x = PackageFeature{} + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PackageFeature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PackageFeature) ProtoMessage() {} + +func (x *PackageFeature) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PackageFeature.ProtoReflect.Descriptor instead. +func (*PackageFeature) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP(), []int{5} +} + +func (x *PackageFeature) GetMaxVettedPackagesPageSize() int32 { + if x != nil { + return x.MaxVettedPackagesPageSize + } + return 0 +} + +type OffsetCheckpointFeature struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The maximum delay to emmit a new OffsetCheckpoint if it exists + // + // Required + MaxOffsetCheckpointEmissionDelay *durationpb.Duration `protobuf:"bytes,1,opt,name=max_offset_checkpoint_emission_delay,json=maxOffsetCheckpointEmissionDelay,proto3" json:"max_offset_checkpoint_emission_delay,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *OffsetCheckpointFeature) Reset() { + *x = OffsetCheckpointFeature{} + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *OffsetCheckpointFeature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OffsetCheckpointFeature) ProtoMessage() {} + +func (x *OffsetCheckpointFeature) ProtoReflect() protoreflect.Message { + mi := &file_com_daml_ledger_api_v2_version_service_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OffsetCheckpointFeature.ProtoReflect.Descriptor instead. +func (*OffsetCheckpointFeature) Descriptor() ([]byte, []int) { + return file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP(), []int{6} +} + +func (x *OffsetCheckpointFeature) GetMaxOffsetCheckpointEmissionDelay() *durationpb.Duration { + if x != nil { + return x.MaxOffsetCheckpointEmissionDelay + } + return nil +} + +var File_com_daml_ledger_api_v2_version_service_proto protoreflect.FileDescriptor + +const file_com_daml_ledger_api_v2_version_service_proto_rawDesc = "" + + "\n" + + ",com/daml/ledger/api/v2/version_service.proto\x12\x16com.daml.ledger.api.v2\x1a2com/daml/ledger/api/v2/experimental_features.proto\x1a\x1egoogle/protobuf/duration.proto\"\x1c\n" + + "\x1aGetLedgerApiVersionRequest\"\x7f\n" + + "\x1bGetLedgerApiVersionResponse\x12\x18\n" + + "\aversion\x18\x01 \x01(\tR\aversion\x12F\n" + + "\bfeatures\x18\x02 \x01(\v2*.com.daml.ledger.api.v2.FeaturesDescriptorR\bfeatures\"\xc8\x03\n" + + "\x12FeaturesDescriptor\x12P\n" + + "\fexperimental\x18\x01 \x01(\v2,.com.daml.ledger.api.v2.ExperimentalFeaturesR\fexperimental\x12V\n" + + "\x0fuser_management\x18\x02 \x01(\v2-.com.daml.ledger.api.v2.UserManagementFeatureR\x0euserManagement\x12Y\n" + + "\x10party_management\x18\x03 \x01(\v2..com.daml.ledger.api.v2.PartyManagementFeatureR\x0fpartyManagement\x12\\\n" + + "\x11offset_checkpoint\x18\x04 \x01(\v2/.com.daml.ledger.api.v2.OffsetCheckpointFeatureR\x10offsetCheckpoint\x12O\n" + + "\x0fpackage_feature\x18\x05 \x01(\v2&.com.daml.ledger.api.v2.PackageFeatureR\x0epackageFeature\"\x93\x01\n" + + "\x15UserManagementFeature\x12\x1c\n" + + "\tsupported\x18\x01 \x01(\bR\tsupported\x12-\n" + + "\x13max_rights_per_user\x18\x02 \x01(\x05R\x10maxRightsPerUser\x12-\n" + + "\x13max_users_page_size\x18\x03 \x01(\x05R\x10maxUsersPageSize\"K\n" + + "\x16PartyManagementFeature\x121\n" + + "\x15max_parties_page_size\x18\x01 \x01(\x05R\x12maxPartiesPageSize\"R\n" + + "\x0ePackageFeature\x12@\n" + + "\x1dmax_vetted_packages_page_size\x18\x01 \x01(\x05R\x19maxVettedPackagesPageSize\"\x84\x01\n" + + "\x17OffsetCheckpointFeature\x12i\n" + + "$max_offset_checkpoint_emission_delay\x18\x01 \x01(\v2\x19.google.protobuf.DurationR maxOffsetCheckpointEmissionDelay2\x90\x01\n" + + "\x0eVersionService\x12~\n" + + "\x13GetLedgerApiVersion\x122.com.daml.ledger.api.v2.GetLedgerApiVersionRequest\x1a3.com.daml.ledger.api.v2.GetLedgerApiVersionResponseB\x80\x02\n" + + "\x1acom.com.daml.ledger.api.v2B\x13VersionServiceProtoP\x01ZPgithub.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2;apiv2\xa2\x02\x04CDLA\xaa\x02\x16Com.Daml.Ledger.Api.V2\xca\x02\x16Com\\Daml\\Ledger\\Api\\V2\xe2\x02\"Com\\Daml\\Ledger\\Api\\V2\\GPBMetadata\xea\x02\x1aCom::Daml::Ledger::Api::V2b\x06proto3" + +var ( + file_com_daml_ledger_api_v2_version_service_proto_rawDescOnce sync.Once + file_com_daml_ledger_api_v2_version_service_proto_rawDescData []byte +) + +func file_com_daml_ledger_api_v2_version_service_proto_rawDescGZIP() []byte { + file_com_daml_ledger_api_v2_version_service_proto_rawDescOnce.Do(func() { + file_com_daml_ledger_api_v2_version_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_version_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_version_service_proto_rawDesc))) + }) + return file_com_daml_ledger_api_v2_version_service_proto_rawDescData +} + +var file_com_daml_ledger_api_v2_version_service_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_com_daml_ledger_api_v2_version_service_proto_goTypes = []any{ + (*GetLedgerApiVersionRequest)(nil), // 0: com.daml.ledger.api.v2.GetLedgerApiVersionRequest + (*GetLedgerApiVersionResponse)(nil), // 1: com.daml.ledger.api.v2.GetLedgerApiVersionResponse + (*FeaturesDescriptor)(nil), // 2: com.daml.ledger.api.v2.FeaturesDescriptor + (*UserManagementFeature)(nil), // 3: com.daml.ledger.api.v2.UserManagementFeature + (*PartyManagementFeature)(nil), // 4: com.daml.ledger.api.v2.PartyManagementFeature + (*PackageFeature)(nil), // 5: com.daml.ledger.api.v2.PackageFeature + (*OffsetCheckpointFeature)(nil), // 6: com.daml.ledger.api.v2.OffsetCheckpointFeature + (*ExperimentalFeatures)(nil), // 7: com.daml.ledger.api.v2.ExperimentalFeatures + (*durationpb.Duration)(nil), // 8: google.protobuf.Duration +} +var file_com_daml_ledger_api_v2_version_service_proto_depIdxs = []int32{ + 2, // 0: com.daml.ledger.api.v2.GetLedgerApiVersionResponse.features:type_name -> com.daml.ledger.api.v2.FeaturesDescriptor + 7, // 1: com.daml.ledger.api.v2.FeaturesDescriptor.experimental:type_name -> com.daml.ledger.api.v2.ExperimentalFeatures + 3, // 2: com.daml.ledger.api.v2.FeaturesDescriptor.user_management:type_name -> com.daml.ledger.api.v2.UserManagementFeature + 4, // 3: com.daml.ledger.api.v2.FeaturesDescriptor.party_management:type_name -> com.daml.ledger.api.v2.PartyManagementFeature + 6, // 4: com.daml.ledger.api.v2.FeaturesDescriptor.offset_checkpoint:type_name -> com.daml.ledger.api.v2.OffsetCheckpointFeature + 5, // 5: com.daml.ledger.api.v2.FeaturesDescriptor.package_feature:type_name -> com.daml.ledger.api.v2.PackageFeature + 8, // 6: com.daml.ledger.api.v2.OffsetCheckpointFeature.max_offset_checkpoint_emission_delay:type_name -> google.protobuf.Duration + 0, // 7: com.daml.ledger.api.v2.VersionService.GetLedgerApiVersion:input_type -> com.daml.ledger.api.v2.GetLedgerApiVersionRequest + 1, // 8: com.daml.ledger.api.v2.VersionService.GetLedgerApiVersion:output_type -> com.daml.ledger.api.v2.GetLedgerApiVersionResponse + 8, // [8:9] is the sub-list for method output_type + 7, // [7:8] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_com_daml_ledger_api_v2_version_service_proto_init() } +func file_com_daml_ledger_api_v2_version_service_proto_init() { + if File_com_daml_ledger_api_v2_version_service_proto != nil { + return + } + file_com_daml_ledger_api_v2_experimental_features_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_com_daml_ledger_api_v2_version_service_proto_rawDesc), len(file_com_daml_ledger_api_v2_version_service_proto_rawDesc)), + NumEnums: 0, + NumMessages: 7, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_com_daml_ledger_api_v2_version_service_proto_goTypes, + DependencyIndexes: file_com_daml_ledger_api_v2_version_service_proto_depIdxs, + MessageInfos: file_com_daml_ledger_api_v2_version_service_proto_msgTypes, + }.Build() + File_com_daml_ledger_api_v2_version_service_proto = out.File + file_com_daml_ledger_api_v2_version_service_proto_goTypes = nil + file_com_daml_ledger_api_v2_version_service_proto_depIdxs = nil +} diff --git a/chain/canton/types/com/daml/ledger/api/v2/version_service_grpc.pb.go b/chain/canton/types/com/daml/ledger/api/v2/version_service_grpc.pb.go new file mode 100644 index 00000000..63ba19ef --- /dev/null +++ b/chain/canton/types/com/daml/ledger/api/v2/version_service_grpc.pb.go @@ -0,0 +1,130 @@ +// Copyright (c) 2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc (unknown) +// source: com/daml/ledger/api/v2/version_service.proto + +package apiv2 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + VersionService_GetLedgerApiVersion_FullMethodName = "/com.daml.ledger.api.v2.VersionService/GetLedgerApiVersion" +) + +// VersionServiceClient is the client API for VersionService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// Allows clients to retrieve information about the ledger API version +type VersionServiceClient interface { + // Read the Ledger API version + GetLedgerApiVersion(ctx context.Context, in *GetLedgerApiVersionRequest, opts ...grpc.CallOption) (*GetLedgerApiVersionResponse, error) +} + +type versionServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewVersionServiceClient(cc grpc.ClientConnInterface) VersionServiceClient { + return &versionServiceClient{cc} +} + +func (c *versionServiceClient) GetLedgerApiVersion(ctx context.Context, in *GetLedgerApiVersionRequest, opts ...grpc.CallOption) (*GetLedgerApiVersionResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(GetLedgerApiVersionResponse) + err := c.cc.Invoke(ctx, VersionService_GetLedgerApiVersion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// VersionServiceServer is the server API for VersionService service. +// All implementations must embed UnimplementedVersionServiceServer +// for forward compatibility. +// +// Allows clients to retrieve information about the ledger API version +type VersionServiceServer interface { + // Read the Ledger API version + GetLedgerApiVersion(context.Context, *GetLedgerApiVersionRequest) (*GetLedgerApiVersionResponse, error) + mustEmbedUnimplementedVersionServiceServer() +} + +// UnimplementedVersionServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedVersionServiceServer struct{} + +func (UnimplementedVersionServiceServer) GetLedgerApiVersion(context.Context, *GetLedgerApiVersionRequest) (*GetLedgerApiVersionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetLedgerApiVersion not implemented") +} +func (UnimplementedVersionServiceServer) mustEmbedUnimplementedVersionServiceServer() {} +func (UnimplementedVersionServiceServer) testEmbeddedByValue() {} + +// UnsafeVersionServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to VersionServiceServer will +// result in compilation errors. +type UnsafeVersionServiceServer interface { + mustEmbedUnimplementedVersionServiceServer() +} + +func RegisterVersionServiceServer(s grpc.ServiceRegistrar, srv VersionServiceServer) { + // If the following call pancis, it indicates UnimplementedVersionServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&VersionService_ServiceDesc, srv) +} + +func _VersionService_GetLedgerApiVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetLedgerApiVersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(VersionServiceServer).GetLedgerApiVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: VersionService_GetLedgerApiVersion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(VersionServiceServer).GetLedgerApiVersion(ctx, req.(*GetLedgerApiVersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// VersionService_ServiceDesc is the grpc.ServiceDesc for VersionService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var VersionService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "com.daml.ledger.api.v2.VersionService", + HandlerType: (*VersionServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetLedgerApiVersion", + Handler: _VersionService_GetLedgerApiVersion_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "com/daml/ledger/api/v2/version_service.proto", +} diff --git a/chain/canton/proto/helpers.go b/chain/canton/types/helpers.go similarity index 94% rename from chain/canton/proto/helpers.go rename to chain/canton/types/helpers.go index 6affd91c..e0d60e15 100644 --- a/chain/canton/proto/helpers.go +++ b/chain/canton/types/helpers.go @@ -1,13 +1,13 @@ -package proto +package types import ( "crypto/rand" "fmt" "time" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" "google.golang.org/protobuf/types/known/durationpb" ) diff --git a/chain/canton/proto/helpers_test.go b/chain/canton/types/helpers_test.go similarity index 92% rename from chain/canton/proto/helpers_test.go rename to chain/canton/types/helpers_test.go index db93bef0..f5fb527d 100644 --- a/chain/canton/proto/helpers_test.go +++ b/chain/canton/types/helpers_test.go @@ -1,11 +1,11 @@ -package proto +package types import ( "testing" "time" - v2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/interactive" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" "github.com/stretchr/testify/require" ) diff --git a/go.mod b/go.mod index c2b5da26..c3861ab2 100644 --- a/go.mod +++ b/go.mod @@ -71,7 +71,6 @@ require ( github.com/harshavardhana/blake2b-simd v0.0.0-20160628082310-f6a3512276ac github.com/holiman/uint256 v1.3.2 github.com/kaspanet/kaspad v0.12.22 - github.com/noders-team/go-daml v0.6.1 github.com/pkg/errors v0.9.1 github.com/vmihailenco/msgpack/v5 v5.4.1 golang.org/x/time v0.9.0 @@ -141,7 +140,6 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgraph-io/badger/v4 v4.5.0 // indirect github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect - github.com/digital-asset/dazl-client/v8 v8.9.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/emicklei/dot v1.6.2 // indirect diff --git a/go.sum b/go.sum index e1ebfa11..a6e48eab 100644 --- a/go.sum +++ b/go.sum @@ -244,8 +244,6 @@ cosmossdk.io/x/tx v1.0.0-alpha.3 h1:+55/JFH5QRqnFhOI2heH3DKsaNL0RpXcJOQNzUvHiaQ= cosmossdk.io/x/tx v1.0.0-alpha.3/go.mod h1:h4pQ/j6Gfu8goB1R3Jbl4qY4RjYVNAsoylcleTXdSRg= cosmossdk.io/x/upgrade v0.2.0-rc.1 h1:YO865mCFIsFyjzl1fOsOr7Hw2iVGJhTGwecUC3u0YBY= cosmossdk.io/x/upgrade v0.2.0-rc.1/go.mod h1:xt0idx/1eRsn5C9/YHubGBE5j5goZTgaKu1HNOXgdac= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -339,8 +337,6 @@ github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEe github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.2-0.20240711233432-c7949e1f6b9a h1:rNUteH7x0G1/4zorsH0yXDx5e6vuAkSWWD/z70v5vx8= github.com/centrifuge/go-substrate-rpc-client/v4 v4.2.2-0.20240711233432-c7949e1f6b9a/go.mod h1:k61SBXqYmnZO4frAJyH3iuqjolYrYsq79r8EstmklDY= @@ -402,8 +398,8 @@ github.com/consensys/bavard v0.1.30 h1:wwAj9lSnMLFXjEclKwyhf7Oslg8EoaFz9u1QGgt0b github.com/consensys/bavard v0.1.30/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= github.com/consensys/gnark-crypto v0.17.0 h1:vKDhZMOrySbpZDCvGMOELrHFv/A9mJ7+9I8HEfRZSkI= github.com/consensys/gnark-crypto v0.17.0/go.mod h1:A2URlMHUT81ifJ0UlLzSlm7TmnE3t7VxEThApdMukJw= -github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= -github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/cordialsys/go-aptos-sdk v0.0.0-20250509215447-cc739925dd04 h1:k2/8TDHfPX3zA5GABSEhbVNBNiW0aNOy7nZQQuoittg= github.com/cordialsys/go-aptos-sdk v0.0.0-20250509215447-cc739925dd04/go.mod h1:hzXqFO40XA/kcmAP26WDJmc7WiJcoLZlnvR0ZVWXu9g= github.com/cordialsys/go-json v0.10.5-sonic-replace h1:9wdSnZ7KBekIZ9tLiCEQAkY6kEHp44IdcQFnKUNSxLI= @@ -474,16 +470,8 @@ github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMb github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/digital-asset/dazl-client/v8 v8.7.1 h1:W/U9xRoreGOq9kfcgwLkcHphp/dPxQrPBldsoBqtt9U= -github.com/digital-asset/dazl-client/v8 v8.7.1/go.mod h1:q1KevCJ8FpH8je2MnnjN8/QUfhstB4fKpyKyqDtqFh0= -github.com/digital-asset/dazl-client/v8 v8.9.0 h1:F2qTUWtHAjhGyRGV+xTim+VAFwM99FpcOx4+wowvPnY= -github.com/digital-asset/dazl-client/v8 v8.9.0/go.mod h1:q1KevCJ8FpH8je2MnnjN8/QUfhstB4fKpyKyqDtqFh0= -github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= -github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= -github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -574,8 +562,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= -github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -685,8 +671,6 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -915,12 +899,6 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= -github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= -github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= -github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -938,8 +916,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/noders-team/go-daml v0.6.1 h1:TIDliHjkq8I6o0/rFJR2CYfPCESp8sO3+ZNiqy2Pv/U= -github.com/noders-team/go-daml v0.6.1/go.mod h1:QeH3C2liWjY0Ik9Yl0DXpgROXO9bIbM8MvkQA58Bw9M= github.com/novifinancial/serde-reflection/serde-generate/runtime/golang v0.0.0-20220519162058-e5cd3c3b3f3a h1:oMG8C4E7DFkat7WQicw4JNa/dYUaqO7RvLPbkFdADIA= github.com/novifinancial/serde-reflection/serde-generate/runtime/golang v0.0.0-20220519162058-e5cd3c3b3f3a/go.mod h1:NrRYJCFtaewjIRr4B9V2AyWsAEMW0Zqdjs8Bm+bACbM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -969,16 +945,14 @@ github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA= github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= -github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= -github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= +github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= -github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= @@ -1144,12 +1118,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdrpp/goxdr v0.1.1 h1:E1B2c6E8eYhOVyd7yEpOyopzTPirUeF6mVOfXfGyJyc= github.com/xdrpp/goxdr v0.1.1/go.mod h1:dXo1scL/l6s7iME1gxHWo2XCppbHEKZS7m/KyYWkNzA= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xssnick/tonutils-go v1.9.8 h1:Sq382w8H63sjy5y+j13b9mytHPLf7H94LW+OmxZ4h/c= From e5aefb9e965a2e1489f2426c493ce95489d6d45b Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Thu, 2 Apr 2026 19:11:05 -0400 Subject: [PATCH 21/23] canton: some cleanup --- chain/canton/address/address.go | 39 ++- chain/canton/address/address_test.go | 21 ++ chain/canton/client/client.go | 21 +- chain/canton/client/client_test.go | 6 +- chain/canton/tx/create_account_tx.go | 50 +-- chain/canton/tx/create_account_tx_test.go | 32 +- chain/canton/tx/hash_validation_test.go | 255 ++++++++++++++++ .../canton/{tx_input => tx}/topology_hash.go | 2 +- chain/canton/tx/topology_hash_test.go | 61 ++++ chain/canton/tx/tx_test.go | 5 +- chain/canton/tx_input/create_account_input.go | 27 +- .../tx_input/create_account_input_test.go | 3 +- chain/canton/tx_input/hash_validation_test.go | 285 ------------------ .../testdata/live_topology_vector.json | 7 - chain/canton/tx_input/topology_hash_test.go | 62 ---- chain/canton/tx_input/tx_input.go | 4 + 16 files changed, 430 insertions(+), 450 deletions(-) create mode 100644 chain/canton/tx/hash_validation_test.go rename chain/canton/{tx_input => tx}/topology_hash.go (98%) create mode 100644 chain/canton/tx/topology_hash_test.go delete mode 100644 chain/canton/tx_input/hash_validation_test.go delete mode 100644 chain/canton/tx_input/testdata/live_topology_vector.json delete mode 100644 chain/canton/tx_input/topology_hash_test.go diff --git a/chain/canton/address/address.go b/chain/canton/address/address.go index a865e24e..0e1c6b9e 100644 --- a/chain/canton/address/address.go +++ b/chain/canton/address/address.go @@ -34,10 +34,10 @@ func NewAddressBuilder(cfgI *xc.ChainBaseConfig) (xc.AddressBuilder, error) { // - 0x12 = SHA-256 algorithm code (varint) // - 0x20 = 32-byte digest length (varint) func (ab AddressBuilder) GetAddressFromPublicKey(publicKeyBytes []byte) (xc.Address, error) { - if len(publicKeyBytes) != 32 { - return "", fmt.Errorf("invalid ed25519 public key length: expected 32 bytes, got %d", len(publicKeyBytes)) + fingerprint, err := FingerprintFromPublicKey(publicKeyBytes) + if err != nil { + return "", err } - fingerprint := computeFingerprint(publicKeyBytes) name := hex.EncodeToString(publicKeyBytes) addr := xc.Address(name + "::" + fingerprint) @@ -48,10 +48,11 @@ func (ab AddressBuilder) AddressRegistrationRequired(address xc.Address) bool { return true } -// computeFingerprint returns the Canton key fingerprint for a raw Ed25519 public key. -// -// fingerprint = "1220" + hex(SHA-256(bigEndianUint32(12) || rawPubKey)) -func computeFingerprint(rawPubKey []byte) string { +// FingerprintFromPublicKey returns the Canton key fingerprint for a raw Ed25519 public key. +func FingerprintFromPublicKey(rawPubKey []byte) (string, error) { + if len(rawPubKey) != 32 { + return "", fmt.Errorf("invalid ed25519 public key length: expected 32 bytes, got %d", len(rawPubKey)) + } // HashPurpose.PublicKeyFingerprint id=12 encoded as big-endian int32 (4 bytes) var purposeBytes [4]byte binary.BigEndian.PutUint32(purposeBytes[:], 12) @@ -62,7 +63,29 @@ func computeFingerprint(rawPubKey []byte) string { digest := h.Sum(nil) // Multihash: varint(0x12=SHA-256) || varint(0x20=32) || digest - return "1220" + hex.EncodeToString(digest) + return "1220" + hex.EncodeToString(digest), nil +} + +// FingerprintFromPartyID recomputes the Canton key fingerprint from a party ID +// whose name segment is the hex-encoded Ed25519 public key produced by AddressBuilder. +func FingerprintFromPartyID(addr xc.Address) (string, error) { + name, fingerprint, err := ParsePartyID(addr) + if err != nil { + return "", err + } + + publicKeyBytes, err := hex.DecodeString(name) + if err != nil { + return "", fmt.Errorf("invalid Canton party name %q: expected hex-encoded public key: %w", name, err) + } + computed, err := FingerprintFromPublicKey(publicKeyBytes) + if err != nil { + return "", err + } + if computed != fingerprint { + return "", fmt.Errorf("canton party fingerprint mismatch: computed %q from address public key, got %q", computed, fingerprint) + } + return computed, nil } // ParsePartyID splits a Canton party ID into its name and fingerprint components. diff --git a/chain/canton/address/address_test.go b/chain/canton/address/address_test.go index 1e6bc283..7b502a64 100644 --- a/chain/canton/address/address_test.go +++ b/chain/canton/address/address_test.go @@ -36,6 +36,27 @@ func TestGetAddressFromPublicKey(t *testing.T) { require.Equal(t, "122093aa96c5554371f0d1fd471ce282f3b590ab0758f35c124924c8e3715910bbe1", fingerprint) } +func TestFingerprintFromPublicKey(t *testing.T) { + t.Parallel() + + publicKeyBytes, err := hex.DecodeString("e5c86207770b9fb67d73eb4cb8cd6a5f6a5d6a63c66a5459bd77cca45fda6ede") + require.NoError(t, err) + + fingerprint, err := FingerprintFromPublicKey(publicKeyBytes) + require.NoError(t, err) + require.Equal(t, "122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8", fingerprint) +} + +func TestFingerprintFromPartyID(t *testing.T) { + t.Parallel() + + addr := xc.Address("e5c86207770b9fb67d73eb4cb8cd6a5f6a5d6a63c66a5459bd77cca45fda6ede::122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8") + + fingerprint, err := FingerprintFromPartyID(addr) + require.NoError(t, err) + require.Equal(t, "122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8", fingerprint) +} + func TestParsePartyID(t *testing.T) { validFP := "1220" + hex.EncodeToString(make([]byte, 32)) // "1220" + 64 zeros diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 069cee35..26bbea73 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -890,11 +890,7 @@ func (client *Client) FetchBlock(ctx context.Context, args *xclient.BlockArgs) ( // KeyFingerprintFromAddress extracts the key fingerprint from a Canton party address func KeyFingerprintFromAddress(addr xc.Address) (string, error) { - _, fingerprint, err := cantonaddress.ParsePartyID(addr) - if err != nil { - return "", err - } - return fingerprint, nil + return cantonaddress.FingerprintFromPartyID(addr) } var _ xclient.CreateAccountClient = &Client{} @@ -1005,16 +1001,11 @@ func (client *Client) FetchCreateAccountInput(ctx context.Context, args *xclient "multihash_len": len(topologyResp.GetMultiHash()), }).Info("create-account: generated external party topology") - txns := make([][]byte, 0, len(topologyResp.GetTopologyTransactions())) - for _, txBytes := range topologyResp.GetTopologyTransactions() { - txns = append(txns, txBytes) - } - input := &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAllocate, PartyID: partyID, PublicKeyFingerprint: topologyResp.GetPublicKeyFingerprint(), - TopologyTransactions: txns, + TopologyTransactions: topologyResp.GetTopologyTransactions(), } if err := input.VerifySignaturePayloads(); err != nil { @@ -1126,7 +1117,11 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx if err != nil { return fmt.Errorf("failed to resolve synchronizer for external party allocation: %w", err) } - req := cantonproto.NewAllocateExternalPartyRequest(synchronizerID, cantonInput.TopologyTransactions, cantonInput.Signature, cantonInput.PublicKeyFingerprint) + keyFingerprint, err := cantonaddress.FingerprintFromPartyID(xc.Address(createAccountTx.Input.PartyID)) + if err != nil { + return fmt.Errorf("failed to compute key fingerprint from party ID: %w", err) + } + req := cantonproto.NewAllocateExternalPartyRequest(synchronizerID, cantonInput.TopologyTransactions, cantonInput.Signature, keyFingerprint) _, err = client.ledgerClient.AllocateExternalParty(ctx, req) if err != nil && !isAlreadyExists(err) { return fmt.Errorf("AllocateExternalParty failed: %w", err) @@ -1137,7 +1132,7 @@ func (client *Client) submitCreateAccountTx(ctx context.Context, createAccountTx if err := proto.Unmarshal(cantonInput.SetupProposalPreparedTransaction, &preparedTx); err != nil { return fmt.Errorf("failed to unmarshal setup proposal prepared transaction: %w", err) } - keyFingerprint, err := createAccountTx.KeyFingerprint() + keyFingerprint, err := KeyFingerprintFromAddress(xc.Address(cantonInput.PartyID)) if err != nil { return fmt.Errorf("failed to determine signing fingerprint for setup proposal accept: %w", err) } diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index f1d4cb22..a0fc6899 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -628,8 +628,7 @@ func mustSerializedCreateAccountInput(t *testing.T) []byte { t.Helper() input := &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAllocate, - PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PartyID: "e5c86207770b9fb67d73eb4cb8cd6a5f6a5d6a63c66a5459bd77cca45fda6ede::122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8", TopologyTransactions: [][]byte{{0x01}}, } bz, err := input.Serialize() @@ -641,8 +640,7 @@ func mustSerializedCreateAccountTx(t *testing.T) ([]byte, []byte) { t.Helper() input := &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAllocate, - PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PartyID: "e5c86207770b9fb67d73eb4cb8cd6a5f6a5d6a63c66a5459bd77cca45fda6ede::122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8", TopologyTransactions: [][]byte{{0x01}}, } args, err := xcbuilder.NewCreateAccountArgs(xc.CANTON, xc.Address(input.PartyID), []byte{0x01, 0x02}) diff --git a/chain/canton/tx/create_account_tx.go b/chain/canton/tx/create_account_tx.go index 953912b1..cf06eb1c 100644 --- a/chain/canton/tx/create_account_tx.go +++ b/chain/canton/tx/create_account_tx.go @@ -7,8 +7,10 @@ import ( xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" - cantonaddress "github.com/cordialsys/crosschain/chain/canton/address" "github.com/cordialsys/crosschain/chain/canton/tx_input" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" + "github.com/cordialsys/crosschain/testutil" + "google.golang.org/protobuf/proto" ) type CreateAccountTx struct { @@ -64,13 +66,17 @@ func (tx *CreateAccountTx) Sighashes() ([]*xc.SignatureRequest, error) { } switch tx.Input.Stage { case tx_input.CreateAccountStageAllocate: - hash, err := tx_input.ComputeTopologyMultiHash(tx.Input.TopologyTransactions) + hash, err := ComputeTopologyMultiHash(tx.Input.TopologyTransactions) if err != nil { return nil, err } return []*xc.SignatureRequest{xc.NewSignatureRequest(hash)}, nil case tx_input.CreateAccountStageAccept: - return tx.Input.Sighashes() + hash, err := computeCreateAccountAcceptSighash(tx.Input) + if err != nil { + return nil, err + } + return []*xc.SignatureRequest{xc.NewSignatureRequest(hash)}, nil default: return nil, fmt.Errorf("unsupported create-account stage %q", tx.Input.Stage) } @@ -104,27 +110,6 @@ func (tx *CreateAccountTx) GetMetadata() ([]byte, bool, error) { return bz, true, nil } -func (tx *CreateAccountTx) KeyFingerprint() (string, error) { - if tx == nil || tx.Input == nil { - return "", fmt.Errorf("create-account tx input is nil") - } - switch tx.Input.Stage { - case tx_input.CreateAccountStageAllocate: - if tx.Input.PublicKeyFingerprint == "" { - return "", fmt.Errorf("public key fingerprint is empty") - } - return tx.Input.PublicKeyFingerprint, nil - case tx_input.CreateAccountStageAccept: - _, fingerprint, err := cantonaddress.ParsePartyID(xc.Address(tx.Input.PartyID)) - if err != nil { - return "", fmt.Errorf("failed to parse party ID: %w", err) - } - return fingerprint, nil - default: - return "", fmt.Errorf("unsupported create-account stage %q", tx.Input.Stage) - } -} - func cloneCreateAccountInput(input *tx_input.CreateAccountInput) *tx_input.CreateAccountInput { if input == nil { return nil @@ -141,6 +126,23 @@ func cloneCreateAccountInput(input *tx_input.CreateAccountInput) *tx_input.Creat return &cloned } +func computeCreateAccountAcceptSighash(input *tx_input.CreateAccountInput) ([]byte, error) { + if input == nil { + return nil, fmt.Errorf("create-account tx input is nil") + } + if len(input.SetupProposalPreparedTransaction) == 0 { + return nil, fmt.Errorf("setup proposal prepared transaction is empty") + } + + var preparedTx interactive.PreparedTransaction + if err := proto.Unmarshal(input.SetupProposalPreparedTransaction, &preparedTx); err != nil { + return nil, fmt.Errorf("failed to unmarshal setup proposal prepared transaction: %w", err) + } + fmt.Println("-----") + testutil.JsonPrint(&preparedTx) + return tx_input.ComputePreparedTransactionHash(&preparedTx) +} + func parseCreateAccountSignaturePayload(data []byte) ([]byte, error) { if len(data) < createAccountPayloadPrefixLen { return nil, fmt.Errorf("create-account tx payload is too short") diff --git a/chain/canton/tx/create_account_tx_test.go b/chain/canton/tx/create_account_tx_test.go index bda9f14e..9e143899 100644 --- a/chain/canton/tx/create_account_tx_test.go +++ b/chain/canton/tx/create_account_tx_test.go @@ -1,19 +1,22 @@ -package tx +package tx_test import ( "encoding/hex" - "encoding/json" - "os" "testing" xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" + cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" ) +const liveAcceptCreateAccountInputHex = `00000000000024907b227374616765223a226163636570745f65787465726e616c5f70617274795f73657475705f70726f706f73616c222c226465736372697074696f6e223a225369676e207369676e61747572655f726571756573742e7061796c6f61642c20617070656e642074686520726177207369676e61747572652068657820746f206372656174655f6163636f756e745f696e7075742c207468656e207375626d69742074686520636f6d62696e656420686578207769746820607863207375626d6974202d2d636861696e2063616e746f6e205c7530303363636f6d62696e65645f6865785c7530303365602e222c2270617274795f6964223a22306664393161366131343337383030316337316630363930653035383933373237303331353331633832363133376132633230626532383162313538386164663a3a3132323035653737646566663732396530333765383233303034333038623966323662616265613861613963306365306536663338333632623731356664613437633036222c2273657475705f70726f706f73616c5f70726570617265645f7472616e73616374696f6e223a224371306643674d794c6a4553415441613367674b41544843507463494374514943674d794c6a4553516a41774e4463344f444e6b4d6d49344f4745785a445932596d4578596a63334d5463784d6a63774e546b354d4759784e7a466c4d44413259575a684f5449354d324d324d6a6b78596a4e6a595463795a5463345a44493159686f4e6333427361574e6c4c5746746457786c64434a68436b41324e325a68597a4a6d4f44557a596d4e6c4f4752695a6a42694f5467784e324a694e574a684e324d314f5759784d4755344d544977596a646a4f4441344e6a6b325a6a63774d54426c4e575977597a68684e7a6b78456731546347787059325575515731316247563047673557595778705a47463062334a536157646f6443724141334b3941777068436b41324e325a68597a4a6d4f44557a596d4e6c4f4752695a6a42694f5467784e324a694e574a684e324d314f5759784d4755344d544977596a646a4f4441344e6a6b325a6a63774d54426c4e575977597a68684e7a6b78456731546347787059325575515731316247563047673557595778705a47463062334a536157646f64424a5343674e6b63323853537a704a52464e504f6a6f784d6a49775a6a4979595468694f4759795a4467784d324d794e574935595459344e47526a4e47526b4e544a694e544d79595441784e7a526b4f4755334d3245784d324e6b5a6a4a69595746695a6d5a6d4e7a55784f444d7a4e784b5341516f4564584e6c63684b4a415471474154426d5a446b7859545a684d54517a4e7a67774d44466a4e7a466d4d4459354d4755774e5467354d7a63794e7a417a4d54557a4d574d344d6a59784d7a64684d6d4d794d474a6c4d6a6778596a45314f4468685a4759364f6a45794d6a41315a5463335a47566d5a6a63794f5755774d7a646c4f44497a4d4441304d7a4134596a6c6d4d6a5a6959574a6c5954686859546c6a4d474e6c4d4755325a6a4d344d7a5979596a63784e575a6b59545133597a4132456d384b43585a6862476c6b5958527663684a694f6d426a62334a6b6157467363336c7a6447567463793132595778705a474630623349744d546f364d5449794d4755325a6d4a68597a6b7759324e6b4d546b33597a4d314e6a59354d54686d4f546b354e7a637a596a41304e446b315a5445314e32466b597a466d596a67774d3249354e6d566b5a544a6c59574531596a4e685a475979686745775a6d51354d574532595445304d7a63344d444178597a63785a6a41324f54426c4d4455344f544d334d6a63774d7a45314d7a466a4f4449324d544d3359544a6a4d6a42695a5449344d5749784e5467345957526d4f6a6f784d6a49774e5755334e32526c5a6d59334d6a6c6c4d444d335a5467794d7a41774e444d774f4749355a6a4932596d46695a57453459574535597a426a5a54426c4e6d597a4f444d324d6d49334d54566d5a4745304e324d774e6a4a67593239795a476c6862484e356333526c62584d74646d467361575268644739794c5445364f6a45794d6a426c4e6d5a6959574d354d474e6a5a4445354e324d7a4e5459324f5445345a6a6b354f5463334d3249774e4451354e5755784e5464685a474d785a6d49344d444E694F545A6C5A4755795A5746684E57497A5957526D4F6F59424D475A6B4F5446684E6D45784E444D334F4441774D574D334D5759774E6A6B775A5441314F446B7A4E7A49334D444D784E544D78597A67794E6A457A4E324579597A4977596D55794F4446694D5455344F47466B5A6A6F364D5449794D44566C4E7A646B5A575A6D4E7A49355A54417A4E3255344D6A4D774D44517A4D4468694F5759794E6D4A68596D56684F4746684F574D77593255775A545A6D4D7A677A4E6A4A694E7A45315A6D52684E44646A4D44593659474E76636D52705957787A65584E305A57317A4C585A6862476C6B59585276636930784F6A6F784D6A49775A545A6D596D466A4F54426A593251784F54646A4D7A55324E6A6B784F4759354F546B334E7A4E694D4451304F54566C4D5455335957526A4D575A694F44417A596A6B325A57526C4D6D5668595456694D32466B5A68725843676F424D73492B30416F4B7A516F4B417A49754D524A434D44426C4F544D774E6D55334E4451774D4746684E6A49324D32466A596D49784E5467325A444A6A5A4445344D546C684D544D794D4442684D57526A4D545178595451315A6D466B4D4445354D3255784E7A4E6C4F5463344767317A63477870593255745957313162475630496D734B514459335A6D466A4D6D59344E544E69593255345A474A6D4D4749354F444533596D4931596D4533597A55355A6A45775A5467784D6A42694E324D344D4467324F545A6D4E7A41784D4755315A6A426A4F4745334F544553456C4E7762476C6A5A533542625856735A5852536457786C63786F5456484A68626E4E6D5A584A51636D56686348427962335A686243715A42484B5742417072436B41324E325A68597A4A6D4F44557A596D4E6C4F4752695A6A42694F5467784E324A694E574A684E324D314F5759784D4755344D544977596A646A4F4441344E6A6B325A6A63774D54426C4E575977597A68684E7A6B7845684A5463477870593255755157313162475630556E56735A584D61453152795957357A5A6D567955484A6C59584277636D39325957775355676F445A484E76456B733653555254547A6F364D5449794D4759794D6D4534596A686D4D6D51344D544E6A4D6A56694F5745324F44526B597A526B5A445579596A557A4D6D45774D5463305A44686C4E7A4E684D544E6A5A475979596D4668596D5A6D5A6A63314D54677A4D7A63536C67454B43484A6C59325670646D5679456F6B424F6F59424D475A6B4F5446684E6D45784E444D334F4441774D574D334D5759774E6A6B775A5441314F446B7A4E7A49334D444D784E544D78597A67794E6A457A4E324579597A4977596D55794F4446694D5455344F47466B5A6A6F364D5449794D44566C4E7A646B5A575A6D4E7A49355A54417A4E3255344D6A4D774D44517A4D4468694F5759794E6D4A68596D56684F4746684F574D77593255775A545A6D4D7A677A4E6A4A694E7A45315A6D52684E44646A4D44595362676F4963484A76646D6C6B5A584953596A7067593239795A476C6862484E356333526C62584D74646D467361575268644739794C5445364F6A45794D6A426C4E6D5A6959574D354D474E6A5A4445354E324D7A4E5459324F5445345A6A6B354F5463334D3249774E4451354E5755784E5464685A474D785A6D49344D444E694F545A6C5A4755795A5746684E57497A5957526D4568594B43585A6862476C6B526E4A766252494A4B576377565438325451594145686F4B44577868633352535A57356C6432566B5158515343536C6E4D46552F4E6B30474142495743676C6C65484270636D567A5158515343536B516E6779395346514741444B474154426D5A446B7859545A684D54517A4E7A67774D44466A4E7A466D4D4459354D4755774E5467354D7A63794E7A417A4D54557A4D574D344D6A59784D7A64684D6D4D794D474A6C4D6A6778596A45314F4468685A4759364F6A45794D6A41315A5463335A47566D5A6A63794F5755774D7A646C4F44497A4D4441304D7A4134596A6C6D4D6A5A6959574A6C5954686859546C6A4D474E6C4D4755325A6A4D344D7A5979596A63784E575A6B59545133597A41324D6B6C45553038364F6A45794D6A426D4D6A4A684F4749345A6A4A6B4F44457A597A4931596A6C684E6A67305A474D305A4751314D6D49314D7A4A684D4445334E4751345A54637A5954457A5932526D4D6D4A6859574A6D5A6D59334E5445344D7A4D334D6D426A62334A6B6157467363336C7A6447567463793132595778705A474630623349744D546F364D5449794D4755325A6D4A68597A6B7759324E6B4D546B33597A4D314E6A59354D54686D4F546B354E7A637A596A41304E446B315A5445314E32466B597A466D596A67774D3249354E6D566B5A544A6C59574531596A4E685A475936686745775A6D51354D574532595445304D7A63344D444178597A63785A6A41324F54426C4D4455344F544D334D6A63774D7A45314D7A466A4F4449324D544D3359544A6A4D6A42695A5449344D5749784E5467345957526D4F6A6F784D6A49774E5755334E32526C5A6D59334D6A6C6C4D444D335A5467794D7A41774E444D774F4749355A6A4932596D46695A57453459574535597A426A5A54426C4E6D597A4F444D324D6D49334D54566D5A4745304E324D774E6A704A52464E504F6A6F784D6A49775A6A4979595468694F4759795A4467784D324D794E574935595459344E47526A4E47526B4E544A694E544D79595441784E7A526B4F4755334D3245784D324E6B5A6A4A69595746695A6D5A6D4E7A55784F444D7A4E7A7067593239795A476C6862484E356333526C62584D74646D467361575268644739794C5445364F6A45794D6A426C4E6D5A6959574D354D474E6A5A4445354E324D7A4E5459324F5445345A6A6B354F5463334D3249774E4451354E5755784E5464685A474D785A6D49344D444E694F545A6C5A4755795A5746684E57497A5957526D4776634B43674577776A37774368727443676F444D693478456F6F424D444133596A5130595455785A5756694D7A46694E6A55795A6A4D344D544D775957526D4D7A497A5A6A55314F446B314E32597A4D6A4D775A6A55304E6A51334D57526D4D5441345A445A6959544E6A5932526A5A57457A593245784D6A45794D6A41784D574E6D4F44466B4D5445324D6A6B78597A51304D325130597A4D354D444D784E474E6A5A4759354F44646A4D544A6C4E6A646D4D4749785A544A6A4E6D466D5A444D795A574D334D54566A5A6D4A6D5A4451794767317A63477870593255745957313162475630496E494B514459335A6D466A4D6D59344E544E69593255345A474A6D4D4749354F444533596D4931596D4533597A55355A6A45775A5467784D6A42694E324D344D4467324F545A6D4E7A41784D4755315A6A426A4F4745334F544553456C4E7762476C6A5A533542625856735A5852536457786C63786F61525868305A584A755957785159584A3065564E6C6448567755484A766347397A5957777153555254547A6F364D5449794D4759794D6D4534596A686D4D6D51344D544E6A4D6A56694F5745324F44526B597A526B5A445579596A557A4D6D45774D5463305A44686C4E7A4E684D544E6A5A475979596D4668596D5A6D5A6A63314D54677A4D7A637159474E76636D52705957787A65584E305A57317A4C585A6862476C6B59585276636930784F6A6F784D6A49775A545A6D596D466A4F54426A593251784F54646A4D7A55324E6A6B784F4759354F546B334E7A4E694D4451304F54566C4D5455335957526A4D575A694F44417A596A6B325A57526C4D6D5668595456694D32466B5A6A4B474154426D5A446B7859545A684D54517A4E7A67774D44466A4E7A466D4D4459354D4755774E5467354D7A63794E7A417A4D54557A4D574D344D6A59784D7A64684D6D4D794D474A6C4D6A6778596A45314F4468685A4759364F6A45794D6A41315A5463335A47566D5A6A63794F5755774D7A646C4F44497A4D4441304D7A4134596A6C6D4D6A5A6959574A6C5954686859546C6A4D474E6C4D4755325A6A4D344D7A5979596A63784E575A6B59545133597A41324D6B6C45553038364F6A45794D6A426D4D6A4A684F4749345A6A4A6B4F44457A597A4931596A6C684E6A67305A474D305A4751314D6D49314D7A4A684D4445334E4751345A54637A5954457A5932526D4D6D4A6859574A6D5A6D59334E5445344D7A4D334F6D426A62334A6B6157467363336C7A6447567463793132595778705A474630623349744D546F364D5449794D4755325A6D4A68597A6B7759324E6B4D546B33597A4D314E6A59354D54686D4F546B354E7A637A596A41304E446B315A5445314E32466B597A466D596A67774D3249354E6D566B5A544A6C59574531596A4E685A475936686745775A6D51354D574532595445304D7A63344D444178597A63785A6A41324F54426C4D4455344F544D334D6A63774D7A45314D7A466A4F4449324D544D3359544A6A4D6A42695A5449344D5749784E5467345957526D4F6A6F784D6A49774E5755334E32526C5A6D59334D6A6C6C4D444D335A5467794D7A41774E444D774F4749355A6A4932596D46695A57453459574535597A426A5A54426C4E6D597A4F444D324D6D49334D54566D5A4745304E324D774E6B6F68525868305A584A755957785159584A3065564E6C6448567755484A766347397A5957786651574E6A5A584230556E317965777035436B41324E325A68597A4A6D4F44557A596D4E6C4F4752695A6A42694F5467784E324A694E574A684E324D314F5759784D4755344D544977596A646A4F4441344E6A6B325A6A63774D54426C4E575977597A68684E7A6B7845684A5463477870593255755157313162475630556E56735A584D614955563464475679626D46735547467964486C545A5852316346427962334276633246735830466A593256776446674259674578596745796172384363727743436E384B514459335A6D466A4D6D59344E544E69593255345A474A6D4D4749354F444533596D4931596D4533597A55355A6A45775A5467784D6A42694E324D344D4467324F545A6D4E7A41784D4755315A6A426A4F4745334F544553456C4E7762476C6A5A533542625856735A5852536457786C63786F6E525868305A584A755957785159584A3065564E6C6448567755484A766347397A5957786651574E6A5A584230556D567A64577830456C6B4B45585A6862476C6B59585276636C4A705A32683051326C6B456B524B516A41774E4463344F444E6B4D6D49344F4745785A445932596D4578596A63334D5463784D6A63774E546B354D4759784E7A466C4D44413259575A684F5449354D324D324D6A6B78596A4E6A595463795A5463345A44493159684A6543685A30636D467563325A6C636C42795A57467763484A76646D467351326C6B456B524B516A41775A546B7A4D445A6C4E7A51304D444268595459794E6A4E6859324A694D5455344E6D5179593251784F4445355954457A4D6A41775954466B597A45304D5745304E575A685A4441784F544E6C4D54637A5A546B334F4349694569434F714B472B4D6D644F6248794F58695251422B46495541314342734E6A4B6D59632F6745534A3445385453496B43414553494B6B4F49754B654C4965354B6D6A59695550363646536D2F733364785576512B6E754B2B75485243644C3749695149416849676850574B72504C587931682B6364346B5841644732544A67625536647A4C68566E6E4E5448773731327867532F424D537277454B686745775A6D51354D574532595445304D7A63344D444178597A63785A6A41324F54426C4D4455344F544D334D6A63774D7A45314D7A466A4F4449324D544D3359544A6A4D6A42695A5449344D5749784E5467345957526D4F6A6F784D6A49774E5755334E32526C5A6D59334D6A6C6C4D444D335A5467794D7A41774E444D774F4749355A6A4932596D46695A57453459574535597A426A5A54426C4E6D597A4F444D324D6D49334D54566D5A4745304E324D774E68496B596A4132597A4177596A45744D54426A4D6930305A544D7A4C544E6C4F446B744E7A46684E6A4E6A4D544A694D445178476C4E6E62473969595777745A47397459576C754F6A6F784D6A49775A6A4979595468694F4759795A4467784D324D794E574935595459344E47526A4E47526B4E544A694E544D79595441784E7A526B4F4755334D3245784D324E6B5A6A4A69595746695A6D5A6D4E7A55784F444D7A4E796F6B4E7A6C694D5446695A5451744D6D4D33595330305A47466D4C5745774D5749744D57466D4E6A51774E4749794D7A49344D4E43667834626E70704D444F726F527744376E344E5436343661544139492B6F67634B417A49754D524B614277704641487445705237724D625A533834457772664D6A39566956667A497739555A484866454931726F387A63366A7968495349424850676445574B527845505577354178544D3335683845755A2F4378347361763079374846632B2F31434567317A63477870593255745957313162475630476E4D4B514459335A6D466A4D6D59344E544E69593255345A474A6D4D4749354F444533596D4931596D4533597A55355A6A45775A5467784D6A42694E324D344D4467324F545A6D4E7A41784D4755315A6A426A4F4745334F544553426C4E7762476C6A5A52494C5157313162475630556E56735A584D61476B563464475679626D46735547467964486C545A5852316346427962334276633246734975454361743443436D514B596A7067593239795A476C6862484E356333526C62584D74646D467361575268644739794C5445364F6A45794D6A426C4E6D5A6959574D354D474E6A5A4445354E324D7A4E5459324F5445345A6A6B354F5463334D3249774E4451354E5755784E5464685A474D785A6D49344D444E694F545A6C5A4755795A5746684E57497A5957526D436F7742436F6B424F6F59424D475A6B4F5446684E6D45784E444D334F4441774D574D334D5759774E6A6B775A5441314F446B7A4E7A49334D444D784E544D78597A67794E6A457A4E324579597A4977596D55794F4446694D5455344F47466B5A6A6F364D5449794D44566C4E7A646B5A575A6D4E7A49355A54417A4E3255344D6A4D774D44517A4D4468694F5759794E6D4A68596D56684F4746684F574D77593255775A545A6D4D7A677A4E6A4A694E7A45315A6D52684E44646A4D44594B5451704C4F6B6C45553038364F6A45794D6A426D4D6A4A684F4749345A6A4A6B4F44457A597A4931596A6C684E6A67305A474D305A4751314D6D49314D7A4A684D4445334E4751345A54637A5954457A5932526D4D6D4A6859574A6D5A6D59334E5445344D7A4D334367734B43536C6E4D46552F4E6B304741416F4C43676B70454A344D765568554267417153555254547A6F364D5449794D4759794D6D4534596A686D4D6D51344D544E6A4D6A56694F5745324F44526B597A526B5A445579596A557A4D6D45774D5463305A44686C4E7A4E684D544E6A5A475979596D4668596D5A6D5A6A63314D54677A4D7A637159474E76636D52705957787A65584E305A57317A4C585A6862476C6B59585276636930784F6A6F784D6A49775A545A6D596D466A4F54426A593251784F54646A4D7A55324E6A6B784F4759354F546B334E7A4E694D4451304F54566C4D5455335957526A4D575A694F44417A596A6B325A57526C4D6D5668595456694D32466B5A6A4B474154426D5A446B7859545A684D54517A4E7A67774D44466A4E7A466D4D4459354D4755774E5467354D7A63794E7A417A4D54557A4D574D344D6A59784D7A64684D6D4D794D474A6C4D6A6778596A45314F4468685A4759364F6A45794D6A41315A5463335A47566D5A6A63794F5755774D7A646C4F44497A4D4441304D7A4134596A6C6D4D6A5A6959574A6C5954686859546C6A4D474E6C4D4755325A6A4D344D7A5979596A63784E575A6B59545133597A41324F576377565438325451594151696F4B4A676F6B4341455349483243442F63646C4D38376A55545A5141426A5A6B6764686A7645463376597131686944516C4F46564B6F4542344B68776F4B417A49754D524B4B415441774E3249304E4745314D57566C596A4D78596A59314D6D597A4F44457A4D47466B5A6A4D794D3259314E5467354E54646D4D7A497A4D4759314E4459304E7A466B5A6A45774F475132596D457A59324E6B593256684D324E684D5449784D6A49774D54466A5A6A67785A4445784E6A49354D574D304E444E6B4E474D7A4F54417A4D54526A5932526D4F546733597A45795A5459335A6A42694D575579597A5A685A6D517A4D6D566A4E7A453159325A695A6D51304D686F4E6333427361574E6C4C5746746457786C64434A79436B41324E325A68597A4A6D4F44557A596D4E6C4F4752695A6A42694F5467784E324A694E574A684E324D314F5759784D4755344D544977596A646A4F4441344E6A6B325A6A63774D54426C4E575977597A68684E7A6B7845684A5463477870593255755157313162475630556E56735A584D61476B563464475679626D46735547467964486C545A5852316346427962334276633246734B6F7745636F6B45436E494B514459335A6D466A4D6D59344E544E69593255345A474A6D4D4749354F444533596D4931596D4533597A55355A6A45775A5467784D6A42694E324D344D4467324F545A6D4E7A41784D4755315A6A426A4F4745334F544553456C4E7762476C6A5A533542625856735A5852536457786C63786F61525868305A584A755957785159584A3065564E6C6448567755484A766347397A5957775362776F4A646D46736157526864473979456D493659474E76636D52705957787A65584E305A57317A4C585A6862476C6B59585276636930784F6A6F784D6A49775A545A6D596D466A4F54426A593251784F54646A4D7A55324E6A6B784F4759354F546B334E7A4E694D4451304F54566C4D5455335957526A4D575A694F44417A596A6B325A57526C4D6D5668595456694D32466B5A684B5341516F4564584E6C63684B4A415471474154426D5A446B7859545A684D54517A4E7A67774D44466A4E7A466D4D4459354D4755774E5467354D7A63794E7A417A4D54557A4D574D344D6A59784D7A64684D6D4D794D474A6C4D6A6778596A45314F4468685A4759364F6A45794D6A41315A5463335A47566D5A6A63794F5755774D7A646C4F44497A4D4441304D7A4134596A6C6D4D6A5A6959574A6C5954686859546C6A4D474E6C4D4755325A6A4D344D7A5979596A63784E575A6B59545133597A4132456C494B4132527A62784A4C4F6B6C45553038364F6A45794D6A426D4D6A4A684F4749345A6A4A6B4F44457A597A4931596A6C684E6A67305A474D305A4751314D6D49314D7A4A684D4445334E4751345A54637A5954457A5932526D4D6D4A6859574A6D5A6D59334E5445344D7A4D334568594B43574E795A5746305A5752426442494A4B57637756543832545159414569454B464842795A57467763484A76646D46735258687761584A6C6330463045676B70454A344D765568554267417953555254547A6F364D5449794D4759794D6D4534596A686D4D6D51344D544E6A4D6A56694F5745324F44526B597A526B5A445579596A557A4D6D45774D5463305A44686C4E7A4E684D544E6A5A475979596D4668596D5A6D5A6A63314D54677A4D7A637959474E76636D52705957787A65584E305A57317A4C585A6862476C6B59585276636930784F6A6F784D6A49775A545A6D596D466A4F54426A593251784F54646A4D7A55324E6A6B784F4759354F546B334E7A4E694D4451304F54566C4D5455335957526A4D575A694F44417A596A6B325A57526C4D6D5668595456694D32466B5A6A71474154426D5A446B7859545A684D54517A4E7A67774D44466A4E7A466D4D4459354D4755774E5467354D7A63794E7A417A4D54557A4D574D344D6A59784D7A64684D6D4D794D474A6C4D6A6778596A45314F4468685A4759364F6A45794D6A41315A5463335A47566D5A6A63794F5755774D7A646C4F44497A4D4441304D7A4134596A6C6D4D6A5A6959574A6C5954686859546C6A4D474E6C4D4755325A6A4D344D7A5979596A63784E575A6B59545133597A41324F6B6C45553038364F6A45794D6A426D4D6A4A684F4749345A6A4A6B4F44457A597A4931596A6C684E6A67305A474D305A4751314D6D49314D7A4A684D4445334E4751345A54637A5954457A5932526D4D6D4A6859574A6D5A6D59334E5445344D7A4D334F6D426A62334A6B6157467363336C7A6447567463793132595778705A474630623349744D546F364D5449794D4755325A6D4A68597A6B7759324E6B4D546B33597A4D314E6A59354D54686D4F546B354E7A637A596A41304E446B315A5445314E32466B597A466D596A67774D3249354E6D566B5A544A6C59574531596A4E685A475A516A3779793649754A6C514D3D222C2273657475705F70726F706F73616C5F68617368223A2271574D6D39662B4F76682B417143304F444A70793561714B7365316761554D34397A68397A6674364844453D222C2273657475705F70726F706F73616C5F68617368696E67223A322C2273657475705F70726F706F73616C5F7375626D697373696F6E5F6964223A2233333433366635612D363666642D663636652D343638392D336538613739316431633563227D` + +const allocateCreateAccountPartyID = "e5c86207770b9fb67d73eb4cb8cd6a5f6a5d6a63c66a5459bd77cca45fda6ede::122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8" + func TestCreateAccountTxRoundTrip(t *testing.T) { t.Parallel() @@ -25,8 +28,7 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { name: "allocate", input: &tx_input.CreateAccountInput{ Stage: tx_input.CreateAccountStageAllocate, - PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PartyID: allocateCreateAccountPartyID, TopologyTransactions: [][]byte{{0x01, 0x02}}, }, }, @@ -44,14 +46,14 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { args, err := xcbuilder.NewCreateAccountArgs(xc.CANTON, xc.Address(tt.input.PartyID), []byte{0x01, 0x02}) require.NoError(t, err) - tx, err := NewCreateAccountTx(args, tt.input) + tx, err := cantontx.NewCreateAccountTx(args, tt.input) require.NoError(t, err) sighashes, err := tx.Sighashes() require.NoError(t, err) require.Len(t, sighashes, 1) if tt.input.Stage == tx_input.CreateAccountStageAllocate { - expectedHash, err := tx_input.ComputeTopologyMultiHash(tt.input.TopologyTransactions) + expectedHash, err := cantontx.ComputeTopologyMultiHash(tt.input.TopologyTransactions) require.NoError(t, err) require.Equal(t, expectedHash, sighashes[0].Payload) } else { @@ -70,10 +72,10 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { metadataBz, ok, err := tx.GetMetadata() require.NoError(t, err) require.True(t, ok) - metadata, err := ParseMetadata(metadataBz) + metadata, err := cantontx.ParseMetadata(metadataBz) require.NoError(t, err) - parsedUnsigned, err := ParseCreateAccountTxWithMetadata(unsigned, metadata) + parsedUnsigned, err := cantontx.ParseCreateAccountTxWithMetadata(unsigned, metadata) require.NoError(t, err) require.Equal(t, tt.input.Stage, parsedUnsigned.Input.Stage) @@ -83,7 +85,7 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { signed, err := tx.Serialize() require.NoError(t, err) - parsedSigned, err := ParseCreateAccountTxWithMetadata(signed, metadata) + parsedSigned, err := cantontx.ParseCreateAccountTxWithMetadata(signed, metadata) require.NoError(t, err) require.Equal(t, "dead", hex.EncodeToString(parsedSigned.Input.Signature)) require.NotEmpty(t, tx.Hash()) @@ -94,15 +96,7 @@ func TestCreateAccountTxRoundTrip(t *testing.T) { func loadLiveAcceptInput(t *testing.T) *tx_input.CreateAccountInput { t.Helper() - data, err := os.ReadFile("../tx_input/testdata/live_create_account_accept.json") - require.NoError(t, err) - - var fixture struct { - CreateAccountInput string `json:"create_account_input"` - } - require.NoError(t, json.Unmarshal(data, &fixture)) - - encoded, err := hex.DecodeString(fixture.CreateAccountInput) + encoded, err := hex.DecodeString(liveAcceptCreateAccountInputHex) require.NoError(t, err) input, err := tx_input.ParseCreateAccountInput(encoded) diff --git a/chain/canton/tx/hash_validation_test.go b/chain/canton/tx/hash_validation_test.go new file mode 100644 index 00000000..57a3b56b --- /dev/null +++ b/chain/canton/tx/hash_validation_test.go @@ -0,0 +1,255 @@ +package tx_test + +import ( + "bytes" + "strconv" + "testing" + + xc "github.com/cordialsys/crosschain" + xcbuilder "github.com/cordialsys/crosschain/builder" + cantontx "github.com/cordialsys/crosschain/chain/canton/tx" + "github.com/cordialsys/crosschain/chain/canton/tx_input" + v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" + v1 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" +) + +func TestComputePreparedTransactionHash(t *testing.T) { + t.Parallel() + + preparedTx := hashTestPreparedTransaction("1", hashTestExerciseNode("TransferPreapproval_Send", hashTestAmountRecord("10.0"))) + + hash1, err := tx_input.ComputePreparedTransactionHash(preparedTx) + require.NoError(t, err) + + hash2, err := tx_input.ComputePreparedTransactionHash(preparedTx) + require.NoError(t, err) + + require.Equal(t, hash1, hash2) + require.NotEmpty(t, hash1) +} + +func TestValidatePreparedTransactionHashFlows(t *testing.T) { + t.Parallel() + + vectors := []struct { + name string + preparedTx *interactive.PreparedTransaction + }{ + { + name: "transfer_preapproval_send", + preparedTx: hashTestPreparedTransaction("1", hashTestExerciseNode("TransferPreapproval_Send", hashTestAmountRecord("10.0"))), + }, + { + name: "transfer_offer_send", + preparedTx: hashTestPreparedTransaction("1", hashTestCreateNode("TransferOffer", hashTestTransferOfferArgument("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "10.0"))), + }, + { + name: "create_account_accept", + preparedTx: hashTestPreparedTransaction("1", hashTestExerciseNode("ExternalPartySetupProposal_Accept", hashTestEmptyRecord())), + }, + { + name: "complete_transfer_offer", + preparedTx: hashTestPreparedTransaction("1", hashTestExerciseNode("AcceptedTransferOffer_Complete", hashTestEmptyRecord())), + }, + } + + for _, vector := range vectors { + t.Run(vector.name, func(t *testing.T) { + t.Parallel() + + hash := hashTestPreparedTransactionHash(t, vector.preparedTx) + require.NoError(t, tx_input.ValidatePreparedTransactionHash(vector.preparedTx, hash)) + + wrongHash := append([]byte(nil), hash...) + wrongHash[len(wrongHash)-1] ^= 0xff + require.ErrorContains(t, tx_input.ValidatePreparedTransactionHash(vector.preparedTx, wrongHash), "prepared transaction hash mismatch") + }) + } +} + +func TestCreateAccountAcceptSighashes_UsesPreparedTransactionHash(t *testing.T) { + t.Parallel() + + preparedTx := hashTestPreparedTransaction("1", hashTestExerciseNode("ExternalPartySetupProposal_Accept", hashTestEmptyRecord())) + preparedBz, err := proto.Marshal(preparedTx) + require.NoError(t, err) + + input := &tx_input.CreateAccountInput{ + Stage: tx_input.CreateAccountStageAccept, + PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + SetupProposalPreparedTransaction: preparedBz, + } + + args, err := xcbuilder.NewCreateAccountArgs(xc.CANTON, xc.Address(input.PartyID), []byte{0x01, 0x02}) + require.NoError(t, err) + + tx, err := cantontx.NewCreateAccountTx(args, input) + require.NoError(t, err) + + sighashes, err := tx.Sighashes() + require.NoError(t, err) + require.Len(t, sighashes, 1) + + expectedHash, err := tx_input.ComputePreparedTransactionHash(preparedTx) + require.NoError(t, err) + require.Equal(t, expectedHash, sighashes[0].Payload) +} + +func TestValidatePreparedTransactionHash_LiveCreateAccountAccept(t *testing.T) { + t.Parallel() + + input := loadLiveAcceptInput(t) + + var preparedTx interactive.PreparedTransaction + require.NoError(t, proto.Unmarshal(input.SetupProposalPreparedTransaction, &preparedTx)) + + expectedHash, err := tx_input.ComputePreparedTransactionHash(&preparedTx) + require.NoError(t, err) + require.NoError(t, tx_input.ValidatePreparedTransactionHash(&preparedTx, expectedHash)) + require.NoError(t, input.VerifySignaturePayloads()) + + args, err := xcbuilder.NewCreateAccountArgs(xc.CANTON, xc.Address(input.PartyID), []byte{0x01, 0x02}) + require.NoError(t, err) + tx, err := cantontx.NewCreateAccountTx(args, input) + require.NoError(t, err) + + sighashes, err := tx.Sighashes() + require.NoError(t, err) + require.Len(t, sighashes, 1) + require.Equal(t, expectedHash, sighashes[0].Payload) +} + +func hashTestPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTransaction { + tx := &interactive.PreparedTransaction{ + Transaction: &interactive.DamlTransaction{ + Version: "2", + Roots: []string{nodeID}, + Nodes: []*interactive.DamlTransaction_Node{ + { + NodeId: nodeID, + VersionedNode: &interactive.DamlTransaction_Node_V1{ + V1: node, + }, + }, + }, + }, + Metadata: &interactive.Metadata{ + SubmitterInfo: &interactive.Metadata_SubmitterInfo{ + ActAs: []string{"sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, + CommandId: "command-id", + }, + SynchronizerId: "sync-id", + TransactionUuid: "transaction-uuid", + PreparationTime: 1, + InputContracts: []*interactive.Metadata_InputContract{}, + }, + } + if node.GetExercise() != nil { + seedID, err := strconv.Atoi(nodeID) + if err != nil { + panic(err) + } + tx.Transaction.NodeSeeds = []*interactive.DamlTransaction_NodeSeed{ + {NodeId: int32(seedID), Seed: bytes.Repeat([]byte{0x11}, 32)}, + } + } + return tx +} + +func hashTestPreparedTransactionHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { + t.Helper() + hash, err := tx_input.ComputePreparedTransactionHash(preparedTx) + require.NoError(t, err) + return hash +} + +func hashTestCreateNode(entity string, argument *v2.Value) *v1.Node { + return &v1.Node{ + NodeType: &v1.Node_Create{ + Create: &v1.Create{ + TemplateId: &v2.Identifier{ + PackageId: "pkg", + ModuleName: "Splice.Wallet.TransferOffer", + EntityName: entity, + }, + ContractId: "001122", + PackageName: "splice-wallet", + Argument: argument, + }, + }, + } +} + +func hashTestExerciseNode(choice string, chosenValue *v2.Value) *v1.Node { + return &v1.Node{ + NodeType: &v1.Node_Exercise{ + Exercise: &v1.Exercise{ + TemplateId: &v2.Identifier{ + PackageId: "pkg", + ModuleName: "Splice.Wallet", + EntityName: "Any", + }, + ContractId: "001122", + PackageName: "splice-wallet", + ChoiceId: choice, + ChosenValue: chosenValue, + }, + }, + } +} + +func hashTestTransferOfferArgument(receiver string, amount string) *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "receiver", + Value: &v2.Value{Sum: &v2.Value_Party{Party: receiver}}, + }, + { + Label: "amount", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func hashTestAmountRecord(amount string) *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + } +} + +func hashTestEmptyRecord() *v2.Value { + return &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{}, + }, + } +} diff --git a/chain/canton/tx_input/topology_hash.go b/chain/canton/tx/topology_hash.go similarity index 98% rename from chain/canton/tx_input/topology_hash.go rename to chain/canton/tx/topology_hash.go index 57979125..06fe2913 100644 --- a/chain/canton/tx_input/topology_hash.go +++ b/chain/canton/tx/topology_hash.go @@ -1,4 +1,4 @@ -package tx_input +package tx import ( "crypto/sha256" diff --git a/chain/canton/tx/topology_hash_test.go b/chain/canton/tx/topology_hash_test.go new file mode 100644 index 00000000..cc453f00 --- /dev/null +++ b/chain/canton/tx/topology_hash_test.go @@ -0,0 +1,61 @@ +package tx_test + +import ( + "encoding/hex" + "fmt" + "testing" + + cantontx "github.com/cordialsys/crosschain/chain/canton/tx" + "github.com/stretchr/testify/require" +) + +func TestComputeTopologyMultiHashFailures(t *testing.T) { + t.Parallel() + + _, err := cantontx.ComputeTopologyMultiHash(nil) + require.ErrorContains(t, err, "topology transactions are empty") + + _, err = cantontx.ComputeTopologyMultiHash([][]byte{{}}) + require.ErrorContains(t, err, "topology transaction is empty") +} + +func TestComputeTopologyMultiHash_LiveVector(t *testing.T) { + t.Parallel() + + type testcase struct { + transactions []string + expectedHash string + } + var vectors = []testcase{ + { + transactions: []string{ + "0ab602080110011aaf024aac020a8601366166636665383630353565643562616636613437663537356636353566666162333836653032373938653332626463373736303363613233386239623635623a3a313232306662383337613930373963363665333962646538643435646663366537396463383066376339333139343061303164363632326534666565306234303933336310011a620a5e76616c696461746f722d636f726469616c73797374656d733a3a31323230653666626163393063636431393763333536363931386639393937373362303434393565313537616463316662383033623936656465326561613562336164661002323b0a3710041a2c302a300506032b65700321006afcfe86055ed5baf6a47f575f655ffab386e02798e32bdc77603ca238b9b65b2a0301050430011001101e", + }, + expectedHash: "12206947cbe26cda1680526f5a6957927b9272bc5ca3d2af6dc7946d9c3182bfe8de", + }, + { + transactions: []string{ + "0ab602080110011aaf024aac020a8601366166636665383630353565643562616636613437663537356636353566666162333836653032373938653332626463373736303363613233386239623635623a3a313232306662383337613930373963363665333962646538643435646663366537396463383066376339333139343061303164363632326534666565306234303933336310011a620a5e76616c696461746f722d636f726469616c73797374656d733a3a31323230653666626163393063636431393763333536363931386639393937373362303434393565313537616463316662383033623936656465326561613562336164661002323b0a3710041a2c302a300506032b65700321006afcfe86055ed5baf6a47f575f655ffab386e02798e32bdc77603ca238b9b65b2a0301050430011001101e", + "0ab602080110011aaf024aac020a8601366166636665383630353565643562616636613437663537356636353566666162333836653032373938653332626463373736303363613233386239623635623a3a313232306662383337613930373963363665333962646538643435646663366537396463383066376339333139343061303164363632326534666565306234303933336310011a620a5e76616c696461746f722d636f726469616c73797374656d733a3a31323230653666626163393063636431393763333536363931386639393937373362303434393565313537616463316662383033623936656465326561613562336164661002323b0a3710041a2c302a300506032b65700321006afcfe86055ed5baf6a47f575f655ffab386e02798e32bdc77603ca238b9b65b2a0301050430011001101e", + }, + expectedHash: "1220be0f167448e37dc76a3bc98ed58fd8a901bc0c9f2c3fe4336e334d45674a138d", + }, + } + for i, vector := range vectors { + t.Run(fmt.Sprintf("case_%d", i), func(t *testing.T) { + t.Parallel() + + transactions := make([][]byte, 0, len(vector.transactions)) + for _, transaction := range vector.transactions { + transaction, err := hex.DecodeString(transaction) + require.NoError(t, err) + transactions = append(transactions, transaction) + } + + hash, err := cantontx.ComputeTopologyMultiHash(transactions) + require.NoError(t, err) + require.Equal(t, vector.expectedHash, hex.EncodeToString(hash)) + }) + } + +} diff --git a/chain/canton/tx/tx_test.go b/chain/canton/tx/tx_test.go index 165b2a61..a5f05d70 100644 --- a/chain/canton/tx/tx_test.go +++ b/chain/canton/tx/tx_test.go @@ -1,4 +1,4 @@ -package tx +package tx_test import ( "bytes" @@ -7,6 +7,7 @@ import ( xc "github.com/cordialsys/crosschain" xcbuilder "github.com/cordialsys/crosschain/builder" + cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" @@ -50,7 +51,7 @@ func TestNewTx_UsesPreparedTransactionForTransferFlows(t *testing.T) { SubmissionId: "submission-id", } - tx, err := NewTx(input, args, 1) + tx, err := cantontx.NewTx(input, args, 1) require.NoError(t, err) hash, err := tx_input.ComputePreparedTransactionHash(vector.preparedTx) diff --git a/chain/canton/tx_input/create_account_input.go b/chain/canton/tx_input/create_account_input.go index 315c54a1..df5bdfc2 100644 --- a/chain/canton/tx_input/create_account_input.go +++ b/chain/canton/tx_input/create_account_input.go @@ -27,7 +27,11 @@ type CreateAccountInput struct { Stage string `json:"stage"` // Used only for conflict checking, but not actually in the transaction? + // The PartyID is the same as the address, looks like this: + // e5c86207770b9fb67d73eb4cb8cd6a5f6a5d6a63c66a5459bd77cca45fda6ede::122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8 + // or, :: PartyID string `json:"party_id"` + // Need to make the tx submit -- likely we can compute this on our own // and drop it from the input PublicKeyFingerprint string `json:"public_key_fingerprint,omitempty"` @@ -128,26 +132,6 @@ func (i *CreateAccountInput) Serialize() ([]byte, error) { return payload, nil } -// Sighashes returns the payload for the current pending step. -func (i *CreateAccountInput) Sighashes() ([]*xc.SignatureRequest, error) { - switch i.Stage { - case CreateAccountStageAllocate: - return nil, fmt.Errorf("allocate-stage sighash is derived by the Canton create-account tx") - case CreateAccountStageAccept: - preparedTx, err := i.setupProposalPreparedTransaction() - if err != nil { - return nil, err - } - hash, err := ComputePreparedTransactionHash(preparedTx) - if err != nil { - return nil, err - } - return []*xc.SignatureRequest{xc.NewSignatureRequest(hash)}, nil - default: - return nil, fmt.Errorf("unsupported create-account stage %q", i.Stage) - } -} - func (i *CreateAccountInput) SetSignatures(sigs ...*xc.SignatureResponse) error { if len(sigs) != 1 { return fmt.Errorf("expected 1 signature, got %d", len(sigs)) @@ -162,9 +146,6 @@ func (i *CreateAccountInput) VerifySignaturePayloads() error { } switch i.Stage { case CreateAccountStageAllocate: - if i.PublicKeyFingerprint == "" { - return fmt.Errorf("public key fingerprint is empty") - } if len(i.TopologyTransactions) == 0 { return fmt.Errorf("topology transactions are empty") } diff --git a/chain/canton/tx_input/create_account_input_test.go b/chain/canton/tx_input/create_account_input_test.go index 7c05c1ad..f4cb5f7b 100644 --- a/chain/canton/tx_input/create_account_input_test.go +++ b/chain/canton/tx_input/create_account_input_test.go @@ -24,8 +24,7 @@ func TestCreateAccountInputVerifySignaturePayloadsAllocateStage(t *testing.T) { input := &CreateAccountInput{ Stage: CreateAccountStageAllocate, - PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - PublicKeyFingerprint: "1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + PartyID: "e5c86207770b9fb67d73eb4cb8cd6a5f6a5d6a63c66a5459bd77cca45fda6ede::122079aa518eac66dcd662887155c5c7ee36d3b62e38ed0ded2ddc0c7050460bccc8", TopologyTransactions: [][]byte{{0x01, 0x02}}, } diff --git a/chain/canton/tx_input/hash_validation_test.go b/chain/canton/tx_input/hash_validation_test.go deleted file mode 100644 index 8be5d13d..00000000 --- a/chain/canton/tx_input/hash_validation_test.go +++ /dev/null @@ -1,285 +0,0 @@ -package tx_input - -import ( - "bytes" - "encoding/hex" - "encoding/json" - "os" - "strconv" - "testing" - - v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" - "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" - v1 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive/transaction/v1" - "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" -) - -func TestComputePreparedTransactionHash(t *testing.T) { - t.Parallel() - - preparedTx := testPreparedTransaction("1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))) - - hash1, err := ComputePreparedTransactionHash(preparedTx) - require.NoError(t, err) - - hash2, err := ComputePreparedTransactionHash(preparedTx) - require.NoError(t, err) - - require.Equal(t, hash1, hash2) - require.NotEmpty(t, hash1) -} - -func TestValidatePreparedTransactionHash_Flows(t *testing.T) { - t.Parallel() - - vectors := []struct { - name string - preparedTx *interactive.PreparedTransaction - verify func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) - }{ - { - name: "transfer_preapproval_send", - preparedTx: testPreparedTransaction("1", testExerciseNode("TransferPreapproval_Send", testAmountRecord("10.0"))), - verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { - t.Helper() - require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) - }, - }, - { - name: "transfer_offer_send", - preparedTx: testPreparedTransaction("1", testCreateNode("TransferOffer", testTransferOfferArgument("receiver::1220bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "10.0"))), - verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { - t.Helper() - require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) - }, - }, - { - name: "create_account_accept", - preparedTx: testPreparedTransaction("1", testExerciseNode("ExternalPartySetupProposal_Accept", testEmptyRecord())), - verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { - t.Helper() - preparedBz, err := proto.Marshal(preparedTx) - require.NoError(t, err) - - input := &CreateAccountInput{ - Stage: CreateAccountStageAccept, - PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - SetupProposalPreparedTransaction: preparedBz, - } - require.NoError(t, input.VerifySignaturePayloads()) - sighashes, err := input.Sighashes() - require.NoError(t, err) - require.Len(t, sighashes, 1) - require.Equal(t, hash, sighashes[0].Payload) - }, - }, - { - name: "complete_transfer_offer", - preparedTx: testPreparedTransaction("1", testExerciseNode("AcceptedTransferOffer_Complete", testEmptyRecord())), - verify: func(t *testing.T, preparedTx *interactive.PreparedTransaction, hash []byte) { - t.Helper() - require.NoError(t, ValidatePreparedTransactionHash(preparedTx, hash)) - }, - }, - } - - for _, vector := range vectors { - vector := vector - t.Run(vector.name, func(t *testing.T) { - t.Parallel() - - hash := testPreparedTransactionHash(t, vector.preparedTx) - vector.verify(t, vector.preparedTx, hash) - - wrongHash := append([]byte(nil), hash...) - wrongHash[len(wrongHash)-1] ^= 0xff - - switch vector.name { - case "create_account_accept": - preparedBz, err := proto.Marshal(vector.preparedTx) - require.NoError(t, err) - input := &CreateAccountInput{ - Stage: CreateAccountStageAccept, - PartyID: "party::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - SetupProposalPreparedTransaction: preparedBz, - } - require.NoError(t, input.VerifySignaturePayloads()) - sighashes, err := input.Sighashes() - require.NoError(t, err) - require.Len(t, sighashes, 1) - require.NotEqual(t, wrongHash, sighashes[0].Payload) - default: - require.ErrorContains(t, ValidatePreparedTransactionHash(vector.preparedTx, wrongHash), "prepared transaction hash mismatch") - } - }) - } -} - -func TestValidatePreparedTransactionHash_LiveCreateAccountAcceptMismatch(t *testing.T) { - t.Parallel() - - input := mustLoadLiveCreateAccountAcceptInput(t) - - var preparedTx interactive.PreparedTransaction - require.NoError(t, proto.Unmarshal(input.SetupProposalPreparedTransaction, &preparedTx)) - - expectedHash, err := ComputePreparedTransactionHash(&preparedTx) - require.NoError(t, err) - - err = ValidatePreparedTransactionHash(&preparedTx, expectedHash) - require.NoError(t, err) - - require.NoError(t, input.VerifySignaturePayloads()) -} - -func mustLoadLiveCreateAccountAcceptInput(t *testing.T) *CreateAccountInput { - t.Helper() - - data, err := os.ReadFile("testdata/live_create_account_accept.json") - require.NoError(t, err) - - var fixture struct { - CreateAccountInput string `json:"create_account_input"` - } - require.NoError(t, json.Unmarshal(data, &fixture)) - - encoded, err := hex.DecodeString(fixture.CreateAccountInput) - require.NoError(t, err) - - input, err := ParseCreateAccountInput(encoded) - require.NoError(t, err) - return input -} - -func testPreparedTransaction(nodeID string, node *v1.Node) *interactive.PreparedTransaction { - tx := &interactive.PreparedTransaction{ - Transaction: &interactive.DamlTransaction{ - Version: "2", - Roots: []string{nodeID}, - Nodes: []*interactive.DamlTransaction_Node{ - { - NodeId: nodeID, - VersionedNode: &interactive.DamlTransaction_Node_V1{ - V1: node, - }, - }, - }, - }, - Metadata: &interactive.Metadata{ - SubmitterInfo: &interactive.Metadata_SubmitterInfo{ - ActAs: []string{"sender::1220aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, - CommandId: "command-id", - }, - SynchronizerId: "sync-id", - TransactionUuid: "transaction-uuid", - PreparationTime: 1, - InputContracts: []*interactive.Metadata_InputContract{}, - }, - } - if node.GetExercise() != nil { - seedID, err := strconv.Atoi(nodeID) - if err != nil { - panic(err) - } - tx.Transaction.NodeSeeds = []*interactive.DamlTransaction_NodeSeed{ - {NodeId: int32(seedID), Seed: bytes.Repeat([]byte{0x11}, 32)}, - } - } - return tx -} - -func testPreparedTransactionHash(t *testing.T, preparedTx *interactive.PreparedTransaction) []byte { - t.Helper() - hash, err := ComputePreparedTransactionHash(preparedTx) - require.NoError(t, err) - return hash -} - -func testCreateNode(entity string, argument *v2.Value) *v1.Node { - return &v1.Node{ - NodeType: &v1.Node_Create{ - Create: &v1.Create{ - TemplateId: &v2.Identifier{ - PackageId: "pkg", - ModuleName: "Splice.Wallet.TransferOffer", - EntityName: entity, - }, - ContractId: "001122", - PackageName: "splice-wallet", - Argument: argument, - }, - }, - } -} - -func testExerciseNode(choice string, chosenValue *v2.Value) *v1.Node { - return &v1.Node{ - NodeType: &v1.Node_Exercise{ - Exercise: &v1.Exercise{ - TemplateId: &v2.Identifier{ - PackageId: "pkg", - ModuleName: "Splice.Wallet", - EntityName: "Any", - }, - ContractId: "001122", - PackageName: "splice-wallet", - ChoiceId: choice, - ChosenValue: chosenValue, - }, - }, - } -} - -func testTransferOfferArgument(receiver string, amount string) *v2.Value { - return &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "receiver", - Value: &v2.Value{Sum: &v2.Value_Party{Party: receiver}}, - }, - { - Label: "amount", - Value: &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "amount", - Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -func testAmountRecord(amount string) *v2.Value { - return &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{ - Fields: []*v2.RecordField{ - { - Label: "amount", - Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, - }, - }, - }, - }, - } -} - -func testEmptyRecord() *v2.Value { - return &v2.Value{ - Sum: &v2.Value_Record{ - Record: &v2.Record{}, - }, - } -} diff --git a/chain/canton/tx_input/testdata/live_topology_vector.json b/chain/canton/tx_input/testdata/live_topology_vector.json deleted file mode 100644 index 4d730121..00000000 --- a/chain/canton/tx_input/testdata/live_topology_vector.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "public_key_fingerprint": "1220fb837a9079c66e39bde8d45dfc6e79dc80f7c931940a01d6622e4fee0b40933c", - "multi_hash": "12206947cbe26cda1680526f5a6957927b9272bc5ca3d2af6dc7946d9c3182bfe8de", - "topology_transactions": [ - "0ab602080110011aaf024aac020a8601366166636665383630353565643562616636613437663537356636353566666162333836653032373938653332626463373736303363613233386239623635623a3a313232306662383337613930373963363665333962646538643435646663366537396463383066376339333139343061303164363632326534666565306234303933336310011a620a5e76616c696461746f722d636f726469616c73797374656d733a3a31323230653666626163393063636431393763333536363931386639393937373362303434393565313537616463316662383033623936656465326561613562336164661002323b0a3710041a2c302a300506032b65700321006afcfe86055ed5baf6a47f575f655ffab386e02798e32bdc77603ca238b9b65b2a0301050430011001101e" - ] -} diff --git a/chain/canton/tx_input/topology_hash_test.go b/chain/canton/tx_input/topology_hash_test.go deleted file mode 100644 index bc58e49d..00000000 --- a/chain/canton/tx_input/topology_hash_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package tx_input - -import ( - "encoding/hex" - "encoding/json" - "os" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestComputeTopologyMultiHashFailures(t *testing.T) { - t.Parallel() - - _, err := ComputeTopologyMultiHash(nil) - require.ErrorContains(t, err, "topology transactions are empty") - - _, err = ComputeTopologyMultiHash([][]byte{{}}) - require.ErrorContains(t, err, "topology transaction is empty") -} - -func TestComputeTopologyMultiHash_LiveVector(t *testing.T) { - t.Parallel() - - vector := mustLoadLiveTopologyVector(t) - hash, err := ComputeTopologyMultiHash(vector.topologyTransactions) - require.NoError(t, err) - require.Equal(t, vector.multiHash, hash) -} - -type liveTopologyVector struct { - multiHash []byte - topologyTransactions [][]byte -} - -func mustLoadLiveTopologyVector(t *testing.T) liveTopologyVector { - t.Helper() - - data, err := os.ReadFile("testdata/live_topology_vector.json") - require.NoError(t, err) - - var fixture struct { - MultiHash string `json:"multi_hash"` - TopologyTransactions []string `json:"topology_transactions"` - } - require.NoError(t, json.Unmarshal(data, &fixture)) - - multiHash, err := hex.DecodeString(fixture.MultiHash) - require.NoError(t, err) - - topologyTransactions := make([][]byte, 0, len(fixture.TopologyTransactions)) - for _, encoded := range fixture.TopologyTransactions { - tx, err := hex.DecodeString(encoded) - require.NoError(t, err) - topologyTransactions = append(topologyTransactions, tx) - } - - return liveTopologyVector{ - multiHash: multiHash, - topologyTransactions: topologyTransactions, - } -} diff --git a/chain/canton/tx_input/tx_input.go b/chain/canton/tx_input/tx_input.go index 2e3d9cff..ac641c03 100644 --- a/chain/canton/tx_input/tx_input.go +++ b/chain/canton/tx_input/tx_input.go @@ -26,6 +26,7 @@ type TxInput struct { } var _ xc.TxInput = &TxInput{} +var _ xc.TxInputWithUnix = &TxInput{} func init() { registry.RegisterTxBaseInput(&TxInput{}) @@ -42,6 +43,9 @@ func NewTxInput() *TxInput { func (input *TxInput) GetDriver() xc.Driver { return xc.DriverCanton } +func (input *TxInput) SetUnix(unix int64) { + // TODO +} func (input *TxInput) SetGasFeePriority(other xc.GasFeePriority) error { // Canton does not use gas fees in the traditional sense From 09f42ce8d8d026b2c75b2c48cf30d597d956f643 Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Mon, 13 Apr 2026 10:27:40 +0200 Subject: [PATCH 22/23] Canton: Add upload token standard dars script --- scripts/upload_canton_token_standard_dars.sh | 152 +++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100755 scripts/upload_canton_token_standard_dars.sh diff --git a/scripts/upload_canton_token_standard_dars.sh b/scripts/upload_canton_token_standard_dars.sh new file mode 100755 index 00000000..3e4e4ab8 --- /dev/null +++ b/scripts/upload_canton_token_standard_dars.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + cat <<'EOF' +Upload Canton token-standard interface DARs to a participant using grpcurl. + +Required environment variables: + PARTICIPANT_HOST gRPC host:port of the participant + AUTH_TOKEN Bearer token with package upload rights + +Optional environment variables: + SYNCHRONIZER_ID Target synchronizer/domain id for vetting + PROTO_ROOT Defaults to ~/Source/splice/canton/community/ledger-api/src/main/protobuf + PACKAGE_PROTO Defaults to com/daml/ledger/api/v2/admin/package_management_service.proto + VALIDATE_FIRST Defaults to 1. Set to 0 to skip ValidateDarFile calls. + LIST_AFTER Defaults to 1. Set to 0 to skip ListKnownPackages at the end. + +The script uploads these DARs in dependency order: + splice-api-token-metadata-v1 + splice-api-token-holding-v1 + splice-api-token-transfer-instruction-v1 + splice-api-token-allocation-v1 + splice-api-token-allocation-request-v1 + splice-api-token-allocation-instruction-v1 +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +: "${PARTICIPANT_HOST:?PARTICIPANT_HOST is required}" +: "${AUTH_TOKEN:?AUTH_TOKEN is required}" + +PROTO_ROOT="${PROTO_ROOT:-$HOME/Source/splice/canton/community/ledger-api/src/main/protobuf}" +PACKAGE_PROTO="${PACKAGE_PROTO:-com/daml/ledger/api/v2/admin/package_management_service.proto}" +VALIDATE_FIRST="${VALIDATE_FIRST:-1}" +LIST_AFTER="${LIST_AFTER:-1}" + +DAR_METADATA="${DAR_METADATA:-$HOME/Source/splice/token-standard/splice-api-token-metadata-v1/.daml/dist/splice-api-token-metadata-v1-1.0.0.dar}" +DAR_HOLDING="${DAR_HOLDING:-$HOME/Source/splice/token-standard/splice-api-token-holding-v1/.daml/dist/splice-api-token-holding-v1-1.0.0.dar}" +DAR_TRANSFER_INSTR="${DAR_TRANSFER_INSTR:-$HOME/Source/splice/token-standard/splice-api-token-transfer-instruction-v1/.daml/dist/splice-api-token-transfer-instruction-v1-1.0.0.dar}" +DAR_ALLOCATION="${DAR_ALLOCATION:-$HOME/Source/splice/token-standard/splice-api-token-allocation-v1/.daml/dist/splice-api-token-allocation-v1-1.0.0.dar}" +DAR_ALLOC_REQ="${DAR_ALLOC_REQ:-$HOME/Source/splice/token-standard/splice-api-token-allocation-request-v1/.daml/dist/splice-api-token-allocation-request-v1-1.0.0.dar}" +DAR_ALLOC_INSTR="${DAR_ALLOC_INSTR:-$HOME/Source/splice/token-standard/splice-api-token-allocation-instruction-v1/.daml/dist/splice-api-token-allocation-instruction-v1-1.0.0.dar}" + +DARS=( + "$DAR_METADATA" + "$DAR_HOLDING" + "$DAR_TRANSFER_INSTR" + "$DAR_ALLOCATION" + "$DAR_ALLOC_REQ" + "$DAR_ALLOC_INSTR" +) + +for dar in "${DARS[@]}"; do + if [[ ! -f "$dar" ]]; then + echo "DAR not found: $dar" >&2 + exit 1 + fi +done + +if [[ ! -f "$PROTO_ROOT/$PACKAGE_PROTO" ]]; then + echo "Proto not found: $PROTO_ROOT/$PACKAGE_PROTO" >&2 + exit 1 +fi + +grpc_call() { + local method="$1" + grpcurl \ + -H "authorization: Bearer $AUTH_TOKEN" \ + -import-path "$PROTO_ROOT" \ + -proto "$PACKAGE_PROTO" \ + -d @ \ + "$PARTICIPANT_HOST" \ + "$method" +} + +json_for_dar() { + local dar="$1" + local submission_id="$2" + local action="$3" + + if [[ -n "${SYNCHRONIZER_ID:-}" ]]; then + jq -n \ + --arg darFile "$(base64 < "$dar" | tr -d '\n')" \ + --arg submissionId "$submission_id" \ + --arg synchronizerId "$SYNCHRONIZER_ID" \ + --arg action "$action" \ + 'if $action == "validate" then + { + darFile: $darFile, + submissionId: $submissionId, + synchronizerId: $synchronizerId + } + else + { + darFile: $darFile, + submissionId: $submissionId, + vettingChange: "VETTING_CHANGE_VET_ALL_PACKAGES", + synchronizerId: $synchronizerId + } + end' + else + jq -n \ + --arg darFile "$(base64 < "$dar" | tr -d '\n')" \ + --arg submissionId "$submission_id" \ + --arg action "$action" \ + 'if $action == "validate" then + { + darFile: $darFile, + submissionId: $submissionId + } + else + { + darFile: $darFile, + submissionId: $submissionId, + vettingChange: "VETTING_CHANGE_VET_ALL_PACKAGES" + } + end' + fi +} + +validate_dar() { + local dar="$1" + local sid="validate-$(basename "$dar")-$(date +%s)" + json_for_dar "$dar" "$sid" "validate" | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/ValidateDarFile" +} + +upload_dar() { + local dar="$1" + local sid="upload-$(basename "$dar")-$(date +%s)" + json_for_dar "$dar" "$sid" "upload" | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/UploadDarFile" +} + +for dar in "${DARS[@]}"; do + echo "==> $(basename "$dar")" + if [[ "$VALIDATE_FIRST" == "1" ]]; then + echo " validating" + validate_dar "$dar" + fi + echo " uploading" + upload_dar "$dar" +done + +if [[ "$LIST_AFTER" == "1" ]]; then + echo "==> listing known packages" + printf '{}' | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/ListKnownPackages" +fi From 2b3b82ab83df7ef86baa2545cefd809afc6778cb Mon Sep 17 00:00:00 2001 From: PawelBis <24803993+PawelBis@users.noreply.github.com> Date: Tue, 14 Apr 2026 13:49:41 +0200 Subject: [PATCH 23/23] CANTON: Token setup scripts + balance implementation --- chain/canton/client/client.go | 104 +++++++++- chain/canton/client/client_test.go | 181 +++++++++++++++++- chain/canton/client/ledger.go | 84 ++++++++ factory/defaults/chains/testnet.yaml | 10 +- scripts/create_canton_dummy_holding.sh | 234 +++++++++++++++++++++++ scripts/list_canton_token_holdings.sh | 191 ++++++++++++++++++ scripts/upload_canton_dummy_token_dar.sh | 136 +++++++++++++ 7 files changed, 929 insertions(+), 11 deletions(-) create mode 100755 scripts/create_canton_dummy_holding.sh create mode 100755 scripts/list_canton_token_holdings.sh create mode 100755 scripts/upload_canton_dummy_token_dar.sh diff --git a/chain/canton/client/client.go b/chain/canton/client/client.go index 26bbea73..18a15c81 100644 --- a/chain/canton/client/client.go +++ b/chain/canton/client/client.go @@ -794,6 +794,61 @@ func parseHumanAmountToBlockchain(value string, decimals int32) (xc.AmountBlockc return human.ToBlockchain(decimals), true } +func parseCantonTokenContract(contract xc.ContractAddress) (string, string, bool) { + parts := strings.SplitN(string(contract), "#", 2) + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", false + } + return parts[0], parts[1], true +} + +func getRecordFieldValue(record *v2.Record, key string) (*v2.Value, bool) { + if record == nil { + return nil, false + } + for _, field := range record.GetFields() { + if field.GetLabel() == key { + return field.GetValue(), true + } + } + return nil, false +} + +func extractTokenHoldingView(created *v2.CreatedEvent) (owner string, instrumentAdmin string, instrumentID string, amount string, ok bool) { + if created == nil { + return "", "", "", "", false + } + for _, view := range created.GetInterfaceViews() { + interfaceID := view.GetInterfaceId() + if interfaceID == nil || interfaceID.GetModuleName() != "Splice.Api.Token.HoldingV1" || interfaceID.GetEntityName() != "Holding" { + continue + } + record := view.GetViewValue() + ownerValue, ok := getRecordFieldValue(record, "owner") + if !ok || ownerValue.GetParty() == "" { + return "", "", "", "", false + } + instrumentValue, ok := getRecordFieldValue(record, "instrumentId") + if !ok || instrumentValue.GetRecord() == nil { + return "", "", "", "", false + } + adminValue, ok := getRecordFieldValue(instrumentValue.GetRecord(), "admin") + if !ok || adminValue.GetParty() == "" { + return "", "", "", "", false + } + idValue, ok := getRecordFieldValue(instrumentValue.GetRecord(), "id") + if !ok || idValue.GetText() == "" { + return "", "", "", "", false + } + amountValue, ok := getRecordFieldValue(record, "amount") + if !ok || amountValue.GetNumeric() == "" { + return "", "", "", "", false + } + return ownerValue.GetParty(), adminValue.GetParty(), idValue.GetText(), amountValue.GetNumeric(), true + } + return "", "", "", "", false +} + func parseRecoveryLookupId(value string) (int64, string, bool) { idx := strings.Index(value, "-") if idx <= 0 || idx == len(value)-1 { @@ -809,7 +864,46 @@ func parseRecoveryLookupId(value string) (int64, string, bool) { func (client *Client) FetchBalance(ctx context.Context, args *xclient.BalanceArgs) (xc.AmountBlockchain, error) { zero := xc.NewAmountBlockchainFromUint64(0) if contract, ok := args.Contract(); ok { - return zero, fmt.Errorf("token balance queries not yet supported for Canton, contract: %s", contract) + partyID := string(args.Address()) + if partyID == "" { + return zero, fmt.Errorf("empty address") + } + ledgerEnd, err := client.ledgerClient.GetLedgerEnd(ctx) + if err != nil { + return zero, fmt.Errorf("failed to get ledger end: %w", err) + } + packageID, err := client.ledgerClient.ResolvePackageIDByName(ctx, "splice-api-token-holding-v1") + if err != nil { + return zero, fmt.Errorf("failed to resolve token holding interface package: %w", err) + } + contracts, err := client.ledgerClient.GetTokenHoldingContracts(ctx, partyID, ledgerEnd, packageID) + if err != nil { + return zero, fmt.Errorf("failed to query token holding contracts for party %s: %w", partyID, err) + } + + admin, instrumentID, ok := parseCantonTokenContract(contract) + if !ok { + return zero, fmt.Errorf("invalid Canton token contract %q, expected #", contract) + } + decimals := client.Asset.GetChain().Decimals + if assetCfg, ok := client.Asset.FindAdditionalNativeAsset(contract); ok && assetCfg.Decimals > 0 { + decimals = assetCfg.Decimals + } + + totalBalance := xc.NewAmountBlockchainFromUint64(0) + for _, c := range contracts { + created := c.GetCreatedEvent() + _, holdingAdmin, holdingID, amount, ok := extractTokenHoldingView(created) + if !ok || holdingAdmin != admin || holdingID != instrumentID { + continue + } + bal, ok := parseHumanAmountToBlockchain(amount, decimals) + if !ok { + continue + } + totalBalance = totalBalance.Add(&bal) + } + return totalBalance, nil } return client.FetchNativeBalance(ctx, args.Address()) @@ -881,7 +975,13 @@ func (client *Client) FetchDecimals(ctx context.Context, contract xc.ContractAdd if client.Asset.GetChain().IsChain(contract) { return int(client.Asset.GetChain().GetDecimals()), nil } - return 0, fmt.Errorf("token decimals are not supported for Canton, contract: %s", contract) + if assetCfg, ok := client.Asset.FindAdditionalNativeAsset(contract); ok && assetCfg.Decimals > 0 { + return int(assetCfg.Decimals), nil + } + if _, _, ok := parseCantonTokenContract(contract); ok { + return int(client.Asset.GetChain().GetDecimals()), nil + } + return 0, fmt.Errorf("invalid Canton token contract %q, expected #", contract) } func (client *Client) FetchBlock(ctx context.Context, args *xclient.BlockArgs) (*txinfo.BlockWithTransactions, error) { diff --git a/chain/canton/client/client_test.go b/chain/canton/client/client_test.go index a0fc6899..6d291297 100644 --- a/chain/canton/client/client_test.go +++ b/chain/canton/client/client_test.go @@ -15,7 +15,9 @@ import ( cantontx "github.com/cordialsys/crosschain/chain/canton/tx" "github.com/cordialsys/crosschain/chain/canton/tx_input" v2 "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2" + "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/admin" "github.com/cordialsys/crosschain/chain/canton/types/com/daml/ledger/api/v2/interactive" + xclient "github.com/cordialsys/crosschain/client" txinfo "github.com/cordialsys/crosschain/client/tx_info" xctypes "github.com/cordialsys/crosschain/client/types" "github.com/sirupsen/logrus" @@ -66,8 +68,12 @@ func TestFetchDecimals(t *testing.T) { Driver: xc.DriverCanton, Decimals: 18, }, + ChainClientConfig: &xc.ChainClientConfig{}, }, } + client.Asset.NativeAssets = []*xc.AdditionalNativeAsset{ + xc.NewAdditionalNativeAsset("DUMMY", "", xc.ContractAddress("issuer-party#DummyHolding"), 10, xc.AmountHumanReadable{}), + } decimals, err := client.FetchDecimals(context.Background(), "") require.NoError(t, err) @@ -77,8 +83,79 @@ func TestFetchDecimals(t *testing.T) { require.NoError(t, err) require.Equal(t, 18, decimals) + decimals, err = client.FetchDecimals(context.Background(), xc.ContractAddress("issuer-party#DummyHolding")) + require.NoError(t, err) + require.Equal(t, 10, decimals) + + decimals, err = client.FetchDecimals(context.Background(), xc.ContractAddress("issuer-party#Unconfigured")) + require.NoError(t, err) + require.Equal(t, 18, decimals) + _, err = client.FetchDecimals(context.Background(), xc.ContractAddress("SOME_TOKEN")) - require.ErrorContains(t, err, "token decimals are not supported for Canton") + require.ErrorContains(t, err, "invalid Canton token contract") +} + +func TestFetchBalanceTokenHolding(t *testing.T) { + t.Parallel() + + party := xc.Address("owner-party") + stateStub := &stateServiceStub{ + ledgerEnd: 123, + activeContractsResponses: []*v2.GetActiveContractsResponse{ + { + ContractEntry: &v2.GetActiveContractsResponse_ActiveContract{ + ActiveContract: &v2.ActiveContract{ + CreatedEvent: testTokenHoldingCreatedEvent("owner-party", "issuer-party", "DummyHolding", "12.3456789012"), + }, + }, + }, + { + ContractEntry: &v2.GetActiveContractsResponse_ActiveContract{ + ActiveContract: &v2.ActiveContract{ + CreatedEvent: testTokenHoldingCreatedEvent("owner-party", "issuer-party", "OtherToken", "99.0"), + }, + }, + }, + }, + } + packageStub := &packageManagementStub{ + resp: &admin.ListKnownPackagesResponse{ + PackageDetails: []*admin.PackageDetails{ + {Name: "splice-api-token-holding-v1", PackageId: "holding-package-id"}, + }, + }, + } + client := &Client{ + Asset: &xc.ChainConfig{ + ChainBaseConfig: &xc.ChainBaseConfig{ + Chain: xc.CANTON, + Driver: xc.DriverCanton, + Decimals: 18, + }, + ChainClientConfig: &xc.ChainClientConfig{}, + }, + ledgerClient: &GrpcLedgerClient{ + authToken: "token", + stateClient: stateStub, + packageManagementClient: packageStub, + logger: logrus.NewEntry(logrus.New()), + }, + } + client.Asset.NativeAssets = []*xc.AdditionalNativeAsset{ + xc.NewAdditionalNativeAsset("DUMMY", "", xc.ContractAddress("issuer-party#DummyHolding"), 10, xc.AmountHumanReadable{}), + } + + balance, err := client.FetchBalance(context.Background(), xclient.NewBalanceArgs(party, xclient.BalanceOptionContract(xc.ContractAddress("issuer-party#DummyHolding")))) + require.NoError(t, err) + require.Equal(t, "123456789012", balance.String()) + require.NotNil(t, stateStub.lastActiveContractsReq) + require.Contains(t, stateStub.lastActiveContractsReq.GetEventFormat().GetFiltersByParty(), "owner-party") + filter := stateStub.lastActiveContractsReq.GetEventFormat().GetFiltersByParty()["owner-party"].GetCumulative()[0].GetInterfaceFilter() + require.NotNil(t, filter) + require.Equal(t, "holding-package-id", filter.GetInterfaceId().GetPackageId()) + require.Equal(t, "Splice.Api.Token.HoldingV1", filter.GetInterfaceId().GetModuleName()) + require.Equal(t, "Holding", filter.GetInterfaceId().GetEntityName()) + require.True(t, filter.GetIncludeInterfaceView()) } func TestValidatorServiceUserIDFromToken(t *testing.T) { @@ -737,11 +814,18 @@ func (s *updateServiceStub) GetUpdateByOffset(context.Context, *v2.GetUpdateByOf } type stateServiceStub struct { - ledgerEnd int64 + ledgerEnd int64 + lastActiveContractsReq *v2.GetActiveContractsRequest + activeContractsResponses []*v2.GetActiveContractsResponse + activeContractsErr error } -func (s *stateServiceStub) GetActiveContracts(context.Context, *v2.GetActiveContractsRequest, ...grpc.CallOption) (grpc.ServerStreamingClient[v2.GetActiveContractsResponse], error) { - panic("unexpected call") +func (s *stateServiceStub) GetActiveContracts(_ context.Context, req *v2.GetActiveContractsRequest, _ ...grpc.CallOption) (grpc.ServerStreamingClient[v2.GetActiveContractsResponse], error) { + s.lastActiveContractsReq = req + if s.activeContractsErr != nil { + return nil, s.activeContractsErr + } + return &activeContractsStreamStub{responses: s.activeContractsResponses}, nil } func (s *stateServiceStub) GetConnectedSynchronizers(context.Context, *v2.GetConnectedSynchronizersRequest, ...grpc.CallOption) (*v2.GetConnectedSynchronizersResponse, error) { @@ -756,6 +840,49 @@ func (s *stateServiceStub) GetLatestPrunedOffsets(context.Context, *v2.GetLatest panic("unexpected call") } +type activeContractsStreamStub struct { + grpc.ClientStream + responses []*v2.GetActiveContractsResponse + index int +} + +func (s *activeContractsStreamStub) Recv() (*v2.GetActiveContractsResponse, error) { + if s.index >= len(s.responses) { + return nil, io.EOF + } + resp := s.responses[s.index] + s.index++ + return resp, nil +} + +func (s *activeContractsStreamStub) Header() (metadata.MD, error) { return metadata.MD{}, nil } +func (s *activeContractsStreamStub) Trailer() metadata.MD { return metadata.MD{} } +func (s *activeContractsStreamStub) CloseSend() error { return nil } +func (s *activeContractsStreamStub) Context() context.Context { return context.Background() } +func (s *activeContractsStreamStub) SendMsg(any) error { return nil } +func (s *activeContractsStreamStub) RecvMsg(any) error { return nil } + +type packageManagementStub struct { + resp *admin.ListKnownPackagesResponse + err error +} + +func (s *packageManagementStub) ListKnownPackages(context.Context, *admin.ListKnownPackagesRequest, ...grpc.CallOption) (*admin.ListKnownPackagesResponse, error) { + return s.resp, s.err +} + +func (s *packageManagementStub) UploadDarFile(context.Context, *admin.UploadDarFileRequest, ...grpc.CallOption) (*admin.UploadDarFileResponse, error) { + panic("unexpected call") +} + +func (s *packageManagementStub) ValidateDarFile(context.Context, *admin.ValidateDarFileRequest, ...grpc.CallOption) (*admin.ValidateDarFileResponse, error) { + panic("unexpected call") +} + +func (s *packageManagementStub) UpdateVettedPackages(context.Context, *admin.UpdateVettedPackagesRequest, ...grpc.CallOption) (*admin.UpdateVettedPackagesResponse, error) { + panic("unexpected call") +} + func testAmuletCreatedEvent(owner string, initialAmount string) *v2.CreatedEvent { return &v2.CreatedEvent{ ContractId: "contract-id", @@ -793,6 +920,52 @@ func testAmuletCreatedEvent(owner string, initialAmount string) *v2.CreatedEvent } } +func testTokenHoldingCreatedEvent(owner string, issuer string, instrumentID string, amount string) *v2.CreatedEvent { + return &v2.CreatedEvent{ + ContractId: "token-contract-id", + InterfaceViews: []*v2.InterfaceView{ + { + InterfaceId: &v2.Identifier{ + PackageId: "holding-package-id", + ModuleName: "Splice.Api.Token.HoldingV1", + EntityName: "Holding", + }, + ViewValue: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "owner", + Value: &v2.Value{Sum: &v2.Value_Party{Party: owner}}, + }, + { + Label: "instrumentId", + Value: &v2.Value{ + Sum: &v2.Value_Record{ + Record: &v2.Record{ + Fields: []*v2.RecordField{ + { + Label: "admin", + Value: &v2.Value{Sum: &v2.Value_Party{Party: issuer}}, + }, + { + Label: "id", + Value: &v2.Value{Sum: &v2.Value_Text{Text: instrumentID}}, + }, + }, + }, + }, + }, + }, + { + Label: "amount", + Value: &v2.Value{Sum: &v2.Value_Numeric{Numeric: amount}}, + }, + }, + }, + }, + }, + } +} + func extractCommandAmountNumeric(t *testing.T, record *v2.Record) string { t.Helper() diff --git a/chain/canton/client/ledger.go b/chain/canton/client/ledger.go index 5601cbd4..3120c0f0 100644 --- a/chain/canton/client/ledger.go +++ b/chain/canton/client/ledger.go @@ -61,6 +61,7 @@ type GrpcLedgerClient struct { // Bearer token injected into every gRPC call authToken string adminClient admin.PartyManagementServiceClient + packageManagementClient admin.PackageManagementServiceClient commandClient v2.CommandServiceClient completionClient v2.CommandCompletionServiceClient interactiveSubmissionClient interactive.InteractiveSubmissionServiceClient @@ -116,6 +117,7 @@ func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityCon return &GrpcLedgerClient{ authToken: authToken, adminClient: admin.NewPartyManagementServiceClient(conn), + packageManagementClient: admin.NewPackageManagementServiceClient(conn), stateClient: v2.NewStateServiceClient(conn), updateClient: v2.NewUpdateServiceClient(conn), completionClient: v2.NewCommandCompletionServiceClient(conn), @@ -133,6 +135,32 @@ func NewGrpcLedgerClient(target string, authToken string, cfg runtimeIdentityCon }, nil } +func (c *GrpcLedgerClient) ResolvePackageIDByName(ctx context.Context, packageName string) (string, error) { + if packageName == "" { + return "", errors.New("empty required argument: packageName") + } + + authCtx := c.authCtx(ctx) + resp, err := c.packageManagementClient.ListKnownPackages(authCtx, &admin.ListKnownPackagesRequest{}) + if err != nil { + return "", fmt.Errorf("list known packages: %w", err) + } + + var latest *admin.PackageDetails + for _, detail := range resp.GetPackageDetails() { + if detail.GetName() != packageName { + continue + } + if latest == nil || detail.GetKnownSince().AsTime().After(latest.GetKnownSince().AsTime()) { + latest = detail + } + } + if latest == nil { + return "", fmt.Errorf("package not found: %s", packageName) + } + return latest.GetPackageId(), nil +} + // authCtx injects the Canton validator bearer token into the gRPC context. func (c *GrpcLedgerClient) authCtx(ctx context.Context) context.Context { if c.authToken == "" { @@ -317,6 +345,62 @@ func (c *GrpcLedgerClient) GetActiveContracts(ctx context.Context, partyID strin return activeContracts, nil } +func (c *GrpcLedgerClient) GetTokenHoldingContracts(ctx context.Context, partyID string, ledgerEnd int64, packageID string) ([]*v2.ActiveContract, error) { + if partyID == "" { + return nil, errors.New("empty required argument: partyID") + } + if packageID == "" { + return nil, errors.New("empty required argument: packageID") + } + + req := &v2.GetActiveContractsRequest{ + ActiveAtOffset: ledgerEnd, + EventFormat: &v2.EventFormat{ + Verbose: true, + FiltersByParty: map[string]*v2.Filters{ + partyID: { + Cumulative: []*v2.CumulativeFilter{{ + IdentifierFilter: &v2.CumulativeFilter_InterfaceFilter{ + InterfaceFilter: &v2.InterfaceFilter{ + InterfaceId: &v2.Identifier{ + PackageId: packageID, + ModuleName: "Splice.Api.Token.HoldingV1", + EntityName: "Holding", + }, + IncludeInterfaceView: true, + IncludeCreatedEventBlob: false, + }, + }, + }}, + }, + }, + }, + } + + authCtx := c.authCtx(ctx) + stream, err := c.stateClient.GetActiveContracts(authCtx, req) + if err != nil { + return nil, fmt.Errorf("failed to query token holding contracts for party %s: %w", partyID, err) + } + + activeContracts := make([]*v2.ActiveContract, 0) + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return nil, fmt.Errorf("error reading token holding contracts for party %s: %w", partyID, err) + } + contract := resp.GetActiveContract() + if contract == nil || contract.GetCreatedEvent() == nil { + continue + } + activeContracts = append(activeContracts, contract) + } + return activeContracts, nil +} + func (c *GrpcLedgerClient) CreateUser(ctx context.Context, partyId string) error { authCtx := c.authCtx(ctx) req := &admin.GrantUserRightsRequest{ diff --git a/factory/defaults/chains/testnet.yaml b/factory/defaults/chains/testnet.yaml index 9f307c8c..cb76d10e 100644 --- a/factory/defaults/chains/testnet.yaml +++ b/factory/defaults/chains/testnet.yaml @@ -225,11 +225,11 @@ chains: fee_limit: "100.0" confirmations_final: 1 custom_config: - keycloak_url: "" - keycloak_realm: "" - rest_api_url: "" - scan_proxy_url: "" - scan_api_url: "" + keycloak_url: "env:CANTON_KEYCLOAK_URL" + keycloak_realm: "env:CANTON_KEYCLOAK_REALM" + rest_api_url: "env:CANTON_REST_API_URL" + scan_proxy_url: "env:CANTON_SCAN_API_URL" + scan_api_url: "env:CANTON_SCAN_NODE_URL" validator_auth: "env:CANTON_VALIDATOR_BASIC_AUTH" canton_ui_auth: "env:CANTON_UI_BASIC_AUTH" diff --git a/scripts/create_canton_dummy_holding.sh b/scripts/create_canton_dummy_holding.sh new file mode 100755 index 00000000..1e6ae726 --- /dev/null +++ b/scripts/create_canton_dummy_holding.sh @@ -0,0 +1,234 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + cat <<'EOF' +Create a live DummyHolding token contract on a Canton participant using grpcurl. + +This targets the example token implementation package: + splice-token-test-dummy-holding + +Required environment variables: + PARTICIPANT_HOST gRPC host:port of the participant + AUTH_TOKEN Bearer token value, unless AUTH_HEADER is provided + OWNER_PARTY Party that will own the holding + AMOUNT Decimal amount, for example 10.0 + +Optional environment variables: + AUTH_HEADER Full authorization header value, e.g. "Bearer ey..." or "Basic abc..." + ISSUER_PARTY Defaults to OWNER_PARTY + USER_ID Optional Ledger API user id. Omitted if unset. + COMMAND_ID Defaults to dummy-holding- + SUBMISSION_ID Defaults to create-dummy-holding- + DEDUP_SECONDS Defaults to 300 + SYNCHRONIZER_ID Optional synchronizer/domain id + PACKAGE_NAME Defaults to splice-token-test-dummy-holding + +Notes: + - DummyHolding has signatories owner and issuer. + - The auth token must be authorized to act_as both parties. + - The script uses gRPC reflection and auto-resolves the uploaded package_id from ListKnownPackages. +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +: "${PARTICIPANT_HOST:?PARTICIPANT_HOST is required}" +: "${AUTH_TOKEN:?AUTH_TOKEN is required}" +: "${OWNER_PARTY:?OWNER_PARTY is required}" +: "${AMOUNT:?AMOUNT is required}" + +AUTH_HEADER="${AUTH_HEADER:-Bearer $AUTH_TOKEN}" +ISSUER_PARTY="${ISSUER_PARTY:-$OWNER_PARTY}" +USER_ID="${USER_ID:-}" +COMMAND_ID="${COMMAND_ID:-dummy-holding-$(date +%s)}" +SUBMISSION_ID="${SUBMISSION_ID:-create-dummy-holding-$(date +%s)}" +DEDUP_SECONDS="${DEDUP_SECONDS:-300}" +PACKAGE_NAME="${PACKAGE_NAME:-splice-token-test-dummy-holding}" + +grpc_call() { + local method="$1" + local tmp + tmp="$(mktemp)" + if ! grpcurl \ + -H "authorization: $AUTH_HEADER" \ + -d @ \ + "$PARTICIPANT_HOST" \ + "$method" >"$tmp"; then + cat "$tmp" >&2 || true + rm -f "$tmp" + return 1 + fi + cat "$tmp" + rm -f "$tmp" +} + +resolve_package_id() { + local response + response="$(printf '{}' | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/ListKnownPackages")" || return 1 + if ! jq -e '(.package_details // .packageDetails) != null' >/dev/null <<<"$response"; then + echo "Unexpected ListKnownPackages response:" >&2 + echo "$response" >&2 + return 1 + fi + jq -r --arg packageName "$PACKAGE_NAME" ' + (.package_details // .packageDetails) + | map(select(.name == $packageName)) + | sort_by((.known_since // .knownSince)) + | last + | (.package_id // .packageId // empty) + ' <<<"$response" +} + +PACKAGE_ID="$(resolve_package_id)" +if [[ -z "$PACKAGE_ID" ]]; then + echo "Could not resolve package id for $PACKAGE_NAME. Upload the implementation DAR first." >&2 + exit 1 +fi + +build_request() { + if [[ -n "${SYNCHRONIZER_ID:-}" ]]; then + jq -n \ + --arg packageId "$PACKAGE_ID" \ + --arg owner "$OWNER_PARTY" \ + --arg issuer "$ISSUER_PARTY" \ + --arg amount "$AMOUNT" \ + --arg userId "$USER_ID" \ + --arg commandId "$COMMAND_ID" \ + --arg submissionId "$SUBMISSION_ID" \ + --arg dedupDuration "${DEDUP_SECONDS}s" \ + --arg synchronizerId "$SYNCHRONIZER_ID" \ + ' + { + commands: ( + { + commandId: $commandId, + commands: [ + { + create: { + templateId: { + packageId: $packageId, + moduleName: "Splice.Api.Token.Test.DummyHolding", + entityName: "DummyHolding" + }, + createArguments: { + recordId: { + packageId: $packageId, + moduleName: "Splice.Api.Token.Test.DummyHolding", + entityName: "DummyHolding" + }, + fields: [ + { label: "owner", value: { party: $owner } }, + { label: "issuer", value: { party: $issuer } }, + { label: "amount", value: { numeric: $amount } } + ] + } + } + } + ], + deduplicationDuration: $dedupDuration, + actAs: [$owner, $issuer], + submissionId: $submissionId, + synchronizerId: $synchronizerId + } + | if $userId != "" then . + { userId: $userId } else . end + ), + transactionFormat: { + eventFormat: { + filtersByParty: { + ($owner): { + cumulative: [ + { + templateFilter: { + templateId: { + packageId: $packageId, + moduleName: "Splice.Api.Token.Test.DummyHolding", + entityName: "DummyHolding" + }, + includeCreatedEventBlob: true + } + } + ] + } + }, + verbose: true + }, + transactionShape: "TRANSACTION_SHAPE_ACS_DELTA" + } + }' + else + jq -n \ + --arg packageId "$PACKAGE_ID" \ + --arg owner "$OWNER_PARTY" \ + --arg issuer "$ISSUER_PARTY" \ + --arg amount "$AMOUNT" \ + --arg userId "$USER_ID" \ + --arg commandId "$COMMAND_ID" \ + --arg submissionId "$SUBMISSION_ID" \ + --arg dedupDuration "${DEDUP_SECONDS}s" ' + { + commands: ( + { + commandId: $commandId, + commands: [ + { + create: { + templateId: { + packageId: $packageId, + moduleName: "Splice.Api.Token.Test.DummyHolding", + entityName: "DummyHolding" + }, + createArguments: { + recordId: { + packageId: $packageId, + moduleName: "Splice.Api.Token.Test.DummyHolding", + entityName: "DummyHolding" + }, + fields: [ + { label: "owner", value: { party: $owner } }, + { label: "issuer", value: { party: $issuer } }, + { label: "amount", value: { numeric: $amount } } + ] + } + } + } + ], + deduplicationDuration: $dedupDuration, + actAs: [$owner, $issuer], + submissionId: $submissionId + } + | if $userId != "" then . + { userId: $userId } else . end + ), + transactionFormat: { + eventFormat: { + filtersByParty: { + ($owner): { + cumulative: [ + { + templateFilter: { + templateId: { + packageId: $packageId, + moduleName: "Splice.Api.Token.Test.DummyHolding", + entityName: "DummyHolding" + }, + includeCreatedEventBlob: true + } + } + ] + } + }, + verbose: true + }, + transactionShape: "TRANSACTION_SHAPE_ACS_DELTA" + } + }' + fi +} + +echo "Resolved package id: $PACKAGE_ID" >&2 +build_request \ + | grpc_call "com.daml.ledger.api.v2.CommandService/SubmitAndWaitForTransaction" diff --git a/scripts/list_canton_token_holdings.sh b/scripts/list_canton_token_holdings.sh new file mode 100755 index 00000000..da9407cc --- /dev/null +++ b/scripts/list_canton_token_holdings.sh @@ -0,0 +1,191 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + cat <<'EOF' +List Canton token-standard holdings for a party using grpcurl. + +Required environment variables: + PARTICIPANT_HOST gRPC host:port of the participant + PARTY_ID Party whose holdings should be listed + AUTH_TOKEN Bearer token value, unless AUTH_HEADER is provided + +Optional environment variables: + AUTH_HEADER Full authorization header value, e.g. "Bearer ey..." or "Basic abc..." + CONTRACT Optional token selector in the form # + PACKAGE_NAME Defaults to splice-api-token-holding-v1 + LEDGER_END Optional fixed offset. If unset, fetched from GetLedgerEnd. + RAW Defaults to 0. Set to 1 to print the raw streaming response. + +Output: + A JSON array of holdings with: + - contract_id + - owner + - instrument_admin + - instrument_id + - amount + - template +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +: "${PARTICIPANT_HOST:?PARTICIPANT_HOST is required}" +: "${PARTY_ID:?PARTY_ID is required}" +: "${AUTH_TOKEN:?AUTH_TOKEN is required}" + +AUTH_HEADER="${AUTH_HEADER:-Bearer $AUTH_TOKEN}" +CONTRACT="${CONTRACT:-}" +PACKAGE_NAME="${PACKAGE_NAME:-splice-api-token-holding-v1}" +LEDGER_END="${LEDGER_END:-}" +RAW="${RAW:-0}" + +grpc_call() { + local method="$1" + local tmp + tmp="$(mktemp)" + if ! grpcurl \ + -H "authorization: $AUTH_HEADER" \ + -d @ \ + "$PARTICIPANT_HOST" \ + "$method" >"$tmp"; then + cat "$tmp" >&2 || true + rm -f "$tmp" + return 1 + fi + cat "$tmp" + rm -f "$tmp" +} + +resolve_package_id() { + local response + response="$(printf '{}' | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/ListKnownPackages")" || return 1 + if ! jq -e '(.package_details // .packageDetails) != null' >/dev/null <<<"$response"; then + echo "Unexpected ListKnownPackages response:" >&2 + echo "$response" >&2 + return 1 + fi + jq -r --arg packageName "$PACKAGE_NAME" ' + (.package_details // .packageDetails) + | map(select(.name == $packageName)) + | sort_by((.known_since // .knownSince)) + | last + | (.package_id // .packageId // empty) + ' <<<"$response" +} + +if [[ -z "$LEDGER_END" ]]; then + ledger_end_response="$(printf '{}' | grpc_call "com.daml.ledger.api.v2.StateService/GetLedgerEnd")" || exit 1 + if ! jq -e '(.offset // .ledger_end // .ledgerEnd) != null' >/dev/null <<<"$ledger_end_response"; then + echo "Unexpected GetLedgerEnd response:" >&2 + echo "$ledger_end_response" >&2 + exit 1 + fi + LEDGER_END="$(jq -r '(.offset // .ledger_end // .ledgerEnd)' <<<"$ledger_end_response")" +fi + +PACKAGE_ID="$(resolve_package_id)" +if [[ -z "$PACKAGE_ID" ]]; then + echo "Could not resolve package id for $PACKAGE_NAME" >&2 + exit 1 +fi + +tmp="$(mktemp)" +trap 'rm -f "$tmp"' EXIT + +jq -n \ + --arg party "$PARTY_ID" \ + --arg packageId "$PACKAGE_ID" \ + --argjson ledgerEnd "$LEDGER_END" \ + '{ + activeAtOffset: $ledgerEnd, + eventFormat: { + filtersByParty: { + ($party): { + cumulative: [ + { + interfaceFilter: { + interfaceId: { + packageId: $packageId, + moduleName: "Splice.Api.Token.HoldingV1", + entityName: "Holding" + }, + includeInterfaceView: true, + includeCreatedEventBlob: false + } + } + ] + } + }, + verbose: true + } + }' \ + | grpc_call "com.daml.ledger.api.v2.StateService/GetActiveContracts" >"$tmp" + +if ! jq -e 'type == "object" or type == "array"' >/dev/null <"$tmp"; then + echo "Unexpected GetActiveContracts response:" >&2 + cat "$tmp" >&2 + exit 1 +fi + +if jq -e 'type == "object" and ((has("activeContract") or has("active_contract")) | not) and ((has("offsetCheckpoint") or has("offset_checkpoint")) | not) and has("contractEntry")' >/dev/null <"$tmp"; then + jq '.activeContract = (.contractEntry.activeContract // .contractEntry.active_contract // null)' "$tmp" >"${tmp}.normalized" + mv "${tmp}.normalized" "$tmp" +fi + +if [[ "$RAW" == "1" ]]; then + cat "$tmp" + exit 0 +fi + +jq -s --arg contract "$CONTRACT" ' + def active_contract: (.activeContract // .active_contract // null); + def created_event: (.createdEvent // .created_event // null); + def template_id: (.templateId // .template_id // null); + def interface_views: (.interfaceViews // .interface_views // []); + def view_value: (.viewValue // .view_value // null); + def fields: (.fields // []); + def value: (.value // {}); + def record: (.record // {}); + map(select((active_contract) != null)) + | map((active_contract | created_event)) + | map({ + contract_id: (.contractId // .contract_id), + template: ( + if template_id == null then "" + else ((template_id.moduleName // template_id.module_name) + ":" + (template_id.entityName // template_id.entity_name)) + end + ), + owner: ( + interface_views[0] | view_value | fields[] + | select(.label == "owner") + | (.value.party // .value.party_id // "") + ), + instrument_admin: ( + interface_views[0] | view_value | fields[] + | select(.label == "instrumentId") + | (.value.record // .value.record_value // {}) | fields[] + | select(.label == "admin") + | (.value.party // .value.party_id // "") + ), + instrument_id: ( + interface_views[0] | view_value | fields[] + | select(.label == "instrumentId") + | (.value.record // .value.record_value // {}) | fields[] + | select(.label == "id") + | (.value.text // "") + ), + amount: ( + interface_views[0] | view_value | fields[] + | select(.label == "amount") + | (.value.numeric // "") + ) + }) + | if $contract == "" then . + else map(select((.instrument_admin + "#" + .instrument_id) == $contract)) + end +' "$tmp" diff --git a/scripts/upload_canton_dummy_token_dar.sh b/scripts/upload_canton_dummy_token_dar.sh new file mode 100755 index 00000000..f4e7c3f9 --- /dev/null +++ b/scripts/upload_canton_dummy_token_dar.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash + +set -euo pipefail + +usage() { + cat <<'EOF' +Upload a concrete Canton token implementation DAR to a participant using grpcurl. + +This script targets the smallest token-standard example implementation: + splice-token-test-dummy-holding + +Required environment variables: + PARTICIPANT_HOST gRPC host:port of the participant + AUTH_TOKEN Bearer token with package upload rights + +Optional environment variables: + SYNCHRONIZER_ID Target synchronizer/domain id for vetting + PROTO_ROOT Defaults to ~/Source/splice/canton/community/ledger-api/src/main/protobuf + PACKAGE_PROTO Defaults to com/daml/ledger/api/v2/admin/package_management_service.proto + VALIDATE_FIRST Defaults to 1. Set to 0 to skip ValidateDarFile calls. + LIST_AFTER Defaults to 1. Set to 0 to skip ListKnownPackages at the end. + TOKEN_IMPL_DAR Defaults to the built dummy holding DAR in the Splice repo. + +Before using this script: + 1. Upload the token-standard interface DARs first. + 2. Build the implementation DAR if it is missing. +EOF +} + +if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then + usage + exit 0 +fi + +: "${PARTICIPANT_HOST:?PARTICIPANT_HOST is required}" +: "${AUTH_TOKEN:?AUTH_TOKEN is required}" + +PROTO_ROOT="${PROTO_ROOT:-$HOME/Source/splice/canton/community/ledger-api/src/main/protobuf}" +PACKAGE_PROTO="${PACKAGE_PROTO:-com/daml/ledger/api/v2/admin/package_management_service.proto}" +VALIDATE_FIRST="${VALIDATE_FIRST:-1}" +LIST_AFTER="${LIST_AFTER:-1}" +TOKEN_IMPL_DAR="${TOKEN_IMPL_DAR:-$HOME/Source/splice/token-standard/examples/splice-token-test-dummy-holding/.daml/dist/splice-token-test-dummy-holding-0.0.2.dar}" + +if [[ ! -f "$TOKEN_IMPL_DAR" ]]; then + echo "DAR not found: $TOKEN_IMPL_DAR" >&2 + echo "Build it first, for example:" >&2 + echo ' cd ~/Source/splice/token-standard/examples/splice-token-test-dummy-holding' >&2 + echo ' ~/.cache/daml-build/3.3.0-snapshot.20250502.13767.0.v2fc6c7e2/damlc/damlc build' >&2 + exit 1 +fi + +if [[ ! -f "$PROTO_ROOT/$PACKAGE_PROTO" ]]; then + echo "Proto not found: $PROTO_ROOT/$PACKAGE_PROTO" >&2 + exit 1 +fi + +grpc_call() { + local method="$1" + grpcurl \ + -H "authorization: Bearer $AUTH_TOKEN" \ + -import-path "$PROTO_ROOT" \ + -proto "$PACKAGE_PROTO" \ + -d @ \ + "$PARTICIPANT_HOST" \ + "$method" +} + +json_for_dar() { + local dar="$1" + local submission_id="$2" + local action="$3" + + if [[ -n "${SYNCHRONIZER_ID:-}" ]]; then + jq -n \ + --arg darFile "$(base64 < "$dar" | tr -d '\n')" \ + --arg submissionId "$submission_id" \ + --arg synchronizerId "$SYNCHRONIZER_ID" \ + --arg action "$action" \ + 'if $action == "validate" then + { + darFile: $darFile, + submissionId: $submissionId, + synchronizerId: $synchronizerId + } + else + { + darFile: $darFile, + submissionId: $submissionId, + vettingChange: "VETTING_CHANGE_VET_ALL_PACKAGES", + synchronizerId: $synchronizerId + } + end' + else + jq -n \ + --arg darFile "$(base64 < "$dar" | tr -d '\n')" \ + --arg submissionId "$submission_id" \ + --arg action "$action" \ + 'if $action == "validate" then + { + darFile: $darFile, + submissionId: $submissionId + } + else + { + darFile: $darFile, + submissionId: $submissionId, + vettingChange: "VETTING_CHANGE_VET_ALL_PACKAGES" + } + end' + fi +} + +validate_dar() { + local dar="$1" + local sid="validate-$(basename "$dar")-$(date +%s)" + json_for_dar "$dar" "$sid" "validate" | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/ValidateDarFile" +} + +upload_dar() { + local dar="$1" + local sid="upload-$(basename "$dar")-$(date +%s)" + json_for_dar "$dar" "$sid" "upload" | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/UploadDarFile" +} + +echo "==> $(basename "$TOKEN_IMPL_DAR")" +if [[ "$VALIDATE_FIRST" == "1" ]]; then + echo " validating" + validate_dar "$TOKEN_IMPL_DAR" +fi +echo " uploading" +upload_dar "$TOKEN_IMPL_DAR" + +if [[ "$LIST_AFTER" == "1" ]]; then + echo "==> listing known packages" + printf '{}' | grpc_call "com.daml.ledger.api.v2.admin.PackageManagementService/ListKnownPackages" +fi