Solana light client

1. 引言

Solana已接收提案——Simple Payment and State Verification 中指出:
资源有限的客户端可运行light client来参与Solana网络,可在无需信任第三方的情况下,确认其提交的交易已提交到账本。

Solana中的Validators会将最近确认交易的签名在本地存储一段时间,已确保这些交易不会被重复处理。

客户端可:

  • 通过Validator提供的JSON RPC端口来查询其提交的交易是否已被处理。
  • 通过注册监听Validator提供的PubSub通知,可获知某签名是否已被Validator注意到。

以上两种方式,客户端都可验证一笔支付,但是,这不是a proof,需完全信任某单一Validator。

为了进一步减少客户端对某单一Validator的信任,可改为:

  • 使用Merkle Proofs来锚定 该Validator在账本中的response,允许客户端通过验证 其选择的足够多数量的Validators是否已确认该交易。通过多个Validators的attestations可进一步减少对某单一Validator的信任。

2. Solana的light client

light client:是指不运行validator的参与者。
light client 可在无需增加资源投入的情况下验证账本,其提供的安全性要高于信任某一远程Validator。

Validator并不会将交易签名提交给light client,而是生成:

  • a Merkle Proof from the transaction of interest to the root of a Merkle Tree of all transactions in the including block。

该Merkle Root存在ledger entry中,并经由Validators投票来提供共识合法性。

light client的安全性还取决于其初始收录的validators set。随着网络中Validators变化,light client也需要使用receipts来更新其内部的validators set。

考虑到性能,Validators本身可能也会想用light client API。如,在初始启动a validator的过程中,该validator可使用a receipt来验证一个由cluster提供的checkpoint of the state。

3. Receipts

A receipt为a minimal proof,用于证明:

  • 1)某一交易被包含在某一区块——Transaction Inclusion Proof;
  • 2)该区块已经由light client所选择的validators set 投票——;
  • 3)投票达到了要求的确认深度(desired confirmation depth)——Chain of Entries。

3.1 Transaction Inclusion Proof

Transaction Inclusion Proof为一种数据结构,包含了:

  • 某笔交易经由Entry-Merkle到达Block-Merkle的Merkle Path。

Block-Merkle会与the required set of validator votes一起,被包含在a Bank-Hash中。
包含后续validator投票的PoH entry chain(源自Bank-Hash)即为proof of confirmation。

3.1.1 Transaction Merkle

An Entry-Merkle即为a Merkle Root,包含了某个entry中的所有交易,按签名排序。

entry中的每笔交易均通过如下方式被merkled:【由此可证明某交易T被包含在某entryE中。】

poh.record(hash_transactions(transactions)).unwrap().hash
pub fn hash_transactions(transactions: &[VersionedTransaction]) -> Hash {
    // a hash of a slice of transactions only needs to hash the signatures
    let signatures: Vec<_> = transactions
        .iter()
        .flat_map(|tx| tx.signatures.iter())
        .collect();
    let merkle_tree = MerkleTree::new(&signatures);
    if let Some(root_hash) = merkle_tree.get_root() {
        *root_hash
    } else {
        Hash::default()
    }
}

pub struct VersionedTransaction {
    /// List of signatures
    #[serde(with = "short_vec")]
    pub signatures: Vec<Signature>,
    /// Message to sign.
    pub message: VersionedMessage,
}
pub enum VersionedMessage {
    Legacy(Message),
    V0(v0::Message),
}

A Block-Merkle为the Merkle Root of all the Entry-Merkles sequenced in the block。

在这里插入图片描述

将以上2个merkle proof一起,即可证明a transaction T被包含在bank hash为B的某block中。

Accounts-Hash为the hash of th econcatentation of the state hashes of each account modified during the current slot,即:

A

c

c

o

u

n

t

s

H

a

s

h

=

H

a

s

h

(

H

a

s

h

(

a

c

c

o

u

n

t

1

s

t

a

t

e

)

H

a

s

h

(

a

c

c

o

u

n

t

2

s

t

a

t

e

)

.

.

.

H

a

s

h

(

a

c

c

o

u

n

t

n

s

t

a

t

e

)

)

AccountsHash=Hash(Hash(account1_{state})||Hash(account2_{state})||...||Hash(accountn_{state})|)

AccountsHash=Hash(Hash(account1state)Hash(account2state)...Hash(accountnstate))

receipt需要transaction status,因为需要为block构建state receipt。同一区块中可能有具有相同state的2笔交易,仅根据state无法区分一笔交易是否提交成功。尽管可能没必要encode the full status code,但是需要一个status bit来标记交易是否成功。

当前Solana中并未实现Block-Merkle,因此,为了验证entry E在 bank hash为B 的block中,需提供该block中的所有entry hashes。这样的实现效率很低,未来Solana应该会实现Block-Merkele。

3.1.2 Block Headers

为了验证Transaction inclusion proofs,light client应能推断出网络中的拓扑结构。

light client应能跟踪新生成的block headers,如新来的2个bank hash为A,B的区块,light client应能判断出AB的ancestor(具体见下面提到的 Optimistic Confirmation Proof)。header中的内容将用于计算bank hash。

Bank-Hash=Hash(Accounts-Hash || Block-Merkle)

在这里插入图片描述
具体代码实现为

		let mut hash = hashv(&[
            self.parent_hash.as_ref(),
            accounts_delta_hash.hash.as_ref(),
            &signature_count_buf,
            self.last_blockhash().as_ref(),
        ]);

可跟现有的Validator replay logic中的streaming logic来实现该逻辑

			if let Some(sender) = bank_notification_sender {
                sender
                    .send(BankNotification::Root(root_bank))
                    .unwrap_or_else(|err| warn!("bank_notification_sender failed: {:?}", err));
            }

3.1.3 Optimistic Confirmation Proof

当前可通过a listener that monitors gossip and the replay pipeline for votes来获得optimistic confirmation信息,具体为

				if is_confirmed {
                    new_optimistic_confirmed_slots.push((*slot, last_vote_hash));
                    // Notify subscribers about new optimistic confirmation
                    if let Some(sender) = bank_notification_sender {
                        sender
                            .send(BankNotification::OptimisticallyConfirmed(*slot))
                            .unwrap_or_else(|err| {
                                warn!("bank_notification_sender failed: {:?}", err)
                            });
                    }
                }

对bank hash为B的区块的每一个投票都是a signed transaction。一旦投票数达到了某阈值T,即可认为该区块是optimistially confirmed。参与投票的这T个validators需要show that the block with bank hash B was optimistically confirmed。

但是,当前signed votes本身并不存储,未来可能需要维护在Rocksdb数据库中,以key (Slot, Hash, Pubkey)索引,来表示the slot of the vote, bank hash of the vote 以及 vote account pubkey responsible for the vote。

可扩展现有的signature subscription logic,将transaction merkle proof和optimistic confirmation proof通过RPC提供给订阅者。
当探测到optimistic confirmation,即会通知订阅者“Confirmed” confirmation。同时,需要提供一个flag来标记应返回transaction merkle proof和optimistic confirmation proof。

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'.

3.1.4 Proof of Stake Distributioin

当收到transaction merkle proof 和optimistic confirmation proof时,客户端需验证交易T确实optimistially confirmed在bank hash为B的block中。
最后,需要验证,在optimistic proof中的投票确实超过了T%的质押,以保证“optimistic confirmation”的安全性。

对于每个epoch,当stake set变化时,将所有的stakes写到a system account,然后validators可订阅该system account。然后全节点提供a merkle proving that the system account state was updated in some block B,再show that the block B was optimistically confirmed/rooted。

3.2 Account State Verification

可通过向cluster提交包含某TBD指令的交易来验证某account的state(如balance或其它数据)。然后client可使用Transaction Inclusion Proof来验证该cluster是否同意 that the account has reached the expected state。

3.3 Validator Votes

Leaders可将股权与权重合并到一个entry中。这将减少创建receipt所需的entry数量。

3.4 Chain of Entries

A receipt has a PoH link from the payment or state Merkle Path root to a list of consecutive validation votes.

receipt中包含:

  • Transaction -> Entry-Merkle -> Block-Merkle -> Bank-Hash

receipt中还包含一组PoH entries:

  • Validator vote entries
  • Ticks
  • Light entries
/// 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 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.

3.5 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 Block-Merkle is the Merkle Root and will appear in votes included in an Entry. The light client can simulate fork selection for the consecutive votes and verify that the receipt is confirmed at the desired lockout threshold.

3.6 Synthetic State

Synthetic state should be computed into the Bank-Hash 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-Hash. They should live under known accounts, and therefore have an index into the hash concatenation.

参考资料

[1] Solana已接收提案——Simple Payment and State Verification
[2] 用于Solana-Ethereum的zk-bridge方案——=nil; Foundation’s In-EVM Solana Light-Client State Verification

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇

)">
下一篇>>