Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIMD-0052: Add Receipt Root to Bankhash #52

Open
wants to merge 71 commits into
base: main
Choose a base branch
from
Open
Changes from 43 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
c1a05af
Create 0023-Diet-client-v0.md
harsh4786 Apr 26, 2023
f2e1949
Update 0023-Diet-client-v0.md
harsh4786 Apr 26, 2023
c1143c7
Update 0023-Diet-client-v0.md
harsh4786 Apr 26, 2023
1b6577b
Update 0023-Diet-client-v0.md
harsh4786 Apr 26, 2023
1534b5b
Update 0023-Diet-client-v0.md
harsh4786 Apr 26, 2023
4021f25
Update 0023-Diet-client-v0.md
harsh4786 Apr 27, 2023
c555a78
Update and rename 0023-Diet-client-v0.md to 0023-diet-client-v0.md
anoushk1234 May 1, 2023
c9a5ad7
Update 0023-diet-client-v0.md
anoushk1234 May 1, 2023
248fb16
Update 0023-diet-client-v0.md
anoushk1234 May 1, 2023
dcde05f
update
anoushk1234 May 3, 2023
42be819
Update 0023-diet-client-v0.md
anoushk1234 May 6, 2023
18b5bb2
update
anoushk1234 May 6, 2023
289ab7c
Update 0023-diet-client-v0.md
harsh4786 May 6, 2023
1d78fbb
Update 0023-diet-client-v0.md
harsh4786 May 6, 2023
9bc9c9e
Update 0023-diet-client-v0.md
harsh4786 May 6, 2023
7a8bcc8
Update 0023-diet-client-v0.md
anoushk1234 May 6, 2023
08b657e
stake logic
anoushk1234 May 16, 2023
1ef37b0
init
0xNineteen May 24, 2023
bc6c304
fix
0xNineteen May 24, 2023
938dec6
up
0xNineteen May 24, 2023
79d5879
update
0xNineteen May 24, 2023
c5a2a38
Update and rename 0023-diet-client-v0.md to 0023-consensus-and-transa…
anoushk1234 May 25, 2023
50c56bd
Merge branch 'main' of https://github.com/tinydancer-io/solana-improv…
0xNineteen May 25, 2023
8ee393e
update
0xNineteen May 25, 2023
4bb3bc2
update
0xNineteen May 25, 2023
a64f6ed
update
0xNineteen May 25, 2023
0682f07
update
0xNineteen May 25, 2023
13c9b44
fix
0xNineteen May 25, 2023
3f59b53
spell check
0xNineteen May 25, 2023
8d604a0
remove old simd
0xNineteen May 25, 2023
aaaf936
add merkle proof info
0xNineteen May 26, 2023
1afc14b
add more merkle info
0xNineteen May 26, 2023
617bee7
up
0xNineteen May 26, 2023
6f0eb58
update
anoushk1234 May 26, 2023
1da4621
format
anoushk1234 May 26, 2023
400c527
update
anoushk1234 May 26, 2023
b72c237
Update 0023-consensus-and-transaction-inclusion-verification.md
anoushk1234 May 30, 2023
0248900
update
0xNineteen May 30, 2023
1f1fc48
update
0xNineteen May 30, 2023
e44a303
Update 0023-consensus-and-transaction-inclusion-verification.md
anoushk1234 May 30, 2023
fea5002
fix
0xNineteen May 30, 2023
6acf506
Merge pull request #3 from 0xNineteen/main
anoushk1234 May 30, 2023
887c053
Update and rename 0023-consensus-and-transaction-inclusion-verificati…
anoushk1234 May 30, 2023
9d70e39
fix lint
anoushk1234 Jun 3, 2023
0023e7b
fix lint
anoushk1234 Jun 3, 2023
c50f2b6
fix lint
anoushk1234 Jun 3, 2023
489f2f1
fix simd lint
anoushk1234 Jun 3, 2023
a4aeb7f
fix simd lint
anoushk1234 Jun 4, 2023
19d9bbe
Create 00xx-add-transaction-receipts-in-crds.md
harsh4786 Jun 25, 2023
6a0b744
Revert "Create 00xx-add-transaction-receipts-in-crds.md"
harsh4786 Jun 26, 2023
16bd03b
Create 0058-transaction-receipts
anoushk1234 Jul 18, 2023
0a48f4d
Rename 0058-transaction-receipts to 0064-transaction-receipts
anoushk1234 Jul 18, 2023
941a25a
Delete 0064-transaction-receipts
anoushk1234 Jul 18, 2023
c74d8b4
update simd with receipts
anoushk1234 Aug 5, 2023
8a0eea5
fix
anoushk1234 Aug 5, 2023
7205af1
fix
anoushk1234 Aug 5, 2023
2fee5ff
update author
anoushk1234 Aug 7, 2023
e40077b
fix
anoushk1234 Aug 21, 2023
931506f
simd 52 changes wip
harsh4786 Oct 22, 2023
dfc6b83
simd 52 changes wip
harsh4786 Oct 22, 2023
d8ca3dd
modify summary
harsh4786 Nov 14, 2023
0614f5c
fix lint
harsh4786 Nov 14, 2023
82d017d
fix lint
harsh4786 Nov 14, 2023
1068a23
fixes
harsh4786 Nov 14, 2023
52124c6
fix lint
harsh4786 Nov 14, 2023
0d825d0
fix
harsh4786 Nov 14, 2023
bef2cb2
update
harsh4786 Nov 14, 2023
200611e
fix
harsh4786 Nov 14, 2023
b7b7b00
update
harsh4786 Nov 14, 2023
2f0e293
update
harsh4786 Nov 15, 2023
e425a1a
fix
harsh4786 Nov 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions proposals/0052-consensus-and-transaction-inclusion-verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
simd: '0052'
title: Consensus and Transaction Inclusion Verification
authors:
- Harsh Patel (Tinydancer)
- Anoushk Kharangate (Tinydancer)
- x19 (Tinydancer)
category: Standard
type: Core
status: Draft
created: 2023-05-30
---

## Summary

This SIMD describes the overall design and changes required that allows users to verify that a supermajority of the validators has voted on the slot that their transaction was included in the block without fully trusting the RPC provider.

Check failure on line 16 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 238]

proposals/0052-consensus-and-transaction-inclusion-verification.md:16:81 MD013/line-length Line length [Expected: 80; Actual: 238]

This includes two main changes:
1) Adding a new RPC method which provides a proof that a transaction has been included in a slot and

Check failure on line 19 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 101]

proposals/0052-consensus-and-transaction-inclusion-verification.md:19:81 MD013/line-length Line length [Expected: 80; Actual: 101]

Check failure on line 19 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Lists should be surrounded by blank lines [Context: "1) Adding a new RPC method whi..."]

proposals/0052-consensus-and-transaction-inclusion-verification.md:19 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "1) Adding a new RPC method whi..."]
2) Modifying the blockhash to be computed as a Merkle Tree and include transaction statuses

Check failure on line 20 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 91]

proposals/0052-consensus-and-transaction-inclusion-verification.md:20:81 MD013/line-length Line length [Expected: 80; Actual: 91]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be very hesitant to modify something as central as block hash calculation without a working PoC.
The block hash mixin already includes a Merkle tree over the transaction signatures.
Why not create an inclusion proof against the data commited to by the bank hash instead?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah we could draft a PoC if that would help

if we did an inclusion proof as it is now we would need a merkle proof of the tx sig in the Entry and then a hashpath from the Entry to the blockhash - so we would need to transmit all the Entries (assuming worse case the tx sig is in the first entry) which we thought was inefficient

image

but were open to doing it this way (using the current sequential proof) if the merkle entry change is too big

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ripatel-jump we still need to modify it to include statuses, even if we can prove txn inclusion we need to also prov that the execution was successful. Also this is actually a known issue solana-labs/solana#7053 and was going to be implemented as part of the SPV proposal.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the simplest PoC for making the entries a merkle would probs be:

  • modify bank to store entry hashes with a new method register_entry and new field entry_leaves
pub fn register_entry(&self, entry: Hash) { 
	// entry_leaves: RwLock<Vec<Entry>>
	self.entry_leaves.write().unwrap().push(entry);
}
  • then modify process_replay_results to read and register the entries (where the bank is frozen for both the TVU and TPU paths)
if bank.is_complete() { 
	let (entries, _, _) = blockstore.get_slot_entries_with_shred_info(bank.slot(), 0, false).unwrap();
	entries.iter().for_each(|e| bank.register_entry(e.hash));
	bank.freeze();
	// ...
}
  • note: we store the entries on the bank so we dont modify bank.freeze() - this is similar to how it currently works where the last_blockhash is read from a queue on freeze

  • and lastly, modify bank.hash_internal_state() to generate a merkle root from the saved entries:

fn hash_internal_state(&self) -> Hash {
	// ... 
	let merkle_tree = MerkleTree::new(&self.entry_leaves.read().unwrap());
	let last_blockhash  = merkle_tree.get_root().unwrap();
	// .. 
}


This SIMD is the first step in implementing a consensus verifying client as first described in [SIMD #10](https://github.com/solana-foundation/solana-improvement-documents/pull/10) and a majority of the changes mentioned in the accepted [Simple Payment and State Verification

Check failure on line 22 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 275]

proposals/0052-consensus-and-transaction-inclusion-verification.md:22:81 MD013/line-length Line length [Expected: 80; Actual: 275]
proposal](https://docs.solana.com/proposals/simple-payment-and-state-verification).

## Motivation

Currently, for a user to validate whether their transaction is valid and included in a block it needs to trust the confirmation from the RPC. This has been a glaring attack vector for malicious actors that could lie to users if it's in their own interest.

Check failure on line 27 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 256]

proposals/0052-consensus-and-transaction-inclusion-verification.md:27:81 MD013/line-length Line length [Expected: 80; Actual: 256]
Copy link
Contributor

@ripatel-fd ripatel-fd May 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current protocol would allow formulating transaction inclusion proofs (against the block/PoH hash) without changes

Copy link

@0xNineteen 0xNineteen May 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this part is just noting that we would still need a new RPC method to provide a proof


To combat this, mature entities like exchanges run full nodes that process the entire ledger and can verify entire blocks. The downside of this is that it's very costly to run a full node which makes it inaccessible to everyday users,exposing users to potential attacks from malicious nodes. This is where diet clients come in, users run the client to verify the confirmation of their transaction without trusting the RPC.

Check failure on line 29 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 422]

proposals/0052-consensus-and-transaction-inclusion-verification.md:29:81 MD013/line-length Line length [Expected: 80; Actual: 422]

However, this is only the consensus verifying stage of the client, and with only these changes, the RPC provider can still trick users, hence we also discuss future work that will be implemented in future SIMDs to provide a fully trustless setup.

Check failure on line 31 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 247]

proposals/0052-consensus-and-transaction-inclusion-verification.md:31:81 MD013/line-length Line length [Expected: 80; Actual: 247]

## Alternatives Considered

None

## New Terminology

TransactionProof: A structure containing necessary information to verify if a transaction was included in the bank hash of a slot.

Check failure on line 39 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 130]

proposals/0052-consensus-and-transaction-inclusion-verification.md:39:81 MD013/line-length Line length [Expected: 80; Actual: 130]

```rs
// new RPC struct to verify tx inclusion
pub struct TransactionProof {
pub proof: Vec<Hash>,
pub parent_hash: Hash,
pub accounts_delta_hash: Hash,
pub signature_count_buf: [u8; 8],
}
```

The proof variable will provide a Merkle hashpath from the transaction to the blockhash; which is then used with the other variables to compute the bankhash.

Check failure on line 51 in proposals/0052-consensus-and-transaction-inclusion-verification.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 157]

proposals/0052-consensus-and-transaction-inclusion-verification.md:51:81 MD013/line-length Line length [Expected: 80; Actual: 157]

## Detailed Design

The protocol interaction will be as follows:
- A user sends a transaction and it lands in slot N
- The user requests proof that the transaction is included in slot N using the new RPC method
- The user verifies that the proof includes the transaction signature and a success status
- The user constructs the merkle tree to derive the root hash
- The user computes the expected bankhash using the root hash, `parent_hash`, `accounts_delta_hash` and `signature_count`
- The user retrieves the epoch’s current validator set and stake amounts from a trusted source (making this step trustless is future work)
Copy link

@leoluk leoluk May 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the crucial step, though. IMO, this SIMD only makes sense as long as there's a plausible path towards achieving this.

Copy link

@mschneider mschneider May 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we have the same issue in lite-rpc, it's currently impossible to construct without a full runtime. Eth2 has an interesting solution: https://github.com/ethereum/annotated-spec/blob/master/altair/sync-protocol.md

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the SPV also mentions one possible solution involving writing to a system account here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we have the same issue in lite-rpc, it's currently impossible to construct without a full runtime. Eth2 has an interesting solution: https://github.com/ethereum/annotated-spec/blob/master/altair/sync-protocol.md

Yea this is what we were exploring as well, but this would need a small committee of trusted validators.

- The user requests blocks from slots > N (up to 32 slots past N given the 32 block depth finality)
- The user parses vote transactions from the blocks, verifying their signature, and computing the sum of stake which voted on the bankhash they computed in step 3
- If the sum of stake is greater than or equal to 2/3 of the total stake then their transaction has been finalized under a supermajority trust assumption (making this assumption require only a single honest validator is also future work)


#### Modifying the Blockhash

We propose modifying the blockhash computation to
1) Compute the blockhash using a Merkle Tree of entries and
2) Include the status (either succeeding or failing) of each transaction in each Entry leaf

To produce the blockhash for a slot, the current implementation hashes Entries in a sequential way which requires a O(N) proof size to provide a hashpath from a transaction to a blockhash. Implementing change 1) would allow for a more efficient O(log(N)) proof size. The current Entry implementation already hashes transaction signatures using a Merkle Tree to get the Entry’s hash, so this change would only modify how the Entry’s hashes are hashed together to get a blockhash.

For change 2), the blockhash is currently computed using only transaction signatures, and does not include transaction statuses which means we are unable to prove if a transaction has succeeded or failed. Implementing 2) would enable verifying a transactions status, as mentioned in the [accepted proposal](https://docs.solana.com/proposals/simple-payment-and-state-verification#transaction-merkle) and in a [previous github issue](https://github.com/solana-labs/solana/issues/7053)).

Fig #1 shows an example hashpath from a transaction and its signature to a bankhash with both of the proposed changes implemented.
<figure>
<img width="468" alt="Figure showing the hashpath to the transaction" src="https://github.com/tinydancer-io/solana-improvement-documents/assets/32778608/5370950d-e27b-4c1b-9f04-6e9164789e65">
<figcaption>Fig #1</figcaption>
</figure>


#### New RPC Methods

We also need a new RPC method to provide proofs to clients. This method would be called `get_transaction_proof` which would take a transaction signature as input and return a `TransactionProof` struct

```rs
// new RPC method
pub async fn get_transaction_proof(&self, signature: Signature) -> Result<TransactionProof>;
```

Below is psuedocode of the RPC method:

```rs
pub async fn get_transaction_proof(&self, signature: Signature) -> Result<TransactionProof> {
// first retrieve all the entries
let slot = self.get_slot_of_signature(&signature);
let (entries, _, is_full) = self.blockstore.get_slot_entries_with_shred_info(slot, 0, false)
// require all of the entries
assert!(is_full)

// compute the Merkle hashpath from the signature and status to the blockhash
let proof = entries.get_merkle_proof(&signature);

// get variables used to compute the bankhash
let bank_forks = self.bank_forks.read().unwrap();
let bank = bank_forks.get(slot);

let parent_hash = bank.parent_hash();
let accounts_delta_hash = bank
.rc
.accounts
.accounts_db
.calculate_accounts_delta_hash(slot).0;
let mut signature_count_buf = [0u8; 8];
LittleEndian::write_u64(&mut signature_count_buf[..], bank.signature_count());

Ok(TransactionProof{
proof,
parent_hash,
accounts_delta_hash,
signature_count_buf,
})
}
```

Below is client pseudocode for verifying a transaction:

```rust
let tx_sig = "..."; // tx signature of interest
let slot = 19; // slot which includes the tx

// call the new RPC
let tx_proof: TransactionProof = get_tx_proof(&tx_sig, endpoint);

// verify the transaction signature proof is valid and status is success
let leaf = hash_leaf!([tx_sig, TxStatus::Success]);
let verified = tx_proof.proof.verify_path(&leaf);
assert!(verified);

// compute the blockhash
let last_blockhash = tx_proof.proof.get_root();

// compute the expected bankhash
let bankhash = hashv(&[
tx_proof.parent_hash.as_ref(),
tx_proof.accounts_delta_hash.as_ref(),
tx_proof.signature_count_buf.as_ref(),
last_blockhash.as_ref()
]);

// parse vote transactions and stake amounts on expected bankhash
let (voted_stake_amount, total_stake_amount) = parse_votes_from_blocks(slot, bankhash)

// validate supermajority voted for expected bankhash
let supermajority_verified = 3 * voted_stake_amount >= 2 * total_stake_amount;
assert!(supermajority_verified)
```

## Impact

This proposal will improve the overall security and decentralization of the Solana network allowing users to access the blockchain in a trust minimized way unlike traditionally where users had to fully trust their RPC providers. Dapp developers don't have to make any changes as wallets can easily integrate the client making it compatible with any dapp.

## Security Considerations

### Trust Assumptions and Future Work

While this SIMD greatly reduces the user's trust in an RPC, the light client will still need to make certain trust assumptions. This includes finding a trusted source for the validator set per epoch (including their pubkeys and stake weights) and trusting that all transactions are valid (in case the supermajority is corrupt). We plan to solve these problems in future SIMDs to provide a full trustless setup including data availability sampling and fraud proving which will only require a single honest full node.
Loading