此文面向 Web2 工程师,介绍以区块链技术为核心的 Web3 相关基础知识。
主要围绕 blockchain 的基本概念,不涉及具体的币,也不提供任何投资建议。
本文主要关注技术实现和日常操作,不会涉及期货、套利、交易等金融工具的操作。
在讲区块链以前,先介绍一些金融的历史。
货币本应该作为一般等价物,充当交易的媒介。在过去人们会倾向于使用具有普遍稀缺性的天然物质作为货币,后来就逐渐收敛于金银铜这几个具有稀缺性和延展性的贵金属。
再后来随着皇权的扩大,政府逐渐垄断了贵金属的货币发行权,人们对货币的信心,从金属本身的价值,逐步转移到对皇权的信心上。
因为长期的统治和驯化,人们对货币的信心,变成了对皇权的信心。简而言之,人们认可价值五英镑的银币不是因为银币中含银量值五英镑,而是因为硬币上刻着的国王的肖像宣示着它值五英镑。
这一观念的转变,开启了漫长的劣币驱逐良币的通胀史。既然仅仅依靠权威就可以赋予货币价值。 那么政府为了增加收入,就会倾向于铸造越来越劣质的同等面额货币。
整个古代的皇家铸币史,就是一部不断循环上演的通胀与崩溃史。
19 世纪进入近代社会后,金本位货币开始盛行。即货币的发行方承诺持有和货币等价的黄金,人们可以随时用货币按照固定比例兑换黄金。
但是黄金是天然通缩的,而经济总量是不断增长的,导致货币供应不足,货币的价值不断上升,人们会倾向于囤积货币而不是投资生产,从而损害经济发展。
而且更重要的是,金本位的货币极大的限制了政府扩大财政支出的能力。
在金本位的货币制度下,政府要想扩大支出,就必须先囤积更多的黄金。
1933 年 4 月 5 日,罗斯福总统签署了 6102 法案,宣布美国的私人黄金流通非法, 所有私人黄金必须上缴国家。这一举措使得美国政府的黄金储备大幅增加,从而可以发行更多的货币,扩大财政支出。
1971 年尼克松出台一系列金融改革法案,其中就包括暂停美元与黄金的兑换,美元就此脱离黄金本位。
BTC 的发明者中本聪,声称自己的生日是 1975 年 4 月 5 日,正好就是 6102 法案的日期。BTC 每 2016 个区块进行一次难度调整,正好就是 6102 法案的数字相反。
二战后凯恩斯主义横行,认为经济周期虽然不可避免,但是政府可以通过货币政策进行逆周期调节,从而减少经济波动的幅度,化解危机。
最简单的解释就是,当社会经济过热的时候,利用加息等手段收紧货币,从而抑制通胀;当经济低迷的时候,利用降息等手段扩大货币供应,从而刺激经济。
比如疫情期间各国都遇到经济低迷,为了刺激经济,美联储等央行纷纷降息,甚至实行负利率,也被称为 QE(Quantitative Easing,量化宽松)。
人们也似乎已经接受了这个“洗脑”,温和通胀是有利的,因为经济总规模在增长,货币也应该随之增长。 但实际上货币增长的速度远高于经济增长的速度,这也是为什么货币相对于商品,一直在稳定的贬值,即通胀。
哈耶克指出,在亚当·斯密撰写《国富论》,阐述国家的职责所在时,根本没有提到铸币权。 铸币权是近年来国家滥用权力的产物,是导致通胀和经济危机的根源。
货币应该是一种自由市场的产物,仅作为一般等价物作为交易流通所用,而不应该作为一种金融工具,被反过来用来干涉市场。
应该放任第三方自由发行货币,货币选定自己的价值锚定物,人们可以根据自己的需要,自由地选择自己所使用的货币。 哈耶克的这个设想,被一些人认为,是预言了未来的加密货币市场。
1978 年 RSA 算法发表。1979 年 Merkel-Tree。1985 年 ECC。1990 年 Schnorr 发表 Schnorr Signature,但是申请了专利,于 2008 年 3 月过期。
1980 年 Samuel Konkin III 发表《New Libertarian Manifesto》,号召人们利用密码学工具打破政府垄断。
1997 年,《The Sovereign Individual》出版,预言了民族国家的解体,和未来的数字化社会。
1998 年 Timothy May 发表《Crypto Anarchist Manifesto》,提出基于密码学的数字世界无政府主义。
1999 年,Elon Musk 创办电子支付平台 X.com。同一年 Milton Freeman 预言,互联网会减弱政府对人们的控制,而且互联网上一定会出现一种新的,匿名的货币形式。
1992 年《Pricing via Processing or Combatting Junk Mail》 发表,PoW 作为一种反垃圾邮件的方式被提出。
1997 年《Formalizing and Securing Relationships on Public Networks》发表,提出基于密码学的数字资产交易和 smart contract。
1998 Nick Szabo 开发了 BitGold,几乎就是 BTC 的雏形。同样是 1998 年,Wei Dai 在发表 B-Money 时提出了 PoS 的构想。但是它们都没能解决分布式账本下的多花问题(double-spending)。
2008 年 8 月 18 日,在刚刚经历了无锚法币制造了又一次经济危机之后, Satoshi 在 bitcoin.org 上发表了他的白皮书,提出可以通过 PoW 解决分布式账本下的多花问题。
BTC 白皮书的核心目的是解决分布式账本的 double spending,对于 BTC 的很多核心功能都完全没有提及。
Satoshi 和社区一起工作了两年,完善了 BTC 的设计,2009 年 1 月 3 日,第一个 BTC 创世区块(Genesis Block)被挖出。
2010 年 12 月 12 日,Satoshi 留下最后一条公开信息,之后就消失了。
此后社区在不断的争吵中成长,最终大小区块之争矛盾日益激化,2015 年 7 月 30 日,Vitalik Butarin 和一众大区块支持者发表了 Ethereum。
在 BTC 的原教旨支持者看来,Ethereum 只是一个最大的 shitcoin。
Web3 世界言必称“去中心化、分布式、防篡改、抗审查”,其技术核心就是区块链(Blockchain)。
区块链本身的技术原理很简单,身为技术人员,只需要掌握如下知识点:
Hash 虽然已经足以保证数据的完整性,但是当原始数据量较大时,任何更新和校验都需要重算整个数据的 Hash 值,这样效率很低。
而 Merkle Tree 通过将原始数据切片,从而实现高效的部分校验和更新。 (KZG 的功能和 Merkle-Tree 一致,此处就不细说了)
好了,你已经足够了解区块链了😂
每一个区块,最重要的作用就是打包交易记录。
Web3 和 Web2 世界最大的区别,就是 Web3 中并不会有一个中心化的服务器负责运行整个网络。
Web3 的网络,以去中心分布式节点的方式,运行于世界各地。负责运行这些节点的,就是矿工。
矿工的核心职责,除了维持网络的正常运行和通讯外,最重要的就是尽快响应交易者发来的交易请求,将其打包为新的区块,添加到区块链头部。
每一个矿工运行的都是相同的代码,他们互相间是完全对等的(此处暂不考虑质押的情形)。 矿工们所运行的同质化的代码,也就是这个区块链网络的 Protocol。
这个 Protocol 中会详细地定义如何处理交易、如何将交易打包为区块、如何广播区块、如何校验区块、以及如何激励矿工。
比如 BTC 的 protocol 定义,矿工可以在新生成的区块中,通过创建 coinbase trasaction 为自己的账户凭空转入一笔 BTC,这也就是人们俗称的“挖到矿了”。
这是一个 coinbase transaction,挖到矿的矿工为两个地址转入了新诞生的 BTC。
为了尽可能获取更多的利益,矿工们都希望区块链网络能够接受自己的区块作为新的区块链头部。
所以矿工尽可能快和多的打包交易,生成新的区块,然后将这个区块尽可能广的散播出去,如果这个区块被广为接受成为区块链头部的新区块,这名矿工就可以获取挖出新区块所附带的奖励。
当某一个矿工接收到其他矿工发来的区块时,它会根据 Protocol 的规则校验这个区块,如果校验通过,那么它知道自己在本轮竞争中已经落后了。它最明智的选择就是立即停止当前的工作,将收到的区块添加到头部,同时尽最大可能将这个区块广播出去,然后开始新一轮的竞争。
每个矿工都在自顾自的生成自己的区块,然后将其广播出去。 即使所有的矿工都是诚实的,由于网络的延迟,还是有可能在不同的区域, 有不同的区块都被各自隔阂的矿工们接受成为了新的区块链头部。此时,我们就称网络出现了分叉(Fork)。
这种情况类似于分布式系统中的脑裂(Split Brain)。这种情况不会持续太久。 对区块链历史存在歧义的矿工终将相遇,根据 BTC Protocol 的规定,历史最长的链将被认为是正确的链, 其他较短的分叉会被抛弃。那些不幸选择了错误分叉的矿工,相当于白白浪费了自己的算力。
既然每生成一个新区块都可以给自己发奖励,那么矿工们肯定会倾向于疯狂生成新的区块。
在 BTC 的协议中也考虑到了这一点,它通过调整挖矿 PoW 的难度,来让区块的生成速率保持在 10 分钟一个。
1992 年的论文 'Pricing via Processing or Combatting Junk Mail' 最早提及了 PoW 的思想。
PoW 的想法最早被应用于反垃圾邮件领域,简而言之,要想保持匿名性的同时防止滥用,最简单的方式就提高发送者的成本。
比如我要求每个发信者,必须在邮件正文以外,再提供一个 nonce 值。且这个 nonce 值需要满足,hash(content + nonce) 的前缀有 N 个 0。
这样,通过约定 N 的大小,就可以控制发送邮件的成本,从而防止滥发的垃圾邮件。
在 BTC 的每一个区块的 header 中,就存在这么一个 nonce 值。矿工们通过生成这个 nonce 值,使得整个区块的 hash 值满足一定的条件,从而使这个区块能够通过其他节点的校验。
所以 BTC 中的每一个区块,都是在当时历史条件下,一定量算力(十分钟)的证明。前文提到遇到分叉时会选择历史最长的链,这句话其实不正确,准确的说,是选择历史算力最大的链。
通过 PoW 和基于哈希的链表,区块链提供了一种去中心化的信任机制。
但 PoW 也不是完全可靠的,如果有人控制了超过全网 51% 的算力,那么他就可以生成任意的区块, 并且让这个区块成为网络中的最长链,从而迫使其他节点接受这个链。
拒绝转入 PoS 的 Ethereum Classic(ETC) 仍然在使用 PoW,因为网络规模较小,曾多次遭受 51% Attack。
在 Web2 领域,可以使用 RAFT 协议来解决分布式共识问题。 RAFT 的核心在于选主,只有 leader 可以写入数据。而各个节点参与选主的依据,就是自己所持有的数据长度和 term 的大小。
但是 Web2 领域面临的是非拜占庭问题,主要的问题来自于网络的不可靠。 而 Web3 领域面临的是拜占庭问题,即每一个节点都可能是恶意的,会提供假数据。
所以无论是 BTC 还是 Ethereum,生成新区块前不需要选主,而是每个节点各自生成新区块,然后通过竞争去抢占合并入链的机会。
PoW 因其“浪费”大量能源而长期广受诟病,以 Ethereum 为代表的很多新生代的区块链项目都采用了 PoS(Proof of Stake)的共识机制。
PoS 的核心思想是,不再通过算力来竞争生成新区块,而是通过质押 coin 的形式参与激励。 质押了 coin 的人能够成为 validator,负责新区块的生成和校验。
PoS 的优势在于节约能源,但是其安全性和去中心化程度都不如 PoW。 最富裕的成员会垄断网络,而且很多 PoS 的区块链实际上根本无法从算法层面提供足够的健壮性, 更多是靠 stake slashing 作为威胁来抑制恶意行为。
最近很火的一个 PoS 的链就是 solana,它通过类似 RAFT 的选主协议来大幅提高吞吐。但是在拜占庭条件下,选主最大的威胁就是主节点可能作恶。
虽然因为有 validator 的存在使得主节点很难伪造数据,但是主节点可以通过罢工的形式对网络构成 DoS 攻击。
虽然区块链到处吹嘘去中心化分布式,尤其 Ethereum 还经常自称世界计算机。 但实际上,从技术的角度来说,目前的主流区块链的计算能力是很原始和低下的。
虽然每一个节点都是分布式的并行运算,但是它们都是在竞争唯一一个区块上链的份额。 所以从最终的链的角度来看,根本不存在任何的并行,有的只是完全串行化的交易记录。
也就是说,目前的区块链网络,无论有多少节点在运行,其真实的计算能力,只有一个独占的线程。 而且这个线程没有任何并发,没有任何形式的资源竞争,只有完全序列化的计算。
前文谈论的都是较为底层的 blockchain network protocol 和矿工。
而大部分用户实际上是不需要和这些底层的东西打交道的。 每一个 blockchain network,我们称之为 Layer-1 chain,都会定义至少一种 coin, 用户设立激励机制,维持网络的运转。比如 Bitcoin 网络的 BTC,Ethereum 网络的 ETH。
交易者在 Layer-1 chain 上的任何操作,都需要支付一定量的 coin 作为手续费。 这个手续费的去向由 Protocol 规定,可能一部分归矿工,一部分焚毁(burn),一部分收归基建基金。
前文提到,区块链上的每一个区块都是存储交易记录的。 而这些交易记录,就是用户在 Layer-1 chain 上的操作。 所有的这些操作,如果涉及到资产,那么都需要这个资产的所有者使用自己的私钥签名。
所谓的钱包,其实就是一个管理用户私钥的工具。通过私钥可以生成公钥,而钱包地址,往往就是公钥的哈希值。
所以这些虚拟货币实际上并没有“保存”在钱包里,而是以交易记录的形式存在于区块链的历史记录之中, 交易者通过钱包内的私钥,来行使对这些资产的所有权。
每一个私钥,就对应一个钱包地址,也就是区块链上的一个账户。
可以利用简单的几行代码批量生成大量的随机私钥,一般来说一个链上总共允许有 2^256 个账户, 远远多于宇宙中离子的数量,基本是无需担心别人恰好碰撞出了你的私钥地址。
私钥决定了所有资产的所有权,所以一定要妥善保管。但是链上的一切操作都需要使用私钥签名, 越频繁使用的东西越难保密。所以为了增强安全性,我们会将私钥分类为冷钱包和热钱包。
大量的核心资产,存放在冷钱包中,冷钱包的私钥一般离线存储于安全的地方,如保险箱里的手抄纸(纸钱包), 或者固件加密的硬件钱包(硬钱包)。而少量频繁操作的资产存放在热钱包中, 热钱包的私钥暴露风险会更高一些,但是因为资产量少,损失也会更小。
虽然区块链号称去中心化和匿名,但其实追查资金的流向和身份是一件比传统金融系统更容易的事情,也很难保护用户隐私。
链上的每一笔交易都是公开透明的,可以轻易地追查每一笔资金的流向。所以用户最好常备多个地址, 避免让交易地址和提币地址间产生明显的关联。
解除资金关联的的方式一般是通过交易所或混币所。利用交易所提币可以让交易对外人不可见, 仅有交易所能够关联你的地址。利用混币所则是可以对所有人都不可见,但是需要支付更高的手续费。
混币所和交易所的核心原理是一致的,就是将很多人的资产汇合进一个地址,再分别转给各自的收款地址,让外人难以追踪每一笔资金的具体流向。
虽然交易都记录在区块上,但是不同的协议,记载交易的具体形式仍然存在很大区别。目前最主流的两种交易形式就是 UTXO 和 Account。
Ethereum 和传统金融(如银行)都采用账户模式,也就是在持久化的数据中,存储账户和余额。 这样做的优点是实现简单,但是要追踪每一笔钱的去向就变得比较困难。
比如如果一个内鬼悄悄篡改了某个账户的余额,那么这个账户的所有者是很难察觉的。只能通过频繁和繁复的对账,去监控金额的不一致性。
BTC 采用的是 Unspent Transaction Outputs(UTXOs)模式, 每个地址下记录的是尚未消费的入账记录(UTXO),每一个 UTXO 都包含一个金额和其源自的交易(Transaction ID)。
每一个交易都由若干个 inputs 和 outputs 组成,其中 inputs 就是付款方支付的 UTXOs,outputs 就是收款方收到的 UTXOs。 每一笔交易都会销毁输入的 UTXOs 同时诞生一些新的输出的 UTXOs。通过回溯交易历史,每个 UTXO 最终可以追溯到其由矿工挖出时产生的 coinbase 交易(coinbase transaction)。
BTC 的每一笔交易的转账费用也通过其中所包含的 UTXO 数量来确定。
因此,作为私人钱包管理者,应该尽量避免持有大量小额 UTXO。 在网络转账费较低的时候,可以通过将小额 UTXO 批量转账给自己的方式,以较低成本将其融合成一个大额的 UTXO。
如果一个 UTXO 的面额小于转账所需的费用,那么这个 UTXO 实际上已经失去了价值,被称为比特币尘埃(bitcoin dust)。
正因为 BTC 采用了 UTXO 而非账本模式,所以实际上 BTC 并不是严格意义上的 FT(Fungible Token)。 每一个 BTC 之间实际上是有区别的,每一个 BTC 都可以回溯到最初的被挖出矿时的 coinbase transaction 的第 n 笔 output。
BTC 的最小单位被称为 Satoshi,1 BTC = 100,000,000 Satoshi,简称为 Sats。通过 UTXO,每一个 Sats 都是独一无二的来源。
根据其来源,可以将 Sats 按照稀有度分类:
BTC 除了可以通过 UTXO 来建议唯一性外,还可以通过其他的一些技术手段来为 BTC 增加一些特殊的属性。 BTC 允许在交易中携带一些和交易无关的自定义数据,根据这些数据不同的存放位置,可将其称为 Runes(符文) 和 Inscription(铭文)。
Inscription 是 BRC-20 的技术基础
前文介绍了 Layer-1 chain 的基本概念,以及用户如何在链上进行交易。但是光这些是不足以支撑起币圈繁荣的生态的。
本章以 Ethereum 的智能合约为例,介绍以 token 为核心的 layer-2 生态。
根据前文的描述,我们知道 blockchain 实际上是一个分布式的链表,可以用来永久存储信息。而且这个链由矿工所运行的计算节点来维护。
那么,给这个链在存储之外,增加一点点的计算功能,使得矿工在打包交易时,也能顺带运行一些代码,这些代码可以修改和存储链上的数据,这就是智能合约。
Smart Contract 这个概念最早由 Nick Szabo 在 1970 年提出,所以也别觉得 Ethereum 是什么伟大的创造。
Ethereum 上,每个矿工节点都会运行一个 EVM(Ethereum Virtual Machine),这个虚拟机可以运行一种叫做 Solidity 的高级语言编写的智能合约。
部署智能合约,就像是一次交易,其代码将会永久存储在链上,并且会生成一个地址,其他的用户可以通过这个地址来调用这个智能合约。
智能合约就是一个函数方法(methods),可以理解为面向对象的一个 class。它可以声明一些内部变量,这些变量会存储于链上,用户可以通过调用方法来修改这些变量。
EVM 实际上执行的是 OpCode,可以理解为 EVM 的汇编。
Solidity 编写的高级代码会先编译为 OpCode 再发不到链上供 EVM 运行。 所以虽然区块链是完全透明的,但是并不代表所有的合约都是开源的,未开源的合约只能通过 OpCode 去逆向。
基于智能合约,我们就可以发行自己的币了, 为了和 layer-1 的 coin 相区分,利用智能合约发行的币我们称为 layer-2 的 token。
其实原理非常简单,你声明一个 class,然后声明一些内部变量,其中一个变量是 mapping,用来保存 user address -> balance
的账本。
然后再设计一些方法,比如用于转账的 transfer
,用户创造货币的 mint
,用户查询余额的 balanceOf
等,这个 smart contract 就相当于定义了一种全新的 token。
简而言之,就是在 EVM 内创建一个账本,记录每个人(一个钱包地址),有多少钱(token)。 一个合约对应一种 token,合约的地址就是 token 的地址。
为了方便交互,Ethereum 基金会定义了 ERC-20 标准,只要你的合约包含如下 methods,那么你的 token 就可以作为一种标准 ERC-20 FT 被其他的钱包和交易所所支持。
totalSupply()
balanceOf(account)
transfer(to, amount)
allowance(owner, spender)
approve(spender, amount)
transferFrom(from, to, amount)
contract ERC20 {
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
function mint(address _to, uint256 _value) public onlyOwner {
balanceOf[_to] += _value;
totalSupply += _value;
emit Transfer(address(0), _to, _value);
}
function transfer(
address _to,
uint256 _value
) public returns (bool success) {
require(balanceOf[msg.sender] >= _value, "Insufficient balance");
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function balance() external view returns (uint256) {
return balanceOf[msg.sender];
}
}
代码非常简单易懂,没有并行和并发,不需要考虑任何数据冲突。
所谓的挖矿,就是调用一下合约的 mint
方法,然后编辑账本,给某个地址增加一点余额。
所谓的转账,就是调用一下合约的 transfer
方法,然后编辑账本,给一个地址减少一点余额,给另一个地址增加一点余额。
只要你的 contract 符合 ERC-20 标准,就可以将合约地址作为一个 FT Token,登记到任何支持 ERC-20 的平台或钱包。
我发行了一种名为 laisky 的 ERC-20 token
利用合约地址 0xe5e908B3Afe47F5CC75b5eC8CA843cCb135AdB6c
,可以将其倒入到小狐狸 MetaMask 中
所以 ERC-20 说白了就只是一个 mapping,记录每一个地址的余额,仅此而已。
它的缺点是,每一个 token 都是一样的,没有任何区别。为了能更好的和独特的资产建立联系,Ethereum 基金会定义了 ERC-721 标准,用来定义一种独特的 token,也就是 NFT(Non-Fungible Token)。
ERC-721 实际上就是比 ERC-20 增加了一个 _tokenId
,现在每一个 token 都是唯一的了。而且每一个 token 都会存储一份 metadata,用来保存一个 JSON 格式的数据,这个数据可以包含 token 的名字、描述、图片等信息。
{
"name": "NFT Laisky 01",
"description": "This is an example NFT URI pointing to a resource.",
"image": "https://s3.laisky.com/public/head.png",
"external_url": "https://blog.laisky.com/about/?lang=en",
"attributes": [
{
"trait_type": "Color",
"value": "Blue"
},
{
"trait_type": "Size",
"value": "Medium"
}
]
}
实际上现在基本已经不需要你手写合约代码,有很多开源框架可以直接集成和使用。
编写合约可以使用 openzeppelin,在 Wizard 上鼠标点点就可以一键生成代码: https://docs.openzeppelin.com/contracts/5.x/wizard
测试和部署合约可以使用 Foundry: https://book.getfoundry.sh/
ERC-20/ERC-721 的每一次交易只能涉及一个 token,而且每一个合约也只能发行一种 token,这在 GameFi 这种需要大量不同类型的 token 的场景下是不够的。 所以人们提出了 ERC-1155 标准,它可以同时发行多种 token,每一种 token 都是独立的,但是可以通过一个合约来管理。 而且可以在一次交易中同时转账不同数目且不同类型的 tokens。
ERC-721 虽然具有了唯一性,但是它不可拆分。这一特性对于数字藏品而言是合理的,但是在金融领域,比如为了实现分红或共同所有权,我们需要一种可以拆分的 NFT token。
所以人们提出了 ERC-3525 标准,这一标准定义的 token 也称为 SFT,它的 Token 既有唯一的 _tokenId
,又可以被无限拆分。
智能合约一旦部署,就无法修改。如果重新部署一个新合约,既会导致旧合约所有内部数据的丢失,也会导致合约地址的变更,这对于用户来说是不可接受的。
为了解决这个问题,人们提出了基于 Proxy 的合约升级方案。这种方案的核心思想是, 将合约的代码和数据分离,面向客户的是负责保存数据的 Proxy 合约, 但是 Proxy 中不包含任何逻辑代码,只是将所有的请求,都转发给实现业务代码的 Implementation 合约。
当需要升级时,只需要部署一个新的 Implementation 合约,然后将 Proxy 合约的指针更新为新的 Implementation 合约地址即可。
https://remix.ethereum.org/ 提供了本地的 EVM,可以开发和调试 solidity 代码和智能合约。
如果你想实际发布上线的话,可以先尝试 Sepolia 测试网,功能和主网完全一样,不过 Coin 使用 SETH,比真正的 ETH 便宜很多很多,还有很多水龙头(Faucet)可以免费领取。
实在不够用的话,也可以找我要一些。
前面提到过,整个 Ethereum 其实是一个单线程,当你的合约代码被执行时,实际上就是全网唯一在被运行的代码。 这一特性虽然让吞吐量变得非常糟糕,但是让编程变得无比简单,而且还能实现一些很深情的功能。
闪电贷(Flash Loans)就是借助这一特性所实现的神奇功能之一。你可以在一个 method 里,完成放贷、投资和还款的全部流程。在函数结束前,检查一下用户是否已经还款,如果没有,则调用 revert 回滚本次调用。
放贷、投资、还款一气呵成,债务人永无跑路的可能,这种奇迹只有加密货币和智能合约能够实现。
// Function to request a flash loan
function flashLoan(
IERC3156FlashBorrower receiver,
uint256 amount,
bytes calldata data
) external {
// Ensure the amount requested is at least the minimum
require(amount >= minimumBorrowAmount, "Amount below minimum borrow");
// Calculate the fee
uint256 fee = (amount * feePercentage) / 10000;
// Transfer the requested amount to the receiver
token.transfer(address(receiver), amount);
// Execute the receiver's operation
bytes32 result = receiver.onFlashLoan(msg.sender, address(token), amount, fee, data);
// Verify that the receiver has returned the borrowed amount plus the fee
require(token.balanceOf(address(this)) >= amount + fee, "Insufficient funds returned");
// Ensure the receiver's operation returned the expected hash
require(result == keccak256("ERC3156FlashBorrower.onFlashLoan"), "Invalid return value");
// Transfer the fee to the contract owner
token.transfer(msg.sender, fee);
}
预言机,名字很玄乎,实际上就是同步链外数据到链上,从而让智能合约拥有了获取链外数据的能力。
简而言之就是智能合约不能请求外部数据,所以需要找到一种方式让链外数据能够被保存到链上,这个解决方案就是 Oracle。
Oracle 的代码逻辑就是一个存储 + 异步任务引擎,接口定义如下
// 这是一个很标准的异步任务流程,发起任务,拿到 taskID,然后轮询 taskID 直到任务完成。
//
// 当某个 consumer(其他的智能合约)需要 offchain 数据时,就请求 Oracle 的 request 接口,
// 创建一个异步任务,拿到 requestID。Oracle 本身也就是一个智能合约,也不能请求外部,
// 所以不可能实时处理请求,只能等链外的组件喂数据,所以只能以异步任务的模式来实现。
//
// 一般一个 Oracle 只负责某一类的任务,比如获取当前币价,或者获取一个随机数。
// 任务创建后会 emit 一个 Event,链外的基础设施监听到这个事件后就可以开始喂数据。
function request() external onlyOwner returns (uint256 requestId)
// fulfill 函数就是给 offchain 的基础设施喂数据用的,
// offchain 通过 Event 事件了解到有新的任务被创建了,然后准备好所需的数据,
// 用 fulfill 函数把数据喂给 Oracle,Oracle 再把数据和 requestID 一起保存到内部的一个 mapping 变量里,
// 这就实现了将链外数据保存到链上。
function fulfill(uint256 _requestId, uint256[] memory _randomWords) internal override
// consumer 在创建完任务后,轮询该接口获取任务的执行结果,也就是所请求的 offchain data
function getRequestStatus(uint256 _requestId) external view returns (uint256 paid, bool fulfilled, uint256[] memory result)
区块链上的一切操作都会上链,可以通过区块链浏览器(Explorer)来查看所有的历史交易记录,每一个 layer-1 都会有自己的 explorer。
前面简单介绍了币圈的技术基础。相信很多人可能已经摩拳擦掌想要试试了,本章简单介绍一些生态和基本的安全防护意识。
俗话说币圈完全是一个黑暗森林,这里面充满了各种各样的陷阱和坑,无数的黑客在蠢蠢欲动,一定要小心保护好自己的资产。
一般人上手币圈的第一步就是注册一个交易所账户,然后通过交易所来购买自己的第一枚币。
交易所本质上实际上就很不 Web3,从区块链的角度来看,整个交易所,实际上就是某个人的钱包地址。 交易所本质上就是一个 Web2 的中心化应用,所以也被称为 CEX(Centralized Exchange)。
你在交易所的账户就是这个应用的数据库中的一条记录,你在上面的所有买卖,也只是交易所数据的一些变化。 只有当你进行链上提币的时候,你的资产才会真正的从交易所的钱包中转移到你的钱包中。
依靠交易所,对于普通用户来说,要比自己持有链上资产更安全。 但是交易所账户主要需要防范跑路(rug)和盗号。
RUG 不用多说,因为你的 coin/token 实际上都是存在交易所的钱包里的,这个钱包的控制人完全可能卷款跑路。 一般来说,很多大交易所会通过多签(multi-sign)的形式提高安全性,但这也并不是万无一失的。
如果你的浏览器 Cookie 被盗,黑客可以伪装成你在交易所内操作,虽然因为无法完成 2FA 导致黑客无法直接提币或转账, 但是黑客可以通过对敲(wash trade)的方式,将你的资产利用市场交易的方式转移到他的账户中。
每一个 Layer-1 chain 都会有自己的协议,所以往往也会有自己的钱包,比如 BTC 的 Bitcoin Core,ETH 的 MetaMask,Arweave 的 ArConnect。
这些钱包不仅仅是一个管理私钥的工具,还是和链上交互的工具,可以通过钱包来签名交易,调用智能合约等。
一般来说,钱包的主要功能可以分为如下几个:
低风险操作,网站会读取你的钱包地址,用来展示你的资产和交易记录。
这是个只读操作,而且实际上网站也没法通过 Connect 识别你的身份。毕竟只需要你提供地址,而你可以提供任何人的地址。
网站请求你使用钱包私钥对某条消息进行签名,这是一个高风险操作,因为签过名后,网站就可以确认私钥的所有者认可了这条消息。 最常见的签名就是登录网站时的签名,其功能类似于 FIDO/WebAuthn。
在执行签名时,一定要认真检查签名的消息内容。最坏情况下,这是一个授权交易, 某个合约请求你授权它花费你的资产,一旦你签了名,那么拿到这个签名的黑客,就可以把这个合约内你关联的全部资产都转走。
签名这个机制的设计是非常傻逼的(原谅我说脏话),设计这东西的人非蠢即坏。 它既不防御 MITM 攻击,也不防御 Replay 攻击,而且还会让用户误解为签名是安全的。
更可恶的是很多网站还在使用盲签名,也就是将消息内容经过哈希处理后再交给用户签名,用户完全无从得知自己签了什么东西。
你可以在钱包内执行转账,
转账最大的风险,就是输错地址。一旦你输错了地址,那么这笔钱就会永远消失在链上,无法找回。
黑客也会故意误导你,试图让你错误输入地址,一般采取两种方法:
很多钱包,比如 MetaMask,仅仅会显示地址的首尾几个字符,用户可能也习惯简单看看首尾就确认了,这是非常危险的。
Approve 可以授权某个合约能够花费你的资产,这是一个非常危险的操作。
比如你去 OpenSea 上拍卖一个你持有的 NFT,OpenSea 就会让你的钱包发起一个 Approve 操作,让你授权它能够操作你的 NFT。 Approve 操作后,虽然看上去你的资产还在你的钱包里,但是实际上这个合约已经可以随时转走你的资产。
养成习惯时常去 https://revoke.cash/ 这样的网站检查自己钱包的授权,及时撤销不必要的授权。
Permit 是一个大坑,极端危险,简而言之就是 Sign 和 Approve 的结合体。
Permit 可以让你以签名的形式,授权对方花费你的资产。然后对方可以利用这个签名,去调用你的钱包合约,花费你的资产,而且整个花费的过程,都不会出现在你钱包地址的交易历史之中,可谓窃取无痕。
它看上去是一个签名,实际上是一个 Approve,偷你钱你还看不出来。
CEX 上所有的交易都是基于加密货币,一般不会支持直接使用法币(fiat)进行买卖。 所以用户需要先将自己的法币兑换成加密货币,兑换的方式往往是 C2C 交易。
也就是由交易所撮合,提供一个卖家,你将法币转入到卖家的账户,卖家将对应的加密货币转入你在 CEX 的账户。 出入金最怕的就是黑钱,黑钱具有传染性,一旦某个账户被认定为黑钱,那么一段时间内所有和这个账户有过交易的账户都会被冻结。
一般建议尽量不要使用微信/支付宝进行出入金操作,尽量使用不常用的银行卡。
既然提到了 CEX,也简单提一下 DEX(Decentralized Exchange)。
AMM(Automated Market Maker)是 DEX 的一种实现方式,它不需要撮合,而是通过一种算法来自动调整交易对的价格。 本质上其实就是一个智能合约,它通过合约能够自动交易这个 layer-1 上的所有 layer-2 token。
LP(Liquidity Provider)将两种货币存入到 AMM 合约中形成一个交易对,AMM 保证这两种货币的乘积不变,一种货币被买入得越多,它就会自动变得越贵。 AMM 通过自动调整杠杆,来保证交易对的价格能够和市场保持一致。LP 可以赚取交易手续费。
AMM 的一个缺点是 Inpermanent Loss,也就是当交易对的价格发生变化时,LP 的资产价值会发生变化,这种变化是永久的,而且往往表现为净损失。
比如 LP 存入了 1 BTC 和 100 USDT,交易所中有 10BTC 和 1000 USDT,LP 持股 10%。 假设 BTC 价格上涨了4️倍到了 400USDT,交易所中剩余 5BTC 和 2000USDT。如果 LP 此时提款,可以获得 0.5BTC + 200U 合计 400U。
但如果 LP 不参与交易所,仍旧持有 1 BTC + 100 USDT,那么他的资产价值是 500U,参与 AMM 会让 LP 亏本,这就是 Permanent Loss。 可以通过交易手续费,来缓解 LP 的无常损失。
推荐国内 SlowMist 团队维护的《区块链黑暗森林自救手册》
https://github.com/slowmist/Blockchain-dark-forest-selfguard-handbook/blob/main/README_CN.md
前面讲到目前以 BTC 和 Ethereum 为代表的区块链项目存在的两个阻碍发展的问题:
针对上述两点,这章以 Arweave 为例,介绍一些新的技术方案,也许可以完全解决上述问题。
此前介绍过好几次,这里就不再详细介绍了。
Arweave 作为一个 Layer-1,它的每一个区块都是用户提交的数据。通过鼓励矿工存储稀少的区块,从而实现让所有的区块都有尽可能多的备份。
以相对低廉的价格实现了永久数据存储,目前 Arweave 已经成为 NFT 等链外数据存储的首选。
上传时一次付费,永久存储
注册可获得 100 MB 的 Arweave 免费永久存储,使用起来和 s3/minio 一样轻松。上传完成获得 KeyID
后,可以拼接在 https://ario.laisky.com/<YOUR_FILE_ID>
查看。
注意,上传后一般需要等到 3-5 分钟,才能通过网关访问到这个文件。
比如你正在看的这个 slide,也被我上传到了 arweave: https://ario.laisky.com/Gc5yvj1lqkXUEAJSjsa7_l_LdxyXyW91BB0XGaM7XgQ#/
后端工程师熟悉的微服务,服务于服务间的调用非常难以追溯,所以 DDD 中也提出了 Event Sourcing 的概念,依赖消息队列和消息存储,将所有的服务调用都记录为事件,以便于追溯。
每一个微服务作为 stateless 的服务,只负责按顺序处理消息队列中的消息,并且产生新的消息。 平台的管理者可以通过重放消息队列中的消息,来重现整个系统在任何时刻的状态。
这里插入这段内容,是因为 Arweave AO 的设计和 Event Sourcing 有异曲同工之妙。
Event System only Appends, All transactions are Asynchronous
AO 是 Arweave 团队最新提出的去中心化,分布式并行计算架构,它的核心思想是将计算和存储分离, 以 Arweave 为存储基础,在上层构建以消息单元、计算单元、调度单元为核心的 AO 计算网络。
AO 的架构简单的说,就是每一个人,都可以运行一个 VM,这个 VM 会接收到消息,然后处理消息,并且发送消息,本质上就像是微服务中的一个服务。 它可以有状态,但是它的状态并不需要上链,因为它的状态是可以通过消息队列来重现的。
举个实际的例子,在 AO 中实现一个 ERC-20 代币。你完全可以在本地运行一个 EVM,然后运行 ERC-20 的合约代码。 只不过所有的数据都存储在本地就足够了,而不需要上链。
任何和这个代币的交互,都可以转发到你的计算节点上进行处理。如果网络上还有其他的 ERC-20 合约,完全可以在其他的计算节点上并行处理,互不干扰, 这和 Ethereum 的全网竞争一个单线程的处理能力是完全不同的。
如果你的计算节点挂掉了也没关系,调度器会自动从网络中找到其他可用的计算节点,然后通过重放相同的代码和消息,来重现你挂掉前的最终状态。
这就是 Event Sourcing 的思想,也是 AO 的核心,在 AO 中称为 holographic state mechanism(全息状态机制)。
ARIO 是 Arweave 的网关层,基于 Arweave 的存储,提供了一系列的数据访问服务:
前文提到 Ethereum 所具有的很多局限性,比如存储昂贵,计算能力有限,交易速度慢等等。 也介绍了 Arweave 和 AO 的一些解决方案。
不过 Ethereum 社区本身也是有意识到这些问题的,他们为提高吞吐、存储和安全性,也有很多长远的规划。