處理與 Safrole 協議相關的狀態更新。Safrole 負責驗證者的選擇、輪換和 Ticket 管理
目的是根據最新的 slot、entropy、offenders 以及 extrinsics 中提交的 tickets 來更新 Safrole 狀態。最終返回更新後的 SafrolePostState,並根據不同條件可能附帶返回 epochMark 以及 ticketsMark
-
初始化與驗證: 讀取配置、計算當前與新 epoch/phase,並驗證 slot 以及 extrinsics 的合法性。
-
VRF: 建立 RingContext、Commitment 與 Verifier,並根據是否發生 epoch 變更更新驗證者集合與 ticketsVerifier。
-
update entropy: 根據新的 entropy 更新熵池,新熵池的更新邏輯根據是否發生 epoch 變更而不同。
-
決定更新形式(ticketsOrKeys): 根據新舊 epoch 與 phase 的狀態,決定更新後的 ticketsOrKeys 型態。
-
生成 Epoch Mark 與 Tickets Mark:
-
處理 extrinsics 中的新 ticket 並更新 accumulator: 確保新票據已排序且唯一,然後合併進票據 accumulator,並在必要時修剪超出的部分。
-
組合新的 SafrolePostState: 把所有更新後的部分組合成新的 state 並返回,附帶必要的 epochMark 與 ticketsMark。
state change:
public mutating func mergeWith(postState: SafrolePostState) {
safroleState.nextValidators = postState.nextValidators
safroleState.ticketsVerifier = postState.ticketsVerifier
safroleState.ticketsOrKeys = postState.ticketsOrKeys
safroleState.ticketsAccumulator = postState.ticketsAccumulator
entropyPool = postState.entropyPool
validatorQueue = postState.validatorQueue
currentValidators = postState.currentValidators
previousValidators = postState.previousValidators
timeslot = postState.timeslot
}
-
初始化與 Epoch 計算 從 config 中取得 epochLength,根據當前 timeslot 計算 currentEpoch 與 lastEpoch(currentEpoch 為 0 時,lastEpoch 為 nil)。
-
處理每個 verdict
-
更新 punishSet 與收集 offenders 建立 validSigners 為 currentValidators 與 previousValidators 的 ed25519 聯集,排除已在 judgements.punishSet 中的。 將 validatorKey 插入 newJudgements.punishSet,同時加入 offenders 陣列。
-
檢查 report hash 的唯一性 建立 allReports 為 disputes.verdicts 的 reportHash 與 judgements.goodSet、banSet、wonkySet 的聯集。 檢查 allReports 的數量是否與預期(各集合的 count 之和)一致,否則拋出 duplicatedReport。
-
統計 votes 與根據票數分類報告
-
核查 culprits 與 banSet 的一致性 遍歷 disputes.culprits,確保每個 culprit.reportHash 都存在於 newJudgements.banSet 中,否則拋出 invalidCulprit。
-
移除報告 遍歷 newReports,對於每筆包含 workReport 的報告,如果其 hash 存在於 tobeRemoved 中,則將該報告設為 nil。
-
返回更新後的 state 與 offenders 使用更新後的 newJudgements 與 newReports 建構 DisputesPostState,並返回該 state 以及 offenders 陣列。
state change:
public mutating func mergeWith(postState: DisputesPostState) {
judgements = postState.judgements
reports = postState.reports
}
分開處理 availability 與 reports 的 extrinsics
-
清除過期 Reports 遍歷 reports(複製為 newReports),若 report 的 timeslot 加上 preimageReplacementPeriod 小於或等於當前 timeslot,就設為 nil。
-
Assurances 驗證 對 extrinsic.assurances 進行驗證(parentHash 與 signature 檢查)。
-
累計每個 Core 的票數 根據 assurances 的布林值統計每個 core 的票數,存入 availabilityCount 陣列。
-
產生 Available Reports 對每個 core,若票數達到 TwoThirdValidatorsPlusOne 閾值,從 reports 中取出對應的 workReport,並將 newReports 中該位置設為 nil。
State 變更: availableReports 陣列被建立;newReports 中滿足條件的 report 被移除(設為 nil)。
- 返回更新結果 返回更新後的 newReports(保留未達標的 report)和 availableReports(已達標的 workReport)。
state change:
availableReports
-
Core Assignment 與 Key 準備
-
逐筆處理 extrinsic.guarantees
-
Duplicate WorkPackage 檢查
-
refinementContext 驗證
-
更新 Reports 與輸出
-
取得 Accumulatable Reports 根據 availableReports 與當前 index(timeslot mod epochLength)呼叫 getAllAccumulatableReports,取得 accumulatableReports 與 newQueueItems。
-
執行 Accumulation 建立 initialAccState(包含 accounts、validatorQueue、authorizationQueue、privilegedServices)。 呼叫 execution(...) 執行 accumulation,獲得 accumulateOutput(包含更新後的 validatorQueue、authorizationQueue、privilegedServices、transfers、commitments 及 gasUsed)。
-
處理 Transfers 分組 accumulateOutput.transfers 依 ServiceIndex,對每組呼叫 onTransfer(...) 計算 gasUsed,組成 transfersStats。
-
更新 Accounts State 將 accountsMutRef.value 賦值回 self,更新內部 service accounts state(同時影響 validatorQueue、authorizationQueue、privilegedServices)。
-
更新 Accumulation History 從 accumulatableReports 中取出 accumulated reports(根據 accumulateOutput.numAccumulated),構成 newHistoryItem。 將 accumulationHistory 按 epochLength 做更新:新 history item 放到最後一個位置,其餘 history 向前移位。
-
更新 Accumulation Queue
-
計算 Accumulation Root 與 Statistics 將 accumulateOutput.commitments 排序後,依據編碼結果進行 binary Merklization,產生 accumulation root。 根據 accumulateOutput.gasUsed 與 accumulated reports 統計各 service 的 gas 使用量與報告數,形成 accumulateStats。
let authorizationResult = try newState.update(
config: config,
timeslot: block.header.timeslot,
auths: block.extrinsic.reports.guarantees.map { ($0.workReport.coreIndex, $0.workReport.authorizerHash) }
)
這個 function 主要是用來更新 authorization 的狀態(AuthorizationPostState)
state change:
public mutating func mergeWith(postState: AuthorizationPostState) {
coreAuthorizationPool = postState.coreAuthorizationPool
}
}
這個 function 主要的功能是處理 ExtrinsicPreimages,並根據檢查結果建立一組 PreimageUpdate,最終返回一個 PreimagesPostState。
-
檢查排序與唯一性 從輸入的 ExtrinsicPreimages 中取出 preimages,並驗證它們是否已排序且唯一;若不符合,則拋出 preimagesNotSorted 錯誤。
-
逐筆處理每個 preimage
-
對每個 preimage:
-
計算 hash(使用 blake2b256hash())。
-
使用 get(...) 檢查先前狀態中是否已存在相同 preimage;若存在,拋出 duplicatedPreimage 錯誤。
-
再次呼叫 get(...) 驗證該 preimage 是否已被請求(isRequested 為非 nil),否則拋出 preimageNotUsed 錯誤。
-
如果檢查通過,則建立一個 PreimageUpdate(包含 serviceIndex、hash、data、length 及 timeslot)並加入更新列表。
-
state change:
public mutating func mergeWith(postState: PreimagesPostState) {
for update in postState.updates {
self[serviceAccount: update.serviceIndex, preimageHash: update.hash] = update.data
self[serviceAccount: update.serviceIndex, preimageHash: update.hash, length: update.length] =
LimitedSizeArray([update.timeslot])
}
}