Skip to content

Instantly share code, notes, and snippets.

@dazraf
Last active November 12, 2020 11:50
Show Gist options
  • Save dazraf/87c56a6039391f0613066ee2d6fe6c0e to your computer and use it in GitHub Desktop.
Save dazraf/87c56a6039391f0613066ee2d6fe6c0e to your computer and use it in GitHub Desktop.

Review of version 2: Corda State Hierarchy Design document

(and with respect to work done in Cordite)

Terminology

  • Corda - the open source version of Corda, including the finance and core modules
  • Cordite - a collection of cordapps for decentralised businesses
  • Cordite DGL - the distributed general ledger for accounts and tokens as defined in Cordite
  • Cordite DAO - see Cordite DAO

Summary (TL;DR)

  1. Several of the changes in Corda are good and very welcome: FungibleState and LinearPointer. We note that the use of the latter with Tokens, in the way suggested in the document, will carry a performance cost.

  2. There are other design concerns - most of these are either functionally minimal or related to performance. These are covered in the Design Review section.

  3. Apart from these, there is an almost one-to-one correspondence between the Cordite implementation and this proposal such that, with a minimal set of renames / refactorings, would match the specification.

  4. The Cordite project welcomes contributions to refactor the existing implementation towards the intended design.

  5. The Cordite project welcomes any roadmap that hollows out Cordite DGL into Corda finance without creating two competing implementations.

  6. The Cordite DGL codebase is expected to continue to advance with new features layered on top of Corda finance.

About Cordite

Goals

  • Wide spread adoption of Corda
  • Build awareness and understanding of the benefits of Corda
  • Encourage use of Corda by demonstrating how it will help improve your business
  • Support thought leaders in using Corda

Cordite Design Principles:

  1. Don't fork Corda. Stronger together
  2. Minimal core system with flexibility to extend
  3. Support widest functionality and be least prescriptive
  4. Provide exemplar CorDapps using Cordite
  5. Minimise CorDapp knowledge of Cordite
  6. Code is not law. Cordite will re-use existing legal frameworks to make law is code

Cordite Cordapp Design Principles:

  1. Don't be opinionated. You lose people for every opinion
  2. Don't implement anything more than the minimum required. Let others extend
  3. Don't wait. WYSIWYG. Raise feature requests on Corda and work round
  4. Be Open Source (Presently 24 contributors, multiple maintainers from disparate orgs)
  5. No manual test. Aggressive use of automated testing from unit to full scale environments
  6. Sustain code quality and test coverage with code reviews and commit gates
  7. Maintain a bi-weekly cadence. Have the ability to release at any moment in time from a "green" build

Cordite DGL / Tokens requirements summary

In the slack conversations some asked for the requirements for Tokens in Cordite. This a precis of a large number of requirements captured as project tickets.

Built for: NatWest CurrencyPay and RBS Rewards, but with an eye on new use-cases being discovered via Chorum.

  1. Define a unit level instrument (Token type) that can represent fiat, crypto currencies, reward tokens, audio credits or units of basic tokenised assets - equities, bonds, mortgages
  2. Should be able to support aliasing - it multiple ‘instrument’ codes - for example XBT, BTC
  3. Aliasing should also support validity date ranges (for example ISINs)
  4. Must be able to support micro units and hence exponent should be part of definitiion
  5. Corda Parties should be able to create Token types with ‘strong’ issuance such that Tokens are unique by Issuer and Token Name and be universally unique
  6. Tokens should be referenced by their unique identifier across nodes without the need for copying the whole token definition
  7. Corda Parties must be able to create accounts to store tokens
  8. Accounts must be able to support multiple token types
  9. Accounts should be uniquely identifiable across all nodes - using node identity plus account name
  10. Accounts must support aliases so that they can be identified by existing methods, such as IBAN, Sortcode and Account Number
  11. Accounts must support multiple financial structures such as trading book hierarchies and accounting hierarchies so that aggregation of positions and financial position can be calculated
  12. Accounts should support multiple owners (e.g. joint accounts, business accounts) and only allow transfers when a quorum of signatures is achieved
  13. Accounts should be able to span multiple nodes for resilience and decentralisation
  14. Accounts should be able to be owned by non node (i.e. user) parties
  15. Tokens must only be issued to accounts
  16. Tokens must be able to be transferred between accounts on the same node or between nodes using primary or aliased account identifiers
  17. All Token transactions must produce a summary of debits and credits
  18. Tokens and Accounts should be searchable by primary and secondary (alias) identifiers
  19. We must be able to listen to account changes by specifying single or groups of primary identifiers or tags.
  20. Tokens may be issued back-to-back from existing off-ledger assets, in which case it should be possible to immobilise the off-ledger asset thereby ensuring that the underlying assets cannot be 'spent' independantly from the issued token. The Token should be a specialised form a PromissoryNote with immediate or future maturity and partial redemption.

Design Review

Static Class diagram

It would be helpful if the static class diagram was done to show all dependencies and inheritance relationships, ideally using a standard like UML. It would also be helpful to show example assets and their representation in this hiearchy, to give futher context and a useful reference for the written narrative.

Issuance and Issuer

  1. It is debatable whether a Commodity does not have an issuer. Logically it would be the miner, farmer, a quality assurance gate provisioned by a buyer or distributor etc.

  2. Likewise for freehold real-estate with the issuer being either a sovereign or proxy; and for chattels being the manufacturer.

  3. Cryptocurrencies - the nature of the issuer depends on the coin. Some that are issued by a foundation or group of "master" nodes (e.g see Dash), which could be identified natively as a DAO

  4. Typically, cryptocurrencies being tokenised on the Corda Ledger will need to have an issuer that holds the required keys to settle the respective tokens, when called upon by an owner. Without an issuer, how does one exchange XBTC (Bitcoin on Corda) for it's underlying 'BTC'?

FungibleState and Ownable

The separation of Fungible from Ownable is a good step. Notably because the notion of Ownable in Corda is somewhat constrained to a single party. In the real-world, joint ownership is not unheard of. Furthermore, for digital mutuals, joint ownership will be a central concept.

We also suggest for consideration the dropping of the withNewOwner method as being mandatory. This limits transfers of state to simple semantics. The case in point is on metering invoices (and it could be said invoices in general) where one will only want to be able to transfer state if certain contract conditions are met - i.e. when paying and invoice, transfer back to the payee can only be done under the condition that there is payment in some kind of token.

Suggest we reconsider semantics of Ownable to be broader. Or introduce an alternative type to represent joint ownership.

TokenType, TokenType.Definition, TokenDescription

These are very close to Cordite's TokenType,State, TokenType.Descriptor with minimal refactoring. The changes proposed open up potential new use-cases, which is good, but they may also possibly hamper performance for tokens at scale. Notably, to resolve LinearPointers to TokenTypes will be a very common operation incurring per transaction overheads of unbounded size because TokenType is effectively open to carry any payload. See the next section for more detail.

LinearPointer

As a general construct, this is a useful addition to Core Corda. The issue is how to resolve a pointer to its LinearState. The Pointer doesn't contain the source party. The design document suggests transferring the TokenType with each transaction as reference data, but notes:

embedding the pointed-to state may not always be preferable, especially if it is quite large

Indeed this is the case with tokens at large - transferring the definition adds an unnecessary duplication of reference state per transaction (O(N) space), obviating the need for LinearPointer, and causing inflation of network and disk representation. This is particularly a concern because as a node operator, one cannot estimate the potential size of network messages and disk storage of TokenTypes because it is an open type. Furthermore, there is a performance cost for functions such as getBalance, where a join is required between the FungibleState table and the TokenType table, degrading from O(N) to O(N.log(N)) in the worst case.

In lieu of an efficient pointer type in Corda, Cordite DGL reviewed the above concerns and concluded:

  1. tokens need to carry a descriptor that can be serialisable to a well-formed string that is human and machine readable, meaningful enough for database queries, and without implying the need for additional states and joins. This string carries the issuer name so that the string is globally referentially unique.

  2. as a result, TokenTypes are sealed. Any ancillary information about the token type has to be encoded in a seperate and distinct state type.

Suggestions

  1. make the transfer of reference data a one-time operation that does not incur per transaction cost overheads; or make the pointer type carry the originator party so that it may be recovered on a lazy basis from the source node using a core API call.

  2. enforce the naming of the externalId for the LinearState used by TokenType.Description to be a well-formed string representing a unique 'symbol' for the token, it's number of decimal places, and its issuer / creator. That way, generalised queries for amounts by type, can be served with no joins, and no additional states (reference or otherwise).

  3. Suggest keeping ancilliary data regarding the TokenType (e.g. bond default status) as being out-of-band data that is (a) optional; (b) can use data-distribution groups or other techniques for sharing (some of these may wish to monetised); (c) is completely decoupled from the core Token design.

  4. Is there a reason to limit this pointer to only LinearState?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment