1. Solidity函数、权限、函数修饰符、事件
a. 函数
i. 概念:solidity也是一门函数式编程语言,函数可以做为其参数、变量、返回值
ii. 函数属于值类型,支持多个返回值
iii. 调用方式:
1. 内部调用:
a. 内部调用采用的是EVM跳转调用,所以它能直接使用上下文环境中的数据,因为不用拷贝数据,所以在传递数据时会非常高效
b. 对合约内的函数,引入的库函数以及从父合约中继承的函数都可以进行内部调用
2. 外部调用
a. 外部调用采用外部交易调用,使用external时,必须使用外部的方式调用其它合约的函数。对于一个外部调用,所有函数的参数必须拷贝到内存中。
3. 注意:上面的internal以及external是指函数的调用方式,与可见性中的internal、external是两个概念
iv. 函数定义类型
1. View:只读,不改变合约内部状态
a. 以下操作会修改状态
i. 写入状态变量.
ii. 触发事件
iii. 创建其它合约.
iv. 使用自毁函数.
v. 发送以太币.
vi. 调用任何没有被标记为 view 或者 pure的函数.
vii. 底层调用.
viii. 使用包含一些操作码的内联汇编.
b. getter函数会默认标记为view
c. 注意,如果有修改状态操作的函数加上view,编译器不会报错,只会给出一个警告
2. Pure:不会修改合约状态,也不能读取合约状态(可以读取与状态无关的数据)
a. 除去view中的限制,还包括以下内容
i. 读取状态变量
ii. 访问this.balance或者address.balance
iii. 访问block,tx,msg任何成员(msg.sig以及msg.data除外)
iv. 调用任何没有标记为pure的函数
v. 使用包含某些操作码的内联汇编
b. 注意:在版本0.4.17之前,编译器没有强制规定pure不能读取状态。
3. Fallback
a. 每一个合约中都有一个没有名字的函数,该函数没有参数,没有返回值,这就是回调函数
b. 以下两种情况下会调用回调函数
i. 调用合约时,没有匹配上任何一个函数
ii. 给合约发送ether时,交易中根本没有提供数据
c. 给合约发送ether时,要注意以下情况
i. 合约没有定义回调函数的话,接收ehter会触发异常
ii. 如果回调函数需要接收ehter,必须要有payable修饰符
4. 函数重载
a. 同名函数可以重载
5. 自毁函数(selfdestruct)
a. 自毁函数可以摧毁当前合约,将该合约的以太币转移到给定的地址
b. 注意:如果合约被自毁后有人发送以太币到这个合约地址,那这些以太币会消失,无法赎回
6. 常函数(constant)
a. 常函数不会修改区块链上的任何状态(没有强制规定、会警告)
7. 访问函数(getter)
a. 编译器为自动为所有的public的状态变量创建访问函数
b. 访问函数有外部(external)可见性。如果通过内部(internal)的方式访问,比如直接访问,你可以直接把它当一个变量进行使用,但如果使用外部(external)的方式来访问,如通过this.,那么它必须通过函数的方式来调用
8. 其它内置函数
a. 加密函数
i. Keccak256(…)returns (bytes32);使用以太坊的(keccak-256)计算hash(该函数会先将所有参数进行连接再计算)
1. keccka256("ab","cd")
ii. Sha3(…)returns(bytes32);同上
1. sha3("ab","cd");
iii. Ripemd160(…)returns(bytes20):使用ripemd-160计算hash值,返回bytes20
1. ripemd160("abc")
iv. Sha256(…)returns(bytes32);使用sha-256计算hash值,返回bytes32
1. sha256("def");
v. ecrecover(bytes32,byte,bytes32,bytes32) return(address);恢复与公钥相关的地址
b. 数据函数
i. addmod(uint x,uint y, uint k)returns(uint)// (x+y)%k
ii. mulmod(uint x, uint y, uint k)returns(uint)// (x*y)%k
b. 可见性或权限
i. 可见性
1. Internal:不能在当前合约的上下文环境以外的地方执行,内部函数只能在当前合约内被使用。如在当前的代码块内,包括内部库函数,和继承的函数中。默认情况下,函数为internal
2. external:
a. 外部函数由地址和函数方法签名两部分组成。可作为外部函数调用的参数,或者由外部函数调用返回
b. external可以通过交易调用、也可以通过其它合约调用
c. 如果是用this调用,那它是在通过external的方式调用
d. 不能在内部调用一个外部函数
ii. 权限
1. Public:公开函数是合约接口的一部分,可以通过内部,其它合约、或者消息来进行调用。对于public类型的状态变量,会自动创建一个访问器
2. Private:私有函数和状态变量仅在当前合约中可以访问,在继承的合约内,不可访问
3. 注意:所有在合约内的东西对外部的观察者来说都是可见,将某些东西标记为private仅仅阻止了其它合约来进行访问和修改,但并不能阻止其它人看到相关的信息
c. 函数修改器(Modifier)
i. 修改器的作用是在函数执行前检查某种前置条件是否满足,
ii. Modifier是一种合约属性,可以被继承,还可以被派生的合约重写
iii. 一个函数可以有多个修改器,其间采用空格或回车分隔,修改器的生效顺序与定义顺序是一样的
d. 事件(event)
i. 事件是使用EVM日志内置功能的方便工具,在DAPP的接口中,它可以反过来调用Javascript的监听事件的回调。
ii. 为什么要有事件?在真实的环境中,发送交易调用智能合约的过程是如下:
1. 交易发送->打包->被执行 在发送完之后,不会马上返回执行结棍,只能立刻返回交易HASH。所以我们需要通过事件来通知外部实体。
iii. 事件在合约中可被继承。当被调用时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并合并到区块链中,只要区块可以访问就一直存在(至少Frontier,Homestead是这样,但Serenity也许会不一样)。日志和事件在合约内不可直接被访问,即使是创建日志的合约。