Filecoin - winningPoSt 逻辑介绍

[复制链接]
12755 |0
发表于 2020-5-11 18:00:33 | 显示全部楼层 |阅读模式

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(ctxcontext.Context,addraddress.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,跨越了不少接口:

Filecoin - winningPoSt 逻辑介绍

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

01 抽查个数设置

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

pubconstWINNING_POST_CHALLENGE_COUNT:usize=66;
pubconstWINNING_POST_SECTOR_COUNT:usize=1;

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

02Sector 的抽查逻辑

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

letmuthasher=Sha256::new();
hasher.input(AsRef::<[u8]>::as_ref(&prover;_id));
hasher.input(AsRef::<[u8]>::as_ref(&randomness;));
hasher.input(&n.to;_le_bytes()[..]);

lethash=hasher.result();

letsector_challenge=LittleEndian::read_u64(&hash.as;_ref()[..8]);
letsector_index=sector_challenge%sector_set_len;

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

03Challenge 的叶子抽查逻辑

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

letmuthasher=Sha256::new();
hasher.input(AsRef::<[u8]>::as_ref(&randomness;));
hasher.input(&sector;_id.to_le_bytes()[..]);
hasher.input(&leaf;_challenge_index.to_le_bytes()[..]);
lethash=hasher.result();

letleaf_challenge=LittleEndian::read_u64(&hash.as;_ref()[..8]);

letchallenged_range_index=leaf_challenge%(pub_params.sector_size/NODE_SIZEasu64);

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

04 零知识证明电路

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

Filecoin - PoREP 电路介绍

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

//1.Verifycomm_r
letcomm_r_last_num=num::AllocatedNum::alloc(cs.namespace(||"comm_r_last"),||{
comm_r_last
.map(Into::into)
.ok_or_else(||SynthesisError::AssignmentMissing)
})?;

letcomm_c_num=num::AllocatedNum::alloc(cs.namespace(||"comm_c"),||{
comm_c
.map(Into::into)
.ok_or_else(||SynthesisError::AssignmentMissing)
})?;

letcomm_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.VerifyH(Comm_C||comm_r_last)==comm_r
{
lethash_num=::Function::hash2_circuit(
cs.namespace(||"H_comm_c_comm_r_last"),
&comm;_c_num,
&comm;_r_last_num,
)?;

//Checkactualequality
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.VerifyInclusionPaths
for(i,(leaf,path))inleafs.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,
)?;
}

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

总结:

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

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

热门版块
快速回复 返回顶部 返回列表