Transaction Inclusion Proposal (#12936)
Co-authored-by: Carl Lin <carl@solana.com>
This commit is contained in:
@ -61,22 +61,25 @@ A transaction inclusion proof is a data structure that contains a Merkle Path
|
|||||||
from a transaction, through an Entry-Merkle to a Block-Merkle, which is included
|
from a transaction, through an Entry-Merkle to a Block-Merkle, which is included
|
||||||
in a Bank-Hash with the required set of validator votes. A chain of PoH Entries
|
in a Bank-Hash with the required set of validator votes. A chain of PoH Entries
|
||||||
containing subsequent validator votes, deriving from the Bank-Hash, is the proof
|
containing subsequent validator votes, deriving from the Bank-Hash, is the proof
|
||||||
of confirmation. Clients can examine this ledger data and compute finality using
|
of confirmation.
|
||||||
Solana's fork selection rules.
|
|
||||||
|
#### Transaction Merkle
|
||||||
|
|
||||||
An Entry-Merkle is a Merkle Root including all transactions in a given entry,
|
An Entry-Merkle is a Merkle Root including all transactions in a given entry,
|
||||||
sorted by signature.
|
sorted by signature. Each transaction in an entry is already merkled here:
|
||||||
|
https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67bb6bdbaefc7f833bbed3563/ledger/src/entry.rs#L205.
|
||||||
|
This means we can show a transaction `T` was included in an entry `E`.
|
||||||
|
|
||||||
A Block-Merkle is the Merkle Root of all the Entry-Merkles sequenced in the block.
|
A Block-Merkle is the Merkle Root of all the Entry-Merkles sequenced in the
|
||||||
|
block.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
A Bank-Hash is the hash of the concatenation of the Block-Merkle and Accounts-Hash
|
Together the two merkle proofs show a transaction `T` was included in a block
|
||||||
|
with bank hash `B`.
|
||||||
|
|
||||||

|
An Accounts-Hash is the hash of the concatentation of the state hashes of
|
||||||
|
each account modified during the current slot.
|
||||||
An Accounts-Hash is the hash of the concatentation of the state hashes of each
|
|
||||||
account modified during the current slot.
|
|
||||||
|
|
||||||
Transaction status is necessary for the receipt because the state receipt is
|
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
|
constructed for the block. Two transactions over the same state can appear in
|
||||||
@ -85,6 +88,103 @@ 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
|
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.
|
code, but a single status bit to indicate the transaction's success.
|
||||||
|
|
||||||
|
Currently, the Block-Merkle is not implemented, so to verify `E` was an entry
|
||||||
|
in the block with bank hash `B`, we would need to provide all the entry hashes
|
||||||
|
in the block. Ideally this Block-Merkle would be implmented, as the alternative
|
||||||
|
is very inefficient.
|
||||||
|
|
||||||
|
#### Block Headers
|
||||||
|
In order to verify transaction inclusion proofs, light clients need to be able
|
||||||
|
to infer the topology of the forks in the network
|
||||||
|
|
||||||
|
More specifically, the light client will need to track incoming block headers
|
||||||
|
such that given two bank hashes for blocks `A` and `B`, they can determine
|
||||||
|
whether `A` is an ancestor of `B` (Below section on
|
||||||
|
`Optimistic Confirmation Proof` explains why!). Contents of header are the
|
||||||
|
fields necessary to compute the bank hash.
|
||||||
|
|
||||||
|
A Bank-Hash is the hash of the concatenation of the Block-Merkle and
|
||||||
|
Accounts-Hash described in the `Transaction Merkle` section above.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
In the code:
|
||||||
|
|
||||||
|
https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67bb6bdbaefc7f833bbed3563/runtime/src/bank.rs#L3468-L3473
|
||||||
|
|
||||||
|
```
|
||||||
|
let mut hash = hashv(&[
|
||||||
|
// bank hash of the parent block
|
||||||
|
self.parent_hash.as_ref(),
|
||||||
|
// hash of all the modifed accounts
|
||||||
|
accounts_delta_hash.hash.as_ref(),
|
||||||
|
// Number of signatures processed in this block
|
||||||
|
&signature_count_buf,
|
||||||
|
// Last PoH hash in this block
|
||||||
|
self.last_blockhash().as_ref(),
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
A good place to implement this logic along existing streaming logic in the
|
||||||
|
validator's replay logic: https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67bb6bdbaefc7f833bbed3563/core/src/replay_stage.rs#L1092-L1096
|
||||||
|
|
||||||
|
#### Optimistic Confirmation Proof
|
||||||
|
|
||||||
|
Currently optimistic confirmation is detected via a listener that monitors
|
||||||
|
gossip and the replay pipeline for votes:
|
||||||
|
https://github.com/solana-labs/solana/blob/b6bfed64cb159ee67bb6bdbaefc7f833bbed3563/core/src/cluster_info_vote_listener.rs#L604-L614.
|
||||||
|
|
||||||
|
Each vote is a signed transaction that includes the bank hash of the block the
|
||||||
|
validator voted for, i.e. the `B` from the `Transaction Merkle` section above.
|
||||||
|
Once a certain threshold `T` of the network has voted on a block, the block is
|
||||||
|
considered optimistially confirmed. The votes made by this group of `T`
|
||||||
|
validators is needed to show the block with bank hash `B` was optimistically
|
||||||
|
confirmed.
|
||||||
|
|
||||||
|
However other than some metadata, the signed votes themselves are not
|
||||||
|
currently stored anywhere, so they can't be retrieved on demand. These votes
|
||||||
|
probably need to be persisted in Rocksdb database, indexed by a key
|
||||||
|
`(Slot, Hash, Pubkey)` which represents the slot of the vote, bank hash of the
|
||||||
|
vote, and vote account pubkey responsible for the vote.
|
||||||
|
|
||||||
|
Together, the transaction merkle and optimistic confirmation proofs can be
|
||||||
|
provided over RPC to subscribers by extending the existing signature
|
||||||
|
subscrption logic. Clients who subscribe to the "SingleGossip" confirmation
|
||||||
|
level are already notified when optimistic confirmation is detected, a flag
|
||||||
|
can be provided to signal the two proofs above should also be returned.
|
||||||
|
|
||||||
|
It is important to note that optimistcally confirming `B` also implies that all
|
||||||
|
ancestor blocks of `B` are also optimistically confirmed, and also that not
|
||||||
|
all blocks will be optimistically confirmed.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
B -> B'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
So in the example above if a block `B'` is optimisically confirmed, then so is
|
||||||
|
`B`. Thus if a transaction was in block `B`, the transaction merkle in the
|
||||||
|
proof will be for block `B`, but the votes presented in the proof will be for
|
||||||
|
block `B'`. This is why the headers in the `Block headers` section above are
|
||||||
|
important, the client will need to verify that `B` is indeed an ancestor of
|
||||||
|
`B'`.
|
||||||
|
|
||||||
|
#### Proof of Stake Distribution
|
||||||
|
|
||||||
|
Once presented with the transaction merkle and optimistic confirmation proofs
|
||||||
|
above, a client can verify a transaction `T` was optimistially confirmed in a
|
||||||
|
block with bank hash `B`. The last missing piece is how to verify that the
|
||||||
|
votes in the optimistic proofs above actually constitute the valid `T`
|
||||||
|
percentage of the stake necessay to uphold the safety guarantees of
|
||||||
|
"optimistic confirmation".
|
||||||
|
|
||||||
|
One way to approach this might be for every epoch, when the stake set changes,
|
||||||
|
to write all the stakes to a system account, and then have validators subscribe
|
||||||
|
to that system account. Full nodes can then provide a merkle proving that the
|
||||||
|
system account state was updated in some block `B`, and then show that the
|
||||||
|
block `B` was optimistically confirmed/rooted.
|
||||||
|
|
||||||
### Account State Verification
|
### Account State Verification
|
||||||
|
|
||||||
An account's state (balance or other data) can be verified by submitting a
|
An account's state (balance or other data) can be verified by submitting a
|
||||||
|
Reference in New Issue
Block a user