1.区块链安全体系架构
分法1
PoW:工作量证明 (Proof Of Work,简称POW),简单理解就是一份证明,用来确认你做过一定量的工作。. 监测工作的整个过程通常是极为低效的,而通过对工作的结果进行认证来证明完成了相应的工作量,则是一种非常高效的方式。
PoS:权益证明 (POS) 在2011年,在一个比特币论坛中一位名为QuantumMechanic的用户提出一项技术,他称之为 “权益证明 (proof-of-stake)” 。. 基础概念是,让每个人互相竞争挖矿是很浪费的。. 因此相反的是,权益证明通过选举的形式,其中任意节点被随机选择来验证下一个区块。. 在这里有一些小的术语区别,权益证明中没有矿工,但是有验证者 (validator)。. 并不让人们”挖 (mine)”新区块 而是"铸造 (mint)” 或"制造 (forge)”新区块。. 验证者并不是被完全随机选择的,要成为验证者, 节点需要在网络中存入一定数量的货币作为权益, 可以将这理解为保证金。. 权益的份额大小决定了被选为验证者的几率,从而得以创建下一个区块,这是线性相关的。.
BFT:BFT( Byzantine Fault Tolerance)称为 拜占庭容错。拜占庭容错技术是一类分布式计算领域的容错技术。拜占庭假设是对现实世界的模型化,由于硬件错误、网络拥塞或中断以及遭到恶意攻击等原因,计算机和网络可能出现不可预料的行为。拜占庭容错技术被设计用来处理这些异常行为,并满足所要解决的问题的规范要求。
APIs接口:应用程序编程接口。
更详细的分法请看大大的区块链简介
分法2(类似分法1)
分法3
DApp:DApp就是D+App,D是英文单词decentralization的首字母,单词翻译中文是去中心化,即DApp为去中心化应用。
链平台存在另一种分法:
DeFi:DeFi 是 Decentralized Finance 的简称,它指的是在传统金融系统之外重建传统金融产品的协议、平台、应用程序和工具的生态系统。
2.变量
2-1.变量
变量的声明:
**类型| 可见性(public或private)| 变量名
例:uint public auctionEndTime;
变量的分类:
2-1-1.状态变量:状态变量的值可以永久存储在合约的存储空间里;
· 状态变量可以声明为常量或不可变量。不管定义成那种类型,合约创建后都无法修改。
· 如果把合约比作类,状态变量可以看作类的成员变量
2-1-2.本地变量:本地变量的值只在函数执行期间存在,可以看作函数的临时变量。
2-1-3.全局变量:一类特殊变量,用于获取有关区块链的信息。
进入:常见全局变量
2-2.类型
值类型:
· 布尔型bool
支持常见的运算!&& || == !=
· 整型int/uint/uint8/int256/uint256
支持常见的运算,比较运算,位运算,移位运算,+ - * / ,模运算,指数运算
· 定点数fixed point number
fixed/unfixed/fixedMxN/ufixedMxN(x相当于*)
M代表类型的位数,是8的倍数
N代表小数点的位数,取值范围是0——80
· 枚举类型
枚举将变量限制为仅有几个预定义值之一
enum ActionChoices {GoLeft,GoRight,GoStraght,SitStill};
· Address
地址类型
· address : 以太坊地址类型,20字节
· address payable;和address -样,但是额外还有transfer和send成员
· 二者的区别是address payable可以接受转账,address 不可以。
类型转换
· 可以隐式的把address payable转为address,反之不可
· address转为address payable需要显示转换payable (
· address 和uint160 bytes20 contract可以相互显示转换
支持的运算
· <=,<,==,I=,>= and >
· 二者的区别是从0.5.0开始的
· 定长字节数组bytesN
支持的运算
· Comparisons; <=,<,==,!=,>=,> (evaluate to bool)
· Bit operators:&,|.^ (bitwise exclusive or),~(bitwise negation)
· Shift operators:<< (left shift), >> (right shift)
· 移位运算符使用无符号整数类型作为右操作数(但返回左操作数的类型),表示要移位的位数。按有符号类型进行移位将产生编译错误。
· Index access: If x is of type bytesI, then x[k for 0 <= k < I returns the k th byte(read-only).
· Prior to version 0.8.0, byte used to be an alias for bytesl.
· 动态数组的大小是引用
bytes——动态大小的字节数组,是引用类型
string——动态大小的UTF-8字符串数组,是引用类型
引用类型:
· 使用引用类型必须明确提供存储该类型的数据区域
存储区域
如果使用引用类型,则始终必须明确提供存储该类型的数据区域
·内存memory (其生命周期仅限于函数调用期间)
.存储storage (存储状态变量的位置,生命周期限于合约的生命周期) .
·calldata (包含函数参数的特殊数据位置)
在0.5.0版本之前,可以省略数据位置,编译器会根据变量类型、函数类型等默认指定位置
导致影子变量漏洞。
但现在所有复杂类型都必须给出明确的数据位置。
· 结构体
struct Funder{
address addr;
uint amount;
}
结构体类型可以在映射和数组中使用,它们本身可以包括映射和数组。
结构体不可以包含其自身类型的成员,因为结构体的大小必须是有限的。
· 数组
静态数组:T[k]——编译时确定数组大小;
动态数组:T[ ]——运行时确定数组大小;
多维数组:有5个动态数组的数组表示成X[][5];
X[3]表示有3个X元素,即使X是动态数组。
数组成员:length
push()
push(x)
pop()
数组切片:
截至目前,数组切片仅适用于calldata数组。x[start:end]:
start :开始位置,默认值为0,包含此元素
end :结束为止,默认值为数组长度,不包含此元素
x[:2]:x[0]. x[1]
x[2:]:x[2].x[3].x[4]x[length-1]
x[2:5]: x[2].x[3].x[4]
bytes,string,bytes1[ ]:
bytes和string类型的变量是特殊的数组。
string不同于bytes的是它不支持length和索引访问;
bytes相当于bytes1[],不同之处在于
bytes1存储在memory和calldata时,会给每一个元素填充 31字节。存储在storage时不会填充。
bytes 不会填充字节,而是紧密存储。
bytess = "Storage"; bytes1 t= s[1];
· 映射
mapping(KeyType => _ValueType) _VariableName;
· KeyType :可以是值类型,bytes, string。 不可以是其他用户定义,或复杂的类型如,映射,结构体,数组。
· _ValueType :可以是任意类型,包括映射,结构体,数组类型。
3.语句
1.条件语句
· if…else…和C++/C语法相同
· 不支持非布尔型转布尔型,如不支持if(1){…}
2.循环语句
· 循环:for/while/do while
· 结束循环的语句:break/continue/return
3.抛异常的语句
assert():assert(bool condition):if condition is false,当前执行会被终止并回滚所有的执行
require():require(bool condition):if condition is false,当前执行会被终止并回滚所有的执行
assert()和require()的区别:
gas消耗不同:
assert会消耗剩余的所有gas,并回滚所有的操作。require会返回剩余的gas,并回滚所有的操作。
使用场景不同:
assert用于检测一些非法的条件,避免永远不可能发生的情况,如存在溢出,不变量改变。
require用于确保些合法的条件, 如输入或状态变量等满足要求,外部合约的返回值满足要求。
revert():
新版本: 结合error语句使用revert CustimError(arg1,arg2);
兼顾旧版本:revert();
if (!condition)revert(...);
require(condition,...);
二者是等价的。
try/catch:
仅外部函数调用和合约创建调用支持try/catch
try后面可以跟一个外部调用的表达式,或者一个合约创建语句,如new ContractName()
4.不支持的语句
· 不支持select case 语句
· 不支持goto语句
5.事件event
事件可以用于输出日志。Solidity 中的事件就像其他语言的日志功能一样,只是日志不是记录到控制台或文件,而是保存在以太坊区块链中。
格式
event event name([data to record: var_ type Var name)
示例
event MyEvent (uint256 date,string value );
触发事件:
emit MyEvent(block.timestamp,'hello');
6.错误error
Solidity中的错误提供了一种方便且高效的方式来向用户解释操作失败的原因。它们可以在合约内部和外部定义(包括接口和库)错误不能被重载或覆盖,但会被继承。只要作用域不同,就可以在多个地方定义相同的错误。错误实例只能使用revert语句创建。
格式
error error name(([data to record: var_ type var name]);
示例
error InsufficientBalance(uint256 available,uint256 required);
触发错误:
error InsufficientBalance(available:balance[msg.sender],required:amount);
7.修饰器modifier
· 函数修饰器可修改函数的语义。实际执行时,把修饰器的代码复制到函数体的前面。
4.函数
1.定义
函数是代码的可执行单元。函数通常在合约内定义但也可以在合约外定义。语法如下:
function 函数名 函数参数 可见性等修饰符 return 返回值 修饰器
· function(){ public| private | internal | external }[pure| constant | view |payable] [returns()] [modifier]
例:
function helper(uint x) pure returns (uint){
return x*2;
}
2.参数
参数的声明方式与变量相同,未使用的参数名称可以省略。
参数可以用作任何其他局部变量,也可以赋值给它们。
3.返回值
函数可以返回任意数量的值返回值的定义和参数定义的语法相同,跟在return关键字之后。return(v0,v1,vn)可用于返回多个值。返回的数量和类型必须匹配,也可以经过隐式转换之后匹配。
4.view
view视图:
函数可以声明为视图,当且仅当函数承诺不修改任何状态值(状态变量)。
function f(uint a,uint b) public view returns (uint){
return a*(b+42)+block.timestamp;
}
以下语句被认为会修改状态
1.写状态变量。
2.发出事件。
3.创建其他合约。
4.使用 selfdestruct(销毁合约)。
5.通过调用发送以太币。
6.调用任何未标记为view或pure的函数。
7.使用低级调用。
8.使用包含某些操作码的内联汇编。
5.pure
pure纯函数:
函数可以声明为纯函数,当且仅当函数承诺不读取或修改状态。
function f(uint a,uint b) public pure returns (uint){
return a*(b+42);
}
以下语句被认为会读取状态
1.从状态变量中读取。
2.访问address(this) .balance 或
3.访问block,tx,msg 的任何成员(msg.sig 和msg.data除外)
4. 调用任何未标记为纯函数的函数。
5. 5. 使用包含某些操作码的内联汇编。
6.重载
一个合约可以有多个同名但参数类型不同的函数。这个过程称为“重载”,也适用于继承的函数。
function f(uint _in) public pure returns (uint out){
out=_in;
}
function f(uint _in,bool _really) public pure returns (uint out){
if(_really)
out=_in;
}
7.fallback
一个合约最多可以有一个回退函数,声明方式有以下2种:
· fallback () external [payable]
· fallback (bytes calldata _input) external [payable] returns(bytes memory _output)
calldata _input指合约的存储位置。
payable指一项交易。
· 两者都没有function关键字,且必须是external的。
· 它可以是虚函数,可以重写,也可以有修饰器。
8.receive
一个合约最多可以有一个接收函数,声明方式如下
receive() external payable {.... }
此函数不能有参数,不能返回任何内容,并且必须是external和payable的。
它可以是虚函数,可以重写,也可以有修饰器
5.ERC20标准
接口:
· function name() public view returns (string) function symbol0 public view returns (string)
· function decimals( public view returns (uint8)
· function totalSupply0 public view returns(uint256)
· function balanceOf(address _owner) pul evew returns (uint256 balance)
· function transfer(address _to, uint256 _value) public returns (booI success)
· function transferFrom(address _from ,address _to, uint256 _value) public returns(bool success)
· function approve(address _spender, uint256 _value) public returns (bool success)
· function allowance(address _owner, address _spender)public view returns (uint256 remmaining)
6.可见性
· public
.函数和状态变量在当前合约内和被继承的合约内都可以访问。
· private
.函数和状态变量仅在当前合约内可以访问,在继承的合约内不可访问。
· internal
.函数和状态变量只能通过内部(internal) 访问。如在当前合约中调用或继承的合约里调用,需要注意的是不能加前缀this ,前缀this是表示通过外部(external)方式访问。
· external
不适用于状态变量、适用于外部函数,不能通过内部的方式来发起调用,如f()不可以,但可以通过this.f ()。