(1)账户地址
创建账号,无需上链,其实地址在链上非真实存在的,转账的接收方地址可以是任一符合规则的地址码,也能转账成功,只是没有人有与之匹配的私钥来操作此账户
geth节点重启,上链的数据还是保存着的
(2)合约内常用变量
msg.sender
就是当前调用方法的用户地址this
指的是当前合约的地址address
支持各种算数运算符tx.origin
交易的发送者
(3)函数的可见性 public external internal private
public
:函数默认声明为public 是合约对外接口的一部分external
:声明为external的可以从其它合约或通过Transaction进行调用, 是合约对外接口的一部分- 合约内变量没标名public或external,外部dapp无法获取
internal
:在当前的合约或继承的合约中,只允许以internal的方式调用private
:只能在当前合约中被访问(不可在被继承的合约中访问)- 即使声明为private,仍能被所有人查看到里面的数据。访问权限只是阻止了其它合约访问函数或修改数据。
(4)合约的继承
存在继承关系的合约,只需要布置子合约(它的abi和bin信息中已经包含父合约的信息)
dapp中通过子合约的地址可以直接调父合约的函数
(5)合约A调用合约B
- 合约A内定义一个合约B类型的变量,需要先部署合约B,再将B的address赋值给A内的合约B变量
- 合约B变量未赋值时,无法使用
- 合约B变量赋值后,dapp中通过A合约的地址可以间接调B合约的函数(封装成接口函数)
- 合约A内调用带
payable
标识的合约B变量的函数,调用方法如下 :- 合约B变量.函数.value(给多少钱 将做为msg.value的值)(函数形参);
例如:siringAuction.bid.value(msg.value - autoBirthFee)(_sireId)
;
- 合约B变量.函数.value(给多少钱 将做为msg.value的值)(函数形参);
(6)函数标识 payable 的作用
函数上有一个payable
关键字,如果一个函数需要进行货币操作,必须要带上payable关键字,这样才能正常接收msg.value
。
(7)字符串比较
Solidity 并不支持原生的字符串比较, 只能通过比较两字符串的 keccak256 哈希值来进行判断
require(keccak256(_name) == keccak256("Vitalik"));
(8)多个合约文件
在 Solidity 中,当你有多个文件并且想把一个文件导入另一个文件时,可以使用 import 语句: 相同目录也必须用"./"开头
import "./someothercontract.sol";
(9)存储
Storage
变量是指永久存储在区块链中的变量。 Memory
变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除
- 当函数内使用
Storage
时,相当于指针Sandwich storage mySandwich = sandwiches[_index];
- 当函数内使用
Memory
时,相当于拷贝Sandwich memory anotherSandwich = sandwiches[_index + 1];
(10)字节对齐
当 uint 定义在一个 struct 中的时候,尽量使用最小的整数子类型以节约空间。
并且把同样类型的变量放一起(即在 struct 中将把变量按照类型依次放置),这样 Solidity 可以将存储空间最小化
(11)如果合约想返回一个struct,得改用多个参数
如果合约返回多个参数,代码中定义一个结构体来接收,
且在定义的结构前使用[FunctionOutput],且使用CallDeserializingToObjectAsync
来获取
(12)数组下标从0开始
(13)函数修饰符
view
的作用和constant
一模一样,可以读取状态变量但是不能改;pure
则更为严格,pure修饰的函数不能改也不能读状态变量,否则编译通不过。
(14)require(), assert(), revert()
在 0.4.10 版的 solidity,新增了 require(), assert(), revert() 。
require()
用來檢查較不嚴重的錯誤,可以退回未使用到的 gas。assert()
用來檢查較嚴重的錯誤,會像以前一樣拿走所有 gasLimit 的手續費。寫法基本上都相同,只是處理方式不一樣。revert
跟 require 基本上相同,但是 revert 沒有包括狀態檢查。
(15)tx.origin 和 msg.sender 有什么区别?
tx.origin
交易的发送者。msg.sender
消息的发送者。
交易 transaction 可以包含1个或多个合约 contract。
- 一个合约时,对于合约本身来说,tx.origin 和 msg.sender 是同一个地址。
- 多个合约时,场景如: 用户,合约A ,合约B . 用户 通过合约A ,调合约B. 此时
- 对于合约A:
tx.origin
和msg.sender
都是用户。 - 对于合约B:
tx.origin
是用户msg.sender
是合约A.
- 对于合约A: