book: Add simple payment and state verification proposal (#4200)
automerge
This commit is contained in:
committed by
Grimes
parent
278614fc7c
commit
af1c70f032
18
book/art/spv-bank-merkle.bob
Normal file
18
book/art/spv-bank-merkle.bob
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
+------------+
|
||||||
|
| Bank-Merkle|
|
||||||
|
+------------+
|
||||||
|
^ ^
|
||||||
|
/ \
|
||||||
|
+-----------------+ +-------------+
|
||||||
|
| Bank-Diff-Merkle| | Block-Merkle|
|
||||||
|
+-----------------+ +-------------+
|
||||||
|
^ ^
|
||||||
|
/ \
|
||||||
|
+------+ +--------------------------+
|
||||||
|
| Hash | | Previous Bank-Diff-Merkle|
|
||||||
|
+------+ +--------------------------+
|
||||||
|
^ ^
|
||||||
|
/ \
|
||||||
|
+---------------+ +---------------+
|
||||||
|
| Hash(Account1)| | Hash(Account2)|
|
||||||
|
+---------------+ +---------------+
|
19
book/art/spv-block-merkle.bob
Normal file
19
book/art/spv-block-merkle.bob
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
+---------------+
|
||||||
|
| Block-Merkle |
|
||||||
|
+---------------+
|
||||||
|
^ ^
|
||||||
|
/ \
|
||||||
|
+-------------+ +-------------+
|
||||||
|
| Entry-Merkle| | Entry-Merkle|
|
||||||
|
+-------------+ +-------------+
|
||||||
|
^ ^
|
||||||
|
/ \
|
||||||
|
+-------+ +-------+
|
||||||
|
| Hash | | Hash |
|
||||||
|
+-------+ +-------+
|
||||||
|
^ ^ ^ ^
|
||||||
|
/ | | \
|
||||||
|
+-----------------+ +-----------------+ +-----------------+ +---+
|
||||||
|
| Hash(T1, status)| | Hash(T2, status)| | Hash(T3, status)| | 0 |
|
||||||
|
+-----------------+ +-----------------+ +-----------------+ +---+
|
||||||
|
|
@ -57,6 +57,7 @@
|
|||||||
- [Cluster Test Framework](cluster-test-framework.md)
|
- [Cluster Test Framework](cluster-test-framework.md)
|
||||||
- [Credit-only Accounts](credit-only-credit-debit-accounts.md)
|
- [Credit-only Accounts](credit-only-credit-debit-accounts.md)
|
||||||
- [Validator](validator-proposal.md)
|
- [Validator](validator-proposal.md)
|
||||||
|
- [Simple Payment and State Verification](simple-payment-and-state-verification.md)
|
||||||
|
|
||||||
- [Implemented Design Proposals](implemented-proposals.md)
|
- [Implemented Design Proposals](implemented-proposals.md)
|
||||||
- [Blocktree](blocktree.md)
|
- [Blocktree](blocktree.md)
|
||||||
|
172
book/src/simple-payment-and-state-verification.md
Normal file
172
book/src/simple-payment-and-state-verification.md
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
# Simple Payment and State Verification
|
||||||
|
|
||||||
|
It is often useful to allow low resourced clients to participate in a Solana
|
||||||
|
cluster. Be this participation economic or contract execution, verification
|
||||||
|
that a client's activity has been accepted by the network is typically
|
||||||
|
expensive. This proposal lays out a mechanism for such clients to confirm that
|
||||||
|
their actions have been committed to the ledger state with minimal resource
|
||||||
|
expenditure and third-party trust.
|
||||||
|
|
||||||
|
## A Naive Approach
|
||||||
|
|
||||||
|
Validators store the signatures of recently confirmed transactions for a short
|
||||||
|
period of time to ensure that they are not processed more than once. Validators
|
||||||
|
provide a JSON RPC endpoint, which clients can use to query the cluster if a
|
||||||
|
transaction has been recently processed. Validators also provide a PubSub
|
||||||
|
notification, whereby a client registers to be notified when a given signature
|
||||||
|
is observed by the validator. While these two mechanisms allow a client to
|
||||||
|
verify a payment, they are not a proof and rely on completely trusting a
|
||||||
|
fullnode.
|
||||||
|
|
||||||
|
We will describe a way to minimize this trust using Merkle Proofs to anchor the
|
||||||
|
fullnode's response in the ledger, allowing the client to confirm on their own
|
||||||
|
that a sufficient number of their preferred validators have confirmed a
|
||||||
|
transaction. Requiring multiple validator attestations further reduces trust in
|
||||||
|
the fullnode, as it increases both the technical and economic difficulty of
|
||||||
|
compromising several other network participants.
|
||||||
|
|
||||||
|
## Light Clients
|
||||||
|
|
||||||
|
A 'light client' is a cluster participant that does not itself run a fullnode.
|
||||||
|
This light client would provide a level of security greater than trusting a
|
||||||
|
remote fullnode, without requiring the light client to spend a lot of resources
|
||||||
|
verifying the ledger.
|
||||||
|
|
||||||
|
Rather than providing transaction signatures directly to a light client, the
|
||||||
|
fullnode instead generates a Merkle Proof from the transaction of interest to
|
||||||
|
the root of a Merkle Tree of all transactions in the including block. This Merkle
|
||||||
|
Root is stored in a ledger entry which is voted on by validators, providing it
|
||||||
|
consensus legitimacy. The additional level of security for a light client depends
|
||||||
|
on an initial canonical set of validators the light client considers to be the
|
||||||
|
stakeholders of the cluster. As that set is changed, the client can update its
|
||||||
|
internal set of known validators with [receipts](#receipts). This may become
|
||||||
|
challenging with a large number of delegated stakes.
|
||||||
|
|
||||||
|
Fullnodes themselves may want to use light client APIs for performance reasons.
|
||||||
|
For example, during the initial launch of a fullnode, the fullnode may use a
|
||||||
|
cluster provided checkpoint of the state and verify it with a receipt.
|
||||||
|
|
||||||
|
## Receipts
|
||||||
|
|
||||||
|
A receipt is a minimal proof that; a transaction has been included in a block,
|
||||||
|
that the block has been voted on by the client's preferred set of validators and
|
||||||
|
that the votes have reached the desired confirmation depth.
|
||||||
|
|
||||||
|
The receipts for both state and payments start with a Merkle Path from the
|
||||||
|
value into a Bank-Merkle that has been voted on and included in the ledger. A
|
||||||
|
chain of PoH Entries containing subsequent validator votes, deriving from the
|
||||||
|
Bank-Merkle, is the confirmation proof.
|
||||||
|
|
||||||
|
Clients can examine this ledger data and compute the finality using Solana's fork
|
||||||
|
selection rules.
|
||||||
|
|
||||||
|
### Payment Merkle Path
|
||||||
|
|
||||||
|
A payment receipt is a data structure that contains a Merkle Path from a
|
||||||
|
transaction to the required set of validator votes.
|
||||||
|
|
||||||
|
An Entry-Merkle is a Merkle Root including all transactions in the entry, sorted
|
||||||
|
by signature.
|
||||||
|
|
||||||
|
<img alt="Block Merkle Diagram" src="img/spv-block-merkle.svg" class="center"/>
|
||||||
|
|
||||||
|
A Block-Merkle is a Merkle root of all the Entry-Merkles sequenced in the block.
|
||||||
|
Transaction status is necessary for the receipt because the state receipt is
|
||||||
|
constructed for the block. Two transactions over the same state can appear in
|
||||||
|
the block, and therefore, there is no way to infer from just the state whether a
|
||||||
|
transaction that is committed to the ledger has succeeded or failed in modifying
|
||||||
|
the intended state. It may not be necessary to encode the full status code, but
|
||||||
|
a single status bit to indicate the transaction's success.
|
||||||
|
|
||||||
|
### State Merkle Path
|
||||||
|
|
||||||
|
A state receipt provides a confirmation that a specific state is committed at the
|
||||||
|
end of the block. Inter-block state transitions do not generate a receipt.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
* A sends 5 Lamports to B
|
||||||
|
* B spends 5 Lamports
|
||||||
|
* C sends 5 Lamports to A
|
||||||
|
|
||||||
|
At the end of the block, A and B are in the exact same starting state, and any
|
||||||
|
state receipt would point to the same value for A or B.
|
||||||
|
|
||||||
|
The Bank-Merkle is computed from the Merkle Tree of the new state changes, along
|
||||||
|
with the Previous Bank-Merkle, and the Block-Merkle.
|
||||||
|
|
||||||
|
<img alt="Bank Merkle Diagram" src="img/spv-bank-merkle.svg" class="center"/>
|
||||||
|
|
||||||
|
A state receipt contains only the state changes occurring in the block. A direct
|
||||||
|
Merkle Path to the current Bank-Merkle guarantees the state value at that bank
|
||||||
|
hash, but it cannot be used to generate a “current” receipt to the latest state
|
||||||
|
if the state modification occurred in some previous block. There is no guarantee
|
||||||
|
that the path provided by the validator is the latest one available out of all
|
||||||
|
the previous Bank-Merkles.
|
||||||
|
|
||||||
|
Clients that want to query the chain for a receipt of the "latest" state would
|
||||||
|
need to create a transaction that would update the Merkle Path for that account,
|
||||||
|
such as a credit of 0 Lamports.
|
||||||
|
|
||||||
|
### Validator Votes
|
||||||
|
|
||||||
|
Leaders should coalesce the validator votes by stake weight into a single entry.
|
||||||
|
This will reduce the number of entries necessary to create a receipt.
|
||||||
|
|
||||||
|
### Chain of Entries
|
||||||
|
|
||||||
|
A receipt has a PoH link from the payment or state Merkle Path root to a list of
|
||||||
|
consecutive validation votes.
|
||||||
|
|
||||||
|
It contains the following:
|
||||||
|
* State -> Bank-Merkle
|
||||||
|
or
|
||||||
|
* Transaction -> Entry-Merkle -> Block-Merkle -> Bank-Merkle
|
||||||
|
|
||||||
|
And a vector of PoH entries:
|
||||||
|
|
||||||
|
* Validator vote entries
|
||||||
|
* Ticks
|
||||||
|
* Light entries
|
||||||
|
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
/// This Entry definition skips over the transactions and only contains the
|
||||||
|
/// hash of the transactions used to modify PoH.
|
||||||
|
LightEntry {
|
||||||
|
/// The number of hashes since the previous Entry ID.
|
||||||
|
pub num_hashes: u64,
|
||||||
|
/// The SHA-256 hash `num_hashes` after the previous Entry ID.
|
||||||
|
hash: Hash,
|
||||||
|
/// The Merkle Root of the transactions encoded into the Entry.
|
||||||
|
entry_hash: Hash,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The light entries are reconstructed from Entries and simply show the entry Merkle
|
||||||
|
Root that was mixed in to the PoH hash, instead of the full transaction set.
|
||||||
|
|
||||||
|
Clients do not need the starting vote state. The [fork selection](book/src/fork-selection.md) algorithm is
|
||||||
|
defined such that only votes that appear after the transaction provide finality
|
||||||
|
for the transaction, and finality is independent of the starting state.
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
|
||||||
|
A light client that is aware of the supermajority set validators can verify a
|
||||||
|
receipt by following the Merkle Path to the PoH chain. The Bank-Merkle is the
|
||||||
|
Merkle Root and will appear in votes included in an Entry. The light client can
|
||||||
|
simulate [fork selection](book/src/fork-selection.md) for the consecutive votes
|
||||||
|
and verify that the receipt is confirmed at the desired lockout threshold.
|
||||||
|
|
||||||
|
### Synthetic State
|
||||||
|
|
||||||
|
Synthetic state should be computed into the Bank-Merkle along with the bank
|
||||||
|
generated state.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
* Epoch validator accounts and their stakes and weights.
|
||||||
|
* Computed fee rates
|
||||||
|
|
||||||
|
These values should have an entry in the Bank-Merkle. They should live under
|
||||||
|
known accounts, and therefore have an exact address in the Merkle Path.
|
Reference in New Issue
Block a user