Cover photo

Solidity基础概念的区分——可见性

Solidity作为一个图灵完备的编程语言,跟javascript还有这诸多相似之处。作为目前主流的智能合约语言,有着易学,易用的特点。但是由于区块链的早期阶段和EVM的早期阶段,所有有着各种概念需要区分。

首先讲一下可见性,可见性分为变量可见性和函数可见性。

对于变量的private,public, internal

  • 对于public变量,会自动生成getter函数

    //solidity source codes
    contract Token{
        string public name = "Hardhat Token";
        string public symbol = "HHT";
    ....
    }
    
    //javascript
    describe("getter test", function(){
        it("getter test", async function(){
            const name = await token.name();
            console.log("name: "+ name);
        });
    });
    

    不会默认生成setter函数,内部直接访问name

  • internal 内部可见性变量, 可以在派生和本合约内访问。

  • private 本合约内部可见,派生合约不可见。

    值得注意的是无论是internal, private,还是public都可以通过getStorageA(index)的方式,从区块链节点获取变量的内容,所以不要将confidential的内容上传到blockchain上。

对于函数而言的public,private,external, internal

  • public

    public 函数是合约接口的一部分,可以在内部或通过消息调用。Java中含义一致。函数默认是public。

  • private

    只能在当前合约内部访问,外部和派生的合约是无法访问的。这个与java的private含义也是一致的。

  • external

    external标识的函数是合约接口的一部分。函数只能通过外部的方式调用。外部函数在接收大的数组时更有效。Java中无与此对应的关键字。

  • internal

    函数只能通过内部访问(当前合约或者继承的合约),可在当前合约或继承合约中调用。类似于Java的protected。

    这里最让人迷惑的其实就是public和external,有了public为什么还要提供external呢?

    这里涉及到一个概念叫calldata,就是在交易中发出交易的data部分。

    • 当使用external的时候,函数不会对参数进行copy,仅仅从calldata引用就可以了。

    • 当使用public的时候,函数会对参数进行复制操作。public为了支持从内部和从外部两种调用方式,所以要一视同仁的进行参数拷贝。

      所以如果你能确认只有外部调用,那么就使用external,这样可以为你节省不少gas。

      以下是calldata的说明

go-ethereum
go-ethereum

https://github.com/ethereum/go-ethereum/blob/01e5e9c2c3fa1cf7a9747148dca22d59ff9839b6/core/types/transaction.go#L71

以上是Transaction部分的源码,有兴趣可以自己看。