在Ropsten测试链上放了一个验证区块Hash值的合约。
如果我们要在乙太坊的智能合约内取得过去某个区块的Blockhash,EVM有提供内建函式
blockhash(uint blockNumber),可以取得最近256个区块的Hash值。若是超过256个区
块,内建函式就无能为力了。取而代之的,我们可以要求使用者把区块Hash值及证明传
入合约函式,由合约验证传入的区块Hash值是否正确。
合约位址及程式码见Etherscan:
https://ropsten.etherscan.io/address/2c003df99cab1064ed93e273f54275ee8e24393a
另外有个悬赏合约给找出伪阴性(?)案例的板友1个Ropsten ETH,请见文章最后。
(虽然Ropsten ETH到水龙头拿就有了 XD)
=============================================================================
MMR结构
合约的原理是将区块Hash值用Merkle Mountain Range结构储存
Merkle Mountain Range(MMR)结构就是多棵不同高度的Full Merkle Tree
G
/ \
/ \
C F
/ \ / \
A B D E H
/ \ / \ / \ / \ / \
00 01 02 03 04 05 06 07 08 09 10
如图,11个Blockhash值组成3棵Tree,分别是
Block#00-#07的8个区块组成高度3的Tree
Block#08-#09的2个区块组成高度1的Tree
Block#10的1个区块组成高度0的Tree
合约储存这3棵Tree的Root(称为Peak),也就是G、H、10。
当新的Blockhash值加入MMR结构时,会发生合并现象。
G
/ \
/ \
C F J
/ \ / \ / \
A B D E H I
/ \ / \ / \ / \ / \ / \
00 01 02 03 04 05 06 07 08 09 10 11
Block#11加入后,Block#08-#11合并为1棵高度2的Tree,
合约内储存的内容变成G、J两个Peak。
MMR的证明和验证与一般的Merkle Tree证明流程相同,
要证明00,则额外传入[01,B,F]做为证明,
合约内进行3次hash后,将结果与G比对即可验证。
基本的原理是这样,至于技术细节的说明还在写,若想研究细节请先看程式码。
做了一个简单的网页接口,可以看到MMR结构的现况,产生证明和进行验证:
https://ayukawayen.github.io/MerkleMountainRange/
(建议开Metamask连,Metamask要连到Ropsten链)
=============================================================================
MMR Token
合约需要定期将新区块的Hash值写入MMR结构。
传送Tx至合约位址会呼叫合约的fallback function,触发更新流程。
这个动作需要花费gas,根据更新者所花费的gas值,给予等量的MMR Token做为回报。
任何人都可以传送Tx来协助维护合约,Tx不需要任何input data,Gas limit建议设为
330000。
以下是一个范例Tx的ID,总共花了237,682的gas,获得202,670个MMR Token:
0xff230cc54fe3837a074b99d4056e44b4fd4348b08852728418aba170077ad9f2
MMR Token可以用来支付验证手续费。
其他合约在链上呼叫合约的verifyOnChain()函式时,每次验证收取6000个MMR Token做
为手续费,链下呼叫verify()函式时则不需要手续费。
也可以直接用Ropsten ETH向合约换MMR Token,避免需要验证却无法取得Token的情况。
=============================================================================
悬赏合约
合约位址与程式码同样见Etherscan:
https://ropsten.etherscan.io/address/a702611a1b4cd6149df1bac72d3462e286d3d918
UI还没写好,熟悉Etherscan操作的人可以先使用Etherscan和合约互动。
只要能输入1个blockNumber、2个blockHash及证明,符合以下条件:
两个blockHash都不是0
两个blockHash值不相同
两个blockHash都通过MMR验证
就能取得合约里的所有Ropsten ETH。
两次验证需要12000个MMR Token,底下开放推文,留下Ropsten位址,我会转12000个
Token过去,approve给悬赏合约后,呼叫challengeWithToken()进行挑战。
=============================================================================
如果有在Ropsten上开发智能合约,有验证过去区块的需求的话,也可以试用看看。
不过程式码是未经审查的,可能有bug。