前阵子 Bybit 价值 1.4B 的资产被盗,堪称史上最大金额的盗窃案。黑客所使用的盗窃技术其实并不复杂,某种意义上更说明整个区块链业界的安全观念仍然非常欠缺。
区块链的本质就是保存不可修改的数据块,Ethereum 的 EVM 就是运行在这些 append-only 的数据存储层之上的计算机。其中可以被运行的程序称为合约(Contract)。因为合约一旦被部署上链后,它的调用地址、代码就无法修改,只有数据可以被修改。为了让合约能够在不变更地址的前提下实现升级,人们想出了一个办法就是
从函数调用的角度来考虑,这相当于是 proxy 函数调用了 implementation 函数的代码,但是修改的却是 proxy 函数的数据。这种特殊的调用在 EVM 中称为
然而,这次出事的就是这个 proxy-implementation 的设计。黑客部署了一个恶意的合约,这个合约有一个伪装成转账接口的方法,虽然看上去像是转账
Update: Safe 已经承认了,是因 Safe 的前端文件被黑客替换,导致了这一事件。 #blockchain
ref:
* 我曾写过一篇 web3 的简易入门,可以搜索 Upgradable 一节
* 关于 safe-wallet 被黑的分析
区块链的本质就是保存不可修改的数据块,Ethereum 的 EVM 就是运行在这些 append-only 的数据存储层之上的计算机。其中可以被运行的程序称为合约(Contract)。因为合约一旦被部署上链后,它的调用地址、代码就无法修改,只有数据可以被修改。为了让合约能够在不变更地址的前提下实现升级,人们想出了一个办法就是
proxy-Implementation
模式。也就是部署两个独立的合约,逻辑代码通过 implemenation 合约部署,然后再部署一个保存用户数据的 proxy 合约,proxy 合约作为面向用户的入口层,一旦部署就永久使用,以保证调用地址的稳定。proxy 合约中有一个 master 变量,可以理解为是一个指针,指向 implementation 合约的地址,实际的逻辑代码都是通过调用 implementation 合约来完成的。从函数调用的角度来考虑,这相当于是 proxy 函数调用了 implementation 函数的代码,但是修改的却是 proxy 函数的数据。这种特殊的调用在 EVM 中称为
delegateCall
,即在调用者的上下文中执行被调用者的代码逻辑。这一设计通过对数据和逻辑的拆分,让每个面向用户的 proxy 合约保持了地址和数据的一致性,而实现逻辑的 implementation 合约可以像插件一样随时更替。然而,这次出事的就是这个 proxy-implementation 的设计。黑客部署了一个恶意的合约,这个合约有一个伪装成转账接口的方法,虽然看上去像是转账
transfer(address,uint256)
,但是其实际功能是替换 proxy 合约中的 master 属性,也就是替换其所指向的 implementation 合约地址。然后黑客生成了一个对这个恶意合约的调用 transfer("0xbDd077f651EBe7f7b3cE16fe5F2b025BE2969516", "0")
,这个交易看上去像是一个无害的零额转账,但是因为设置了 operation=1
即启动了 delegateCall
,实际上是执行了恶意合约的修改 proxy 合约中 master 属性的逻辑。很可惜,因为 Safe 的网站前端代码被黑客替换,Bybit 的三位管理员都没能注意到这次调用中的 operation=1
这个高度危险的设置,可能误以为是一次零额转账而签署了交易,黑客从而成功将 proxy 合约所指向的 implementation 修改为指向到自己的恶意合约,完全替换了 proxy 合约的逻辑,最终完成了对 1.4B 资产的盗窃。Update: Safe 已经承认了,是因 Safe 的前端文件被黑客替换,导致了这一事件。 #blockchain
ref:
* 我曾写过一篇 web3 的简易入门,可以搜索 Upgradable 一节
* 关于 safe-wallet 被黑的分析
有三个主要费用 network、computing、action。network 包含消息发送的费用,一般由 sender 付,钱包里一般消息的 value 和 network fee 是分别支付的,而合约中默认是从消息的 value 中支付的。computing 是执行合约的费用,action 是合约发送 external message 的费用,主要就是 emit。(此外还有 storage fee 先不管了)
ctx.value
代表的是 inflow msg 携带的 value,sender 已经付过了 network fee,还没支付 computing 和 action。合约执行后会扣除 computing,执行完成后如果有需要发送的 outflow 消息,那么再扣除 action fee。可以把
ctx.value
理解为税前收入,而且你无法知道会收多少税(computing & action fees)。补充:FunC 里是可以精确计算 fwd_fee 的,但是感觉 tact 不太行,可参考:
* https://docs.ton.org/develop/smart-contracts/fee-calculation
* https://github.com/ton-blockchain/stablecoin-contract/blob/main/contracts/gas.fc
* https://tonviewer.com/config#24
myBalance() - ctx.value
代表合约执行前的余额。可以用 nativeReserve(myBalance() - ctx.value, ReserveExact);
来保护合约余额不被用户消息所消耗。但是你在合约代码中极难通过控制
ctx.value
来计算你能操作的 inflow 余额,因为 computing 和 action 的开销是很难计算的。比如如果你想要把剩余的 inflow value 全部转走,可行的办法是用 nativeReserve
锁定不想转走的余额,然后再用 SendRemainingBalance
mode 发送一条 value 为 0 的消息。SendRemainingBalance
会转走未被 nativeReserve
锁定的全部金额,按照上文描述,也就是所有剩余的 ctx.value
。但是 emit 具体花多少钱?我还不知道怎么算,目前是估计一个经验值,测试网是
0.007
,你可以多锁定 0.01
给 emit。 #blockchainprev: https://t.me/laiskynotes/318
next: https://t.me/laiskynotes/324
最近都在学习 TON 开发,积累了一些经验。TON 有很多独特的设计和开发范式,值得先记个小笔记,主要以 Ethereum/EVM 作对比。这是基于我目前的理解,不一定正确,有兴趣欢迎讨论。
1. 所有的调用都是消息,所有的消息都是异步的。也就是说,你没法同步取得跨合约调用的结果。
2. 每次调用的费用是非确定性的,而且因为整个调用是异步的,没法预知调用的总费用。所以只能先给一个相对较高的手续费,然后等合约执行完后退还余款。TON 的费用的精确控制非常困难,我花了很多时间在这上面,这个以后可以单独讲一篇,简而言之就是整个调用链应该有一个唯一的起点和唯一的终点。唯一的起点是因为交易发起者只有一个人,唯一的终点是因为要汇集所有消息的余额。
注意,交易执行的总费用是很可能超过用户支付的 input value 的,换言之合约在用自己的余额给用户交易付费,要特别小心!
3. 合约在链上不会永久存在,部署 code 和 data 后状态会成为 active,但是同时会开始计费缴纳租金。租金从合约余额扣除,扣完后经过一段时间后合约的数据会被删除,仅保留哈希。用户可以重新上传数据恢复合约。如果一段时间后未恢复,所有的链上数据都会被销毁。之所以这样做是因为 TON 链上交互非常依赖子合约,子合约的数量会随着用户量倍增,必须通过限制合约存活时间来控制链上数据量。
4. 合约不会直接和用户交互,而是会用用户的钱包地址给用户部署一个子合约,然后主合约和这个子合约交互。子合约里会有两个属性,master 指向主合约,owner 指向用户的钱包合约地址。这样做的好处是,因为子合约代码是主合约部署的,那么子合约的行为就是确定性的。所以 TON 的合约开发类似于工厂模式,你首先需要编写一个主合约,然后需要给你所有的交互对象各自编写一个子合约。
5. 主合约内不保存任何用户数据,仅保留必须的全局变量。这是和 EVM 最显著的一个区别。拿 ERC-20 代币来说,EVM 合约需要存储一个巨大的用户账本。而 TON 的主合约什么都不存,只需要给用户部署一个子合约,然后将用户持有的代币信息保存在子合约里即可。因为子合约的代码是主合约部署的,所以行为完全可控和可信。用户间转账只需要子合约间互相通信即可,双方可以通过校验对方的地址来确定合约代码的完整性,毕竟合约地址本质上就是合约代码和初始化数据的哈希,而初始化参数往往就是 master 和 owner 的地址。
6. 我目前的开发组合是 blueprint + tact + tonkeeper。开发体验非常痛苦,缺乏必要的文档和示例,等我有空整理一篇博客。 #blockchain
prev: https://t.me/laiskynotes/296
next: https://t.me/laiskynotes/319
1. 所有的调用都是消息,所有的消息都是异步的。也就是说,你没法同步取得跨合约调用的结果。
2. 每次调用的费用是非确定性的,而且因为整个调用是异步的,没法预知调用的总费用。所以只能先给一个相对较高的手续费,然后等合约执行完后退还余款。TON 的费用的精确控制非常困难,我花了很多时间在这上面,这个以后可以单独讲一篇,简而言之就是整个调用链应该有一个唯一的起点和唯一的终点。唯一的起点是因为交易发起者只有一个人,唯一的终点是因为要汇集所有消息的余额。
注意,交易执行的总费用是很可能超过用户支付的 input value 的,换言之合约在用自己的余额给用户交易付费,要特别小心!
3. 合约在链上不会永久存在,部署 code 和 data 后状态会成为 active,但是同时会开始计费缴纳租金。租金从合约余额扣除,扣完后经过一段时间后合约的数据会被删除,仅保留哈希。用户可以重新上传数据恢复合约。如果一段时间后未恢复,所有的链上数据都会被销毁。之所以这样做是因为 TON 链上交互非常依赖子合约,子合约的数量会随着用户量倍增,必须通过限制合约存活时间来控制链上数据量。
4. 合约不会直接和用户交互,而是会用用户的钱包地址给用户部署一个子合约,然后主合约和这个子合约交互。子合约里会有两个属性,master 指向主合约,owner 指向用户的钱包合约地址。这样做的好处是,因为子合约代码是主合约部署的,那么子合约的行为就是确定性的。所以 TON 的合约开发类似于工厂模式,你首先需要编写一个主合约,然后需要给你所有的交互对象各自编写一个子合约。
5. 主合约内不保存任何用户数据,仅保留必须的全局变量。这是和 EVM 最显著的一个区别。拿 ERC-20 代币来说,EVM 合约需要存储一个巨大的用户账本。而 TON 的主合约什么都不存,只需要给用户部署一个子合约,然后将用户持有的代币信息保存在子合约里即可。因为子合约的代码是主合约部署的,所以行为完全可控和可信。用户间转账只需要子合约间互相通信即可,双方可以通过校验对方的地址来确定合约代码的完整性,毕竟合约地址本质上就是合约代码和初始化数据的哈希,而初始化参数往往就是 master 和 owner 的地址。
6. 我目前的开发组合是 blueprint + tact + tonkeeper。开发体验非常痛苦,缺乏必要的文档和示例,等我有空整理一篇博客。 #blockchain
prev: https://t.me/laiskynotes/296
next: https://t.me/laiskynotes/319
总算把 TON, The Open Network 的白皮书看完了。这个白皮书里描写了一个非常具有野心的技术架构,可以认为它把目前还处于计划中的区块链技术都全部作为基础设施实现了,提供了目前业界最高性能和兼容性的基建。我在这里先简单记个笔记,之后有空写篇博客水文。
当我们提到 TON 时,指的不是一个链,而是一系列链在不同维度组合。首先 TON 有一个扮演全局状态的 master chain,但是这个链只负责状态,不负责具体的 COIN 和账本。在 master chain 之上,可以支持 2^32 个 work chain,每一个 work chain 都可以有自己独立的 COIN 和 protocol,只要这个 work chain 定期将自己的状态提交到 master chain 即可。目前 TON 有一个 work chain,就是 TON coin chain。我们可以认为,TON 天生就自带 layer-2 结构,而且这个 layer-2 还是无限扩展的。
每一个 work chain 还可以根据负载继续动态拆分,最多拆分为 2^60 个 shard chain。理论上每一个账户都可以独占一个 shard chain,每一个账户独立维护自己的 COIN/TOKEN 余额,每一个账户间的交易都可以完全并行。账户与账户间通过异步消息进行传递,消息在 shard chain 间传递的路径为 log_16(N) - 1,其中 N 为 shard chain 的数量。假设目前有 4000 个 shard chains,最多中转两次就能完成消息传递。shard chain 为 TON 提供了近乎无限的并行度,使其成为目前市面上最快的 layer-1,吞吐量理论无上限。
TON 采用 PoS 共识,work chain 的区块经过所有 validators 的校验后可以进入 master chain。validators 还会拆分成小组,构成 shard chain 的 validators。任何一个 validator 可能会被分配给多个 shard chains,这些校验工作可以完全并行运行。除此外还有 fisherman 可以对历史区块提出挑战。
为了尽可能避免硬分叉,TON 所有链上的区块实际上也是一个称为 vertical chain 的子链,只是正常情况下它们是只有一个区块的链。当需要对历史进行矫正时,无需硬分叉,而是在对应的区块上再提交一个新区块即可。
可以看出 TON 提供了近乎无限的并行度和兼容性,难怪称之为 Blockchain of Blockchains。甚至理论上说,目前业界所有的区块链,都可以作为 work chain 运行在 TON 的网络之上。 #blockchain
prev: https://t.me/laiskynotes/281
next: https://t.me/laiskynotes/318
当我们提到 TON 时,指的不是一个链,而是一系列链在不同维度组合。首先 TON 有一个扮演全局状态的 master chain,但是这个链只负责状态,不负责具体的 COIN 和账本。在 master chain 之上,可以支持 2^32 个 work chain,每一个 work chain 都可以有自己独立的 COIN 和 protocol,只要这个 work chain 定期将自己的状态提交到 master chain 即可。目前 TON 有一个 work chain,就是 TON coin chain。我们可以认为,TON 天生就自带 layer-2 结构,而且这个 layer-2 还是无限扩展的。
每一个 work chain 还可以根据负载继续动态拆分,最多拆分为 2^60 个 shard chain。理论上每一个账户都可以独占一个 shard chain,每一个账户独立维护自己的 COIN/TOKEN 余额,每一个账户间的交易都可以完全并行。账户与账户间通过异步消息进行传递,消息在 shard chain 间传递的路径为 log_16(N) - 1,其中 N 为 shard chain 的数量。假设目前有 4000 个 shard chains,最多中转两次就能完成消息传递。shard chain 为 TON 提供了近乎无限的并行度,使其成为目前市面上最快的 layer-1,吞吐量理论无上限。
TON 采用 PoS 共识,work chain 的区块经过所有 validators 的校验后可以进入 master chain。validators 还会拆分成小组,构成 shard chain 的 validators。任何一个 validator 可能会被分配给多个 shard chains,这些校验工作可以完全并行运行。除此外还有 fisherman 可以对历史区块提出挑战。
为了尽可能避免硬分叉,TON 所有链上的区块实际上也是一个称为 vertical chain 的子链,只是正常情况下它们是只有一个区块的链。当需要对历史进行矫正时,无需硬分叉,而是在对应的区块上再提交一个新区块即可。
可以看出 TON 提供了近乎无限的并行度和兼容性,难怪称之为 Blockchain of Blockchains。甚至理论上说,目前业界所有的区块链,都可以作为 work chain 运行在 TON 的网络之上。 #blockchain
prev: https://t.me/laiskynotes/281
next: https://t.me/laiskynotes/318
- https://docs.attest.org/docs/welcome
简单学习了一下 Ethereum Attestation Service(EAS)。根据宣传,这是一个使用标准化接口统一诸多认证的服务,用于简化开发者和用户的认证流程。
实际上,看下来感觉原理其实很简单,说白了就是个在链上存储和展示 JSON 的服务。开发者首先提交一个 schema,也就是这个 JSON 的字段的定义。然后用户(attester)选择一个 schema,填写内容,用自己的私钥签名,发送上链,就完成了认证。
EAS 并不保证这个 attestation 是正确的,只保证它是被签名的,同时提供一个链上的存储,然后用户还可以随时撤销这个 attestation。验证这个 attestation 是否正确是开发者的责任,我觉得可惜的是,EAS 的设计并没有留出给 attestation 标记 verified 属性的地方,导致它并没有完成 attest -> verify 这个完整的流程。
可以看出,实际上 EAS 的逻辑非常简单,一个简单的合约就能实现。 #blockchain
简单学习了一下 Ethereum Attestation Service(EAS)。根据宣传,这是一个使用标准化接口统一诸多认证的服务,用于简化开发者和用户的认证流程。
实际上,看下来感觉原理其实很简单,说白了就是个在链上存储和展示 JSON 的服务。开发者首先提交一个 schema,也就是这个 JSON 的字段的定义。然后用户(attester)选择一个 schema,填写内容,用自己的私钥签名,发送上链,就完成了认证。
EAS 并不保证这个 attestation 是正确的,只保证它是被签名的,同时提供一个链上的存储,然后用户还可以随时撤销这个 attestation。验证这个 attestation 是否正确是开发者的责任,我觉得可惜的是,EAS 的设计并没有留出给 attestation 标记 verified 属性的地方,导致它并没有完成 attest -> verify 这个完整的流程。
可以看出,实际上 EAS 的逻辑非常简单,一个简单的合约就能实现。 #blockchain
最近简单学习了一下区块链中的 cross chain bridge。
它的功能类似于传统金融机构中的自动清算银行 (ACH, Automated Clearing House),ACH 就是负责跨行转账的中转机构。Bridge 就是区块链世界力求去中心化的 ACH。
区块链中的每一个链都是一个自成体系的网络,链与链之间是无法直接通讯的,当链上的资产希望跨链流通时,有两个转换途径:
1. 通过中心化的交易所(CEX),将资产从一条链上提现,然后在另一条链上取款;
2. 通过跨链桥,将资产从一条链上锁定,然后在另一条链上解锁。
跨链桥从功能上来说和 CEX 有相似之处,但它旨在实现更高的去中心化和减少信任假设。一般通过一套自动运行的 DAO(Decentralized Autonomous Organization)来管理跨链桥的运行。跨链桥在两个链(来源链和目标链)上都有部署合约,在目标链上会有自己的代币。用户在来源链上将资产转账给跨链桥的合约,然后跨链桥会在目标链上发行相应数量的代币给用户。在目标合约放款前,会运行一些列的自动化检测和审计程序,这些程序可以分布式部署和运行,然后共同维护一个多签名钱包,当所有的检查程序都通过后,各自用自己的私钥生成一个多签名,然后使用该多签名让目标链上的合约通过 mint 为用户生成新的目标代币。
上面只是描述了多签名跨链桥这一种形式,其他还有各式各样的很多实现形式。但是就目前来说,依赖一个可信第三方(custodian)仍然是无法避免的,本质上跨链桥仍然是一个中心化的,存在信任风险的工具,未来也许有可能通过零知识证明等技术来实现完全去中心化的跨链桥。
美国货币总核查办公室(OCC)的代理审计长 Michael J. Hsu 在 2022 年时也曾发言提到,cross chain bridge 是加密货币世界的基石(尤其各种稳定币都通过跨链桥实现跨链流通),而其对于黑客攻击非常脆弱,需要加强监管。 #blockchain
next: https://t.me/laiskynotes/258
它的功能类似于传统金融机构中的自动清算银行 (ACH, Automated Clearing House),ACH 就是负责跨行转账的中转机构。Bridge 就是区块链世界力求去中心化的 ACH。
区块链中的每一个链都是一个自成体系的网络,链与链之间是无法直接通讯的,当链上的资产希望跨链流通时,有两个转换途径:
1. 通过中心化的交易所(CEX),将资产从一条链上提现,然后在另一条链上取款;
2. 通过跨链桥,将资产从一条链上锁定,然后在另一条链上解锁。
跨链桥从功能上来说和 CEX 有相似之处,但它旨在实现更高的去中心化和减少信任假设。一般通过一套自动运行的 DAO(Decentralized Autonomous Organization)来管理跨链桥的运行。跨链桥在两个链(来源链和目标链)上都有部署合约,在目标链上会有自己的代币。用户在来源链上将资产转账给跨链桥的合约,然后跨链桥会在目标链上发行相应数量的代币给用户。在目标合约放款前,会运行一些列的自动化检测和审计程序,这些程序可以分布式部署和运行,然后共同维护一个多签名钱包,当所有的检查程序都通过后,各自用自己的私钥生成一个多签名,然后使用该多签名让目标链上的合约通过 mint 为用户生成新的目标代币。
上面只是描述了多签名跨链桥这一种形式,其他还有各式各样的很多实现形式。但是就目前来说,依赖一个可信第三方(custodian)仍然是无法避免的,本质上跨链桥仍然是一个中心化的,存在信任风险的工具,未来也许有可能通过零知识证明等技术来实现完全去中心化的跨链桥。
美国货币总核查办公室(OCC)的代理审计长 Michael J. Hsu 在 2022 年时也曾发言提到,cross chain bridge 是加密货币世界的基石(尤其各种稳定币都通过跨链桥实现跨链流通),而其对于黑客攻击非常脆弱,需要加强监管。 #blockchain
next: https://t.me/laiskynotes/258
https://mirror.xyz/firstfan.eth/kGa6jFpYm9qvW3tdlEAdwSEa841xS8DEEvrEyR3uUmI
币圈餐具,老哥用 ArConnect 使用的密码库批量生成 AR 地址转账,转飞了价值 10 万 USDT 的 AR。
原因是密码库有 BUG,首次调用没问题,连续多次调用的话,会因为脏数据而产生不一致的输出。必须每次调用都重新初始化。(以后各位测试密码库 SDK 的时候,要注意多写个 case 测试批量调用下的一致性)
好消息是,因为暴跌,现在只值 8 万 U 了… #blockchain
币圈餐具,老哥用 ArConnect 使用的密码库批量生成 AR 地址转账,转飞了价值 10 万 USDT 的 AR。
原因是密码库有 BUG,首次调用没问题,连续多次调用的话,会因为脏数据而产生不一致的输出。必须每次调用都重新初始化。(以后各位测试密码库 SDK 的时候,要注意多写个 case 测试批量调用下的一致性)
好消息是,因为暴跌,现在只值 8 万 U 了… #blockchain
- blog: https://blog.laisky.com/amend/web3-101/
- slides: https://s3.laisky.com/public/slides/web3-101.slides.html#/
做了一个面向新人的 Blockchain/Web3 技术入门分享,内容很浅,主要是相关概念的介绍,希望能帮助新人快速入门。各位有兴趣的话可以看看,有什么疑问或建议也欢迎在评论里讨论。 #blockchain
- slides: https://s3.laisky.com/public/slides/web3-101.slides.html#/
做了一个面向新人的 Blockchain/Web3 技术入门分享,内容很浅,主要是相关概念的介绍,希望能帮助新人快速入门。各位有兴趣的话可以看看,有什么疑问或建议也欢迎在评论里讨论。 #blockchain
https://x.com/LaiskyCai/status/1797491021565378737 给 AO 的官方视频搞了个机翻字幕,有兴趣的可以看看,我认为对背景介绍的比较全面了。
如果你是后端程序员,那么其实一句话就可以解释:就是 DDD 里的 event-sourcing,不过现在所有的 event 都上链持久化了。 #blockchain
prev: https://t.me/laiskynotes/239
next: https://t.me/laiskynotes/281
如果你是后端程序员,那么其实一句话就可以解释:就是 DDD 里的 event-sourcing,不过现在所有的 event 都上链持久化了。 #blockchain
prev: https://t.me/laiskynotes/239
next: https://t.me/laiskynotes/281
花了两天时间总算看懂了 KZG 证明😢。
如果你熟悉 Merkel-tree 的话,那么可以很容易理解,KZG 的功能完全一致,试图利用一个很小的承诺(Commitment)保证一大堆数据的完整性。在 Merkel-tree 中,Commitment 就是它的树根(Root)。
KZG 的优点在于,当你需要验证消息的完整性,比如某个点确实存在于这个数据集之中时,它所需的计算是常量级,而 Merkel-tree 需要提供所有相关路径的 HASH 值,计算复杂度为
具体的证明过程就不在这里细说了,详见笔记 https://laisky.notion.site/Kate-Zaverucha-Goldberg-KZG-Constant-Sized-Polynomial-Commitments-Alin-Tomescu-30c1406d97fa4ecaa5190827d65faa9b?pvs=4
#blockchain #crypto
如果你熟悉 Merkel-tree 的话,那么可以很容易理解,KZG 的功能完全一致,试图利用一个很小的承诺(Commitment)保证一大堆数据的完整性。在 Merkel-tree 中,Commitment 就是它的树根(Root)。
KZG 的优点在于,当你需要验证消息的完整性,比如某个点确实存在于这个数据集之中时,它所需的计算是常量级,而 Merkel-tree 需要提供所有相关路径的 HASH 值,计算复杂度为
O(logN)
。所以在数据量较大时,KZG 会更有优势。具体的证明过程就不在这里细说了,详见笔记 https://laisky.notion.site/Kate-Zaverucha-Goldberg-KZG-Constant-Sized-Polynomial-Commitments-Alin-Tomescu-30c1406d97fa4ecaa5190827d65faa9b?pvs=4
#blockchain #crypto
https://laisky.notion.site/Solidity-delegatecall-usage-and-pitfalls-3833eadc06ae4528bfa23d194ea8d3cb?pvs=4
前文介绍了 solidity 中变量的持久化存储方式。而我们之所以关心变量的存储位置(slot),就是因为在使用 Proxy 模式时,需要在合约间共享变量,而合约间变量的共享方式就是通过 slot 对齐的。
合约一旦发布就是只读不可更改的,如果想要修复 bug 或升级功能而发布一个新的合约,那么就会得到一个新的地址。为了在保持地址不变的同时更改合约的代码,最常见的实现方法就是使用 Proxy-Implementation 模式。发布一个 Proxy 合约作为接口,地址永远不变。但是实际的业务代码指向 Implementation 合约,implementation 合约可以不断地升级迭代,只要同步更新 Proxy 合约的指向即可。
实现 Proxy 这一功能,依赖于 solidity 的
按照目前最推荐使用的 UUPS Proxy 模式(UUPS 简而言之就是将升级 Implementation 的
此文详细介绍了
前文介绍了 solidity 中变量的持久化存储方式。而我们之所以关心变量的存储位置(slot),就是因为在使用 Proxy 模式时,需要在合约间共享变量,而合约间变量的共享方式就是通过 slot 对齐的。
合约一旦发布就是只读不可更改的,如果想要修复 bug 或升级功能而发布一个新的合约,那么就会得到一个新的地址。为了在保持地址不变的同时更改合约的代码,最常见的实现方法就是使用 Proxy-Implementation 模式。发布一个 Proxy 合约作为接口,地址永远不变。但是实际的业务代码指向 Implementation 合约,implementation 合约可以不断地升级迭代,只要同步更新 Proxy 合约的指向即可。
实现 Proxy 这一功能,依赖于 solidity 的
delegatecall()
,这个函数可以让 Implementation 使用 Proxy 的上下文,即内存数据和存储。而这个数据共享的前提,就要求 Proxy 和 Implementation 的变量声明按照 slot 进行严格的对齐。按照目前最推荐使用的 UUPS Proxy 模式(UUPS 简而言之就是将升级 Implementation 的
upgrade()
method 也放在 Implementation 内定义),为了减少 Proxy 和 Implementation 间的变量冲突,一个最佳实践就是不要在 Proxy 内声明任何非必需的变量,理论上 Proxy 内仅需要定义 owner(设置管理者) 和 implementation(设置 Implementation 的地址) 两个变量即可。所有的业务数据,全部仅在 Implementation 内定义。当 Proxy 使用 delegatecall() 调用 Implementation 时,Proxy 的存储空间会被共享给 Implementation,所以虽然变量仅定义在 Implementation 内,但实际上全部存储于 Proxy 的存储空间内。当 Implementation 迭代升级时,新版本的 Implementation 内的变量声明必须严格对齐于旧版本,仅允许在尾部添加新变量,不允许修改或删除旧变量(append-only)。此文详细介绍了
delegatecall()
时,Proxy 和 Implementation 间变量对齐的注意事项和案例。 #blockchain #evmhttps://laisky.notion.site/Bitcoin-s-UTXO-Model-What-Is-It-and-How-to-Manage-UTXOs-River-d92673a0172841429ec5f998d49f101f?pvs=4
区块链的分布式账本有两个主流实现方式:账户模式(account model)和 UTXO model。
Ethereum 和传统金融(如银行)都采用账户模式,也就是在持久化的数据中,存储账户和余额。这样做的优点是更简单,但是要追踪每一笔钱的去向就变得比较困难。
BTC 采用的是 Unspent Transaction Outputs(UTXOs)模式,每个地址下记录的是尚未消费的入账记录(UTXO),每一个 UTXO 都包含一个金额和其源自的交易(Transaction ID)。每一个交易都由若干个 inputs 和 outputs 组成,其中 inputs 就是付款方支付的 UTXOs,outputs 就是收款方收到的 UTXOs。每一笔交易都会销毁输入的 UTXOs 同时诞生一些新的输出的 UTXOs。通过回溯交易历史,每个 UTXO 最终可以追溯到其由矿工挖出时产生的 coinbase 交易(coinbase transaction)。
综上所述,实际上每个人账户中的每一笔 BTC 都不是完全同质化的,它们可以通过 coinbase 交易 ID 和输出编号(output number)进行唯一识别。正是利用这一点,构建了 BRC-20/BRC-100/BRC-420 等 FT/NFT/铭文生态。
BTC 的每一笔交易的转账费用也通过其中所包含的 UTXO 数量来确定。因此,作为私人钱包管理者,应该尽量避免持有大量小额 UTXO。在网络转账费较低的时候,可以通过将小额 UTXO 批量转账给自己的方式,以较低成本将其融合成一个大额的 UTXO。如果一个 UTXO 的面额小于转账所需的费用,那么这个 UTXO 实际上已经失去了价值,被称为比特币尘埃(bitcoin dust)。 #blockchain
区块链的分布式账本有两个主流实现方式:账户模式(account model)和 UTXO model。
Ethereum 和传统金融(如银行)都采用账户模式,也就是在持久化的数据中,存储账户和余额。这样做的优点是更简单,但是要追踪每一笔钱的去向就变得比较困难。
BTC 采用的是 Unspent Transaction Outputs(UTXOs)模式,每个地址下记录的是尚未消费的入账记录(UTXO),每一个 UTXO 都包含一个金额和其源自的交易(Transaction ID)。每一个交易都由若干个 inputs 和 outputs 组成,其中 inputs 就是付款方支付的 UTXOs,outputs 就是收款方收到的 UTXOs。每一笔交易都会销毁输入的 UTXOs 同时诞生一些新的输出的 UTXOs。通过回溯交易历史,每个 UTXO 最终可以追溯到其由矿工挖出时产生的 coinbase 交易(coinbase transaction)。
综上所述,实际上每个人账户中的每一笔 BTC 都不是完全同质化的,它们可以通过 coinbase 交易 ID 和输出编号(output number)进行唯一识别。正是利用这一点,构建了 BRC-20/BRC-100/BRC-420 等 FT/NFT/铭文生态。
BTC 的每一笔交易的转账费用也通过其中所包含的 UTXO 数量来确定。因此,作为私人钱包管理者,应该尽量避免持有大量小额 UTXO。在网络转账费较低的时候,可以通过将小额 UTXO 批量转账给自己的方式,以较低成本将其融合成一个大额的 UTXO。如果一个 UTXO 的面额小于转账所需的费用,那么这个 UTXO 实际上已经失去了价值,被称为比特币尘埃(bitcoin dust)。 #blockchain
https://laisky.notion.site/Protocol-Specification-of-the-ao-Computer-9226ca385cd74a2c8716efb64704ac19?pvs=4
学习了 Arweave 生态的新项目 AO,我觉得这轮牛市大浪淘金能够看到给世界带来真正进步的技术,可能只有 ZK 和 AO。
L1 基于 Arweave,这是一种能够永久存储大量数据的区块链(区块纺)协议,具体细节这里不多说了。
AO 是基于 Arweave 的二层应用,在永久存储的基础上,构建起了一个消息的分发和处理机制。AO 负责消息的分发和存储,而不负责提供计算,它对计算节点只有一个要求:确定性。
所以这东西很像是微服务领域的 event-driven,每一个计算节点就相当于一个微服务业务节点,AO 网络会永久存储下所有的消息,而且每一个计算节点的消息都是有序的。所以每一个计算节点的任务,就是按照顺序处理完所有的消息,并且进行相应的输出,输出也是消息,也会被永久存储。
AO 的强大之处就在于,计算节点是分布式 + 并行的,每个人都可以运行自己的计算节点,每一个计算节点会有一个唯一的 process id,然后以这个 process id 为地址进行消息传输。这就为网络提供了近乎无限的并行计算能力。
从 Ethereum 的角度来说,它虽然也有无数个 EVM 在并行运行,但是最终能上链的数据实际上只来自一个 EVM,换句话说,你可以把整个 Ethereum 网络视为一个单线程的程序,这一特性为 EVM 提供了确定性和一致性,但恶果就是运算效率和吞吐极其低下。
AO 的每一个计算节点是并行计算的,而且计算节点是无状态的(计算任务是可以有状态的),并不需要存储,所以回避了分布式下的数据一致性问题。实际上计算机节点的任何时刻的状态,都可以用同一段代码和消息输入进行重现,所以计算节点根本不需要持久化存储任何中间数据。
可以期待,在 Arweave 大存储和 AO 大计算的加持下,AR 生态将会给区块链世界带来飞跃性的基础设施进步。 #blockchain
next: https://t.me/laiskynotes/249
学习了 Arweave 生态的新项目 AO,我觉得这轮牛市大浪淘金能够看到给世界带来真正进步的技术,可能只有 ZK 和 AO。
L1 基于 Arweave,这是一种能够永久存储大量数据的区块链(区块纺)协议,具体细节这里不多说了。
AO 是基于 Arweave 的二层应用,在永久存储的基础上,构建起了一个消息的分发和处理机制。AO 负责消息的分发和存储,而不负责提供计算,它对计算节点只有一个要求:确定性。
所以这东西很像是微服务领域的 event-driven,每一个计算节点就相当于一个微服务业务节点,AO 网络会永久存储下所有的消息,而且每一个计算节点的消息都是有序的。所以每一个计算节点的任务,就是按照顺序处理完所有的消息,并且进行相应的输出,输出也是消息,也会被永久存储。
AO 的强大之处就在于,计算节点是分布式 + 并行的,每个人都可以运行自己的计算节点,每一个计算节点会有一个唯一的 process id,然后以这个 process id 为地址进行消息传输。这就为网络提供了近乎无限的并行计算能力。
从 Ethereum 的角度来说,它虽然也有无数个 EVM 在并行运行,但是最终能上链的数据实际上只来自一个 EVM,换句话说,你可以把整个 Ethereum 网络视为一个单线程的程序,这一特性为 EVM 提供了确定性和一致性,但恶果就是运算效率和吞吐极其低下。
AO 的每一个计算节点是并行计算的,而且计算节点是无状态的(计算任务是可以有状态的),并不需要存储,所以回避了分布式下的数据一致性问题。实际上计算机节点的任何时刻的状态,都可以用同一段代码和消息输入进行重现,所以计算节点根本不需要持久化存储任何中间数据。
可以期待,在 Arweave 大存储和 AO 大计算的加持下,AR 生态将会给区块链世界带来飞跃性的基础设施进步。 #blockchain
next: https://t.me/laiskynotes/249
https://taresky.com/crypto-arbitrage
虽然我不是从这篇文章入行的,但是 Taresky 这篇文章写得很好值得推荐。
自从开始套利后,感觉眼界都打开了。以前我对金融市场的理解是很肤浅的,只知道那些低买高卖,高风险高收益的交易者(traders),这些人是市场上的明星。我总是暗暗揣度自己,自认不能承受那么大的风险,也没那么聪明,这钱不是我能赚的。
但实际上金融市场上除了交易者外还有另外一帮人,称为套利者(Arbitrageurs)。交易者会用自己的本金持有商品,并且赌商品的价值会上涨;或者做空头,反正都是用自己的本金去赌商品价值的波动。但是套利者是完全另一个思路,套利者不能接受本金的损失,而只是把本金当着抵押品,去尽可能地赚取手续费或差价等一切蝇头小利。
拿文中所提到的做空对冲套利来说,其实逻辑很简单:
1. 你把自己的本金分成两半,一半做空,另一半购币
2. 如果币价上涨,你的做空合约亏本,但是购入的币价值上涨,本金不变
3. 如果币价下跌,你的做空合约赚钱,但是购入的币价值下跌,本金不变
只要币价的波动没有剧烈到让你的做空被爆仓,你的本金就是安全的,不亏不赚。你实际上赚取的,是期货交易中,做多方付给做空方的手续费,这个手续费会随着市场的交易热度动态调整,一般来说实现 10~40% 的年化收益是比较容易的。15% 的年化如果能持续五年,那就是翻一番,耐心,不要激动,做时间的朋友。
类似的套利逻辑还有很多,套利也不是没有风险的,比如交易所跑路、稳定币发行方跑路、剧烈波动导致爆仓等等,但是这个风险的概率远远小于交易者所承受的风险,比如你可以通过多交保证金以降低本金收益的方式减少爆仓风险,而长期收益可能会比大多数交易者都高。
此外,我感觉,币圈主流币的套利风险可能比传统金融更小。我认为 BTC 的存在是有客观需求的,而且 BTC 的币价在可预期的未来里是不会归零的,即使腰斩,只要耐心等待几年,总能等来下一波的牛市。而传统金融市场上的股票、期货、债券,有可能真的就原地破产,本金归零。而 shitcoins 也是真的可能随时归零的,所以我不会持有小币。
以上不构成投资建议,只是分享一些个人的感想。 #blockchain
虽然我不是从这篇文章入行的,但是 Taresky 这篇文章写得很好值得推荐。
自从开始套利后,感觉眼界都打开了。以前我对金融市场的理解是很肤浅的,只知道那些低买高卖,高风险高收益的交易者(traders),这些人是市场上的明星。我总是暗暗揣度自己,自认不能承受那么大的风险,也没那么聪明,这钱不是我能赚的。
但实际上金融市场上除了交易者外还有另外一帮人,称为套利者(Arbitrageurs)。交易者会用自己的本金持有商品,并且赌商品的价值会上涨;或者做空头,反正都是用自己的本金去赌商品价值的波动。但是套利者是完全另一个思路,套利者不能接受本金的损失,而只是把本金当着抵押品,去尽可能地赚取手续费或差价等一切蝇头小利。
拿文中所提到的做空对冲套利来说,其实逻辑很简单:
1. 你把自己的本金分成两半,一半做空,另一半购币
2. 如果币价上涨,你的做空合约亏本,但是购入的币价值上涨,本金不变
3. 如果币价下跌,你的做空合约赚钱,但是购入的币价值下跌,本金不变
只要币价的波动没有剧烈到让你的做空被爆仓,你的本金就是安全的,不亏不赚。你实际上赚取的,是期货交易中,做多方付给做空方的手续费,这个手续费会随着市场的交易热度动态调整,一般来说实现 10~40% 的年化收益是比较容易的。15% 的年化如果能持续五年,那就是翻一番,耐心,不要激动,做时间的朋友。
类似的套利逻辑还有很多,套利也不是没有风险的,比如交易所跑路、稳定币发行方跑路、剧烈波动导致爆仓等等,但是这个风险的概率远远小于交易者所承受的风险,比如你可以通过多交保证金以降低本金收益的方式减少爆仓风险,而长期收益可能会比大多数交易者都高。
此外,我感觉,币圈主流币的套利风险可能比传统金融更小。我认为 BTC 的存在是有客观需求的,而且 BTC 的币价在可预期的未来里是不会归零的,即使腰斩,只要耐心等待几年,总能等来下一波的牛市。而传统金融市场上的股票、期货、债券,有可能真的就原地破产,本金归零。而 shitcoins 也是真的可能随时归零的,所以我不会持有小币。
以上不构成投资建议,只是分享一些个人的感想。 #blockchain
https://laisky.notion.site/Solidity-layout-and-access-of-storage-state-variables-simply-explained-6fb8c4eaca0d4004b361e4358257fa92?pvs=4
详细介绍了 solidity storage 的存储结构。每一个 smart contract 都有独立的 storage,由 2^{256}-1 个 slots 组成,每个 slot 的长度为 32 bytes。
在 solidity 中声明的 variables 都会在 slot 中从头开始逐一存放,它们存储的位置称为 slot index。
比较奇葩的是 dynamic variables,如 array、mapping 和长度超过 32 bytes 的 string。拿 array 来说,其 slot 内存放的只是其长度,它的成员数据实际上是连续存放在另外一组随机的 slots 里的,这组 slots 的首地址由
理论上,dynamic variables 是有可能和其他的数据的 slot 发生冲突的,但是考虑到 2^256 是一个足够巨大的空间,一般认为超过 2^100 就足够满足密码学的碰撞安全性要求了,ECC-256 的安全等级也就是 2^128,如果你不担心自己的私钥被别人碰撞出来,那么也不需要担心 dynamic variables 和其他 slot 碰撞。
#blockchain #evm
next: https://t.me/laiskynotes/245
详细介绍了 solidity storage 的存储结构。每一个 smart contract 都有独立的 storage,由 2^{256}-1 个 slots 组成,每个 slot 的长度为 32 bytes。
在 solidity 中声明的 variables 都会在 slot 中从头开始逐一存放,它们存储的位置称为 slot index。
比较奇葩的是 dynamic variables,如 array、mapping 和长度超过 32 bytes 的 string。拿 array 来说,其 slot 内存放的只是其长度,它的成员数据实际上是连续存放在另外一组随机的 slots 里的,这组 slots 的首地址由
keccak256(slot index)
计算而来。理论上,dynamic variables 是有可能和其他的数据的 slot 发生冲突的,但是考虑到 2^256 是一个足够巨大的空间,一般认为超过 2^100 就足够满足密码学的碰撞安全性要求了,ECC-256 的安全等级也就是 2^128,如果你不担心自己的私钥被别人碰撞出来,那么也不需要担心 dynamic variables 和其他 slot 碰撞。
#blockchain #evm
next: https://t.me/laiskynotes/245
https://laisky.notion.site/Solidity-c48cc6d6c9924dd5a912e19edaef756c?pvs=4 最近学习 solidity 的一些简单笔记,作为一个 Web2 开发者,主要是厘清很多基础概念,实际的代码是不难的。 #blockchain