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
}
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.
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 X
s , 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?
scratch/
folder where you’re running this command. This is where your account token is stored.damlhub token [paste-token-here]
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]