lotus - 深入理解時空證明的 golang 實現部分(PoSt)

lotus - 深入理解時空證明的 golang 實現部分(PoSt)

參考文章:https://www.chainnews.com/articles/836343087401.htm

lotus 的時空證明(PoSt)在兩個地方會被調用該算法:Winning PoSt 和 Window PoSt。

Winning PoSt 是礦工在出塊時對已經提交的扇區進行證明,證明扇區保存的數據依然存在。

Window PoSt 是礦工在對應的週期內對已經提交的扇區進行證明,證明扇區保存的數據依然存在。

// Balance of Miner Actor should be greater than or equal to
// the sum of PreCommitDeposits and LockedFunds.
// Excess balance as computed by st.GetAvailableBalance will be
// withdrawable or usable for pre-commit deposit or pledge lock-up.
type State struct {
	// Information not related to sectors.
	// TODO: this should be a cid of the miner Info struct so it's not re-written when other fields change.
	Info MinerInfo

	PreCommitDeposits abi.TokenAmount // Total funds locked as PreCommitDeposits
	LockedFunds       abi.TokenAmount // Total unvested funds locked as pledge collateral
	VestingFunds      cid.Cid         // Array, AMT[ChainEpoch]TokenAmount

	// Sectors that have been pre-committed but not yet proven.
	PreCommittedSectors cid.Cid // Map, HAMT[SectorNumber]SectorPreCommitOnChainInfo

	// Information for all proven and not-yet-expired sectors.
	Sectors cid.Cid // Array, AMT[SectorNumber]SectorOnChainInfo (sparse)

	// The first epoch in this miner's current proving period. This is the first epoch in which a PoSt for a
	// partition at the miner's first deadline may arrive. Alternatively, it is after the last epoch at which
	// a PoSt for the previous window is valid.
	// Always greater than zero, his may be greater than the current epoch for genesis miners in the first
	// WPoStProvingPeriod epochs of the chain; the epochs before the first proving period starts are exempt from Window
	// PoSt requirements.
	// Updated at the end of every period by a power actor cron event.
	ProvingPeriodStart abi.ChainEpoch

	// Sector numbers prove-committed since period start, to be added to Deadlines at next proving period boundary.
	NewSectors *abi.BitField

	// Sector numbers indexed by expiry epoch (which are on proving period boundaries).
	// Invariant: Keys(Sectors) == union(SectorExpirations.Values())
	SectorExpirations cid.Cid // Array, AMT[ChainEpoch]Bitfield

	// The sector numbers due for PoSt at each deadline in the current proving period, frozen at period start.
	// New sectors are added and expired ones removed at proving period boundary.
	// Faults are not subtracted from this in state, but on the fly.
	Deadlines cid.Cid

	// All currently known faulty sectors, mutated eagerly.
	// These sectors are exempt from inclusion in PoSt.
	Faults *abi.BitField

	// Faulty sector numbers indexed by the start epoch of the proving period in which detected.
	// Used to track fault durations for eventual sector termination.
	// At most 14 entries, b/c sectors faulty longer expire.
	// Invariant: Faults == union(FaultEpochs.Values())
	FaultEpochs cid.Cid // AMT[ChainEpoch]Bitfield

	// Faulty sectors that will recover when next included in a valid PoSt.
	// Invariant: Recoveries ⊆ Faults.
	Recoveries *abi.BitField

	// Records successful PoSt submission in the current proving period by partition number.
	// The presence of a partition number indicates on-time PoSt received.
	PostSubmissions *abi.BitField

	// The index of the next deadline for which faults should been detected and processed (after it's closed).
	// The proving period cron handler will always reset this to 0, for the subsequent period.
	// Eager fault detection processing on fault/recovery declarations or PoSt may set a smaller number,
	// indicating partial progress, from which subsequent processing should continue.
	// In the range [0, WPoStProvingPeriodDeadlines).
	NextDeadlineToProcessFaults uint64
}

礦工的狀態中,儲存了礦工信息,對應的抵押信息以及扇區的各種狀態。

Info:礦工信息。

PreCommitDeposits:預承諾時抵押數量。

LockedFunds:鎖定抵押數量。

VestingFunds:可兌換數量。

PreCommittedSectors:預承諾區塊,但是還沒有證明。

Sectors:已經證明的並且沒有過期的扇區信息。

ProvingPeriodStart:每個證明週期是起始區塊高度。

NewSectors:新質押的扇區信息。

SectorExpirations:過期扇區信息。

Deadlines:保存證明週期內所有需要提交證明的扇區。

Faults:所以已經失敗的扇區信息。

FaultEpochs:當前證明週期失敗的扇區信息。

Recoveries:失敗扇區中恢復的扇區信息。

PostSubmissions:當前證明週期所有可以正確提交時空證明的扇區。

NextDeadlineToProcessFaults:對錯誤扇區進行恢復時對應的挑戰區間。

// The period over which all a miner's active sectors will be challenged.
const WPoStProvingPeriod = abi.ChainEpoch(builtin.EpochsInDay) // 24 hours

// The duration of a deadline's challenge window, the period before a deadline when the challenge is available.
const WPoStChallengeWindow = abi.ChainEpoch(3600 / builtin.EpochDurationSeconds) // An hour (=24 per day)

// The number of non-overlapping PoSt deadlines in each proving period.
const WPoStPeriodDeadlines = uint64(WPoStProvingPeriod / WPoStChallengeWindow)

WPoStProvingPeriod:證明週期,每天需要證明一次,即 3456 個區塊爲一個週期。

WPoStChallengeWindow:挑戰窗口,每144個區塊爲一個挑戰週期。這裏需要挑戰的扇區個數由對應的扇區大小決定,如32GiB扇區大小對應每個挑戰窗口需要證明2349個扇區。

WPoStPeriodDeadlines:挑戰窗口數量,一個證明週期有24個挑戰。

注意:這裏的參數並不一定是上主網對應的配置。

// Deadline calculations with respect to a current epoch.
// "Deadline" refers to the window during which proofs may be submitted.
// Windows are non-overlapping ranges [Open, Close), but the challenge epoch for a window occurs before
// the window opens.
// The current epoch may not necessarily lie within the deadline or proving period represented here.
type DeadlineInfo struct {
	CurrentEpoch abi.ChainEpoch // Epoch at which this info was calculated.  
	PeriodStart  abi.ChainEpoch // First epoch of the proving period (<= CurrentEpoch). 
	Index        uint64         // A deadline index, in [0..WPoStProvingPeriodDeadlines) unless period elapsed. 
	Open         abi.ChainEpoch // First epoch from which a proof may be submitted, inclusive (>= CurrentEpoch). 
	Close        abi.ChainEpoch // First epoch from which a proof may no longer be submitted, exclusive (>= Open). 
	Challenge    abi.ChainEpoch // Epoch at which to sample the chain for challenge (< Open). 
	FaultCutoff  abi.ChainEpoch // First epoch at which a fault declaration is rejected (< Open). 
}

CurrentEpoch:當前區塊高度。

PeriodStart:當前證明週期起始高度,和ProvingPeriodStart一樣。

Index:挑戰窗口下標。

Open:當前挑戰窗口可以提交扇區證明的起始高度。

Close:當前挑戰窗口可以提交扇區證明的截至高度。

Challenge:作爲挑戰隨機數生成的參數。

FaultCutoff:只有在這個區塊時間之前,才能申明錯誤區塊。

// Calculates the deadline at some epoch for a proving period and returns the deadline-related calculations.
func ComputeProvingPeriodDeadline(periodStart, currEpoch abi.ChainEpoch) *DeadlineInfo {
	periodProgress := currEpoch - periodStart
	if periodProgress >= WPoStProvingPeriod {
		// Proving period has completely elapsed.
		return NewDeadlineInfo(periodStart, WPoStPeriodDeadlines, currEpoch)
	}
	deadlineIdx := uint64(periodProgress / WPoStChallengeWindow)
	if periodProgress < 0 { // Period not yet started.
		deadlineIdx = 0
	}
	return NewDeadlineInfo(periodStart, deadlineIdx, currEpoch)
}

ComputeProvingPeriodDeadline 函數在給定證明週期起始高度和當前區塊高度的情況下計算對應的挑戰窗口的 deadlineInfo 信息。

WindowPoSt 的狀態變化邏輯包括兩部分:每次證明週期起始時間的調整和需要證明的扇區的信息的更新。

offset, err := assignProvingPeriodOffset(rt.Message().Receiver(), currEpoch, rt.Syscalls().HashBlake2b)
periodStart := nextProvingPeriodStart(currEpoch, offset)

assignProvingPeriodOffset 函數隨機生成挑戰窗口數量之間的偏移值。

nextProvingPeriodStart 函數根據當前高度和偏移值找出下一個證明的起始區塊高度。

// Invoked at the end of each proving period, at the end of the epoch before the next one starts.
func handleProvingPeriod(rt Runtime) {
    ...
}

在確定了下一個證明的起始時間後,miner 智能合約都會在當前證明週期結束後會檢查當前證明的狀態並更新對應的下一個證明週期起始時間。

NewSectors是添加的新質押的扇區信息的集合,這裏有三個函數對應相應的操作。

func (a Actor) ProveCommitSector(rt Runtime, params *ProveCommitSectorParams) *adt.EmptyValue {
    ...
}

ProveCommitSector 函數會在提交複製證明時同時將該扇區添加到 NewSectors 結構中。

func (a Actor) TerminateSectors(rt Runtime, params *TerminateSectorsParams) *adt.EmptyValue {
    ...
}

TerminateSectors 會從 NewSectors 結構中刪除扇區信息。

// Invoked at the end of each proving period, at the end of the epoch before the next one starts.
func handleProvingPeriod(rt Runtime) {
    ...
    err = AssignNewSectors(deadlines, st.Info.WindowPoStPartitionSectors, newSectors, assignmentSeed)
    ...
}

handleProvingPeriod 函數會週期性的將 NewSectors 中的扇區分配到不同的挑戰窗口(deadline)中。

AssignNewSectors 函數將 WindowPoStPartitionSectors 個扇區分配到不同的挑戰窗口(deadline)中。

這裏的 WindowPoStPartitionSectors 根據 WindowPoStPartitionSectors 函數獲取,即 32GiB 大小的扇區,沒有挑戰窗口需要挑戰 2349 個扇區。

// Returns the partition size, in sectors, associated with a proof type.
// The partition size is the number of sectors proven in a single PoSt proof.
func (p RegisteredProof) WindowPoStPartitionSectors() (uint64, error) {
	// Resolve to seal proof and then compute size from that.
	sp, err := p.RegisteredSealProof()
	if err != nil {
		return 0, err
	}
	// These numbers must match those used by the proofs library.
	// See https://github.com/filecoin-project/rust-fil-proofs/blob/master/filecoin-proofs/src/constants.rs#L85
	switch sp {
	case RegisteredProof_StackedDRG64GiBSeal:
		return 2300, nil
	case RegisteredProof_StackedDRG32GiBSeal:
		return 2349, nil
	case RegisteredProof_StackedDRG2KiBSeal:
		return 2, nil
	case RegisteredProof_StackedDRG8MiBSeal:
		return 2, nil
	case RegisteredProof_StackedDRG512MiBSeal:
		return 2, nil
	default:
		return 0, errors.Errorf("unsupported proof type: %v", p)
	}
}

WindowPoSt 證明的調度主要在 github.com\filecoin-project\lotus\storage\wdpost_sched.go 和 github.com\filecoin-project\lotus\storage\wdpost_run.go 文件中。

在這裏插入圖片描述

type WindowPoStScheduler struct {
	api              storageMinerApi
	prover           storage.Prover
	faultTracker     sectorstorage.FaultTracker
	proofType        abi.RegisteredProof
	partitionSectors uint64

	actor  address.Address
	worker address.Address

	cur *types.TipSet

	// if a post is in progress, this indicates for which ElectionPeriodStart
	activeDeadline *miner.DeadlineInfo
	abort          context.CancelFunc

	//failed abi.ChainEpoch // eps
	//failLk sync.Mutex
}

WindowPoStScheduler 會監聽鏈上的狀態,在接受新的高度時都會嘗試去調用 doPost 函數,doPost 函數包括兩部分,一個是 runPost 函數,主要是計算需要的時空證明信息,一個是 submitPost 函數,就是將生成的證明提交到鏈上。

鏈上會記錄在一個證明週期內所有提交的證明信息,在每個證明週期結束前 handleProvingPeriod 函數會統一檢查所有證明情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章