github.com/Night-mk/quorum@v21.1.0+incompatible/NOTES.md (about) 1 # Hacking on Quorum / various notes 2 3 ## How does private state work? 4 5 Original commit from Jeff explains the dual public and private state with INITIAL restrictions: 6 ``` 7 commit 763f939f4725daa136161868d3b01fa7a84eb71e 8 Author: Jeffrey Wilcke <jeffrey@ethereum.org> 9 Date: Mon Oct 31 12:46:40 2016 +0100 10 11 core, core/vm: dual state & read only EVM 12 13 This commit implements a dual state approach. The dual state approach 14 separates public and private state by making the core vm environment 15 context aware. 16 17 Although not currently implemented it will need to prohibit value 18 transfers and it must initialise all transactions from accounts on the 19 public state. This means that sending transactions increments the 20 account nonce on the public state and contract addresses are derived 21 from the public state when initialised by a transaction. For obvious 22 reasons, contract created by private contracts are still derived from 23 public state. 24 25 This is required in order to have consensus over the public state at all 26 times as non-private participants would still process the transaction on 27 the public state even though private payload can not be decrypted. This 28 means that participants of a private group must do the same in order to 29 have public consensus. However the creation of the contract and 30 interaction still occurs on the private state. 31 32 It implements support for the following calling model: 33 34 S: sender, (X): private, X: public, ->: direction, [ ]: read only mode 35 36 1. S -> A -> B 37 2. S -> (A) -> (B) 38 3. S -> (A) -> [ B -> C ] 39 40 It does not support 41 42 1. (S) -> A 43 2. (S) -> (A) 44 3. S -> (A) -> B 45 46 Implemented "read only" mode for the EVM. Read only mode is checked 47 during any opcode that could potentially modify the state. If such an 48 opcode is encountered during "read only", it throws an exception. 49 50 The EVM is flagged "read only" when a private contract calls in to 51 public state. 52 ``` 53 54 55 Some things have changed since, let's look at the EVM structure in some more detail: 56 57 ```go 58 type EVM struct { 59 ... 60 // StateDB gives access to the underlying state 61 StateDB StateDB 62 // Depth is the current call stack 63 depth int 64 ... 65 66 publicState PublicState 67 privateState PrivateState 68 states [1027]*state.StateDB 69 currentStateDepth uint 70 readOnly bool 71 readOnlyDepth uint 72 } 73 ``` 74 75 The vanilla EVM has a call depth limit of 1024. Our `states` parallel the EVM call stack, recording as contracts in the public and private state call back and forth to each other. Note it doesn't have to be a "public -> private -> public -> private" back-and-forth chain. It can be any sequence of { public, private }. 76 77 The interface for calling is this `Push` / `Pop` sequence: 78 79 ```go 80 evm.Push(getDualState(evm, addr)) 81 defer func() { evm.Pop() }() 82 // ... do work in the pushed state 83 ``` 84 85 The definitions of `Push` and `Pop` are simple and important enough to duplicate here: 86 87 ```go 88 func (env *EVM) Push(statedb StateDB) { 89 if env.privateState != statedb { 90 env.readOnly = true 91 env.readOnlyDepth = env.currentStateDepth 92 } 93 94 if castedStateDb, ok := statedb.(*state.StateDB); ok { 95 env.states[env.currentStateDepth] = castedStateDb 96 env.currentStateDepth++ 97 } 98 99 env.StateDB = statedb 100 } 101 func (env *EVM) Pop() { 102 env.currentStateDepth-- 103 if env.readOnly && env.currentStateDepth == env.readOnlyDepth { 104 env.readOnly = false 105 } 106 env.StateDB = env.states[env.currentStateDepth-1] 107 } 108 ``` 109 110 Note the invariant that `StateDB` always points to the current state db. 111 112 The other interesting note is read only mode. Any time we call from the private state into the public state (`env.privateState != statedb`), we require anything deeper to be *read only*. Private state transactions can't affect public state, so we throw an EVM exception on any mutating operation (`SELFDESTRUCT, CREATE, SSTORE, LOG0, LOG1, LOG2, LOG3, LOG4`). Question: have any more mutating operations been added? Question: could we not mutate deeper private state?