FilCoin 学习笔记

FilCoin 学习笔记

Cocytus Elias 103 2023-04-26

FileCoin 是基于区块链与 Web3 实现的一个 IPFS 落地应用规范,主要解决的是大量数据存储所带来的一些问题,它包含了一套共识协议(由时空证明 PoSt +复制证明 PoRep)、一个数据存储平台、一套市场(由存储市场和检索市场组成)。

基于 Filecoin 的规范,社区有多种实现,其中应用较为广泛的是 Lotus (采用 Rust 语言和 Go 语言进行开发)。

可以这样理解,FileCoin 是 IPFS 的区块链规范实现,Lotus 是 FileCoin 其中一种的代码实现。

基础概念

交易市场

⚠️ 根据官方文档描述,Filecoin 规范的第一个版本中,存储交易的达成、订单匹配以及检索交易都将在链下进行,并通过支付渠道来进行小额支付。

存储市场 StorageMarket

即 Storage Market,是指 FileCoin 中提供存储服务的矿工以及对应的存储服务器,主要是将用户数据存储起来并收取一定费用。

存储市场上分为两种角色:

  • 客户(Client):想要存储数据的。
  • 服务提供者(Provider):提供存储服务。

存储市场偏重于存储空间、存储性能、存储稳定性。

存储交易流程

  1. 客户(Client)寻找符合条件的服务提供者(Provider)。
  2. 客户(Client)和 服务提供者(Provider)在链下达成交易共识并提供相应资金(如质押费、服务费等),然后客户将数据传输给服务提供者(Provider)。
  3. 交易上链。
  4. 交易将会密封在一个扇区中,直到交易失效(即数据存储是有时效性的)。

⚠️ 目前 Bony 使用的数据版本还会存在客户(Client)质押,但根据 Lotus 官方代码描述,这个后续是会取消掉。正常应该是客户(Client)付存储费用,服务提供者(Provider)付质押费用。

检索市场 RetrievalMarket

检索市场整体是在链下进行,检索市场是基于存储市场提供的一项检索服务,目的是将在存储市场上存储的数据检索出来。

检索市场上同样是分为两种角色:

  • 客户(Client):想要检索数据的。
  • 服务提供者(Provider):提供检索服务。

虽然存储市场和检索市场都是由 客户(Client)和 服务提供者(Provider)两种角色构成,但是在不同的市场,他们的行为不一样。

检索市场偏重于网络速度,主要是快速检索并传输。

检索交易流程

官方文档中的检索工作原理较多,我对其进行了如下简化:

  1. 客户(Client)寻找符合条件的服务提供者(Provider)。
    • 客户(Client)通过 FindProviders() 找到一个服务提供者(Provider)。
    • 客户(Client)通过查询协议以查看其是否满足其检索条件。
  2. 客户(Client)和 服务提供者(Provider)在链下达成交易共识。
    • 客户(Client)通过 RetrievalDealProposal 作为凭证申请数据拉取。
      • 如果服务提供者(Provider)验证提议无效,则拒绝申请。
      • 如果服务提供者(Provider)验证提议有效,则回应一个接受消息,并开始监视数据传输过程。
  3. 客户(Client)建立支付通道,并确保该通道中有足够的资金(也可以叫代金券),同时服务提供者(Provider)会加入此通道。
  4. 服务提供者(Provider)每传输一部分数据便收一部分钱,循环往复,直到整个数据完全传输完成。
    • 服务提供者(Provider)解封指定扇区。
    • 之后进入如下循环:
      • 服务提供者(Provider)通过协议发送数据块时会监视数据传输,直到需要付款为止。
      • 当服务提供者(Provider)认为已经传输一个自定义的最小单位的数据块时,将暂停数据传输并发送付款请求作为中间凭证。
      • 客户(Client)收到付款请求。
      • 客户(Client)链下创建并存储付款凭证。
      • 客户(Client)通过发送支付交互凭证(中间凭证的指针)来服务提供者(Provider),其中包含了 确认接收到部分数据 及 支付通道值(也可以叫代金券) 等信息。
      • 服务提供者(Provider)验证客户(Client)发送的凭证(主要是代金券)并保存,之后可以在链上兑换使用。
      • 从第一步开始逐步重复。
    • 数据传输结束,检索完成。

Actor

Actor 可以理解为是智能合约,它们之间通过互相发送消息,调用 FVM 执行相应的 Method 来完成一些操作(如:创建 Miner、创建多签账户、转账、发放区块奖励、销毁消息 BaseFee 等)

区块链本质是一种状态管理的规范,区块链的链上数据一般都是状态数据,比如当前时间下 高度是多少、有多少节点、有多少笔转账的等等,区块链本身是为了确保状态的不易篡改和公开型(即分布式)。

据 FileCoin 官方介绍,Actor 是一种管理状态的软件设计模式,所有有状态的东西都可以是 actor,而任何状态的更改也必须由 actor 触发。

FileCoin 总共存在十一个内置系统参与者:

其中两个是 FVM 的组成部分

  • InitActor: 用于创建新的 Actor,主要是存储 Public Address 上链映射成的 ID Address 。地址标识为 1,主网为 f01,测试/校准网为 t01。
  • CronActor:在每个区块高度执行重要操作的调度,它可以调用其他的 Actor 去为维护或处理一些事件。地址标识为 3,主网为 f03,测试/校准网为 t03。

其中两个与 FVM 直接发生交互

  • RewardActor: 用于存储未发放的 Fil 及发放 BlockMinerReward 奖励。此 Actor 拥有一个地址。地址标识为 2,主网为 f02,测试/校准网为 t02。
  • AccountActor:管理用户的账户,不是由 InitActor 创建的。

剩余七个不直接与 FVM 交互,一般是通过指定 Method 来调用它们或直接由系统调用

  • StorageMarketActor:用于管理存储、检索交易。一般是通过 Method 调用。地址标识为 5,主网为 f05,测试/校准网为 t05。
  • StorageMinerActor:用于处理存储挖矿以及收集时空证明。系统自动调用。
  • MultisigActor: 用于处理多签账户相关操作。一般是通过 Method 调用。
  • PaymentChannelActor:用于处理支付通道(上述检索市场中的存储通道)相关操作。一般是通过 Method 调用。
  • StoragePowerActor:用于监控每个存储服务器的存储功率。系统自动调用。地址标识为 4,主网为 f04,测试/校准网为 t04。
  • VerifiedRegistryActor: 负责管理已经确认的客户端。系统自动调用。地址标识为 6,主网为 f06,测试/校准网为 t06。
  • SystemActor:指一般的系统 Actor,比如用于销毁 BaseFee 的 F099 等。调用视情况而定。

Address

FileCoin 的定义中,地址(Address)是用于识别 Actor 的标识符。

在日常使用中,地址(Address)一般对应的是下面三种账户类型,但不论是哪一种账户,它们都存在余额(Balance)和消息随机数(Nonce)这两个状态值 。

Account

普通账户(Account)是较常用的一种账户。一般可以理解为非多签账户(Multisig)及矿工账户(Miner)的都是普通账户(Account),包括一些系统 Actor 也是一样。

Multisig

代表多签账户(Multisig),可以看作是普通账户(Account)的一种特殊使用场景。多签账户(Multisig)全名为多重签名账户,每个签名代表是一个普通账户(Account),多签本质就是多个普通账户(Account)同时管理一个公共的普通账户(Account)。

可以将多签账户(Multisig)视为普通账户(Account),但它们之间的操作方式不同。

多签账户(Multisig)主要是为了解决单账户单私钥的安全问题以及多人协同的资金管理问题。

多签账户(Multisig)有以下几个特点:

  • 多签账户(Multisig)的持有者账户(Signers)可以是另一个多签账户(Multisig)。
  • 多签账户(Multisig)的任何持有者账户(Signers)之间都是平等的。
  • 多签账户(Multisig)可以随意增、删、改它的任何持有者账户(Signers)。
  • 多签账户(Multisig)的任何状态变更(如增删改 Signers 或转账)等都需要达到最小审批数(Threshold)。
  • 多签账户(Multisig)的余额(Balance)和消息随机数(Nonce)是独立于任何持有者账户(Signers)之外的。
  • 多多签账户(Multisig)的余额(Balance)可以在初始化的时候设置,也可以在后期转入。 余额(Balance)可以设置线性释放的高度差,即资金锁定。
  • 单个多签账户(Multisig)的持有者账户(Signers)至少是一个,最多为 256 个。如果需要多于 256 个持有者账户(Signers)的时候,可以使用多个多签账户(Multisig)或多签账户(Multisig)与普通账户(Account)结合的方式再创建一个新的多签账户(Multisig)。

多签账户(Multisig)的审批需要注意以下几点:

  • 多签账户(Multisig)的最小审批数(Threshold)默认为全部持有者账户(Signers)的数量。但是可以进行设置,设置最小审批数(Threshold)同样需要审批。
  • 多签账户(Multisig)的最小审批数(Threshold)为 1 ,最大为全部持有者账户(Signers)的数量。如果多签账户(Multisig)因去除持有者账户(Signers)导致最小审批数(Threshold)大于实际的持有者账户(Signers)的数量,则系统会自动设置为实际全部持有者账户(Signers)的数量。
  • 多签账户(Multisig)的任何审批如果没有通过(即同意数小于 Threshold)时,可以随时撤销审批。只有审批发起账户才可以进行撤销。
  • 多签账户(Multisig)的任何审批发起时都默认有一个同意数(即发起者本身),如果最小审批数(Threshold)为 1,则发起就会通过,很难有撤销的余地。

Miner

代表矿工。

目前仅有存储服务才能获得发放的奖励(Reward),所以服务提供者目前是主流的矿工类型。

检索服务提供者也可以算矿工,但是一方面收益较低,另一方面收益也不稳定,属于少数派。

不过在未来可能会加入一个新的矿工类型 修理矿工(Repair miner),用于解决存储矿工不稳定的问题。

矿工(Miner)这里较为复杂,所以分为以下几个部分。

存储服务提供流程

前置:

  • 矿工(Miner)需要预备至少一台存储服务器(更偏向于内存于磁盘性能的机器),创建节点并加入 Lotus 网络。

  • 加入网络后同步 Chain 的各项数据,并在最新高度上创建自己的钱包地址。

  • 创建钱包后,需要购买或借贷 FIL ,用于初始扇区质押。

当前置做完后,就可以正式开始提供存储服务了,提供存储服务需要经过如下流程:

  • 密封扇区(sector)。(可以通过质押扇区(sector)或在存储市场上接单的方式来开始密封,需要注意:接单可能需要开启公网IP。)
  • 提交复制证明获得有效算力 。
  • 提交时空证明。

在提供存储服务后,有了算力,就可以参与区块打包,即出块。

存储服务收益

存储服务收益有几个来源:

  • BlockReward:这个是出块奖励(BlockReward),当矿工(Miner)打包一个区块(Block)时,系统会自动从 RewardActor 中转给此矿工一些 Fil 作为激励。
  • GasReward:这是区块下消息所附带的不确定奖励,这个奖励是 actor 之间发送消息时,如果设置了 GasFee,则此消息的 GasFee 会转给对应的打包矿工(Miner)。需要注意的是 GasFee 由给矿工(Miner)的 GasFee 和给 099 销毁的 BaseFee 组成。
  • 订单存储费用:这个是在存储市场上接单后,由客户(Client)付给服务提供者/矿工(Provider/Miner)的存储费用。
  • 检索服务收益:这个是在检索市场上接单后,由客户(Client)付给服务提供者/矿工(Provider/Miner)的检索费用。
质押费用

矿工(Miner)质押费用(Pledge)分为以下几种:

  • 初始质押/前置质押:这个质押费用(Pledge)是在密封扇区(sector)的时候提供的,密封扇区(sector)有生命周期,在到期之前这些质押(Pledge)都不能取出,只能在到期后一次性取出,当然扇区(sector)也可以在到期前或到期后续期。这是为了确保服务提供的稳定性。
  • 区块奖励质押/后置质押:在每次出块后的出块奖励(BlockReward)是分为两部分发放给矿工,其中 25% 立即释放给矿工(Miner),75% 是分为 180 天线性释放给矿工(Miner)。
  • 存储订单质押:在接存储订单后,需要质押(Pledge)一定金额的 Fil 来确保数据存储的稳定性,在存储订单结束后立即释放。
存储服务惩罚

质押费用的目的是为了确保稳定性,在存储服务不稳定时,自然也有惩罚。

在三种情况下,Filecoin 矿工(Miner)可能会被惩罚并扣除部分质押费用:

  • 违约:在服务到期前丢失数据则会因为违约被扣费。违约费两种扣法:
    • 自愿终止合同:需要支付终止费。
    • 在合同日期结束前使存储服务器脱机:被扣除部分抵押金额,并降低存储能力。
  • 存储故障:证明系统每天都会发起一个 WindoPoSt 随机证明,如果矿工(Miner)不能够查阅存储的客户数据来响应此证明时,就认为扇区故障。
    • 连续两天保持这种状态,则每天都会扣除存储故障费。
    • 如果某个扇区(sector)达到允许的最大连续失败天数,则该扇区获得的所有奖励及其初始质押品将被扣除。
  • 共识错误:试图分叉或操纵区块头选举。即在相同高度开采两个不同的区块。发生这种情况时,矿工(Miner)的存储将暂时中止,并受到处罚。这种情况下,该矿工(Miner)可能会被认为是攻击者从而扣除部分质押。

如果一个扇区(sector)连续掉算力超过 14 天,就会被网络认为是违约或者扇区(sector)被删除了,这种情况下将罚没该扇区(sector)所有的奖励质押(BlockRewardPledge)和初始质押(InitialPledge),也就是说如果一个扇区(sector)确认已经终止了,不但该扇区(sector)的前置质押币(InitialPledge)被全部罚没,而且该扇区(sector)之前获得的所有未释放后置质押(BlockRewardPledge)都将被罚没。

关联地址

一个矿工(Miner)会关联多个地址,分别都是:

  • OwnerID:矿工(Miner)所有者地址,矿工(Miner)初始化时提供的Lotus节点地址,即是谁初始化的这个矿工(Miner)。
  • WorkerID:工人地址。用于发送和支付矿工(Miner)执行的日常操作。
  • Control:控制地址,用于向链提交WindowPoSts证明。control 地址可以创建配置多个。

⚠️ 多签账户(Multisig)和普通账户(Account)都可以作为 OwnerID ,多签账户(Multisig)和普通账户(Account)也都可以将矿工余额(Balance)提取到自己账户里。

OwnerID 主要用于:

  • 更改 Miner 中的 Owner 或 Worker 地址。
  • 可以从 Miner 那里提取余额。
  • 提交 WindowPoSts 证明。

WorkerID 主要用于:

  • 初始化链上 Miner。
  • 更改 Miner 对等 ID 或多地址。
  • 与市场和支付渠道参与者互动。
  • 为新区块(Block)签名。
  • 提交 WindowPoSts 证明。

WorkerID 与 OwnerID 区别:Worker 地址是 Lotus 本地钱包的一部分,矿工可以访问。Miner 将使用它所连接的 Lotus 节点触发所有必要的事务。worker 地址必须有足够的资金来支付 Miner 的日常运营,包括初始化。可以理解为 Worker 是类似于进程、线程的东西,而使用进程、线程就意味着必须有资源(Fil)。

OwnerID 主要用于:

  • 提交 WindowPoSts 证明。
  • 通过使用 Control 地址,来停止一串交易的第一笔交易

虽然以上三种地址都可以提交 WindowPoSts 证明,但是他们之间并不冲突,而是一个优先级的问题:

  • 首先顺序使用第一个有足够资金提交 WindowPoSt 交易的 Control 地址。
  • 如果 Control 地址都没有足够资金,则将使用 Owner 地址。
  • 如果 Owner 地址资金不足或不可用,则将使用 Worker 地址提交 WindowPoSt。
Power

矿工的算力分为两种:

  • 原值算力(RawPower):矿工(Miner)本身提供出的算力值,这是实际算力。
  • 验证算力(QualityAdjustedPower):矿工(Miner)如果获得了验证客户的交易订单,矿工(Miner)因此类订单而增长的算力会乘以一定倍数,最终的值就是验证算力。

需要注意的是,矿工(Miner)分为活跃(有算力)和非活跃(没算力),因为只要有一个节点就能创建一个矿工(Miner)账户,所以非活跃矿工(Miner)可能会比活跃矿工(Miner)还多。

Chain

Chain 就是一个根据 Height 将 Tipset 连接起来的链。可以理解为链表那种形式,但是有所不同。

Tipset

不同于比特币或以太坊,Tipset 是一个区块(Block)的集合而不是区块(Block)本身。但是与比特币或以太坊会出现空块一样,FileCoin 也会出现空 Tipset。

一个 Tipset 下会有 0 或多个区块(Block)。当一个 Tipset 下有矿工打包的区块(Block)时,这就是一个非空的 Tipset,如果一个区块(Block)都没有时,这就是一个空 Tipset。

Tipset 的标识符就是高度(Height)。

Block

一个 Tipset 下会有多个区块(Block),这个区块(Block)与比特币或以太坊的区块(Block)类似。

一个区块下会有 0 或多条消息(Message),一个区块(Block)下的消息(Message)不会重复,但是一个 Tipset 下的消息(Message)有可能重复。

因为有可能一个 Tipset 下的多个区块(Block)同时打包了一条消息(Message)。

并且区块(Block)有可能会成为孤块的可能,即打包了,但是可能由于网络等原因上链失败,就成了孤块。

一个区块(Block)会给打包它的矿工(Miner)出块奖励,但是出块奖励份数(WinCount)有可能会给出多份,这主要是根据出块权重(Weight)来决定。

区块(Block)的标识符为 Cid 类型的。

Lucky

区块(Block)相关的还有一个概念叫做 Lucky 值,它的本质是实际出块数与理论出块数的比例。

Lucky 分为两种:

  • 全网 Lucky 值:FileCoin 理论每 30 秒产生一个新高度,每个高度有 5 个区块。但是实际根据网络、算法及参与者数量,有可能会这个高度没有区块或者是小于5个区块,也有可能这个高度会高于5个。如果某个高度实际出块为10个,那这个高度的 lucky值就是 10 / 5,也就是 200%。
    • 计算方法: 指定高度或高度范围实际出块数 / 理论出块数(指定高度或高度范围 * 5)
  • 矿工(Miner) Lucky 值:矿工(Miner) Lucky 不像全网 Lucky 值,矿工(Miner) Lucky 一般是对某一个高度范围或者时间范围内的区块做一个统计。
    • 计算方法:获得矿工算力占比,从而计算出理论出块数,再与实际出块数做计算。
      • 矿工算力占比:指定高度或高度范围矿工(Miner)算力 / 指定高度或高度范围全网算力
      • 矿工理论出块数:矿工算力占比 * 指定高度或高度范围全网理论出块数
      • 矿工Lucky:定高度或高度范围实际出块数 / 理论出块数

Message

消息(Message)可以说是核心之一,消息(Message)的流转决定了区块链的状态,任何状态的变更都需要消息(Message)的支持。

一条消息由以下几部分组成:

  • From:发送方。
  • To:接收方。
  • Nonce:消息标识随机数,代表这是 From 发送的第几条消息。
  • Method:要在 FVM 中执行的方法。这个消息的名称是由 To 的 ActorFamily 以及 MethodNum 来确定。
  • Params:给执行方法传入的参数。
  • ExitCode:Method 执行结果状态代码,一般为 0(代表执行成功),非 0 代表执行失败。
  • Err:Method 执行异常消息。
  • Return:Method 执行结果,仅部分 Method 有返回值。
  • GasFeeCap: 愿意为每单位 gas 支付的最高价。
  • GasLimit: 消息执行时消耗的 Gas 量限制。GasLimit * GasFeeCap 是为消息支付的最大 FIL 金额。
  • GasPremium: 给矿工的 Gas 手续费单价。GasPremium = GasFeeCap - BaseFee 最终给矿工的金额为:GasPremium * GasLimit。
  • BaseFee:燃烧的基础费率单价。最终燃烧的金额为:BaseFee * GasUsed。
  • Value:转账的金额。
  • Version: 执行此消息使用的 FVM版本。

消息(Message)在正式执行前会推送进内存池中,矿工在打包区块时会去内存池中打包消息(Message)。

消息有两种类型:

  • 用户消息(userMessage):这是由 Account、Multisig、Miner 主动发起的消息,

  • 系统/子调用消息(InternalMessage / SubCallMessage):一般是执行一条用户消息的内部调用流程消息或是系统自定义调用的消息(如线性释放、定期检查证明等)

消息(Message)的标识符为 Cid 类型的。

BaseFee

BaseFee 是每发送一条用户消息(UserMessage)要燃烧/销毁掉的基础费率,每条消息对应的 BaseFee 会自动转给 099 这个账户。

BaseFee 是浮动的,它会随着网络的使用状况而改变,BaseFee 主要是为了应对网络攻击的一种方式,当出现大批恶意攻击流量的时候,有可能会造成网络阻塞,这样会提高 BaseFee,从而增加攻击者的成本。

但是 BaseFee 浮动一般不会很大,有可能连续十几个高度都不改变。

常用标识符基础类型(非代码内使用)

Height

高度是区块链中的通用概念,在比特币和以太坊中,高度表示为生成了多少个区块,每个高度之间的间隔时间不同。

但是在 FileCoin 中,高度代表了时间的推进,FileCoin 是每30秒增长一个高度,我们得知一个高度以及对应的时间后,可以很轻松的换算出另一个高度对应的时间或另一个时间对应的高度。

每个高度下会对应 1 个Tipset。

高度是一个 64 位的数字类型。

⚠️ 在一些场景下,Height 会被叫做 Epoch ,Epoch 与 Height 是等价物。

Cid

Cid 是一个 Hash 值,全称为 Content Identifier 的缩写,是整个 IPFS 生态系统中使用的自描述内容地址。

它的序列化后的字符串格式一般表现为

{
    "/":"bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}

但在实际使用中(除调用 RPC 接口外),一般直接将值(如上述示例中的"bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4") 拿来使用

Addreess

Addreess 是一个字符串类型的,地址由三部分组成:

  • 网络标识符:网络标识符为地址的第一个字符,主要是用于区分主网和测试/校准网。主网地址以 f 开头,测试/校准网地址以 t 开头。
  • 地址类型:地址类型为地址的第二个字符,分为以下三种:
    • ID Address :对应的字符为 0,此类地址由 Public Key Address 上链映射为 ID Address,此类地址在映射成功的一段时间内不稳定,并且会受到链上状态的影响。但此类地址的优势是较短、易记,且节省消息费用。
    • Public Key Address:分为 SECP256K1 地址(对应字符为1 )以及 BLS 地址(对应字符为3 )。此类地址为节点本地初始化的地址,十分稳定,不受链上状态影响,但是较长。
    • Actor Address: 对应的字符为 1,这是一种与公钥无关的健壮地址创建方式,其本质是通过 sha256 哈希出来的。
  • 地址标识:代表对应的账户。

如 f099,代表这是主网的一个 ID 为 99 的 ID Address。

Fil

Fil 是整个 FileCoin 生态中的流通货币,它分为不同单位:

Name Decimal
FIL 1
milliFIL 1000
microFIL 1000000
nanoFIL 1000000000
picoFIL 1000000000000
femtoFIL 1000000000000000
attoFIL 1000000000000000000

参考:

[ 1 ] FileCoin 文档

[ 2 ] FileCoin 规范

[ 3 ] Lotus文档

[ 4 ] Cid 文档

[ 5 ] IPFS 的 Cid 提案

[ 6 ] Lotus 代码库

[ 7 ] FileCoin 状态类型代码库

[ 8 ] FileCoin Actor 代码库

[ 9 ] FileCoin Address 代码库