美文网首页践行区块链
Solidity 中的私有变量不私有

Solidity 中的私有变量不私有

作者: Ashton | 来源:发表于2023-03-15 10:11 被阅读0次

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 启发

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

相关文章

  • JS—私有变量

    私有变量js中没有私有成员的概念,所有对象属性都是公有的,但是却是有私有变量的概念。任何函数中定义的变量都是私有变...

  • 作用域链

    查找私有变量 JS中的私有变量有且只有两种在私有作用域变量提升阶段,声明过的变量(或者函数)形参也是私有变量 [图...

  • 私有变量和私有方法的访问

    OC中没有绝对的私有变量和私有方法对于私有变量,例如在.h文件中使用@private修饰的变量;在.m文件中扩展中...

  • iOS知识点总结

    一、Object-C中变量默认是私有的吗,方法默认是私有的吗? Object-C中既有私有方法,也有私有变量。 1...

  • 2018-06-28 python 类的私有变量和私有方法

    转发python 类的私有变量和私有方法 类的私有变量和私有方法在Python中可以通过在属性变量名前加上双下划线...

  • JavaScript函数表达式——私有变量

    私有变量 任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量,私有变量包括函数的参数,...

  • 1.1 OC中的私有方法

    本小节知识点: 【掌握】OC中的私有变量 【掌握】OC中的私有方法 1.OC中的私有变量 在类的实现即.m文件中也...

  • JavaScript函数_07 私有变量 + 私有函数 + 特权

    私有变量 使用 var 关键字声明在函数内部的变量称为私有变量 私有函数 在函数内部声明的函数称为私有函数 特权方...

  • python下划线定义属性

    类的私有变量和私有方法 在Python中可以通过在属性变量名前加上双下划线定义属性为私有属性 特殊变量命名 1、 ...

  • OC中如何实现私有成员变量

    OC中如何实现私有成员变量 @property生成的成员变量即为私有成员变量@property生成的是: 带下划线...

网友评论

    本文标题:Solidity 中的私有变量不私有

    本文链接:https://www.haomeiwen.com/subject/ydclrdtx.html