Canton transaction issue

Hello,

I’m facing an issue when performing a transaction with a multi domain canton setup of 5 participants (P(A-E)) and 2 domains (D(1-2)).
The architecture is as follows:

P[A,B,C,E] -> D1
P[A,B,D,E] -> D2

Additional setup:

  • All participants except C and D has multi domain support configured
  • A dar with a template Foo was uploaded to all participants
  • A dar with a template Bar was uploaded to C, D and E
  • Template Bar has a choice Choice that takes as parameter a contract for template Foo coming from PA (fooPAcid).
  • Neither Foo contract’s stakeholders have visibility on Bar with the exception of the Bar’s choice controller, which is an observer on both Foos

Now the problem:
Executing this choice on PE with only a fetch for fooPAcid fails the transaction with the following error.

FAILED_PRECONDITION: AUTOMATIC_TRANSFER_FOR_TRANSACTION_FAILED(9,160a9949): Automatically transferring contracts to a common domain failed.

I tried to discover the meaning of this error in the daml docs, but it didn’t give me much info. What is the reason for this error?

Thanks in advance

Hi @David_Martins !
Could you share the two templates and indicate:

  • Which are the contract instances that you have (including the signatories and observers parties)?
  • Who is the party exercising the choice on participant PE?
  • Are all the parties hosted on all the domains ?

Thanks!

Raf

Hello @Rafael_Guglielmetti, thanks for the reply.

For a bit more context I’m working on a DvP project that includes a multi node workflow, that also leverages the Daml Finance library.
I can share snippets of the templates that i have as well as the transaction tree that was logged.

Interface module for Settlement
data View = View
  with
    operator : Party
    provider : Party
    holder : Party
  deriving (Eq, Show)

interface Settlement requires Services.Service where
  viewtype View

  instructTrade : InstructTrade -> Update ()

  nonconsuming choice InstructTrade : ()
    with
      tradeRequestCid : ContractId TradeRequest.TradeRequest
      counterRequestView : TradeRequest.View
    controller (view this).holder
    do instructTrade this arg
Interface module for trade request
data View = View
  with
    operator : Party
    requestorAccount : AccountKey
    counterpartyAccount : AccountKey
    sending : (ContractId Holding.I, InstrumentKey)
    receiving : InstrumentQuantity
    tradePath : [(Party, AccountKey)]
  deriving (Eq, Show)

interface TradeRequest requires Disclosure.I where
  viewtype View
Implementation module for Settlement contract (a service type contract)

This module is present in E and choice’s controller for the is the holder party (Clearinghouse). The “tradeRequestCid” is is an interface cid created in either A or B and “counterRequestView” a View record for a trade request interface. The transaction fails on executing the fetch for “tradeRequestCid”.

template Settlement
  with
    operator : Party
    holder : Party
  where
    signatory operator, holder

    key (operator, holder) : (Party, Party)
    maintainer key._1

    interface instance Service.Service for Settlement where
      view = Service.View with operator, provider = operator, holder

    interface instance Settlement.Settlement for Settlement where
      view = Settlement.View with operator, provider = operator, holder

      instructTrade Settlement.InstructTrade{tradeRequestCid, counterRequestView} = do

          tradeRequestView <- view <$> fetch tradeRequestCid
Implementation module for trade request
template TradeRequest
  with
    operator : Party
    requestorAccount : AccountKey
    counterpartyAccount : AccountKey
    sending : (ContractId Holding.I, InstrumentKey)
    receiving : InstrumentQuantity
    tradePath : [(Party, AccountKey)]
    observers : PartiesMap
  where
    let
      custodian = requestorAccount.custodian
      requestor = requestorAccount.owner

    signatory operator, custodian, requestor
Logged transaction tree

The transaction is accepted be results in failure latter on

  Commands(
    participant5,
    "",
    daml-script,
    4550a631-f415-4b8b-9f4c-08a7f0edb15d,
    Clearinghouse::122097235f1c23d018711fb65dfe766d3ee66f3e1d5d6559249b5273dc86a0a566c4,
    Command(
      Exercise(
        ExerciseCommand(
          Identifier(99b310bc7e2432bd0c706d7b283b041d4ab3b3e3ec1d1e8d71f2661f58f02036, Dvp.Services.Settlement, Settlement),
          00d0feeb1681a436fb8adb384ca71d2a0f439f1ed979cc23ce60a341f5e6b99e65ca0212203e6320ca6466fe7b7ce3cef2c15e57cc0cdeba08ea655e24419873f1a645cfc9,
          InstructTrade,
          Value(
            Record(
              Record(
                Identifier(99b310bc7e2432bd0c706d7b283b041d4ab3b3e3ec1d1e8d71f2661f58f02036, Dvp.Services.Settlement, InstructTrade),
                Vector(
                  RecordField(
                    tradeRequestCid,
                    Value(ContractId(00213a109e8d0f748f469f8a4ee14f659b2703a4565481b56d4f5542f8bf65ed50ca0212203cbc0b51f737064cdaf205eb8dc275a5f2c12dc583430b9d6959d40decd5575c))
                  ),
                  RecordField(
                    counterRequestView,
                    Value(
                      Record(
                        Record(
                          Identifier(99b310bc7e2432bd0c706d7b283b041d4ab3b3e3ec1d1e8d71f2661f58f02036, Dvp.Models.Trade.Request, View),
                          Vector(
                            RecordField(operator, Value(Party(Participant1 Operator::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                            RecordField(
                              requestorAccount,
                              Value(
                                Record(
                                  Record(
                                    Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, AccountKey),
                                    Vector(
                                      RecordField(custodian, Value(Party(Participant1 Custodian::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                                      RecordField(owner, Value(Party(Alice::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                                      RecordField(
                                        id,
                                        Value(
                                          Record(
                                            Record(
                                              Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Id),
                                              RecordField(
                                                unpack,
                                                Value(
                                                  Text(
                                                    Alice::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d@Participant1 Custodian::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d
                                                  )
                                                )
                                              )
                                            )
                                          )
                                        )
                                      )
                                    )
                                  )
                                )
                              )
                            ),
                            RecordField(
                              counterpartyAccount,
                              Value(
                                Record(
                                  Record(
                                    Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, AccountKey),
                                    Vector(
                                      RecordField(custodian, Value(Party(Participant2 Custodian::12206bf2e70b08a87ec8a96e345fd298c89846c9dd3a88cbe153325b7ba0b43ea729))),
                                      RecordField(owner, Value(Party(Bob::12206bf2e70b08a87ec8a96e345fd298c89846c9dd3a88cbe153325b7ba0b43ea729))),
                                      RecordField(
                                        id,
                                        Value(
                                          Record(
                                            Record(
                                              Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Id),
                                              RecordField(
                                                unpack,
                                                Value(
                                                  Text(
                                                    Bob::12206bf2e70b08a87ec8a96e345fd298c89846c9dd3a88cbe153325b7ba0b43ea729@Participant2 Custodian::12206bf2e70b08a87ec8a96e345fd298c89846c9dd3a88cbe153325b7ba0b43ea729
                                                  )
                                                )
                                              )
                                            )
                                          )
                                        )
                                      )
                                    )
                                  )
                                )
                              )
                            ),
                            RecordField(
                              sending,
                              Value(
                                Record(
                                  Record(
                                    Identifier(40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7, DA.Types, Tuple2),
                                    Vector(
                                      RecordField(
                                        _1,
                                        Value(ContractId(000648fde7f1699912f91250be253e2cecfd1020448bb04de9f9beea0e8161dcf4ca0212202150cfbdd249e7d95b67a6809386af54cc44c19c9f41501dfa3570e449880cc7))
                                      ),
                                      RecordField(
                                        _2,
                                        Value(
                                          Record(
                                            Record(
                                              Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, InstrumentKey),
                                              Vector(
                                                RecordField(depository, Value(Party(Central Bank::122004a5609cbbc56b9e8b0642539c59bb4d81d59e26780c4a8d65b93f582025c885))),
                                                RecordField(issuer, Value(Party(Central Bank::122004a5609cbbc56b9e8b0642539c59bb4d81d59e26780c4a8d65b93f582025c885))),
                                                RecordField(
                                                  id,
                                                  Value(
                                                    Record(
                                                      Record(
                                                        Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Id),
                                                        RecordField(unpack, Value(Text(USD)))
                                                      )
                                                    )
                                                  )
                                                ),
                                                RecordField(version, Value(Text(1)))
                                              )
                                            )
                                          )
                                        )
                                      )
                                    )
                                  )
                                )
                              )
                            ),
                            RecordField(
                              receiving,
                              Value(
                                Record(
                                  Record(
                                    Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Quantity),
                                    Vector(
                                      RecordField(
                                        unit,
                                        Value(
                                          Record(
                                            Record(
                                              Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, InstrumentKey),
                                              Vector(
                                                RecordField(depository, Value(Party(Central Securities Depository::12202b19c274f7356d9676c367ad1aa19cb3a08ffbcde8f85547b2b430e1ade3377f))),
                                                RecordField(issuer, Value(Party(Central Securities Depository::12202b19c274f7356d9676c367ad1aa19cb3a08ffbcde8f85547b2b430e1ade3377f))),
                                                RecordField(
                                                  id,
                                                  Value(
                                                    Record(
                                                      Record(
                                                        Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Id),
                                                        RecordField(unpack, Value(Text(TSLA)))
                                                      )
                                                    )
                                                  )
                                                ),
                                                RecordField(version, Value(Text(1)))
                                              )
                                            )
                                          )
                                        )
                                      ),
                                      RecordField(amount, Value(Numeric(1000.0000000000)))
                                    )
                                  )
                                )
                              )
                            ),
                            RecordField(
                              tradePath,
                              Value(
                                List(
                                  List(
                                    Vector(
                                      Value(
                                        Record(
                                          Record(
                                            Identifier(40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7, DA.Types, Tuple2),
                                            Vector(
                                              RecordField(_1, Value(Party(Alice::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                                              RecordField(
                                                _2,
                                                Value(
                                                  Record(
                                                    Record(
                                                      Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, AccountKey),
                                                      Vector(
                                                        RecordField(custodian, Value(Party(Participant1 Custodian::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                                                        RecordField(owner, Value(Party(Alice::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                                                        RecordField(
                                                          id,
                                                          Value(
                                                            Record(
                                                              Record(
                                                                Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Id),
                                                                RecordField(
                                                                  unpack,
                                                                  Value(
                                                                    Text(
                                                                      Alice::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d@Participant1 Custodian::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d
                                                                    )
                                                                  )
                                                                )
                                                              )
                                                            )
                                                          )
                                                        )
                                                      )
                                                    )
                                                  )
                                                )
                                              )
                                            )
                                          )
                                        )
                                      ),
                                      Value(
                                        Record(
                                          Record(
                                            Identifier(40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7, DA.Types, Tuple2),
                                            Vector(
                                              RecordField(_1, Value(Party(Participant1 Custodian::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                                              RecordField(
                                                _2,
                                                Value(
                                                  Record(
                                                    Record(
                                                      Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, AccountKey),
                                                      Vector(
                                                        RecordField(custodian, Value(Party(Central Bank::122004a5609cbbc56b9e8b0642539c59bb4d81d59e26780c4a8d65b93f582025c885))),
                                                        RecordField(owner, Value(Party(Participant1 Custodian::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d))),
                                                        RecordField(
                                                          id,
                                                          Value(
                                                            Record(
                                                              Record(
                                                                Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Id),
                                                                RecordField(
                                                                  unpack,
                                                                  Value(
                                                                    Text(
                                                                      Participant1 Custodian::12205ac75896fe8f3d3f5af37d464a8a2e6402ffb40b8586052824ca71b131439c7d@Central Bank::122004a5609cbbc56b9e8b0642539c59bb4d81d59e26780c4a8d65b93f582025c885
                                                                    )
                                                                  )
                                                                )
                                                              )
                                                            )
                                                          )
                                                        )
                                                      )
                                                    )
                                                  )
                                                )
                                              )
                                            )
                                          )
                                        )
                                      ),
                                      Value(
                                        Record(
                                          Record(
                                            Identifier(40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7, DA.Types, Tuple2),
                                            Vector(
                                              RecordField(_1, Value(Party(Central Bank::122004a5609cbbc56b9e8b0642539c59bb4d81d59e26780c4a8d65b93f582025c885))),
                                              RecordField(
                                                _2,
                                                Value(
                                                  Record(
                                                    Record(
                                                      Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, AccountKey),
                                                      Vector(
                                                        RecordField(custodian, Value(Party(Clearinghouse::122097235f1c23d018711fb65dfe766d3ee66f3e1d5d6559249b5273dc86a0a566c4))),
                                                        RecordField(owner, Value(Party(Central Bank::122004a5609cbbc56b9e8b0642539c59bb4d81d59e26780c4a8d65b93f582025c885))),
                                                        RecordField(
                                                          id,
                                                          Value(
                                                            Record(
                                                              Record(
                                                                Identifier(b1646d11a251b65507ac12de89633d323dc5237ec11127ad66e983d8d6e3e623, Daml.Finance.Interface.Types.Common.Types, Id),
                                                                RecordField(
                                                                  unpack,
                                                                  Value(
                                                                    Text(
                                                                      Central Bank::122004a5609cbbc56b9e8b0642539c59bb4d81d59e26780c4a8d65b93f582025c885@Clearinghouse::122097235f1c23d018711fb65dfe766d3ee66f3e1d5d6559249b5273dc86a0a566c4
                                                                    )
                                                                  )
                                                                )
                                                              )
                                                            )
                                                          )
                                                        )
                                                      )
                                                    )
                                                  )
                                                )
                                              )
                                            )
                                          )
                                        )
                                      )
                                    )
                                  )
                                )
                              )
                            )
                          )
                        )
                      )
                    )
                  )
                )
              )
            )
          )
        )
      )
    ),
    Empty,
    None,
    None,
    Clearinghouse::122097235f1c23d018711fb65dfe766d3ee66f3e1d5d6559249b5273dc86a0a566c4,
    Vector(),
    "",
    Vector()
  )
)

As for party hosting, it’s as follows:

  • Alice and Custodian 1 are hosted on PA
  • Bob and Custodian 2 are hosted on PB
  • Central Bank is hosted on PC
  • Central Securities Depository is hosted on PD
  • Clearinghouse is hosted on PE

Hope these clarifications help, if needed I can provide further context.
Best regards

Hi @David_Martins ,
Sorry for the delay in answering!

I am coming back more precisely to ask question related to your first message:

  • You mentioned templates Foo and Bar. Could you share them ?
  • What are the contract instances for these templates ?
  • Who is the party exercising the choice on PE? (is it the clearinghouse?)
  • Are all the parties hosted on all the domains?

Best,

Rafael

Hello @Rafael_Guglielmetti,

In my reply I have the snippets for the actual templates that Foo and Bar were extrapolated from, where Foo is the TradeRequest template and Bar is the Settlement template, where the Settlement contract was created on PE and the TradeRequest contract was created on PA.
As party hosting is concerned, both D1 and. D2 would know about Alice, Bob, Custodian 1, Custodian 2 and Clearinghouse, D1 would be privy to Central Bank and D2 to Central Securities Depository.
The Clearinghouse party is indeed the controller for the mentioned choice.
Unfortunately, I’m not quite sure, what you mean in the second question, so if you could provide further clarification there, it would be appreciated.

Kind regards

Hey!
Sorry, I got a bit confused by the extrapolation from Foo/Bar to your example.

Some context first,
In Daml, any transaction is performed/coordinated over a single domain. In particular, for a transaction to be executed, all the input contracts (contracts needed for the transaction) have to be on a single domain. By default, Canton will try to automatically transfer the contracts to a suited domain before submitting the transaction.

Roughly, the find candidates for this “shared domain”, Canton will

  1. list all the input contracts
  2. for all the contracts in 1., list all the stakeholders (signatories and observers)
  3. for all the contracts in 1., list all the packages containing the corresponding templates
  4. find a domain on which all the stakeholders (2.) are hosted and all the packages are vetted.

In your case, the transaction involve the CSD and the CentralBank but they don’t share a common domain. What you can do is to connect P3 to domain D2 or connect P4 to domain D1: this should allow the transaction to go through.

Hope this helps.

Raf

1 Like

Hello,

Actually this design came about because of the need to synchronise the transaction in a single domain.
Even though the csd and central bank parties don’t share a domain, they don’t share the transaction either, so, in principle, it should be able to go only through D1.

Yes, but if you look at your transaction tree (snippet you posted above) we see CSD and CentralBank being involved in the transaction, which means they must be connected to a common domain.

They shoiuldn’t be involved in the transaction though, since they only exist as fields on the arguments that the choice takes. Given they are present as fields, a domain must exist that knows about both?

You are right that it is not necessarily an input contract to the transaction.
In order for me to investigate further, could you:

  • Tell me which Canton version you are using
  • Provide the Canton logs
  • Ideally, a full example that reproduces the issue

Thanks.

Best,

Raf

Hello,

To answer the first question, I’m using version 2.7.1, and I’ve sent you a private message for the rest.

Thank you

1 Like

Hi @David_Martins can you file through the support portal, please?