How to fetch a contract from dumlhub Ledger via Java

Thanks @Leonid_Rozenberg

I indeed performed damlhub token eyJ0e…

And got this response but i wonder where the created token is saved so i can use it?

{
“message”: “Saved Daml Hub token with base domain: hub.daml.com”,
“success”: true
}

@liav Please read my response carefully.

damlhub token

is the not same as

damlhub ledger multipartyToken

The latter takes as argument the identity of parties that you want to add to a multiparty JWT. Whereas the former saves your account JWT locally (in the scratch folder) for reuse with other commands.

1 Like

Something like that? (sorry, i couldn’t find the manual nor the help entry on the client)

Command:
damlhub ledger multipartyToken p4np49dc43hsdza3 Carrier Owner

Output:

{
“accessToken”: “eyJ0eXAiOiJKV1QiLCJhbGciOiJSXXXXXXXXXXXXXXX1IiwiaHR0cHM6Ly9kYW1sLmNvbS9sZWRnZXItYXBpIjp7ImFjdEFzIjpbImxlZGdlci1wYXJ0eS04NTRlMwXXXXXXtuhafywLaaVPXmNEqlJS6z2sbSoetYz0KZ1X8G8rIVsP1M-zdw05CSxawMERXm6DJUm5W6raDnvSLUJ3kbh4A5IgJOs”
}

I don’t know if you copy and pasted correctly, sure looks like a lot of Xs :wink: , but yes that’s the right call.

What am i missing?

The command seemed to work (see earlier posts in this thread but now it fails with 401

Command:
damlhub ledger multipartyToken p4np49dc43hsdza3 Carrier Owner

Output:

2022-06-05 15:27:15,982 ERROR [tokens] Tried to compute a URL for .admin, .site; got back //login.hub.daml.com/auth/login which requires the same scope.
Unexpected error: Error: Received a 401 when making a site level API request.
    at TokenManager._this._circularTokenRequirement (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:198:19)
    at TokenManager.refreshToken (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:283:18)
    at TokenManager.<anonymous> (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:237:51)
    at step (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:67:23)
    at Object.next (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:48:53)
    at /Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:42:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:38:12)
    at TokenManager.getToken (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:228:16)
    at TokenManager.<anonymous> (/Users/le056g/.config/yarn/global/node_modules/damlhub-cli/lib/src/dabl/apiTokens.js:221:51)

I assume i need a preliminary login step? I tried running this command just befor the multiParty one but it didn’t help (i used account token):

damlhub token eyJ0eXAiOiJKV1QiLCJh....

@liav Maybe your account token has expired?

  1. Remove the scratch/ folder where you’re running this command. This is where your account token is stored.
  2. Get the latest account token from when you login into DamlHub.
  3. Save it locally with damlhub token [paste-token-here]
  4. Try running damlhub ledger multipartyToken

(@Alex_Matson @dtanabe , I wish there was a better error message here)

Thanks @Leonid_Rozenberg it worked as you suggested.

Can you please refer me to the online documentation of the JSON API/gRPC for ExerciseCommand with actAs and readAs additions (to support multiParty submission)

@liav
When you use HTTP JSON API, the actAs and readAs are taken from the token included in the HTTP request. For multiparty submission you simply need to include the token that contains all the actAs and readAs that you want to use.
For gRPC the act_as and read_as fields are included in the Commands message. You can find the definitions for the Commands message under Ledger API gRPC definitions on GitHub.

Thanks @a_putkov ,

I indeed use the gRPC api rather than the JSON API. If you have a link to the documentation of the multi submit via JSON API i would check it also.

For now, with current gRPC implementation - i couldn’t understand your reply: The fact that actAs and readAs lists are part of the message i’m aware of (see code below) but i wonder if i need to populate them both with same parties

Code:

private void exerciseCommandOnProduct(String contractId, ProductFields productFields, String multiPartyToken) {
        List<String> actAs     = Arrays.asList(damlProperties.getOwnerParty(), "DemoParty");
        List<String> readAs    = Arrays.asList(damlProperties.getOwnerParty(), "DemoParty");

        ArrayList<DamlRecord.Field> fields = new ArrayList<DamlRecord.Field>();
        fields.add(new DamlRecord.Field(new Party(damlProperties.getOwnerParty())));
        fields.add(new DamlRecord.Field(new Party(productFields.getProductCode())));

        DamlRecord choiceArgument = new DamlRecord(fields);

        ExerciseCommand command = new ExerciseCommand(TEMPLATE_ID, contractId, "CustomerCreatesPolicyRequest", choiceArgument);
        List<Command> commands = Collections.singletonList(command);

        final Single<Empty> emptySingle = client.
                getCommandSubmissionClient().
                submit(WORKFLOW_ID, APPLICATION_ID, UUID.randomUUID().toString(), actAs, readAs, commands, multiPartyToken);

        emptySingle.blockingGet();
    }

@liav
My apologies, I thought you were asking how to specify actAs and readAs in gRPC message. Now I understand your question to be about the significance of act_as and read_as fields, right?

act_as must include all parties, whose authority is required to execute the transaction, else the transaction will fail according to Daml ledger authorization rules.

read_as allows you to provide additional parties that may be required for the visibility of contracts involved in the transaction. As stated in the comments for the read_as field in the Commands message spec, "A command can only use contracts that are visible to at least one of the parties in act_as or read_as".

So, if every contract involved in the transaction is visible to at least one party in the act_as list, the read_as list does not need to be populated. However, if at least one contract involved in the transaction is not visible to any party in the act_as list, the transaction will fail unless read_as list contains at least one party, for which that contract is visible. An example, where a contract involved in the transaction may not be visible to any party authorizing the transaction, is a fetch action used in a choice, where the fetched contract is not visible to any of the choice controllers.

Thanks @a_putkov ,

I indeed encounter an issue on the exact topic you’re referring to: authentication.

My submitMulti Java implementation was as @Leonid_Rozenberg advised (see code below).

How can i gain access to the logs in order to understand the root cause of below authentication error thrown from the submit command?

The parties are: Owner2 Public

code:

multi party token is created via damlhub-cli:

damlhub ledger multipartyToken ry3wqxrcdqpkz7xz Owner2 Public

submitMulti:

private void exerciseCommandOnProduct(String contractId, ProductFields productFields, String multiPartyToken) {
        List<String> actAs   = Arrays.asList("Public", "Owner2");
        List<String> readAs = Arrays.asList("Public", "Owner2");

        ArrayList<DamlRecord.Field> fields = new ArrayList<DamlRecord.Field>();
        fields.add(new DamlRecord.Field(new Party("Owner2")));

        DamlRecord choiceArgument = new DamlRecord(fields);

        ExerciseCommand command = new ExerciseCommand(TEMPLATE_ID, contractId, "CustomerCreatesPolicyRequest", choiceArgument);
        List<Command> commands = Collections.singletonList(command);

        final Single<Empty> emptySingle = client.
                getCommandSubmissionClient().
                submit(WORKFLOW_ID, APPLICATION_ID, UUID.randomUUID().toString(), actAs, readAs, commands, multiPartyToken);

        emptySingle.blockingGet();
    }

Caused by: io.grpc.StatusRuntimeException: UNAUTHENTICATED: An error occurred. Please contact the operator and inquire about the request
at io.grpc.Status.asRuntimeException(Status.java:535) ~[grpc-api-1.44.0.jar:1.44.0]
at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:534) ~[grpc-stub-1.44.0.jar:1.44.0]
at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:562) ~[grpc-core-1.44.0.jar:1.44.0]
at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:70) ~[grpc-core-1.44.0.jar:1.44.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:743) ~[grpc-core-1.44.0.jar:1.44.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:722) ~[grpc-core-1.44.0.jar:1.44.0]
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.44.0.jar:1.44.0]
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) ~[grpc-core-1.44.0.jar:1.44.0]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

@liav
As @dtanabe explained in this post on another thread you opened, if you’re en enterprise user, you need to open a support ticket with Digital Asset Support team and provide your ledger ID to have the logs pulled from Daml Hub.

1 Like

@Roy_Silon @cohen.avraham