Evolution plan: multiple notary usage

(Andrius Dagys) #1


Corda’s pluggable consensus model allows multiple notaries to operate in the same network. Depending on trust relationships, different parties will want to use different notaries, or use multiple notaries at the same time, based on who they transact with.
At present CorDapps can specify what notary to use for which flow, and use the NotaryChangeFlow to reassign existing states to a different notary. However, the current process of changing notaries is manual and involves writing custom logic.


  1. Participants can specify what notary to use for a particular flow, state type, and counterparty combination.
  2. Participants can reassign their contract states to a different notary without having to write a custom flow. This might be required when a notary gets decommissioned, or a new, more preferable notary is introduced.
  3. Participants that have different notary preferences can negotiate which common notary to use for a particular transaction. Ideally this would be automated by a fair protocol.


Although the compatibility zone (CZ) and business network (BN) design isn’t finalised, for the first iteration of this design proposal the following assumptions are made:

  1. All nodes in a CZ agree to accept the notaries listed in the global network parameters document.
  2. Individual BNs (and potentially individual nodes) can express different preferences for notaries to use from the global list.
  3. All nodes will have at least one common notary they accept to use (e.g. a global BFT notary).


Taking into consideration different notary preferences, here are the generic steps for parties to transact:

1. Parties agree to initiate a transaction (offline).

2. The initiating party runs a “common notary agreement” protocol. It results in a notary identity that all parties accept. The initiator then starts the desired business flow with the common notary identity.

A new method for this should be exposed on the RPC interface, for example:

val notary = rpc.getCommonNotary(otherParty)
rpc.startFlow(::SellerFlow, otherParty, notary, amount)

Ideally it would be auto-invoked as part of startFlow, but that means we have to enforce a convention for flow constructors, so the notary parameter can be passed on correctly. A potential solution would be introducing a new annotation and a separate getNotaryAndStartFlow method.

The protocol could operate in two steps:

  • Based on counterparties’ notary preferences, find the optimal notary. If there is only one option, return. No message exchange is required, but the tradeoff is that counterparties would each need to verify the chosen notary is correct.
    For example, if we have preferences (A, B, G), and (B, G), the result is B.
  • If there are multiple possibilities, pick a notary randomly. To ensure this is fair, the choice could depend on nonces from each party.
    For example, if we have preferences (A, B, G), and (B, A, G), the best notary to use is either A or B, and will be chosen at random.

The result of the protocol should be cached, with a set expiry time.

3. The flow checks whether states to be used in the transaction are assigned to the correct notary. If not, notary reassignment is performed. Counterparty flows perform the same.

One approach for achieving this would be moving the responsibility of making sure states point to the same notary outside a flow, but that would effectively require writing a “meta-flow” that runs a desired flow. Parties on the receiving end would also have to run some prior special logic.

Another option would be extending the vault query API to perform notary change automatically, when no state with the specified notary is found. However, not all results of a query might get used for a transaction, so it doesn’t make sense to repoint everything in advance.

A third possibility is to have TransactionBuilder perform notary change for all input states that don’t match the transaction notary, but that doesn’t work when the builder is shared between parties, or when adding a state that was sent by another party.

Seems like the best approach is to leave this up to the flow writers to handle on case-by-case basis.

4. A transaction gets built, signed and finalised.

Switching notaries

When a notary gets decommissioned, or a party wants to switch to a different notary and update its preferences, there needs to be a mechanism for bulk state reassignment. The easiest approach is to introduce a new RPC method:

rpc.migrateStates(oldNotary, newNotary, stateType?)

Introduction plan

  1. Expose an RPC method for migrating states to a new notary.
  2. Add configuration options for specifying notary preference – ideally it would be advertised by each node.
  3. Expose an RPC method for negotiating a common notary
  4. Update Finance module to perform automatic notary reassignment (specifically methods like generateSpend())

(Mike Hearn) #2

Thanks Andrius.

My inclination is to say that this is too ambitious for a first phase, but if/when we want to introduce negotiation of notaries it should presumably be a sub-flow introduced into the app flow, rather than something that takes place before an app flow is even invoked. The flow versioning mechanism can be used to figure out if the counterparties app has been upgraded to support notary negotiation.

However, I guess a first phase is to leave things under the control of the zone operator. They can provide an ordered list of notaries. The first notary is always the one that’s used for new states. Other notaries are considered valid until removed, however, states that are assigned to a non-top notary will be steadily and automatically re-assigned in the background via flows the nodes themselves kick off. The big open question in my mind is how it interacts with human confirmation of signings, as humans will not want to manually confirm many many notary updates (or even know what they are…).

A later phase can take away the privileged position of the top notary, and start to delegate more control and power to the individual apps. But in most realistic deployments for now, one notary is going to be enough outside of times of migration! Every other DLT platform offers a single notary forever, bear in mind! :slight_smile:

(richard) #3

Agree with Mike it seems ambitious but seems broadly in the right direction. But…

  1. It seems odd to negotiate the preferred notary for a new transaction without any reference to the State(s) that is/are likely to be consumed in the putative transaction. I guess for FungibleStates that might be reasonable but if the thing we care about is a particular LinearState, a bias towards sticking with the currently appointed notary would seem to be sensible?

  2. To Mike’s comment about deferring to the CZO and their ordered list, we need to ensure our pursuit of purity doesn’t drive potential users to run their own CZs when some small compromises would have allowed them to be BNOs instead. It might just be as simple as adopting the ordering idea from Mike but allowing it to be overridden/amended at the BN level. So if a BNO believes all their transactions must be notarised “in country” then we can support that at the same time as still allowing them to consume transactions notarised elsewhere AND leaving the door open to them notarising transactions elsewhere as they deploy more international CorDapps and gain comfort with the platform.

  3. I didn’t fully understand this: “A third possibility is to have TransactionBuilder perform notary change for all input states that don’t match the transaction notary, but that doesn’t work when the builder is shared between parties, or when adding a state that was sent by another party.” Having some sort of automated “state marshalling” subflow would seem to be a really helpful in-built feature… ie allow people to assemble Transactions consisting of states pointing all over the place and then as part, perhaps, of CollectSignatureFlow, kick off a bunch of sub flows on each node to marshall the states (and in so doing actually change what is in the transaction-to-be-signed… so I agree it’s entirely non-trivial :slight_smile: but would still be cool to do)

(Mike Hearn) #4

The problem is that a BN doesn’t “own” a transaction, because transactions can do many things simultaneously.

The locality requirements some places have are a classic example of questionable regulation - how exactly do you trade internationally if all data must be kept in-country? There are surely various exceptions and caveats to these rules as otherwise I don’t see how even basic things like remittances could continue working.

It’s really very important to keep notarisation away from concepts of data locality and related regulations. They’re just a form of locking service in the end.

Re-aligning states to a shared notary is indeed one of the use cases that motivated the idea of sub-flows and the flow framework in general (pluggable consensus being a requirement that predated the flow framework itself).

(Andrius Dagys) #5

To partially support the “notarise in country” requirement we could allow BNOs run their own “private” notaries. This is slightly similar to the private/public tx approach we discussed a while ago. Here’s how it would look like:

  • CZO provides a list of global notaries.
  • Every participant agrees to accept transactions that have been notarised by any of the global notaries.
  • The operator for business network A provides additional private notaries that are not on the CZ list.
  • A’s participants agree to accept transactions notarised both by global & A’s private notaries. Participants outside this BN don’t accept A’s notaries.
  • Global notaries don’t allow state reassignments to private notaries.
  • If A’s participants want to perform some form of settlement (internally) that e.g. involves global assets, they have to reassign their “agreement” states from a private to a global notary. That is safe to do since no parties outside A will accept these new agreement states as they were historically notarised by an “unknown” notary. But the global asset exchange part of the transaction will be valid and accepted globally.
  • If A’s participants want to transact with B’s participants, they initially have to agree on a shared notary, which could be global or private. Likewise, to involve any global assets their states will have to be repointed to a global notary.
  • This approach could be extended to create multiple layers of “networks” inside a CZ

(richard) #6

(Summary from an email I sent on the same topic)

This is a timing thing. In the long-term vision it is correct that transactions can do many things simultaneously and so geographic notaries make no sense.

BUT… in the short-term, deployments will be simpler. Any given CorDapp, provided by a single BNO, will be the only creator and consumer of the State Object(s) it defines.

If providing the option for that CorDapp preferentially to use a specific notary (from the CZ-level notary list) to notarise its transactions is a way to allay some participants’ fears around data sovereignty, etc., then great. We avoid balkanisation/separate CZs AND have done nothing to prevent complex transactions that act on lots of different types of states in the future.

That’s all I’m saying.

[edit: eurgh… i hate the lack of threading in discourse… this is a response to mike, not andrius]

(richard) #7

do we need to go that far? i think simply allowing any given cordapp preferentially to use a specific notary from the czo-provided list would be good enough (so they would trust all other notaries on the list… but this is academic at first since there wouldn’t BE any transactions from anywhere other than nodes running this cordapp in the early days)

this would work just fine for early cordapps that don’t have complex transactions.

As complex cordapps emerge, the need to use a non-preferred/non-local notary may/will emerge… but we’ll be able to have that technical debate from the position of participants already on a shared CZ.