Editorial: on Proof of State

What do we call “Proof of State”?

What does the distributed ledger of Universa store?

How are the smart contracts in Universa related to each other, and how they can be confirmed as valid, even though the Universa ledger doesn’t store their bodies?

Read on to know the answers.

Is Proof-of-State a consensus algorithm (like PoW/PoS)?

(Hint: no, Universa has PoA consensus)

When we speak about “Proof of State” concept at Universa, it is not a talk about the node consensus algorithms, like Proof-of-Work or Proof-of-Stake, for different blockchain/DLT technologies. (Sidenote: the consensus algorithm in Universa it is more close to POA, “Proof-of-Authority” as it is sometimes named for different systems which also try to prevent the anarchical 51% takeovers).

Proof of State is about how our contracts stay valid, even though the Universa doesn’t keep their bodies.

This is called “Universa Blockchain”; but what are your blocks?

(Hint: smart contract revisions)

With Proof-of-Work, when creating a block, a node has to prove it has done some substantial (though mostly useless) work to obtain the right of block aggregation from the pool of pending transactions it has.

But this is applicable for the situation when the block has to aggregate multiple transactions.

graph RL title[Typical blockchain, e.g. Bitcoin] bl1-->title style title fill:transparent,stroke:transparent linkStyle 0 stroke:#FFF,stroke-width:0; subgraph Block #1 bl1(fa:fa-link Block #1) t1[Transaction #3e2cf1da] t2[Transaction #4362b7de] t3[Transaction #442abeaa] end bl2-->bl1 subgraph Block #2 bl2(fa:fa-link Block #2) t4[Transaction #448c373e] t5[Transaction #4dbd5f04] t6[Transaction #527717b0] t7[Transaction #5541772e] end bl3-->bl2 subgraph Block #3 bl3(fa:fa-link Block #3) t8[Transaction #59600dc0] t9[Transaction #5d05299c] end ellipsis((fa:fa-chain-broken ...))-.->bl3

In Universa, the “blocks” are not something where multiple unrelated transactions are aggregated.

Each “block” in the distributed ledger of Universa is actually the revision of contract.

Like this:

graph RL title[Single building block
of Universa ledger,
not to scale
] h1-->title style title fill:transparent,stroke:transparent linkStyle 0 stroke:#FFF,stroke-width:0; subgraph Contract Blablabla subgraph ... h1(id: #582f9a18) end subgraph state p1[parent: null] o1[origin: null] r1[revision: 1] end end

Or like this:

graph RL title[Each Universa
contract revision
is a contract
itself
] h1-->title style title fill:transparent,stroke:transparent linkStyle 0 stroke:#FFF,stroke-width:0; subgraph Contract Borabora subgraph ... h1(id: #34640320) end subgraph state p1[parent: null] o1[origin: null] r1[revision: 1] end end subgraph Contract Barubaru subgraph ... h2(id: #fd603cbc) end subgraph state p2[fa:fa-link parent: #34640320] o2[fa:fa-link origin: #34640320] r2[revision: 2] end end subgraph Contract Beruberu subgraph ... h3(id: #22e69508) end subgraph state p3[fa:fa-link parent: #fd603cbc] o3[fa:fa-link origin: #34640320] r3[revision: 3] end end o2==>h1 o3==>h1 p2-->h1 p3-->h2 ell3((fa:fa-chain-broken ...))-.->h3

What is the definition of blockchain? According to Wikipedia, it is “A blockchain, originally block chain, is a continuously growing list of records, called blocks, which are linked and secured using cryptography. Each block typically contains a cryptographic hash of the previous block,[6] a timestamp and transaction data”.

The significant difference between Universa and the blockchains like Bitcoin, is that in Bitcoin, each block is published forever.

But in Universa, it 1. doesn’t store (publicly) the information of every block, 2. it doesn’t store non-final blocks at all; thus saving a lot of space and improving performance. And also increasing the anonymity.

And what is most important, is that each block corresponds not to a pack of, say, transactions, but to a single revision change. The independent contracts do not block each other in any way, making it perfectly scalable.

graph RL c1_1[Some contract, rev.1] c1_2[Some contract, rev.2] c1_3[Some contract, rev.3] c1_4[Some contract, rev.4] c1_5((...)) c1_2-->c1_1 c1_3-->c1_2 c1_4-->c1_3 c1_5-->c1_4
graph RL c2_1[Some other contract, rev.1] c2_2[Some other contract, rev.2] c2_3[Some other contract, rev.3] c2_4((...)) c2_2-->c2_1 c2_3-->c2_2 c2_4-->c2_3
graph RL c3_1[Yet another contract, rev.1] c3_2a[Yet another contract, rev.2] c3_2b[Yet another contract, rev.2] c3_3a[Yet another contract, rev.3] c3_3b[Yet another contract, rev.3] c3_4a[Yet another contract, rev.4] c3_5[Yet another contract, rev.5] c3_6((...)) c3_2a-->c3_1 c3_2b-->c3_1 c3_3a-->c3_2a c3_3b-->c3_2b c3_4a-->c3_3a c3_5-->c3_4a c3_5-->c3_3b c3_6-->c3_5

Some words on DAG

The graph structure like above, for a bunch of “Yet another contracts”, is often called “DAG”, or Directed Acyclic Graph. Some modern distributed ledger networks prefer to position themselves as “being a DAG rather than a blockchain”; but a DAG is just a type of graph structure. Universa doesn’t position itself as “being a DAG”; because in Universa, there is not just a single DAG for the whole distributed ledger, but a multitude of DAGs. In Universa, each contract history is a fully independent DAG.

Issue tokens to understand contract revisions

Most easy to comprehend is if we look at some Token-like (split-join-enabled) contract.

When some person, let’s call her Alice for the clarity, creates a new Token contract (and, most likely, immediately mints some fixed/locked amount of these Tokens, and issue them all to herself), she actually builds and registers a new contract, which has the “owner” field assigned to her key, and also has a split-join permission (more on this later).

graph RL subgraph Alice created 100 AliceTokens subgraph ... h1(id: #31d3c60c) end subgraph state ow1[owner: Alice] p1[parent: null] o1[origin: null] r1[revision: 1] d1[data.amount: 100] end subgraph definition spj1[permissions.split_join.join_match_fields: state.origin] end end

Then, she want to issue, say, 10 tokens to her friend Bob, so he becomes the second person in the world having these tokens.

Initially, she had a contract (its revision) where the amount of tokens was, say, 100 tokens, and she was the owner.

But as she transfers some of these tokens to her friend Bob, she actually performs a “split-join” operation (at this moment, only “split”). And she derives two new contracts from this. One of them will have “owner: Bob, amount: 10”, another one will have “owner: Alice, amount 90”.

graph RL subgraph Alice created 100 AliceTokens subgraph ... h1(id: #31d3c60c) end subgraph state ow1[owner: Alice] p1[parent: null] o1[origin: null] r1[revision: 1] d1[data.amount: 100] end subgraph definition spj1[permissions.split_join.join_match_fields: state.origin] end end subgraph Alice gave 10 AliceTokens to Bob subgraph ... h2(id: #35a0e148) end subgraph state ow2[owner: Bob] p2[fa:fa-link parent: #31d3c60c] o2[fa:fa-link origin: #31d3c60c] r2[revision: 2] d2[data.amount: 10] end subgraph definition spj2[permissions.split_join.join_match_fields: state.origin] end end subgraph Alice has 90 AliceTokens after giving 10 AliceTokens to Bob subgraph ... h3(id: #5808f284) end subgraph state ow3[owner: Alice] p3[fa:fa-link parent: #31d3c60c] o3[fa:fa-link origin: #31d3c60c] r3[revision: 2] d3[data.amount: 90] end subgraph definition spj3[permissions.split_join.join_match_fields: state.origin] end end o2==>h1 o3==>h1 p2-->h1 p3-->h1

But both of them will:

  1. Refer to the root, or “origin” contract (so it is clear that these two contracts are for the very same token).
  2. Refer to the contract parent for them (“owner: Alice, amount: 100”).

Altering any of these references would change the binary contents of the contract. So registering (in the Universa’s distributed ledger) the hash sum of the contract would make up yet another link of the chain.

But note:

Registering a new derived contract is allowed only if:

  1. It refers to its parent(s)/origin properly, that is making up an irreversible/irreplaceable chain.

  2. The whole new derived contract is made without any contract permission violations. For example, when giving out 10 tokens from an amount of “your” token, the operation for these two contracts is signed by your private key. Or, even more specifically, it is signed by someone who has the rights to transfer your tokens. (Think: multisig wallets).

  3. The new derived contract(s) are built without violating anything else. For example, if Alice wants to register a batch of operations that atomically revokes a “owner: Alice, amount: 100” contract and creates “owner: Bob, amount: 10” and “owner: Alice, amount: 90” contracts, it will test that the sum “before” is perfectly equal to the sum “after”. Such a split-join can neither create nor lose any amounts.

and finally…:

When registering any contract, you must provide the contracts it has been derived from! In the binary form so it byte-matches the ones which are considered registered in the ledger.

So, summarizing:

To “register” a new contract (a new block in some chain) is just to mark that the contract with some hash is now considered valid, and the contract with some hash is considered revoked.

But to perform this, you have to provide the contract (in the binary form), whose hash is at the moment is considered valid. You must provide the contract in valid state. And the new contract you are deriving has to refer it, and be validly derived from it.

Proof of State: the definition

… if you still need it

So here goes the Proof of State. Each new contract (i.e. block) can switch to a new state to be registered as valid state, if and only if:

  1. the binary original of the contract has been provided, and the hash sum of it is now registered as “in valid state”;
  2. the state change is legitimate and doesn’t violate the requirements defined in the binary original of the contract;
  3. the state change is requested (and signed) by someone who, according to the definitions (inside the contract original), has sufficient rights to perform this change.
  4. the change you are requesting, is allowed to be done, according to the contract structure.

    But by the way, what is “the change you are requesting” in the latter requirement?

    You are requesting joining two contracts (summing their amounts together), and splitting them by two new owners (B1 and B2). As I said already, only the current owner is (usually) allowed to do that for tokens. But besides that, there is one more thing to check. Is 15.2 + 10.3 = 3 + 22.5? Thankfully, yes. That’s another validated aspect of the contract batch.

So, as you provided the originals (not just their hash sums) of the smart contracts to Universa during new contract states registration; and Universa made a lot of check but has nothing against the state modification you are requesting; then Universa registers the whole state change, atomically.

For Universa nodes to store any new contract state, they have to be sure this state change is legit… Here is the “Proof of State”. The smart contract state is legitimate if it is legitimately derived from another legitimate smart contract state. Nothing magical, just, basically, the meaning of the words “Proof of State” themselves.