phymooc / learn-blockchain

0 stars 0 forks source link

Solidity handbook #5

Open phymo opened 2 years ago

phymo commented 2 years ago

Solidity

语言特性

  1. 运行在EVM(以太坊虚拟机)上
  2. 静态,支持继承,类库,自定义类型
  3. 借鉴Python,javascript
  4. 强类型:先定义后赋值再使用

EVM

沙箱封装起来,完全隔离,运行在EVM的代码不能接触网络,进程,文件系统等, 仅合约之间有限交互

Remix

开发智能合约的IDE
用vscode?
在线IDE: remix.ethereum.org

安装 本地remix

https://www.npmjs.com/package/remix-ide

  1. npm install -g remix-ide
  2. npm install remixd -g deprecated
  3. npm install -g @remix-project/remixd

remix-ide 挂载本地源码目录

  1. open browser, click connect to localhost
  2. remixd -s c:\solworkspace --remix-ide http:******

1st HelloWorld.sol program 及运行

  1. _storage.sol
    
    // SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

/**

pragma solidity >=0.7.0 <0.9.0;

contract HelloWorld { string str = "str";

function setStr(string memory _str) public {
    str = _str;
}

function getStr() public view returns (string memory){
    return str;
}

}


3. 编译 solidty compiler: 生成contract
4. 运行:deploy&run transactions
  - 本地环境 javascript VM, 线上环境
  - account
  - gas limit
  - contract
5. 生成deployed contract (可交互 和验证)
6. 打开控制台 查看transaction详细信息

### 注释
1. 单行 //
2. 多行 /* */
3. NATspec格式注释

### 执行过程
1. 编译后生成:
   1. 字节码: 测试网 和 主网
   2. ABI:接口声明 加上web3.js 创建DApp

## 语法
### 版本声明
- pragma
### import
- 语法与ES6非常类似
- `import "filename"`
- `import * as symbolName from "filename"`
- `import "filename" as symbolName`
- `import { symbol1 as alias, symbol2 } from "filename"`

### 数据类型
1. 变量 `string x = "Hello World"`  
    - 作用域:
      1. 状态变量/成员变量-合约内,函数外
      2. 局部变量-函数内
2. 标识符:字符数字下划线$,不以数字开头,区分大小写,驼峰命名
    - 保留字/关键词 (public, private, internal, external, function ...)
3. 数据类型分类:
    - 值类型/基本类型
      1. bool: true/false
      2. int/uint: (int8, int16, ...int256), (uint8, uint16, ...uint256), 256为默认
      3. address
      4. byte: 8bit, 可赋值为 1. 16进制数,2.字符
      5. 定长字节数组: 1. bytes1, bytes2....bytes32. 默认 byte = byte1. 2. 属性:length,可以使用下标访问。3. 与string的区别
      6. 定长浮点(fixed/ufixed)
      7. enum
      8. function
    - 引用类型
      1. Array: bytes, string
      2. Struts
      3. Mapping

4. 运算符和表达式
    - 算术运算符:
      1. \+ - * / % ++ -- **, 
      2. 精度和溢出问题:使用safeMath库 `import SafeMath.sol`, `using SafeMath for uint8`
    - 关系运算符: && || !,
    - 位运算符:& | ^ ~ >> <<
    - 赋值运算符: = += ...
5. 数据类型转换
    - 隐式转换
    - 显式转换:如果转换为更小的类型,那么高位字符将被截断
6. 控制语句
    - 条件判断语句:if (){} else if (){} else{}
    - 循环语句: for, while, do while
    - 跳转语句:break, continue
7. 数组
    - 数组每个元素 类型必须一致
    - 下标 从0开始
    - 可以使用new 创建,也可以直接赋值
    - 内存中,一块连续的区域保存数据
    - 分类:
        1. 定长数组,固定长度
        2. 变长数组:动态长度
    - 声明和创建:
        1. 定长: T[k] = [1,2,3]
        2. 变长: T[] = new unit8[](3)
    - length 属性,不能length 直接赋值修改长度, 
    - 定长数组操作:
        1. int[6] public a = [1,2,3,4,5,6];
        2. a.length
        3. a[2] = 4
        4. 长度不可以修改,不可以push
    - 定长字节数组: bytesX
        1. bytes10 等价于 new bytes(10); 注意不同的定义方式可能有定长和变长的区别;
    - 变长数组:
        1. uint[] a = new uint[](2);
        2. uint[] a = [1, 2, 3];
        3. 可以push
        4. 长度可以变: 但不可以直接赋值length;
    > string 没有push方法,存储在memory的数组也不支持push; (数组默认是存储在storage的);
    - 特殊变长数组:变长字节数组
        1. bytes public name = new bytes(10), 用bytes, 不要使用 bytes[],浪费空间

    - 特殊变长数组: string
        1. 类似于bytes, 但是不提供长度和按序号访问方式
        2. bytes和string可以自由转换
        3. 每个汉字占3个字节
        4. string name = unicode"汉字"; bytes(name).length为6;
    - 二维数组
        1. 定长
        2. 变长
    - 数组字面量
      1. 数组字面量总是静态固定大小的memory数组;
      2. 定长的memory数组并不能赋值给变长的memory数组;
8. 数据存储方式
    - storage:状态变量/成员变量, 可以跨函数使用
    - memory: 临时数据存储,只在函数内部有效,函数参数可以理解为memory 类型;
    - 函数的参数,返回值默认为memory
    - 函数内局部变量 默认为storage
    - 状态变量/成员变量默认为storage
    - memory和storage的转换
        1. storage赋值给storage,仅修改了引用或者指针,指向同一个数据
        2. storage转换为memory,会从storage拷贝岛memory
        3. memory转换为storage, 1. memory赋值给状态变量,2. memory赋值给函数内的局部变量;

9. ETH 账户
    - 普通账户/外部账户 EOA: (余额,不关联代码)
    - 合约账户/内部账户: (关联代码,存储空间)

> 两种账户共用EVM的地址空间,对EVM来说没有区别     
> - 交易:签名的数据包:EOA 发起
> - 消息调用: 合约账户发起

10. 地址
    - 地址包括账户
    - 公钥keccak-256单项哈希去最后20个字节派生的标识符
    - 所有合约的基础,支持比较运算符
11. 交易 Transaction
    - gas: gas price * gas, gas limit
    - balance: address.balance
    - payable: 修饰符 可附加发送ETH
    - transfer()函数: 对指定账户转账
12. 单位
    - 货币单位: eth, wei, finney, szabo
    - 时间单位
13. 全局变量:
    - 区块交易相关
        1. blockhash(unit blockNo)
        2. block.coinbase(addr): 矿工地址
        3. block.difficulty()
        4. block.gaslimit
        5. block.number
        6. block.timestamp()
        7. gasleft()
        8. msg.data(bytes)
        9. msg.gas(uint)(淘汰)
        10. msg.sender(addr)
        11. msg.sig(bytes4)
        12. msg.value(uint)
        13. now(uint)
        14. tx.gasprice
        15. tx.origin(addr)
        16. [addr].balance
        17. [addr].transfer
        18. [addr.send]
        19. [addr].call
        20. [addr].delegatecall (危险操作)
        21. this
        22. selfdestruct(addr)
    - API 编码
    - 错误处理
    - 数学与加密
    - 地址相关
    - 合约相关
14. 函数
    > 与区块链交互的手段  

    - 函数参数:可以使用json命名参数
    - returns: 可以返回多个值
    - 函数调用:
        1. 内部函数调用: 简单的EVM跳转,不用拷贝数据,不需要gas: `g(2)`
        2. 外部函数调用: 会创建EVM消息调用, `this.g(8)` 或者`c.g(2)`, 构造器中不能使用this,因为合约还没有创建
        3. 函数修饰符: 
            - 访问修饰符(可见性):(external, public, internal(virtual, override), private)
            - 类型修饰符: pure: 不能读取和修改状态; view: 不会修改状态,不消耗gas; payable: 可以接受ETH; 
            - 函数返回值: 1. `returns` 关键字, 2. `return` 语句, 3. 可以返回多个值,4. 返回值的接收
            - 函数修饰器(修改器): modifier, 修改函数的执行,1. 定义修改器,2. 使用修改器
            - 常用内置函数: 1. 内置数学函数(addmod, mulmod), 2. 内置加密函数(keccak256, sha256, ripemd160)
15. 
phymo commented 2 years ago

smart contract

与面向对象的类差不多,包括 state 和 function

  1. 构造函数
    • 构造函数 constructor:用于初始化合约,可选函数, 只允许一个构造函数,不支持重载; 部署合约时自动调用构造函数创建合约,不能限制gas
    • 不支持嵌套创建合约
    • 合约内可以用new 创建其他合约
    • 无参构造,有参构造
  2. 继承
    • 四种访问修饰符的继承
    • 关键字 is
    • 本质,代码拷贝
    • 派生合约可以访问父合约所有非私有成员,但不能使用this
      1. 继承列表式, 2. 修改器风格式
    • 重写
  3. 状态变量覆盖 错误
  4. 状态变量不能重写
  5. 可以允许重写函数,但不能重写函数返回值
  6. super 可以访问父类的函数,
    • 多态
    • 多继承
    • modifier 继承
    • 重载:不同参数个数
    • 抽象contract :virtual override
    • 接口 interface: ABI
    • library: delegatecall, import实际上是copy代码, using for 绑定
  1. ABI: application binary interface: 函数的二进制接口的描述
    • abi.encode
    • abi.encodePacked
    • abi.encodeWithSelector
    • abi.encodeWithSignature
phymo commented 2 years ago

mapping

  1. 存储键值对:mapping(key => value), key可以是字符串 整型 等基本数据类型,包括address; value 没有类型限制
  2. mapping不能作为参数的形参使用
  3. mapping可以看作一个哈希表
  4. 存储上,value并不直接存在哈希表中,二十他的keccak256值
  5. mapping 没有length, 也无法使用set设置