merkleTree验证白名单 / 学习智能合约#64

最近FTX爆了,据称是挪用了用户资金!不管是什么技术,最后还是回到了灵魂拷问:利和义,你取哪样?!吃瓜群众们又在那想验证资金的办法,怎么自证清白之类的。其实我想说,这只关乎人性,无关技术。如果真的关乎技术,那应该有N种办法。

这里提这N种办法中的一种:merkletree证明。现在常用于白名单验证:比如证明我是否在名单里呢?电影中辛德勒有个小本本会把名单记下来,很容易查到谁在他的名单里。我们也要把名单记下来,然后一个个去查么?如果人少,这样做没问题。但人一多,特别是gas费很贵的情况下,要在链上维护你的小本本,不是个好办法。最佳的办法是用merkletree证明。

merkletree.jpg

如上图所示,我们可以把名单做成一个树状的结构,两两一组,逐级上联,最后形成一个根。我们只需把最后的根记在链上即可。这有点类似于:我们只需要字典的检索部分即可,真正的内容可以通过检索去查。那么,这里汲及到merkletree是如何证明一个数据是真实在名单里的,其实只要用到哈希函数。

const { MerkleTree } = require('merkletreejs')
const keccak256 = require('keccak256')

let whitelist = [
    "0xc11cb63bdca7627f74ec69c14612522fdb7a0c20",
    "0x1499b8312e6fe58b5d1164d4eccf795367c9e1d3",
    "0x55f510be6ab4c7e07ec6ee637aa83574975d6898",
    "0xcc2fe3615a45fcacc3534d53be41c6543a0a312d",
    "0xee226379db83cffc681495730c11fdde79ba4c0c",
    "0x55f510be6ab4c7e07ec6ee637aa83574975d6898",
    "0x18b2a687610328590bc8f2e5fedde3b582a49cda",
    "0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"
]

const leafNodes = whitelist.map(addr => keccak256(addr));
const merkletree = new MerkleTree(leafNodes, keccak256, {sortPairs: true});
console.log(12, "leafNodes",leafNodes)

const rootHash = merkletree.getRoot().toString('hex');
console.log("rootHash is: ", rootHash);
console.log(merkletree.toString());

console.log("--------verify------------");
const hexProof = merkletree.getHexProof(keccak256("0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"));    
console.log(133, hexProof);      // 如上图所示中的数据[B, C, D, E]
const res =  merkletree.verify(hexProof, keccak256("0x5B38Da6a701c568545dCfcB03FcB875f56beddC4"), rootHash) 
console.log(124,res);  

以上给出了构建merkletree的方法和验证的过程,细心体会下,貌似也不太难。回到链上去证明,过程类似,方法略有区别,这里也展示下:

function verify(
    bytes32[] memory proof,
    bytes32 root,
    bytes32 leaf
) internal pure returns (bool) {
    return processProof(proof, leaf) == root;
}

function whitelist(bytes32[] calldata _merkleProof) public{
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
    require(verify(_merkleProof, merkleRoot, leaf), "Invaild proof.");
}

solidity的实现还算简单。这样在链上只需维护merkletree的根哈希(merkleRoot),链下则维护真正的名单,只是这个维护的办法不是辛德勒的小本本而是merkletree的结构。