Factom公证通:一本由共识算法维护的账本
Factom是一个建立在比特币区块链上的通用的数据层。用户可以通过这个数据层, 方便的为自己的数据创建一个独立的虚拟区块链。用户的单个数据包被称之为一个输入条目(Entry)。Factom不会对用户的数据提出任何格式上的限制。 任何数据都可以加载进来。初一听起来这似乎没什么大不了。 为了达成这个简单的目标, Factom系统却需要实现诸多复杂的特性, 除了系统得是分布式和自动化, 而且它还要”审查免疫”(censorship resistant). 本文会详细阐述Factom背后的机制与原理. 涉及到的专业术语统一归纳到了附件A中, 方便大家查阅。
Factom创建的是一个共识系统, 用户只要把数据输入其中, 便会被及时记录下来。而这整个过程是分布式的, 也不会要求输入者的个人身份信息。这个系统的正常运转依靠的一整套密码学维持的协议。如果有人利用Factom系统作恶, 即使他的行为在数据输入过程中不能立即识别, 稍后不良行为者也会被一个用户投票系统甄别出来并剔除出去.
本文会细述Factom的体系结构,并介绍它的每个模块. 我们会分析对Factom系统可能的一系列攻击,并一一阐述这些问题会如何被化解。只要过半的参与者是诚实的在运行着Factom系统,Factom系统便能正常的运作下去。但是在不良行为者太多的时候, 系统的性能可能会略受影响。这个时候用户投票系统就会发挥作用, 把这些人一一剔除出去。
Factoids
Factom系统会创造一个叫Factoids的电子币。持有Factoids意味着有权使用Factom系统。只要把Factoids转化成输入积分(Entry Credit), 便有权把数据写入Factom系统中。同时运行着Factom的联邦服务器(Federated server)也能收获Factoids作为维护系统的回报。由于每个信息输入需要消耗一定Factoids, 不大可能出现海量垃圾信息被输入系统中。
Factoids的实现和别的加密货币类似。通过一个签名交易, Factoids币可以从一个地址转移到另一个地址,我们也会提供多重签名机制。还可能利用类似UTXO的机制来实现一个轻量级的Factom客服端, 并利用Patricia-Merkle trees技术将之进一步优化。
Factom系统会维护一个单独Factoid链来维护Factoids币的转账信息 Factom联邦服务器能识别有效与无效的Factoids交易, 安全维护Factoid链块.
输入积分(Entry Credit)
Factoids币可以被转换成输入积分(Entry Credit),输入积分维护在独立的链块(Entry Credit Chain)上. 这个链块上持有Entry Credit的公钥地址, 利用该公钥对应的私钥可以签署一个 Factom链操作. 这个操作可以实现2种功能: 一是创建一个新的Factom链. 二是在已有的Factom链上添加一个信息输入。每写入1 KiB的数据需要消耗1个Entry Credit. 如果有人在Factom链上添加信息输入的时候没有付给足够的Entry Credit. 这个操作会被忽略, 已付的Entry Credit会被没收. 完全节点(Full node)看到付费不足的信息输入, 不会广播这个付费不足的操作。这个信息输入也不会被传达到联邦服务器.
一个付费足够的信息输入便可以发起一个操作把数据写入链块, 但这个操作有一定有效时间, 这个时间被称之为输入积分有效时间 Entry Credit Timeout Period (ECTP). 现在把ECTP暂定为24小时. 如果在这个时间内, 数据还没有成功被写入链块. 这个输入就会作废, 对应的输入积分不会被退回. 这样设置是为了避免出现一个无限增长的输入等待队列。
虽然Factoids能转换成输入积分, 但输入积分不能被转换成Factoids. 输入积分也不能在账户之间转换, 它一旦产生就绑定在一个公钥地址上. 我们也考虑给输入积分也设定一个有效时间, 比如几年内还没被使用就失效了. Merkle tree技术可以被利用来在轻量级客户端上帮助识别哪些账户剩余了多少Entry Credit。
输入积分是由Factoids转换生成的。转换交易需要适当的签名(就像任何其他的Factoid交易),并指定输入积分的公钥地址。一旦转换成功, 输入积分就会永久绑定在指定的公钥地址上. Factoids与输入积分的兑换汇率由联邦服务器来决定。
Factoids由一个独立的Factoids链维护. Entry Credit也由一个独立的Entry Credit链来维护. 只有符合Factom协议的有效交易才能通过协议审查, 被写入这些链。
由于Entry Credit只能由Factoids兑换而来, 没有Factoids的人需向Factoids持有者购买才能获得Entry Credit, 来支付Factom系统的使用费用。
以太坊(Ethereum)有着类似模式。在以太坊系统中, Ether 是可以自由交易和流通的. Ether可以按照系统设定的汇率被转换成 Gas。以太坊系统内, 每执行一个合约就会消耗一定数量的Gas. 以太坊的挖矿者会获得恒定数目的 Ether 作为维护网络的回报。
Factom 和以太坊有着类似的架构, 区别就在: Factoids=Ether, 而 Entry Credits=Gas.
Factom的公钥系统
用户必须使用公钥签署他们发起的Factoid交易,数据输入,链操作。如果他们希望行使投票,还需要创建一个身份标识并与一个公钥地址绑定。同时这个公钥地址需持有Entry Credit. Factom服务器必须有一个身份标识和Bitcoin秘钥才能在在比特币链块上发布锚(anchors)。为了进行区分, Entry Credit的链块和Factoid的链块的公钥地址还会使用不同的格式。
Factom的身份标识系统
各单位必须能够建立,维护和保护Factom系统里的身份标识信息。Factom用户需要先给自己建立一个身份标识,才能参与给Factom服务器的投票,和获得奖励。Factom联合服务器(Federated Servers) 以及 Factom审计服务器(Audit Servers) 都必须给自己创建身份标识信息。Factom审计服务器是那些待选的联合服务器, 他们已经获得了一定投票,但票数不够多到成为正式的联合服务器。
Factom里的身份标识是维护在一个链上。这种链包含一组项, 每个项可能包含一个或多个如下的信息:
一个按优先级排序的Entry Credit Key列表
-
一个cold storage key列表
-
一个offline key列表
-
一个backup key列表
-
一个hot key列表
一个按优先级排序的Factoid Key列表
-
一个cold storage key列表
-
一个offline key列表
-
一个backup key列表
-
一个hot key列表
一个按优先级排序的比特币 Public Key列表
-
一个cold storage key列表
-
一个offline key列表
-
一个backup key列表
-
一个hot key列表
在身份标识链中的第一项必须定义Entry Credit公钥的层次结构。每个密钥会被用来签署下一个项。项可以替代之前的Key,但必须通过在当前链块位置上有效的Etnry Credit公共密钥进行签名。
一个条没有用Etnry Credit公共秘钥签名过的Entry会被系统共识算法忽略。这种未被签名的Entry 可能在其他情况下被利用到。
其他层次结构也是可能的,比如被使用于其它的应用。系统对身份标识信息的结构和内容没有限制. Factom和其他应用程序都可以简单地解析身份标识链, 并获取他们所需的信息。
甚至现有的身份标识体系还能进一步改进,只要未来有这样的需要。
Hot key 在应用程序里用来代表身份标识信息。不幸的是,应用系统可能会被破解。所以我们允许利用backup key来修改hot key,以替换泄露的密钥。此外,off line key可以用来代替backup key. Cold storage key是保护身份标识链块的最后一道防线。
给联合服务器投票使用的身份标识信息
联邦服务器和审核服务器(那些待选联合服务器)都是由Factom用户选举产生的。用户需要建立一个身份标识并持有一定Entry Credit 才有权参与投票。一个用户的身份标识信息可以保存Factom公钥, 这个公钥能用于把数据输入写入Factom系统。
用户可以把投票权授权给联合服务器,或是其他的代理. 由他人帮助用户进行投票。
在单靠协议本身已不能识别不良行为的情况下, 联合服务器必须仍然能够和正常用户保持通信和服务. 例如,某些服务器的行为可以明显看出有审查的征兆(patterns of censorship),但该服务器没有明显破坏协议。
被联合服务器使用的身份标识
Bitcoin的公钥可用来把哈希数据上传到比特币区块。它们不能被用于一般的Factom转账。必须同时持有BTC公钥 和 有效OP_RETURN 的时候才能在Factom系统进行Spend transaction . 如果攻击者盗取了BTC公钥,单靠公钥只能盗取到该地址上的BTC, Factom系统不会受到影响。这样的失窃对系统影响很小。
我们还可以按照设计好的规则,用更高优先级的Key把已泄露的Key替换掉。
每个服务器维护一个Matryoshka 哈希链(M-hash)。服务器从秘密值开始,进行R次的哈希(比如10万次)。最后的结果 mr 被记录为自己的身份标识的一部分。利用M-hash, 服务器可以效验之前的hash结果(i.e. mr-1 mr-2 etc.). 其中M的定义:
M = m1 m2 … mq mq+1 … mr
where h(mq) = mq+1 for any mq and mq+1 in M
对于给定的M-hash,无法直接获得 mq ,但可以经过效验进行验证. 这样一个系统使的服务器的行为是确定的 同时又不可预知的。它会避免单个服务器能预测未来的状态。只要两个服务器的信息是保密,下一状态是无法预测的。
具有确定性的随机种子
Factom下一个系统状态完全取决于联合服务器给的随机种子。在每一分钟结束时, 每个联合服务器在各自的M-哈希序列上运行Matryoshka hash。这些hash结果合并在一起,以产生随机种子。只要有一个联合服务器的M-hash是未知的,那合并以后的随机种子就是未知的。Factom系统状态不可能被容易地操纵(详见攻击章节)。
应用程序所使用的身份标识
身份标识的概念不光Factom系统内会使用。相关的一些应用程序也可以维护一个自己的公共密钥的多层结构。创建身份标识后,可以号召该应用程序的客服来使用他们的身份识别系统. 用户可以登录,并操作身份链来更新自己的身份信息. 如果身份标识“B”需要给身份标识“A”提供担保,那么他们发起一个背书操作,签字,并将其放在身份链。A可以进入身份链, 表示是否最终同意这个背书。或B可以自己先签名再把背书发送给A,A再签署,把经过双方签名的背书写入身份链。
身份可以放入授权列表,从授权列表中删除. 授权列表可以是加密的, 可以是私人的,或者由Merkle roots验证的 (不需泄露列表信息 就能验证有效性)。它们可以存储在/不在 Factom。在Factom上构建应用程, 用户身份管理的设计可以很灵活。
Factom网络
Factom协议定义了一系列的通信规则。每分钟大多数联邦服务器会达到成共识。每隔10分钟,达成共识的联邦服务器中会有一个服务器写入一个hash到比特币blockchain。 Factom采用的是相似比特币的P2P网络。该网络是洪水填充(flood fill)。所以全部节点应该都能看到传播中的所有有效交易。P2P网络的连接也是随机的。如果联邦服务器停顿了几秒钟没有发出数据包,他们会被审查服务器替代。 具体被哪个审查服务器替代,由其他联邦服务器来确定。这里有个假设partial synchrony, Dwork Lynch Stockmeyer对此有详细描述[1]。
设计Factom系统的时候, 我们有如下假设:
-
需要验证anchor的节点都已经连接到比特币网络, 可以参看比特币区块的历史记录.
-
节点验证anchor目的是,验证Factom Anchor posts, 和查看服务器的密钥是否被无效使用了。
-
比特币网络正常, 没有频繁分叉。
-
比特币网络是可访问的,并且比特币网络没有分割(segmented)。
-
比特币网络上的交易传播时间是在几秒钟。
-
比特币矿工都没有篡改OP_RETURN,Factom anchors。
-
Factom网络正常, 没有出现子网络与子网络相互分割(segmented)。
-
Factom网络上多数联邦服务器之间消息的传播时间在几秒钟。
-
大部分的联邦服务器是诚实的。
-
有超过2台联邦服务器的Matryoshka hash chain是安全保密的, 没被泄露。
完全节点(Full Node)的定义
Factom网络是一个由众多完全节点构建的点对点网状网络。一个完全节点会维护所有的Directory Blocks, Entry Blocks,Factoid Chain, Entry Credit Chains, server identity Chains。请注意,这里不包括Entry本身。有了这些数据,完全节点就可以验证Entry Commints的有效性。如果发现了无效的Entry Commints, 便能及时拒绝。对于Factoid transactions 和 Entry Reveals 也是同样的道理。
Factom的主要任务是打包数据,同时保证抵御审查(censorship resistant), 也要能够防范垃圾信息。Factom自身的主要职责不是数据存储。而是通过在一个分布式哈希表(DHT)P2P网络实现数据的共享。目前作为一个完全节点需要存储Entry data. 在未来为了降低运行一个完整的节点的门槛,将不要求一个完全节点存储所有的Entry data。
消息的定义
Factom P2P网络主要有5个类型的消息(Message)。服务器消息不在这里细述, 在服务器故障消息(SFM)章节再详细解释服务器消息。剩下的4种消息,有两种消息用于支付手续费,然后创建一个新的链。另外两个消息类型用于支付手续费,然后在已存在链里写入一个Entry。所有消息通过P2P网络广播, 并会被保存在各类链中一段时间。
Chain Create,added to the Entry Credit Chain includes:
-
8字节的时间戳
-
Hash of ChainID
-
Hash of(ChainID+Entry Hash)
-
Entry Hash
-
待使用 Entry Credit 的数目
-
Entry Credit 公钥签名
-
Entry Credit 公钥
Entry Commit,添加到Entry Credit Chain 包括:
-
8字节的时间戳
-
32字节 Hash of the Entry
-
待使用 Entry Credit 的数目
-
Entry Credit 公钥签名
-
Entry Credit 公钥
Chain Reveal 提供:
-
The first Entry that hashes to the Entry Hash in the Chain Create
The first Entry必须包括Chain Name,which hashes to the ChainID in the Chain Create
Entry Reveal只包括Entry 。它会被添加到该Entry中指定的链条。
-
Entry
Entry 包括:
-
ChainID
-
(链创建时会需要)链名称
○[] []字节数组
-
(可选)List of external keys
-
(可选)block of binary data
Confirmation(确认消息)
联合服务器每处理一个Entry data element 都会产生确认消息(Confirmation Message)。此消息通过Factom节点网络传播,它意味着Entry一定会被Factom系统记录。该消息还表示这Entry被记录的时间顺序。Confirmation Message被放置在联邦服务器的进程列表。
Confirmation Message 中有如下信息:
-
Directory Block Height:4个字节
-
ChainID of Server Identity
-
Height:在进程列表中指向本确认消息的的4字节index(每个服务器)
-
Affirmation value (one of:)
○Entry Commit:提交信息的SHA256 Hash
○Entry Reveal: Entry Hash
-
○Entry Chain Create Commit:Commit Message的SHA256 Has
○Chain Create Reveal: Reveal Message的SHA256哈希
○Factom Transaction:transaction的SHA256哈希
○End of Minute Marker:0值
●Serial Hash (one of:)
○SHA256 hash of (default Serial Hash + Block Height + Height + Hash),如果第一个Entry在进程列表中
○SHA256 hash of(the previous Serial Hash + Block Height + Height + this entry’s Hash)
●服务器签名
Proof of Use
用户在Factom系统内购买Entry Credit的同时, 系统会给该用户的”开户服务器”给予一定投票. 但这个投票的效果是递减的. 用户Identify对应的公共私钥会被设定一个递减的权重. 比如第一天投票的权重是180. 在接下来的每天权重都会减少1. 在180天以后, 当初对服务器的投票就归零了. 投票权重从180到0线性递减.
一些意见:
● 用户的Entry Credit购买记录会被追踪180天. 每天的结束时间是0:00 UTC. 每过这个时间点就记为第二天. 指定的服务器1会发出“End Minute”消息来协调block closing。
●越近发生的Entry Credit购买行为被赋予更大的投票权重。
●通过用户身份信息里的Hot Key, 用户可以签署一个代理委托. 让这个用户的投票划归到另一个用户的名下.
●在早期Factom白皮书里, 我们计划的是 Entry写入的时候产生投票. 后来权衡了一下, 改成Entry Credit购买的时候产生投票. 由于Entry写入操作会比Entry Credit购买行为频繁的多, 修改以后给系统带来的负载相应减少很多.
超时周期 Timeout Period(TOP)
每个超时周期所有服务器都需要作出回应。我们可能会将TOP设置成10秒。在比特币网络, 一个消息要广播到50%的节点需要时间低于2秒[2]. 我们正在考虑, 当Factom网络信息传播不够快的时候, 把TOP时间延长.等网络响应时间回复正常以后, 再把TOP回复原值。
服务器心跳 Server Heartbeat
服务器心跳可能是一个有效Factom消息. 在服务器没有Factom信息需要广播的时候, 就会发出一个包含时间戳的空消息, 作为心跳消息。
服务器故障消息 Server Fault Message(SFM)
如果发现任何违法共识算法的现象, 就会产生服务器故障消息. 以服务器A发出一个服务器B的SFMs为例:
●如果一个超时周期内, 服务器A没有收到服务器B的心跳。
●如果服务器B负责将anchor 信息写入比特币区块链, 但失败了.
●服务器B写入一个无效的anchor。
●服务器B持有的比特币密钥签署了一个对Factom没有意义的操作。 (服务器B在Bitcoin上的私钥只能用来写入Factom anchor)
●服务器B未能在TOP周期内, 完成其process list里的任务。
●服务器B的发起无效的Factoid交易。
●服务器B发出一个Entry Reveal Confirmation, 但A在TOP内没有找到匹配的Entry。
●服务器B发出确认, 但是不被B的process list验证.
服务器故障消息可以被修复, 只要发出另一个服务器故障修理消息 Server Fault Repair Message(SFRM)。如果服务器A看到大多数服务器都发布了服务器B的SFM,那么服务器A发出一个Server Reject Message(SRM)和Server Add Message (SAM)给排名最高的待选服务器。 SFMS由发起他的服务器主动清零,或由它们自动超时。
联合服务器与审查服务器 Federated Servers and Audit Servers
Factom系统由n个Federated Server(联邦服务器)共同维护。目前的想法是,n的数字将不小于16. 我们将另有n个Audit Serve(审查服务器)。
一些意见:
●所有Federated Server和Audit Server必须有: 一个Factom的identity,比特币地址,Factoid地址,还有一个地址用于接受Factoid报酬。
●Federated Server的比特币地址用来在比特币blockchain放置锚定(anchor).
●Factoid地址用于管理和保护的Identity Chain.
●用户通过Factom Identity 给Federated Server投票。用户还可以让别人代为投票。投票权重根据 Proof of Use 进行调整。
●投票排名前n服务器是Federated Server.
●除开n个联邦服务器, 投票排名前n+1到2n的服务器是 Audit server.
●所有服务器都必须发布心跳消息 (hearbeat)。 (只有持续发布了心跳信息的Audit server,才有资格晋升为Federated Server)
●如果Federated Server在TOP内没有发布 hearbeat,那么其他Federated Server将发出针对该服务器的SFM报错信息。
●Audit server如果在超过10个TOP的时间内都没有发布 hearbeat, 它将不被考虑晋升为Federated Server。
●如果大多数的服务器对同一个Federated server发布一个SFM报错消息,则该服务器被移出Federated server pool。由排名最高的Audit server代替。
投票数目不够跻身Federated server 和 Audit server的服务器被称为 Candidate servers. 当Audit server数目低于n, 则由投票最高的 Candidate server跻身为Audit server。
共识算法
符号
H(X)表示计算X的哈希值。
Federated Server都记录在Federated Server Pool Chain
Federated server和Audit server根据用户投票选举出来. 服务器的Identity被按序记录在Server Chain.
所有Server Message都记录在Server Fault Chain
记录服务器故障.
Federated Server排序
每个Federated server广播自己的 Matryoshka hash.
所有节点然后计算随机种子(Random Seed).
根据Random Seed 来给Federated Server的Identity 排序. 排在第一的就是 Server 1. 排在第二的就是 Server 2. 直到 Server n.
rs = Random Seed
Scid = 服务器 Identity 的ChainID
为每个Dederated Server 计算 H(rs+ Scid),然后进行排序。
Server 1 排在第一个,
…
Server n 排在最后.
通过Random Seed把Chain分配给服务器
rs = random seed
cs = ChainID
Server 1 保管所有符合这个公式的ChainIDs, h((rs+cs))%n+1 = 1
Server 2 保管所有符合这个公式的ChainIDs, h((rs+cs))%n+1 = 2
…
Server n 保管所有符合这个公式的ChainIDs, h((rs+cs))%n+1 = n
Entry Credit是由Random Seed所确定服务器来处理
rs = the Random Seed
ecs = 签署Entry Credit的public key
Server 1处理所有符合这个公式的Entry Credit, h((rs+ecs))%n+1 = 1
Server 2处理所有符合这个公式的Entry Credit, h((rs+ecs))%n+1 = 2
…
Server n处理所有符合这个公式的Entry Credit, h((rs+ecs))%n+1 = n
Factoid是由Random Seed所确定服务器来处理
rs = the Random Seed
ftxh = hash of the transaction
Server 1处理所有符合这个公式的Factoid交易, h((rs+ftxh))%n+1 = 1
Server 2处理所有符合这个公式的Factoid交易, h((rs+ftxh))%n+1 = 2
…
Server n处理所有符合这个公式的Factoid交易, h((rs+ftxh))%n+1 = n
Factom Full Node 如何传递网络消息
在每一分钟开始的时候:
1.添加分钟分隔符(minute separator)到所有 process list
2. Entry Commit 是有效的条件就是, 是否有付充足的手续费.
3.有效的Entry Commit 将被添加到Entry Commit List
4.转发有效的Entry Commit
5.利用Entry Commit List对Entry Reveal进行验证。
6.有效的Entry Reveal被添加到Entry Reveal List
7.转发有效的Entry Reveal
8.为每个Federated Server建立process list, 记录该服务器发布的 confirmation.
在每一分钟结束的时候:
a. 如果某个Federated Server 的 process list 包含有未知的 Entry Commit/Reveal. 向邻居或者DHT进行查询.
b. 顺序执行每个服务器的process list(即服务器1,…服务器N)
c. 在执行过程中构建 Directory Block 和 Entry block。
i. 每执行一个有效Entry Commit 就在Entry Commit list将其标记为已接受.
ii. 每执行一个有效Entry Reveal 就在Entry Reveal list将其标记为已接受.
iii. Entry Commit 和 Entry Reveal一旦对的上号,就会被移出Entry Commits list 和 Entry Reveals list.
在每10分钟结束时:
a. 我们所有的Entry,和Entry Block. 以一分钟为时间窗口, Entry Block被分隔开。
b. 建立Directory Block header,包含Merkle root 和上一个Directory Block的Serial hash。
c. 继续建立Directory Block. 包含所有在过去的10分钟有Entry的Chain的Chain ID.(以ChainID排序)
d. 计算Directory Block的serial hash,让多数Federated Server来签名。把这些签名添加到Directory Block。
e. 给这些Directory Block和签名创造一个Merkle root。
f. 验证最后一分钟把Merkle root记录到比特币blockchain的服务器的 hot wallet 比特币地址.
g. 清除所有的process list
Federated Server 处理过程
在每一分钟开始的时候:
-
添加分钟分隔符(minute separator)到所有 process list
-
利用上个block的 deterministic seed (DS) 重新排序服务器
-
使用 Random Deterministic Seed (RDS) 给服务器分配ChainID.
-
使用RDS给服务器分配 Entry Credit Chains
-
也许使用RDS分发Factoid
-
清除process list,添加minute separator 到所有 process list。
-
把Entry Commit List 中由本服务器负责的Entry添加Factom消息流的头部(这样他们就可以尽快得到处理)
如何接受Factom消息流:
1.验证消息有效性,扔掉那些无效的。
2.涉及到该由本服务器处理的 ChainIDs,Entry Credit chains, Factoids:
1)添加 Entry Commit 到该服务器的进程列表,并签发Entry Commit Confirmation
2)添加 Entry Reveal 到该服务器的进程列表,并签发Entry Reveal Confirmation
3)添加 Factoid Transaction 到该服务器的进程列表,并签发Factoid Transaction Confirmation
3.对于其他消息
1)添加Entry Commit对进入Entry Commit List
2)添加Entry Reveal对进入Entry Reveal List
3)把来自其他服务器的Confirmation 纳入各自的 process list
在每一分钟结束的时候:
1.发送 End of Process List (EPL) message(包括服务器的 Matryoshka Hash)
2.继续等待, 直到不属于本服务器负责处理的消息都从别的服务器处接收到 End of Process List message
3.迭代所有 process list,按照从sever 1 到 server n 的顺序 建立chain
Rinse 直到本轮10分钟结束
在每10分钟结束时:
-
我们所有的Entry,和Entry Block. 以一分钟为时间窗口, Entry Block被分隔开。
-
建立Directory Block header,包含Merkle root 和上一个Directory Block的Serial hash。
-
继续建立Directory Block. 包含所有在过去的10分钟有Entry的Chain的Chain ID.(以ChainID排序)
-
计算Directory Block的serial hash,让多数Federated Server来签名。把这些签名添加到Directory Block。
-
给这些Directory Block和签名创造一个Merkle root。
-
验证最后一分钟把Merkle root记录到比特币blockchain的服务器的 hot wallet 比特币地址.
-
清除所有的process list
寻找Consensus Head(共识头)
比特币里可以很容易的自动寻找到Consensus Head。连接到系统中的节点会四处打听潜在候选Consensus Head。客户端可以向后扫描看当前blockchain是否源自与正确的genesis block(创世快)。如果确实如此,那么它可以向前扫描,以确保从genesis block到最长的候选链, 都遵循着所有的规则。如果发现了两个有效的blockchain,那么一个软件选择承认有着最大 Proof of Work(POW)的那条链。 Factom依赖于Bitcoin的POW,所以一个完整的Factom客户端需要找到比特币的Head,以便充分验证Factom的历史数据。
Two Stage Scanning (两级扫描)
发现Factom的共识头可以使用类似比特币里的方式。一个Factom客户端需要引导入Factom P2P fllod fill network (洪水填充网络),在设法得知Factom genesis block。一旦他们连接上网络,可以向周围的节点查询哪个是当前的Factom head. 通过和flood fill peer通讯便能得知DHT网络上有哪些节点。
这里有着一个假设, 网络中大部分节点都是诚实的, 他们不会欺骗新入网节点, 报告错误的head. 攻击者可进行 sybil attach并把新入网节点引导向一个假head。如果攻击者提出了许多不同的假head,然后每一个假head需要很多不诚实的节点去证明它。攻击者应该会倾向于用所有不诚实节点引导到一个假head, 而不是分散给多个假head。
Backwards Scanning (向后扫描)
然后客户端将从当前head往后, 下载之前的所有Directory Block header。如果Directory Block header最后追溯到了正确的genesis block,那么就可以开始从genesis block 开始验证网络的历史数据。如果没有追溯到正确的genesis block, 就说明这个head是不正确的. 将其忽略。
Forwards Scanning (向前扫描)
一旦候选 Directory Block (DB) chain 已被选中,客户端将向前扫描,检查每个DB,看数据是否遵循网络规则。扫描结束的时候, 客户端可以得到几个不同程度的结果。DB header指定哪个identity将被允许签署下一个块。Identity里的比特币地址就是可能出现在一个DB的anchor中。
客户将检查比特币blockchain以查看是否有anchor被放置. 如果anchor的放置时间和数据发布时间比较接近.则客户端可以知道该数据是正确。这消除了被攻击的可能性,例如有私钥丢失, 用于创建虚假的历史。
为了减小fork不被大众发现的可能性, 我们对下一个anchor放置在哪个比特币地址有所限制. 如果下一个block包含了两个有效anchor,那么客户端将怀疑网络出现fork了。如果大多数人正确行事,那么他们的反应如在 “A Federated Server Outside the Majority Places an Anchor” 一节中所述。
这有一个缺点: 如果多数节点不能形成一个共识,Factom会停止产生新的block。如果Federated server掉线了,那么Audit server将晋升为Federated server。最坏情况是大多数的Federated server都掉线需要被替换. 尽管大多数服务器掉线会让Factom系统停顿,客户在扫描历史数据是不会感受到太多影响。
批评和潜在的攻击
Factom是中心化的吗?
Factom是一个去中心的协议。服务器想进入Federated Server Pool需要依靠自己的性能和社区的支持。Federated Server Pool负责处理所有链块上的交易.
把Factom系统误解为中心化系统可能源于, 任何一分钟内都有一台 Federated Server负责处理Entry。不过下一分钟, 处理Entry权利就会移交给另一台服务器。没有一台服务器能够长时间控制某条Chain. 在10分钟内,就有10台不同的服务器轮流负责Entry处理。
Federated Server Pool是获得Factom系统实际用户投票最多的那些服务器组成。服务器可以安排停机时间,这不会受到惩罚。由于通信故障或算法故障导致掉线的服务器没有权利参加下一个周期的竞选.
Federated server的备份是Audit server. 有服务器掉出Federated server pool, 就有一台Audit server 顶替空缺, 升级为 Federated server。
Federated server pool的大小是固定的,Federated server 的数目至少不小于16。(确切数字仍在考虑). Audit server pool是相同的大小。付给服务器的报酬数目是固定的。
Factom的去中心化应该会比 比特币还好. 比特币现在最大的前4, 5个矿场便持有超过50%的算力. 即使Factom只有16台服务器,获得50%的网络控制权至少要控制9台服务器. 况且服务器是由用户选举产生的, 随时可能被投票选下去, Factom的去中心化程度比比特币要好. 此外只要有很少一部分服务器没有被挟持, Factom 系统里保存的Entry数据就是安全可靠的.
可能未被发现的 Factom Fork (分叉)
Factom遵循特定的算法(见:寻找Consensus Head那部分). 只要是分叉就能被检测到。只要大多数服务器都是诚实的,便只会有一条链是有效的。如果大多数节点跑到分叉链上了,这必然会被社区察觉。
重新排列Chain Entry
如果客户端为某条 Chain 上的Entry, 提交了一个 Entry Reveal,负责该Chain的服务器需要为那个Entry发出确认信息。客户端一旦接收这个确认信息, 就代表这个 Entry 应该会被Factom记录下来。通过搜集某一台服务器发出的所有确认消息,就可以构造该服务器的整个process list。由于每个确认有一个serial hash 覆盖所有以前的Entry 和新Entry. 这样就能得知process list的顺序和结构.
如果Fedrated Sever 想修改自己Process list,这个变动不能够影响到其他Federated Server上的Process List; 一旦serial hash被广播出去,添加Entry的操作必须附带上 Comfirmation信息 来证明这个Entry的历史. 如果服务器一直等待,直到10分钟结束后还drop Entry,服务器将在第10分钟结束时 无法签署Directory Block; 没有有效的办法来协调process list上的变化。如果服务器不能给Directory Block 提供有效的签名,这种服务器将从Federated server pool 除名. 并且其process list 广播到全网, 被drop 的Entry 将包括在数据集。
一旦Merkle root已被记录到该比特币blockchain,其内容不能改变。
Withholding Deterministic Seed (扣留确定性种子)
Federated server 可延缓广播 End of Process List(EPL) 消息, 直到所有其他服务器已经播出了EPL消息。此刻, 拖延广播EPL的服务器就能够确定Factom系统下一个状态是什么, 因为他知道自己发出的EPL会是什么内容。系统如何面对这种情况呢? 如果服务器拖延广播自己的EPL,大多数网络上的节点会在几秒钟后针对拖延服务器 发送报错消息 Server Fault Message(SFM)。排名最高Audit server 会被提升为 Federated server。接下来的系统状态,就不在攻击者的掌控之中了.
当Federated server关闭了其进程列表后,发出一个SFM. 它需要再发布一个 M-hash 的更新。这将有效防御 拖延EPL的服务器和Audit server 串通一起进行攻击。
这种攻击的效果会随着时间而递减。一旦服务器拖延EPL,其他节点会有数小时时间和攻击服务器不在共识状态. 攻击者只有冒着被清理出Federated server pool的代价才有可能攻击成功. 如果Federated server 多次假装只有在这个关键时刻失去连接,那么很明显,他们正在执行这种攻击。可以向社区说明, 呼吁用户撤回给这个服务器的投票。
Censorship of a User (屏蔽用户攻击)
一台服务器可以尝试屏蔽某些用户, 拒绝把这些用户的Entry上传到到他们负责的Chain。
在Factom要拒绝给一个用户提供服务是相当困难的事。用于管理Entry Credit的公共密钥可以随时间而改变。如果服务器希望通过跟踪某个用户的公钥来拒绝给他们服务. 这些用户可以简单的使用多个公共秘钥来躲避服务器的屏蔽.
另一种方式避免服务器有机会屏蔽用户的办法是, 在每分钟服务器把chain的管理权移交给别的服务器. 总不至于所有服务器都恶意的拒绝给该用户服务吧.
用户可以雇人代其把Entry提交到网络。所以一个公共密钥背后可能代表的是一大群个人用户。想拒绝给单个用户提供服务,变得几乎不可能.
Entry Commit只包括Entry的哈希. 在Entry Reveal广播之前, 没有服务器可以判断这个Entry会被写入哪条Chain. 服务器没有能力阻止Entry被写入特定Chain。
一旦Enty Reveal 被广播,需要再满足两个要求 就保证Entry能被写入系统。其一是,Entry的哈希与某个付费的Entry Commit匹配。其二是, 该Entry Commit付的 Entry Credit 足够多 来承担Entry 的写入费用。就算有某个服务器拒绝把这个Entry写入链块, 这并不能阻止 Entry 被列入Factom链。该Entry 仍保留在协议中,由下一台服务器将其纳入到相应的Factom链。总不至于所有服务器都恶意的拒绝把这个 Entry 写入链块吧.
屏蔽用户攻击是公开的。Entry Commit 不会涉及 Entry 和 Entry归属的Chain. (Enty Comit 只涉及 Entry的hash,和Entry持有的 ChainID)。如果发现了有服务器恶意拖延 Entry Commit 到 Entry Reveal 的处理, 可以呼吁大家撤回给他的投票。
如果用户没有使用代理, 并重复使用一个Entry Credit Key. 恶意服务器 就能够在他第二次使用的时候, 拒绝接受从那个Entry Credit Key提交的Entry Commit. 这种恶意行为相对比较难发现. 用户只需要用恶意服务器不知晓的 Factoid地址转换, 生成另外的 Entry Credit Key. 再用新的Entry Credit Key提交Entry Commit 就能避开这种攻击.
拒绝服务攻击想要取得成功,需要由每个Federated server 的协作。作恶服务器很容易被发现和排除出去。
不当数据被写入Factom系统
在Factom内进行内容审查是非常困难的,几乎是不可能的。在Directory Block和 Entry Block没有数据将是纯文本。Entry本身可以包含任何信息,一旦发现攻击性的材料, 可以把它删除掉。尽管Factom保证所有信息的安全,并不意味着Factom用户会被迫保存不当的信息.
通过发送SFM消息来排挤掉个别服务器
如果大多数服务器都对某个Federated server 发出了SFM消息, 那么该服务器就会被踢出系统. 实现这种攻击 需要掌握过半的 Federated server. 只要50%的Federated server是诚实的, 系统就是安全的。此外,攻击一旦被察觉, 社区会撤回投给涉嫌攻击的服务器的投票, 它们会被很快踢出系统.
Federated server 没有直接的利益动机才发动这种攻击. 就算有服务器被踢出系统, 也会很快有Audit server晋级替代空缺. 攻击服务器不会因为攻击成功 就能分到更多的报酬. 这是从Bitcoin不同,如果大多数的Bitcoin矿工排除少数旷工,少数旷工失去的收益, 会均分给发动攻击的旷工.
攻击的成本
Federated server的不诚信行为可能导致自己辛苦建立的信用消耗殆尽. 如果服务器对用户进行攻击, 这样的行为是公开可见 有据核查的。可以生成Proof of censorship。服务器攻击其他服务器可能就会失去社区的投票, 被踢出系统。如果的确发生了有人控制了过半的服务器, 还成功发动了攻击. 这样的行为只会给他们自己带来大量的损失. 控制过半的服务器还是需要长期的苦心经营 和消耗很多资源的. 如果Factom系统变得不再安全, 用户必然会离开. (如果服务器被坏人掌控, 社区还可以fork出另一个系统.)
服务器出于利益考虑最需要取悦的是Factom系统的使用者,而不是Factoid的持有者。一旦发生了攻击系统的行为, 侵害到了使用者的利益,大家就会撤回给参与攻击的服务器的投票. 这个情况和比特币里某个矿池算力过半, 大家会把算力移出类似。所不同的是,factom社区用户都能撤回投票, 而不是像比特币里只有旷工才有发言权.
P2P网络割裂了
为了能在Factom系统达到共识, 需要大多数服务器的共同参与。确认一个block, 把Audit server晋升为Federated server 也需要大多数服务器的共同参与. 如果P2P网络被分割,多数服务器无法沟通就没法达成共识。我们在设计Factom系统的时候假设了这种情况不会发生.
Federated server 在达到共识前放置一个Anchor
客户端在扫描Bitcoin blockchain的历史数据同时, 会建立一个 consensus decider 的model。理想情况下,每个10分钟内, 每个 Anchor 只会被一个Federated/Audit server 访问。这有一个小小的不同步的现象。Anchor的放置顺序可能与处理的顺序或者 re-org里的顺序不一样。为了缓解这一问题,anchor需要标记自己的高度,因此它们可以用正确的顺序重新排列。有一种特殊情 Federated server 在达到共识前放置了 Anchor。攻击者可以 anchor 一个非法的的 Directory Block,但客户端需要从DHT下载的数据才能辨别这个非法block。所需下载的数据数量可能被恶意的弄的非常大。
为了缓解这种攻击中,Federated server将主动检测到这个错误。所有服务器能看到比特币transaction stream,因此它们在任何anchor 生效前有一段反应时间。如果发现了anchor 放置出现错误, 诚实的服务器会重新提交正确的anchor。再向错误放置了这个anchor的服务器发出Server Fault Message(SFM). SFM多到一定程度, 肇事服务器就会被踢出出 Federated server pool。
未来的用户在扫描链块的时候就会看到10个或更多的待选 anchor。基于Directory block, 他们需要决定那个anchor是正确的. 到最后, 未来用户在解析 Directory block的时候就不会察觉到曾经发生过的攻击事件。
比特币网络不能保证每个提交的交易最后都会被记录进链块,用户扫比特币链块的时候需要多等几个确认, 确保anchor的确被写入链块了。我们假设过大部分Factom服务器的行为是诚实的,所以只有合法的block才会被签收. 这种攻击只会让用户在扫描链块的时候多扫几个块, 才能确认block的合法性. 影响不大. 通过分析而外信息, 还能进一步降低这类攻击带来的影响。
重复提交已上传过的用户数据 Replay Attack
Factom上所有数据是公开的,已提交过的数据可能被人再次恶意提交到系统里去. 有4种用户生成的数据片段有可能受到这种攻击。
-
Chain create. 这是一个付款消息, 包括创建一个新的链的费用,和创建此链第一个entry的费用. 这个消息含有一个时间戳。时间戳必须接近当前时刻。过于陈旧的Chain create消息会被忽略. 时隔很久被重新提交的 Chain create消息通过时间戳可以很容易地过滤掉。时间戳还用作临时值。单一公钥不允许在同一时间发起两笔交易。只要是时间戳和PUBKEY是一致的交易就被认定为重复交易。
-
Reveal Chain. 只有在Create Chain消息还没完成的时候, Reveal Chain消息才是有效的.只有在有人发出Chain create消息, 打算构建一个chain的时候, 网络上的完全节点才会转发Reveal Chain消息. 本消息不容易受到Replay attach,因为一个链只能被创建一次。
-
Entry Commit。此消息支付Entry的提交费用。它有一个时间戳限定了 Entry 提交的最后期限. 完全节点不需要防范本消息的Replay attack. 消息的超时时间可能是一天左右. 与Chain create 消息类似,单一私钥在一个时间点对一个Entry只能发起一个Entry Commit消息。
-
Entry. 在Entry费用已支付后, Entry消息有可能受到Replay attack。同一个Entry 可支付两次,并被插入到一个链两次。系统没有对谁能给Entry付费加以限制, 因此攻击者可以重复给数Entry 进行付费. 为了避免用户的程序受到Etnry Replay attack, 重复付费的Entry需要被识别出来 避免多次被写入系统。一种方案是让Entry包含一个签名时间戳或计数器,但要由应用程序设计师来实现,不是Factom系统。完全节点将不转发未付费的Entry。
结论
Factom尝试建立一个通用的数据发布系统。本系统数据链的验证连接到比特币区块链上,用户只需要访问他们感兴趣的Chain 的 Directory Block和 Entry block, 他们可以忽略掉大多数Factom数据。
我们相信Factom是一个很有用的工具, 可以帮助大家开发复杂的Distributed Autonomous Application(分布式自治程序)。Factom也将帮助大家创造更安全的和防篡改的可信计算机系统。
感谢比特币的开发者们, 尤其是中本聪,没有他们的付出, 也不会有今天的Factom系统。