Solidity 中的私有变量不私有

0x01 看下面被极度简化过的合约代码

// SPDX-License-Identifier: MIT

pragma solidity =0.8.19;

contract Auth {

    string private secret;

    constructor(string memory secret_) {
        secret = secret_;
    }
}

这个代码里声明了一个私有状态变量 secret,部署合约的时候我往里面传了一个值,这个变量的值是可以被读到的么?

0x02 玻璃罩子

有时候感觉智能合约就像是放在区块链这个公开透明的玻璃罩子里面,对这个玻璃罩子外面的人来说,里面是没有任何隐私可言的,不管智能合约的状态变量是 private 的还是 public 的,我们都可以很轻松的读取里面的值。

这里的 private 只对同在这个罩子里的其它智能合约起作用,也就是说,如果一个状态变量声明为 private, 其它智能合约是不能读取这个值的,目前的 SLOAD 指令只能读取当前智能合约的值。

0x03 如何读取

其实我们有不止一种办法来读取到私有状态变量 secret。
最常见的,我们可以使用 getStorageAt,我已经把这个简单合约部署到 BSC 测试网上,地址为 0x4332401C3Ea3aeebF9813dFA3Fe3Ee581ef8572d
下面是我的操作步骤:

  1. 连上节点
> geth attach https://rpc.ankr.com/bsc_testnet_chapel
Welcome to the Geth JavaScript console!

instance: erigon/2.39.0/linux-amd64/go1.19.3
at block: 28080565 (Thu Mar 16 2023 09:19:09 GMT+0800 (CST))
 modules: debug:1.0 erigon:1.0 eth:1.0 net:1.0 rpc:1.0 trace:1.0 txpool:1.0 web3:1.0

To exit, press ctrl-d
  1. 调用 eth.getStorageAt
> eth.getStorageAt("0x4332401C3Ea3aeebF9813dFA3Fe3Ee581ef8572d",0)
"0x2431303000000000000000000000000000000000000000000000000000000008"

"0x2431303000000000000000000000000000000000000000000000000000000008" 就是私有状态变量 secret 的值,因为这个变量是字符串类型,可以使用工具 https://codebeautify.org/hex-string-converter 进行数据转换,把16进制数字转换为一个字符串。

细心一点儿的话,可以会注意到我们获取的数据最后面多了一个数字 8,这是因为字符串本质上是变长数组,需要一些特别处理,这里有更详细的说明:https://docs.soliditylang.org/en/v0.8.10/internals/layout_in_storage.html#mappings-and-dynamic-arrays

getStorageAt 需要传入两个参数,第一个参数是合约地址,第二个参数是要读取的状态变量的存储位置,只要我们知道的变量的位置,就能读取到所存储的值。不过很多时候计算存储位置也是要费点儿功夫的。

其实有时候可能另一种办法更简单,就是直接从设置数据的交易里来读取数据,比如 secret 这个变量是通过构造函数还设置的,那我去看部署合约的交易就好了。连上节点后,通过调用 eth.getTransaction,可以获取到交易的 input 值。

> eth.getTransaction("0xfa73be19403e5361c97d86dc64f25b2e45af330780e301b213107bdbc611c4a2")
......
input: "0x60806040523480156100......05050565b603f806105076000396000f3fe6080604052600080fdfea2646970667358221220b8f76d5e70f478ae42c73d84dfdbe6c705c91a0db013260e4a6d0b5cdd4b620a64736f6c63430008130033000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000042431303000000000000000000000000000000000000000000000000000000000"
......

合约部署交易 input 值的最后一段 “42431303000000000000000000000000000000000000000000000000000000000” 就是要设置的 secret 相关内容,“24313030” 是 secret 参数的值,前面多出来的 "4" 代表的是参数的长度 4 个字节。不过这个本质上是读取参数的值,而不是变量的值,参数的值和变量的值有时候是相同,有时候是不相同的。

0x04 如何在合约中保存秘密

很多时候这需要比较严密的设计,比如我提前给你准备了一个大礼包,这个礼包里放了一大笔 ETH 资产,但只有我把密码告诉你之后你才能使用密码把这个大礼包打开。这个时候,我们把密码直接放合约肯定不行,那么把密码的哈希值放合约里行么?其实也不行,如果不对地址进行校验,当我把密码告诉你之后,很多人都有可能跑在你前面把钱取走,那么多抢跑机器人都在那里蹲着呢。
下面是应对这种场景的简单代码,同时对密码和账户地址进行了校验。

// SPDX-License-Identifier: MIT

pragma solidity =0.8.19;

contract Gift {

    bytes32 private secretHash;
    address private owner;

    constructor(bytes32 secretHash_, address owner_) {
        secretHash = secretHash_;
        owner = owner_;
    }

    function withdraw(string calldata secret) external {
        require(keccak256(abi.encodePacked(secret)) == secretHash);
        require(msg.sender == owner);
        payable(owner).transfer(address(this).balance);
    }

    receive() external payable{}
}

0x05 启发

其实还有很多其它场景,比如口令红包啥的,都有通过智能合约对某个秘密进行校验的需求,要时刻谨记,智能合约里没有秘密。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容