Filecoin - winningPoSt逻辑介绍 区块链

信息发布员 5月前 125

来源: 星想法 作者:Star Li

Lotus的PoSt的部分从electionPoSt变成两种新的PoSt,一种是winningPoSt,一种是windowPoSt。先讲讲winningPoSt吧。winningPoSt,顾名思义,在winning的时候进行的PoSt。所谓的......

Lotus的PoSt的部分从electionPoSt变成两种新的PoSt,一种是winningPoSt,一种是windowPoSt。先讲讲winningPoSt吧。winningPoSt,顾名思义,在winning的时候进行的PoSt。所谓的winning,也就是获取出块权。

简单的说,winningPoSt,随机抽查的一个sector,该sector中的66条随机抽查的merkle path都正确。代码逻辑从Lotus的go的代码说起。一切从出块开始 - lotus/miner/miner.go的Miner结构的mineOne函数。

func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningBase) (*types.BlockMsg, error) {
   mbi, err := m.api.MinerGetBaseInfo(ctx, addr, round, base.TipSet.Key())
     rand, err := m.api.ChainGetRandomness(ctx, base.TipSet.Key(), crypto.DomainSeparationTag_WinningPoStChallengeSeed, base.TipSet.Height()+base.NullRounds, nil)
     prand := abi.PoStRandomness(rand)
     postProof, err := m.epp.ComputeProof(ctx, mbi.Sectors, prand)

其中,MinerGetBaseInfo函数是获取一些基本信息,其中包括需要抽取的sector信息。ComputeProof函数就是计算winningPoSt证明。

因为这些逻辑的具体实现是在rust-fil-proofs,也就是rust语言实现的。从go到rust-fil-proofs,跨越了不少接口:

中间的接口就不介绍了,直接看rust-fil-proofs提供的两个API函数。

1. 抽查个数设置

Sector个数以及总的抽查的叶子个数的定义在rust-fil-proofs/filecoin-proofs/src/constants.rs中:

 

pub const WINNING_POST_CHALLENGE_COUNT: usize = 66;
 pub const WINNING_POST_SECTOR_COUNT: usize = 1;

也就是说,要从有效Sector中抽取一个Sector,并在这个Sector上抽查66个叶子节点。

2. Sector的抽查逻辑

generate_winning_post_sector_challenge函数实现了Sector的抽查逻辑。核心逻辑显然是如何抽查Sector?具体的逻辑在fallback::generate_sector_challenges的函数中:

let mut hasher = Sha256::new();
hasher.input(AsRef::<[u8]>::as_ref(&prover_id));
hasher.input(AsRef::<[u8]>::as_ref(&randomness));
hasher.input(&n.to_le_bytes()[..]);
let hash = hasher.result();
let sector_challenge = LittleEndian::read_u64(&hash.as_ref()[..8]);
let sector_index = sector_challenge % sector_set_len;

简单的说,就是把prover_id, 随机信息,抽查Sector的编号做sha256的hash计算,计算结果和当前有限的Sector个数取模。也就是sector_index就是最终抽查的Sector的id。

3. Challenge的叶子抽查逻辑

generate_winning_post在抽查的Sector形成的merkle树(replica_r_last)上,抽查叶子节点。抽查叶子节点的计算逻辑在fallback::generate_leaf_challenge的函数中:

let mut hasher = Sha256::new();
hasher.input(AsRef::<[u8]>::as_ref(&randomness));
hasher.input(&sector_id.to_le_bytes()[..]);
hasher.input(&leaf_challenge_index.to_le_bytes()[..]);
let hash = hasher.result();
let leaf_challenge = LittleEndian::read_u64(&hash.as_ref()[..8]);
let challenged_range_index = leaf_challenge % (pub_params.sector_size / NODE_SIZE as u64);

把随机信息,sector id和挑战叶子的编号进行hash计算。计算的结果和叶子的总个数取模。32G的Sector,叶子个数为1G个。

4. 零知识证明电路

零知识证明的计算部分可以查看rust-fil-proofs/post/fallback目录。大体的逻辑模块和结构可以查看之前的文章介绍:

Filecoin - PoREP电路介绍

讲讲rust-fil-proofs/post/fallback/circuit.rs中的Sector结构吧。这个结构就代表一个抽查。从synthesize函数可以看出:

 

// 1. Verify comm_r
        let comm_r_last_num = num::AllocatedNum::alloc(cs.namespace(|| "comm_r_last"), || {
            comm_r_last
                .map(Into::into)
                .ok_or_else(|| SynthesisError::AssignmentMissing)
        })?;
        let comm_c_num = num::AllocatedNum::alloc(cs.namespace(|| "comm_c"), || {
            comm_c
                .map(Into::into)
                .ok_or_else(|| SynthesisError::AssignmentMissing)
        })?;
        let comm_r_num = num::AllocatedNum::alloc(cs.namespace(|| "comm_r"), || {
            comm_r
                .map(Into::into)
                .ok_or_else(|| SynthesisError::AssignmentMissing)
        })?;
        comm_r_num.inputize(cs.namespace(|| "comm_r_input"))?;

comm_r作为public输入,其他comm_r_last和comm_c作为private输入。

// 1. Verify H(Comm_C || comm_r_last) == comm_r
        {
            let hash_num = <Tree::Hasher as Hasher>::Function::hash2_circuit(
                cs.namespace(|| "H_comm_c_comm_r_last"),
                &comm_c_num,
                &comm_r_last_num,
            )?;
            // Check actual equality
            constraint::equal(
                cs,
                || "enforce_comm_c_comm_r_last_hash_comm_r",
                &comm_r_num,
                &hash_num,
            );
        }

验证comm_r是否由comm_c和comm_r_last计算得到。

// 2. Verify Inclusion Paths
for (i, (leaf, path)) in leafs.iter().zip(paths.iter()).enumerate() {
    PoRCircuit::<Tree>::synthesize(
        cs.namespace(|| format!("challenge_inclusion_{}", i)),
        Root::Val(*leaf),
        path.clone(),
        Root::from_allocated::<CS>(comm_r_last_num.clone()),
        true,
    )?;
}

验证从叶子节点是否可以正确计算出Merkle树根。

总结:

Lotus的PoSt包括两部分:winningPoSt和windowPoSt。winningPoSt是在获取出块权时,需要提供的PoSt证明。从所有有效的Sector中,抽取一个Sector,并抽查该Sector上的66个叶子。


少客联盟- 版权声明 1、本主题所有言论和图片纯属会员个人意见,与少客联盟立场无关。
2、本站所有主题由该帖子作者发表,该帖子作者信息发布员少客联盟享有帖子相关版权。
3、少客联盟管理员和版主有权不事先通知发贴者而删除本文。
4、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者信息发布员少客联盟的同意。
5、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任。
6、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责。
7、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意。
8、官方反馈邮箱:chinasuc@chinasuc.cn


上一篇:本体技术视点 | 可以把工作邮箱作为公钥吗?
下一篇:开发区块链之前,你该做哪些设计和准备工作?
人生的价值,并不是用时间,而是用深度去衡量的。
最新回复 (0)
    • 少客联盟
      2
        登录 注册 QQ登录(停用)
返回