GENGEN
主页
vuepress
  • GIT命令
  • python+django
  • vue cli搭建项目
  • babel es6转换es5
  • docker aliyun配置
  • npm 配置
  • linux 常用命令
  • Ubuntu 下Linux 命令
  • github
  • gitee
  • csdn
  • 关于我
主页
vuepress
  • GIT命令
  • python+django
  • vue cli搭建项目
  • babel es6转换es5
  • docker aliyun配置
  • npm 配置
  • linux 常用命令
  • Ubuntu 下Linux 命令
  • github
  • gitee
  • csdn
  • 关于我
  • java基础

    • JDK8 函数式编程
    • JDK8 新特性之Date-Time
    • Servlet 源码分析
    • ArrayList 源码
    • LinkedList 源码
    • HashMap 源码
    • String 源码
    • BigDecimal 源码
    • java 类的加载
    • Class 源码
    • Synchronized锁升级
    • 事务的传播机制
    • knowledge
  • JAVA WEB

    • Java Servlet
    • 权限设计
    • logback日志的链路追踪
  • DATABASE

    • MySQL EXPLAIN详解
    • MySQL 索引
    • MySQL 表锁、行锁
    • MySQL ACID与transcation
    • 分布式事务
    • MySQL MVCC机制
    • Mysql 乐观锁与悲观锁
    • 分布式锁1 数据库分布式锁
    • 分布式锁2 Redis分布式锁
    • 分布式锁3 ZK分布式锁
  • SpringCloud

    • SpringCloud服务注册中心之Eureka
    • SpringCloud服务注册中心之Zookeeper
    • SpringCloud服务调用之Ribbon
    • SpringCloud服务调用之OpenFeign
    • SpringCloud服务降级之Hystrix
    • SpringCloud服务网关之Gateway
    • SpringCloud Config分布式配置中心
    • SpringCloud服务总线之Bus
    • SpringCloud消息驱动之Stream
    • SpringCloud链路追踪之Sleuth
    • SpringCloud Alibaba Nacos
    • SpringCloud Alibaba Sentinel
  • Spring

    • SpringBoot
    • Spring-data-jpa入门
    • SpringCloud问题
    • dispatcherServlet 源码分析
    • @SpringBootApplication注解内部实现与原理
    • spring启动初始化初始化
  • 中间件

    • 分布式协调服务器Zookeeper
    • 服务治理Dubbo
    • 分布式配置管理平台Apollo
    • 消息中间件框架Kafka
    • 分布式调度平台ElasticJob
    • 可视化分析工具Kibana
    • ElacticSearch 基础
    • ElacticSearch进阶
    • ElacticSearch集成
  • 环境部署

    • 应用容器引擎Docker
    • DockerCompose服务编排
    • 负载均衡Nginx
    • Nginx的安装配置
    • K8S基础
  • 代码片段

    • listener 监听模式
    • spingboot 整合redis
    • XSS过滤
    • profile的使用
    • ConfigurationProperties注解
  • 设计模式

    • 工厂模式
    • 单例模式
    • 装饰者模式
    • 适配器模式
    • 模板方法模式
    • 观察者模式
  • 读书笔记

    • 《Spring in Action 4》 读书笔记
    • 《高性能mysql》 读书笔记
  • NoSQL

    • Redis基础
    • Redis高级
    • Redis集群
    • Redis应用
  • MQ

    • rabbitMQ基础
    • rabbitMQ高级
    • rabbitMQ集群
  • JVM

    • JVM体系架构概述
    • 堆参数调整
    • GC 分代收集算法
    • JVM 垃圾回收器
    • JVM 相关问题
  • JUC

    • JUC总览
    • volatile关键字
    • CAS
    • ABA问题
    • collections包下线程安全的集合类
    • Lock 锁
    • LockSupport
    • AQS
    • Fork/Join分支框架
    • JUC tools
    • BlockingQueue 阻塞队列
    • Executor 线程池
    • CompletableFuture
    • 死锁以及问题定位分析
  • Shell

    • shell命令
    • shell基础
  • Activiti

    • IDEA下的Activiti HelloWord
    • 流程定义的CRUD
    • 流程实例的执行
    • 流程变量
  • VUE

    • vue基础
    • vue router
    • Vuex
    • Axios 跨域
    • dialog 弹出框使用
    • vue 动态刷新页面
    • vue 封装分页组件
    • vue 动态菜单
    • vue 常用传值
  • Solidity 智能合约

    • Solidity 基础
    • Solidity ERC-20
    • Solidity 101
  • English

    • 时态

1.值类型

  • 值类型(Value Type): 包括布尔、整数等,这类变量赋值时候直接传递数值
  • 引用类型(Reference Type): 包括数组、结构体,这类变量占空间大,赋值时直接传递地址(类似指针)
  • 映射类型(Mapping Type): Solidity中存储键值对的数据结构,可以理解为哈希表

布尔 bool是二值变量,取值true、false

bool public _bool = true;

整型 整型是Solidity中的整数

int public _int =-1; //整数,包括负数
uint public _uint = 1; //无符号整数
uint256 public _uint256 = 2022030; //256位无符号整数

地址类型 Solidity中特有的类型

+  普通地址(address): 存储一个20字节的值(ETH地址的大小)
+ payable address: 比普通地址多了`transfer` `send`两个成员方法,用于接收转账
// 地址
address public _address = 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;
address payable public _address1 = payable(_address); // payable address,可以转账、查余额
// 地址类型的成员
uint256 public balance = _address1.balance; // balance of address

定长字节数组 字节数组分为定长和不定长两种:

    • 定长字节数组: 属于值类型,数组长度在声明之后不能改变。根据字节数组的长度分为 bytes1, bytes8, bytes32 等类型。定长字节数组最多存储 32 bytes 数据,即bytes32。
  • 不定长字节数组: 属于引用类型(之后的章节介绍),数组长度在声明之后可以改变,包括 bytes 等。
// 固定长度的字节数组 
bytes32 public _byte32 = "MiniSolidity"; 
bytes1 public _byte = _byte32[0];

枚举enum

  • 枚举(enum)是 Solidity 中用户定义的数据类型。它主要用于为 uint 分配名称,使程序易于阅读和维护。它与 C 语言 中的 enum 类似,使用名称来代替从 0 开始的 uint:
// 用enum将uint 0, 1, 2表示为Buy, Hold, Sell 
enum ActionSet { Buy, Hold, Sell } 
// 创建enum变量 action 
ActionSet action = ActionSet.Buy;

2. 函数

  • Solidity中函数非常灵活,可以进行各种复杂操作,以下为函数表现形式
function <function name>([parameter types[, ...]]) {internal|external|public|private} [pure|view|payable] [virtual|override] [<modifiers>]
[returns (<return types>)]{ <function body> }

以下为函数部分关键字

  • internal|external|public|private 函数的可见说明符
    • public : 内部和外部都可见
    • private: 本合约内部可见、继承的合约也不可见
    • external: 只能从合约外部访问(但内部可通过this.functhion_name()调用)
    • internal: 只能合约内部访问,继承的合约可用
 **注意 1**:合约中定义的函数需要明确指定可见性,它们没有默认值。

**注意 2**:`public|private|internal` 也可用于修饰状态变量(定义可参考[WTF Solidity 第5讲的相关内容]
`public`变量会自动生成同名的`getter`函数,用于查询数值。未标明可见性类型的状态变量,默认为`internal`。

``

  • [pure|view|payable]:决定函数权限/功能的关键字。payable(可支付的)很好理解,带着它的函数,运行的时候可以给合约转入 ETH。
pure和view的引入,主要是ETH交易需要支付gas fee,合约的状态变量存储在链上,gas fee很贵,而如果不需要修改链上状态,就可以不用支付gas fee。包含 pure、view的函数是不修改链上状态的,因此用户直接调用不需要支付gas fee(注意:合约中非pure、view的函数调研pure或view需要支付gas fee)

ETH中视为修改链上状态的是:
1.写入状态变量
2.释放事件
3.创建其它合约
4.使用 selfdestruct
5.通过调用发送ETH
6.调用任意未标注pure\view的函数
7.使用低级调用(low-level calls)
8.使用包含某些操作码的内联汇编

pure函数即不可读取也不可写入链上的状态变量
view可以读取但不能写入链上状态变量
  • [virtual|override]: 方法是否可以被重写,或者是否是重写方法。virtual用在父合约上,标识的方法可以被子合约重写。override用在自合约上,表名方法重写了父合约的方法。
  • <modifiers>: 自定义的修饰器,可以有0个或多个修饰器。

函数输出

  • 函数输出包含: 返回多种变量、命名式返回、结构式返回读取全部或部分返回值

return 和 returns

  • returns 跟在函数名后,用于声明返回变量类型以及变量名
  • return 用于函数主体中,返回指定变量

返回多种变量

// 返回多个变量
function returnMultiple() public pure returns(uint256, bool, uint256[3] memory){
    return(1, true, [uint256(1),2,5]);
}

returns 声明返回分别是uint256、bool、uint256长度为3的数组
return返回数组中 1,2,5默认是uint8长度,所以首个元素显示强转uint256

命名式返回

// 命名式返回 f
unction returnNamed() public pure returns(uint256 _number, bool _bool, uint256[3] memory _array){ 
_number = 2; 
_bool = false; 
_array = [uint256(3),2,1];
}

该方法我们通过给返回的变量_number、_bool、_array赋值,即可自动返回,当然你可以用return来返回
return(2,false,[uin(3),2,1]);

解构式返回

  • Solidity 支持使用解构式赋值规则来读取函数的全部或部分返回值。
uint256 _number; 
bool _bool;
uint256[3] memory _array;

(_number, _bool, _array) = returnNamed();
  • 读取部分返回值,不读取的留空
(, _bool2, ) = returnNamed();

变量数据存储

  • 引用类型(Reference Type):包括数组array 和结构体struct,这类变量比较复杂,占用空间大,所以我们要声明数据存储的位置

数据位置

  • Solidity数据存储有3类:storage , memory,calldata。不同存储位置需要的gas 成本不同
    • storage存储在链上,类似计算机硬盘,消耗gas多。合约状态变量默认存储storage
    • memory存储在临时内存上,消耗gas少,函数中参数,临时变量一般用memory,不上链,尤其是返回数据类型是变长的情况下,必须加memory,例如string,bytes,array,和自定义结构
    • calldata和memory类似,不同点是calldata变量不能修改,一般用于函数参数
  • 整体gas消耗是:storge > memory > calldata

数据位置和赋值规则

在不同存储类型相互赋值时候,有时会产生独立的副本(修改新变量不会影响原变量),有时会产生引用(修改新变量会影响原变量)。规则如下:

  • 赋值本质上是创建引用指向本体,因此修改本体或者是引用,变化可以被同步:
    • memory赋值给memory,会创建引用,改变新变量会影响原变量。
    • storage(合约的状态变量)赋值给本地storage(函数里的)时候,会创建引用,改变新变量会影响原变量。例子:
uint[] x = [1,2,3]; // 状态变量:数组 x 
function fStorage() public{ 
	//声明一个storage的变量 xStorage,指向x。修改xStorage也会影响
	x uint[] storage xStorage = x; 
	xStorage[0] = 100; 
}
  • 其他情况下,赋值创建的是本体的副本,即对二者之一的修改,并不会同步到另一方。这有时会涉及到开发中的问题,比如从storage中读取数据,赋值给memory,然后修改memory的数据,但如果没有将memory的数据赋值回storage,那么storage的数据是不会改变的。

变量的作用域

Solidity中变量按作用域划分有三种,分别是状态变量(state variable),局部变量(local variable)和全局变量(global variable)

1 .状态变量

状态变量是数据存储在链上的变量,所有合约内函数都可以访问,gas消耗高。状态变量在合约内、函数外声明:

contract Variables { 
	uint public x = 1;
	uint public y; 
	string public z;
 }

我们可以在函数里更改状态变量的值:

function foo() external{ 
	// 可以在函数里更改状态变量的值 
	x = 5; 
	y = 2; 
	z = "0xAA";
 }

2. 局部变量

局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。局部变量的数据存储在内存里,不上链,gas低。局部变量在函数内声明:

function bar() external pure returns(uint){ 
	uint xx = 1; 
	uint yy = 3; 
	uint zz = xx + yy; 
	return(zz);
 }

3.全局变量

全局变量是全局范围工作的变量,都是solidity预留关键字。他们可以在函数内不声明直接使用:

function global() external view returns(address, uint, bytes memory){ 
	address sender = msg.sender; 
	uint blockNum = block.number; 
	bytes memory data = msg.data; 
	return(sender, blockNum, data); 
}

在上面例子里,我们使用了3个常用的全局变量:msg.sender,block.number和msg.data,他们分别代表请求发起地址,当前区块高度,和请求数据。下面是一些常用的全局变量,更完整的列表请看这个链接:

  • blockhash(uint blockNumber): (bytes32) 给定区块的哈希值 – 只适用于最近的256个区块, 不包含当前区块。
  • block.coinbase: (address payable) 当前区块矿工的地址
  • block.gaslimit: (uint) 当前区块的gaslimit
  • block.number: (uint) 当前区块的number
  • block.timestamp: (uint) 当前区块的时间戳,为unix纪元以来的秒
  • gasleft(): (uint256) 剩余 gas
  • msg.data: (bytes calldata) 完整call data
  • msg.sender: (address payable) 消息发送者 (当前 caller)
  • msg.sig: (bytes4) calldata的前四个字节 (function identifier)
  • msg.value: (uint) 当前交易发送的 wei 值
  • block.blobbasefee: (uint) 当前区块的blob基础费用。这是Cancun升级新增的全局变量。
  • blobhash(uint index): (bytes32) 返回跟当前交易关联的第 index 个blob的版本化哈希(第一个字节为版本号,当前为0x01,后面接KZG承诺的SHA256哈希的最后31个字节)。若当前交易不包含blob,则返回空字节。这是Cancun升级新增的全局变量。

4. 全局变量-以太单位与时间单位

以太单位

Solidity中不存在小数点,以0代替为小数点,来确保交易的精确度,并且防止精度的损失,利用以太单位可以避免误算的问题,方便程序员在合约中处理货币交易。

  • wei: 1
  • gwei: 1e9 = 1000000000
  • ether: 1e18 = 1000000000000000000

时间单位

可以在合约中规定一个操作必须在一周内完成,或者某个事件在一个月后发生。这样就能让合约的执行可以更加精确,不会因为技术上的误差而影响合约的结果。因此,时间单位在Solidity中是一个重要的概念,有助于提高合约的可读性和可维护性

  • seconds: 1
  • minutes: 60 seconds = 60
  • hours: 60 minutes = 3600
  • days: 24 hours = 86400
  • weeks: 7 days = 604800
Prev
Solidity ERC-20