Filecoin – winningPoSt逻辑介绍

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

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)

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;

2. Sector的抽查逻辑

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

let mut hasher = Sha256::new();

hasher.input(AsRef::::as_ref(&prover_id));

hasher.input(AsRef::::as_ref(&randomness));

hasher.input(&n.to_le_bytes()[..]);

let hash = hasher.result();

let sector_index = sector_challenge % sector_set_len;

3. Challenge的叶子抽查逻辑

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

let mut hasher = Sha256::new();

hasher.input(AsRef::::as_ref(&randomness));

hasher.input(&sector_id.to_le_bytes()[..]);

hasher.input(&leaf_challenge_index.to_le_bytes()[..]);

let hash = hasher.result();

let challenged_range_index = leaf_challenge % (pub_params.sector_size / NODE_SIZE as u64);

4. 零知识证明电路

Filecoin – PoREP电路介绍

// 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 = ::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,

);

}

// 2. Verify Inclusion Paths

for (i, (leaf, path)) in leafs.iter().zip(paths.iter()).enumerate() {

PoRCircuit::::synthesize(

cs.namespace(|| format!(“challenge_inclusion_{}”, i)),

Root::Val(*leaf),

path.clone(),

Root::from_allocated::(comm_r_last_num.clone()),

true,

)?;

}

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