Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
One of the key features of Quorum is that of Transaction Privacy. To that end, we introduce the notion of 'Public Transactions' and 'Private Transactions'. Note that this is a notional concept only and Quorum does not introduce new Transaction Types, but rather, the Ethereum Transaction Model has been extended to include an optional
privateFor parameter (the population of which results in a Transaction being treated as private by Quorum) and the Transaction Type has a new
IsPrivate method to identify such Transactions.
So called 'Public Transactions' are those Transactions whose payload is visible to all participants of the same Quorum network. These are created as standard Ethereum Transactions in the usual way.
Examples of Public Transactions may include Market Data updates from some service provider, or some reference data update such as a correction to a Bond Security definition.
NOTE: 'Public' Transactions are not Transactions from the public Ethereum network. Perhaps a more appropriate term would be 'common' or 'global' Transactions, but 'Public' is used to contrast with 'Private' Transactions.
So called 'Private Transactions' are those Transactions whose payload is only visible to the network participants whose public keys are specified in the
privateFor parameter of the Transaction .
privateFor can take multiple addresses in a comma separated list. (See Creating Private Transactions under the Using Quorum section).
When the Quorum Node encounters a Transaction with a non-null
privateFor value, it sets the
V value of the Transaction Signature to be either
38 (as opposed to
28 which are the values used to indicate a Transaction is 'public' as per standard Ethereum as specified in the Ethereum yellow paper).
Public vs Private Transaction handling
Public Transactions are executed in the standard Ethereum way, and so if a Public Transaction is sent to an Account that holds Contract code, each participant will execute the same code and their underlying StateDBs will be updated accordingly.
Private Transactions, however, are not executed per standard Ethereum: prior to the sender's Quorum Node propagating the Transaction to the rest of the network, it replaces the original Transaction Payload with a hash of the encrypted Payload that it receives from Constellation/Tessera. Participants that are party to the Transaction will be able to replace the hash with the actual payload via their Constellation/Tessera instance, whilst those Participants that are not party will only see the hash.
The result is that if a Private Transaction is sent to an Account that holds Contract code, those participants who are not party to the Transaction will simply end up skipping the Transaction, and therefore not execute the Contract code. However those participants that are party to the Transaction will replace the hash with the original Payload before calling the EVM for execution, and their StateDB will be updated accordingly. In absence of making corresponding changes to the geth client, these two sets of participants would therefore end up with different StateDBs and not be able to reach consensus. So in order to support this bifurcation of contract state, Quorum stores the state of Public contracts in a Public State Trie that is globally synchronised, and it stores the state of Private contracts in a Private State Trie that is not synchronised globally. For details on how Consensus is achieved in light of this, please refer to the section on Consensus.
Private Transaction Process Flow
Below is a description of how Private Transactions are processed in Quorum:
In this example, Party A and Party B are party to Transaction AB, whilst Party C is not.
Party A sends a Transaction to their Quorum Node, specifying the Transaction payload and setting
privateForto be the public keys for Parties A and B
Party A's Quorum Node passes the Transaction on to its paired Transaction Manager, requesting for it to store the Transaction payload
Party A's Transaction Manager makes a call to its associated Enclave to validate the sender and encrypt the payload
Party A's Enclave checks the private key for Party A and, once validated, performs the Transaction conversion. This entails:
- generating a symmetric key and a random Nonce
- encrypting the Transaction payload and Nonce with the symmetric key from i.
- calculating the SHA3-512 hash of the encrypted payload from ii.
- iterating through the list of Transaction recipients, in this case Parties A and B, and encrypting the symmetric key from i. with the recipient's public key (PGP encryption)
- returning the encrypted payload from step ii., the hash from step iii. and the encrypted keys (for each recipient) from step iv. to the Transaction Manager
Party A's Transaction manager then stores the encrypted payload (encrypted with the symmetric key) and encrypted symmetric key using the hash as the index, and then securely transfers (via HTTPS) the hash, encrypted payload, and encrypted symmetric key that has been encrypted with Party B's public key to Party B's Transaction Manager. Party B's Transaction Manager responds with an Ack/Nack response. Note that if Party A does not receive a response/receives a Nack from Party B then the Transaction will not be propagated to the network. It is a prerequisite for the recipients to store the communicated payload.
Once the data transmission to Party B's Transaction Manager has been successful, Party A's Transaction Manager returns the hash to the Quorum Node which then replaces the Transaction's original payload with that hash, and changes the transaction's
Vvalue to 37 or 38, which will indicate to other nodes that this hash represents a private transaction with an associated encrypted payload as opposed to a public transaction with nonsensical bytecode.
The Transaction is then propagated to the rest of the network using the standard Ethereum P2P Protocol.
A block containing Transaction AB is created and distributed to each Party on the network.
In processing the block, all Parties will attempt to process the Transaction. Each Quorum node will recognise a
Vvalue of 37 or 38, identifying the Transaction as one whose payload requires decrypting, and make a call to their local Transaction Manager to determine if they hold the Transaction (using the hash as the index to look up).
Since Party C does not hold the Transaction, it will receive a
NotARecipientmessage and will skip the Transaction - it will not update its Private StateDB. Party A and B will look up the hash in their local Transaction Managers and identify that they do hold the Transaction. Each will then make a call to its Enclave, passing in the Encrypted Payload, Encrypted symmetric key and Signature.
The Enclave validates the signature and then decrypts the symmetric key using the Party's private key that is held in The Enclave, decrypts the Transaction Payload using the now-revealed symmetric key and returns the decrypted payload to the Transaction Manager.
The Transaction Managers for Parties A and B then send the decrypted payload to the EVM for contract code execution. This execution will update the state in the Quorum Node's Private StateDB only. NOTE: once the code has been executed it is discarded so is never available for reading without going through the above process.