Make daml-script docs work with a Canton sandbox (#12695)

* Make daml-script docs work with a Canton sandbox

This addresses a few issues:

1. The `--wallclock-time` option does not work.
2. Display names are garbage so dropped the "solution" for
`listKnownParties`.
3. We cannot allocate fixed parties even with
`allocatePartyWithHint`. Switched to `--output-file` and user mgmt.

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* debug windows

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* debug scriptexample

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* Update docs/source/daml-script/index.rst
This commit is contained in:
Moritz Kiefer 2022-02-02 22:01:44 +01:00 committed by GitHub
parent c6ed12dc6c
commit 7a5172c025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 81 deletions

View File

@ -24,6 +24,15 @@ genrule(
cp -L $(location :daml/ScriptTest.daml) $$TMP_DIR/daml
cp -L $(location :daml/MultiTest.daml) $$TMP_DIR/daml
cp -L $(location //docs:source/daml-script/template-root/src/ScriptExample.daml) $$TMP_DIR/daml
cat << EOF >> $$TMP_DIR/daml/ScriptExample.daml
initializeFixed : Script ()
initializeFixed = do
alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")
bob <- allocatePartyWithHint "Bob" (PartyIdHint "Bob")
bank <- allocatePartyWithHint "Bank" (PartyIdHint "Bank")
let parties = LedgerParties{{..}}
initialize parties
EOF
cp -L $(location //daml-script/daml:daml-script.dar) $$TMP_DIR/
cat << EOF > $$TMP_DIR/daml.yaml
sdk-version: {sdk}

View File

@ -40,10 +40,11 @@ EXPECTED="$(cat <<'EOF'
MultiTest:listKnownPartiesTest SUCCESS
MultiTest:multiTest SUCCESS
MultiTest:partyIdHintTest SUCCESS
ScriptExample:allocateParties SUCCESS
ScriptExample:initializeFixed SUCCESS
ScriptExample:initializeFromQuery SUCCESS
ScriptExample:queryParties SUCCESS
ScriptExample:initializeUser SUCCESS
ScriptExample:test SUCCESS
ScriptTest:clearUsers SUCCESS
ScriptTest:failingTest FAILURE (com.daml.lf.engine.script.ScriptF$FailedCmd: Command submit failed: FAILED_PRECONDITION: DAML_INTERPRETATION_ERROR(9,XXXXXXXX): Interpretation error: Error: Unhandled Daml exception: DA.Exception.AssertionFailed:AssertionFailed@3f4deaf1{ message = "Assertion failed" }. Details: Last location: [DA.Internal.Exception:168], partial transaction:
ScriptTest:listKnownPartiesTest SUCCESS
ScriptTest:multiPartySubmission SUCCESS

View File

@ -532,10 +532,12 @@ testUserRightManagementForParties p1 p2 = do
pure ()
testUserManagement = do
clearUsers
p1 <- allocateParty "p1"
testUserManagementForParty p1
testUserRightManagement = do
clearUsers
p1 <- allocateParty "p1"
p2 <- allocateParty "p2"
testUserRightManagementForParties p1 p2
@ -547,3 +549,10 @@ jsonUserManagement p1 = do
jsonUserRightManagement : Party -> Script ()
jsonUserRightManagement p1 = do
testUserRightManagementForParties p1 p1
clearUsers : Script ()
clearUsers = do
admin <- validateUserId "participant_admin"
users <- listUsers
forA_ users $ \u ->
when (u.userId /= admin) $ deleteUser u.userId

View File

@ -152,12 +152,12 @@ uniquely. If you call ``allocateParty`` twice with the same display
name, it will create 2 different parties. This is very convenient for
testing since a new party cannot see any old contracts on the ledger
so using new parties for each test removes the need to reset the
ledger.
ledger. We factor out party allocation into a functions so we can reuse it in later sections.
.. literalinclude:: ./template-root/src/ScriptExample.daml
:language: daml
:start-after: -- TEST_ALLOCATE_BEGIN
:end-before: -- TEST_ALLOCATE_END
:start-after: -- ALLOCATE_PARTIES_BEGIN
:end-before: -- ALLOCATE_PARTIES_END
We now call the ``initialize`` function that we defined before on the
parties that we have just allocated.
@ -167,16 +167,6 @@ parties that we have just allocated.
:start-after: -- TEST_INITIALIZE_BEGIN
:end-before: -- TEST_INITIALIZE_END
Another option for getting access to the relevant party ids is to use
``listKnownParties`` to pick out the party with a given display
name. This is mainly useful in demo scenarios because display names
are not guaranteed to be unique.
.. literalinclude:: ./template-root/src/ScriptExample.daml
:language: daml
:start-after: -- INITIALIZE_QUERY_BEGIN
:end-before: -- INITIALIZE_QUERY_END
Queries
-------
@ -211,48 +201,53 @@ inspect its outputs, ideally without having to recompile it. To that end, the
``--output-file``. Both flags take a filename, and said file will be
read/written as JSON, following the :doc:`/json-api/lf-value-specification`.
The ``--output-file`` option instructs ``daml script`` to write the result of
the given ``--script-name`` to the given filename (creating the file if it does
not exist; overwriting it otherwise). This is most usfeful if the given program
has a type ``Script b``, where ``b`` is a meaningful value, which is not the
case here: all of our ``Script`` programs have type ``Script ()``.
The ``--output-file`` option instructs ``daml script`` to write the
result of the given ``--script-name`` to the given filename (creating
the file if it does not exist; overwriting it otherwise). This is most
useful if the given program has a type ``Script b``, where ``b`` is a
meaningful value. In our example, we can use this to write out the
party ids that have been allocated by ``allocateParties``:
If the ``--input-file`` flag is specified, the ``--script-name`` flag must
point to a function of one argument returning a ``Script``, and the function
will be called with the result of parsing the input file as its argument. For
example, we can initialize our ledger using the ``initialize`` function defined
above. It takes a ``LedgerParties`` argument, so a valid file for
``--input-file`` would look like:
``daml script --dar .daml/dist/script-example-0.0.1.dar --script-name ScriptExample:allocateParties --ledger-host localhost --ledger-port 6865 --output-file ledger-parties.json``
The resulting file will look similar to the following but the actual
party ids will be different each time you run it:
.. literalinclude:: ./template-root/ledger-parties.json
:language: daml
Using that file, we can initialize our ledger passing it in via ``--input-file``:
Next, we want to call the ``initialize`` function with those parties
using the ``--input-file`` flag. If the ``--input-file`` flag is
specified, the ``--script-name`` flag must point to a function of one
argument returning a ``Script``, and the function will be called with
the result of parsing the input file as its argument. For example, we
can initialize our ledger using the ``initialize`` function defined
above. It takes a ``LedgerParties`` argument, so a valid file for
``--input-file`` would look like:
Using the previosuly created ``-ledger-parties.json`` file, we can
initialize our ledger as follows:
``daml script --dar .daml/dist/script-example-0.0.1.dar --script-name ScriptExample:initialize --ledger-host localhost --ledger-port 6865 --input-file ledger-parties.json``
If you open Navigator, you can now see the contracts that have been created.
.. _script-ledger-initialization:
Using Daml Script for Ledger Initialization
===========================================
You can use Daml script to initialize a ledger on startup. To do so,
specify an ``init-script: ScriptExample:initializeFixed`` field in
your ``daml.yaml``. This will automatically be picked up by ``daml
start`` and used to initialize sandbox. Since it is often useful to
create a party with a specific party identifier during development, you can
use the ``allocatePartyWithHint`` function which accepts not only the
display name but also a hint for the party identifier. On Sandbox, the hint
will be used directly as the party identifier of the newly allocated
party. This allows us to implement ``initializeFixed`` as a small
wrapper around the ``initialize`` function we defined above:
specify an ``init-script: ScriptExample:initializeUser`` field in your
``daml.yaml``. This will automatically be picked up by ``daml start``
and used to initialize sandbox. During development not being able to
control party ids can often be inconvenient. Here, we rely on
:ref:`users <user-service>` which do put us in control of
their id. User ids can be used in Navigator, triggers & other tools
instead of party ids.
.. literalinclude:: ./template-root/src/ScriptExample.daml
:language: daml
:start-after: -- INITIALIZE_FIXED_BEGIN
:end-before: -- INITIALIZE_FIXED_END
:start-after: -- INITIALIZE_USER_BEGIN
:end-before: -- INITIALIZE_USER_END
Migrating from Scenarios
------------------------

View File

@ -1,10 +1,6 @@
sdk-version: __VERSION__
name: script-example
source: src
parties:
- Alice
- Bob
- Bank
version: 0.0.1
# script-dependencies-begin
dependencies:
@ -12,5 +8,3 @@ dependencies:
- daml-stdlib
- daml-script
# script-dependencies-end
sandbox-options:
- --wall-clock-time

View File

@ -1,5 +1,5 @@
{
"alice": "Alice",
"bob": "Bob",
"bank": "Bank"
"bank": "party-93affbfe-8717-4996-990c-9f4c5a889663::12201d00faa0968d7ab81e63ad6ad4ee0d31b08a3581b1d8596e68a1356f27519ccb",
"alice": "party-99595f45-75e3-4373-997c-fbdf899439f7::12201d00faa0968d7ab81e63ad6ad4ee0d31b08a3581b1d8596e68a1356f27519ccb",
"bob": "party-6e38e1ed-c070-4ded-ba20-073e0dbdb13c::12201d00faa0968d7ab81e63ad6ad4ee0d31b08a3581b1d8596e68a1356f27519ccb"
}

View File

@ -40,6 +40,15 @@ data LedgerParties = LedgerParties with
bob : Party
-- LEDGER_PARTIES_END
-- ALLOCATE_PARTIES_BEGIN
allocateParties : Script LedgerParties
allocateParties = do
alice <- allocateParty "alice"
bob <- allocateParty "bob"
bank <- allocateParty "Bank"
pure (LedgerParties bank alice bob)
-- ALLOCATE_PARTIES_END
-- INITIALIZE_SIGNATURE_BEGIN
initialize : LedgerParties -> Script ()
initialize parties = do
@ -64,12 +73,7 @@ initialize parties = do
test : Script ()
test = do
-- TEST_SIGNATURE_END
-- TEST_ALLOCATE_BEGIN
alice <- allocateParty "Alice"
bob <- allocateParty "Bob"
bank <- allocateParty "Bank"
let parties = LedgerParties bank alice bob
-- TEST_ALLOCATE_END
parties@LedgerParties{..} <- allocateParties
-- TEST_INITIALIZE_BEGIN
initialize parties
@ -87,30 +91,15 @@ test = do
-- TEST_QUERIES_END
-- INITIALIZE_FIXED_BEGIN
initializeFixed : Script ()
initializeFixed = do
bank <- allocatePartyWithHint "Bank" (PartyIdHint "Bank")
alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice")
bob <- allocatePartyWithHint "Bob" (PartyIdHint "Bob")
let parties = LedgerParties{..}
-- INITIALIZE_USER_BEGIN
initializeUser : Script ()
initializeUser = do
parties <- allocateParties
bank <- validateUserId "bank"
alice <- validateUserId "alice"
bob <- validateUserId "bob"
_ <- createUser (User bank (Some parties.bank)) [CanActAs parties.bank]
_ <- createUser (User alice (Some parties.alice)) [CanActAs parties.alice]
_ <- createUser (User bob (Some parties.bob)) [CanActAs parties.bob]
initialize parties
-- INITIALIZE_FIXED_END
-- INITIALIZE_QUERY_BEGIN
queryParties : Script (Optional LedgerParties)
queryParties = do
knownParties <- listKnownParties
pure $ do
bank <- party <$> find (\p -> p.displayName == Some "Bank") knownParties
alice <- party <$> find (\p -> p.displayName == Some "Alice") knownParties
bob <- party <$> find (\p -> p.displayName == Some "Bob") knownParties
pure LedgerParties{..}
initializeFromQuery : Script ()
initializeFromQuery = do
optParties <- queryParties
case optParties of
None -> fail "Could not find parties with correct display names"
Some parties -> initialize parties
-- INITIALIZE_QUERY_END
-- INITIALIZE_USER_END