区块链“智能合约”从基础到入门——掌握本篇就够啦!!!

创作不易,对你有所帮助的话,你的三连,是对笔者(小k)最大的支持与鼓励。
转载:请备注原文链接!!!

一丶开发环境:

(1)Remix

——可能需要翻墙,比较慢,但是方便直接用

(2)WeBASE-Front

——代码高亮美观,使用方便,但需要自行搭建环境

二丶Solidity概述

在这里插入图片描述

  • 智能合约Smart Contract :一套旨在以信息化方式传播、验证或执行合同的计算机协议
  • 以太坊虚拟机Ethereum Virtual Machine : 一个轻量级的虚拟机,用于在网络上运行智能合约。EVM的构建是为了模拟可由物理CPU执行的操作,还负责以太坊的许多关键功能
  • Solidity :以太坊推出用来编写智能合约的编程语言

三丶基本类型

(1)Int

  • 用intx和uintx来申明,其中x是一个8-256之间的8的倍数,表示有多少个bit。如int8 ,uint32。
  • 比较:<=,<,==,!=,>=,>
  • 位运算:&,|,^,~,<<,>>
  • 数值运算:加减乘除,%取余,**指数。0的0次方等于1
  • type(x).min和type(x).max给出该类型的上下界
  • 溢出会被截断

(2)address

可以是合约地址,也可以是账户地址

  • address与address payable:储存160个bit长的信息,也就是一个地址。
  • address payable 相对于address多了可以向此地址转账的功能
  • .balance给出该地址的金额
  • .transfer()和.send()对于一个address payable代表向其转账
address payable x = address(0x123);
address myAddress = address(this);
if(x.balance < 10 && myAddress.balance >= 10){
    
    
	x.transfer(10);// or x.send(10)

申明一个地址为0x123的可接受转账的地址x
获取当前合约的地址myAddress
判断x的账户余额是否小于10并且当前合约的地址大于等于10
x.transfer(10)代表的是当前合约向x转账

(3)Bool

  • 用bool x来申明
  • 操作符 !,&&,||,==,!=
  • &&操作和||操作是短路运算

(4)数组

  • 定长数组:bytes1,bytes3, … bytes32表示储存了1个,2个…32个byte的数组
  • bytes32 x:可以用下标访问
  • 具有位运算
  • 常规数组和C++类似:int a[10]
  • 也可以申明动长数组:int a[]。动长数组有a.length返回长度, a.push(x) 在最后添加一个新元素x并返回新长度

(5)Char and String

  • 用char来申明字符变量
  • string相当于一个char的数组,但是目前的版本不支持使用.length以及下标访问,需要转化为bytes访问字节形式的内容
string s;
bytes(s).length
bytes(s)[7] = 'x'

(6)Mapping

  • 用mapping(_keytype => _valuetype),基本上就是个哈希表
	mapping(address => uint) public balance;
	function update(uint newBalance) public {
    
    
		balances[msg.sender] = newBalance;
	}

申明一个balance从地址映射的uint的值
uint没有具体申明,默认为uint256
申明一个函数(后面详细介绍)
在整体上,智能合约不是一个完成的程序,需要被其他人调用自己才能实现真正的动作
msg.sender是调用者地址(后面会详细介绍)
balance[address] = uint256(具体问题,具体分析)

(7)Struct

struct Voter{
    
    //投票者
	uint weight;//权重
	bool voted;//是否投过票
	address delegate;//地址
	uint vote;//票数
	}

四丶预定义变量

(1)block

区块的相关信息

  • block.blockhash(uint blockNumber) retruns(bytes32) 指定区块的区块哈希,不推荐,建议使用blockhash(uint blockNumber)代替
  • block.coinbase(address):挖出当前区块的矿工地址
  • block.difficulty(uint):当前区块难度
  • block.gaslimit(uint):当前区块gas限额
  • block.number(uint):当前区块号
  • block.timestamp(uint):自uinx epoch其当前区块以秒计的时间戳

(2)msg

  • msg.data(bytes):完整的calldata
  • msg.gas(uint):剩余gas,不推荐,建议使用gasleft()代替
  • msg.sender(address):当前调用的消息发送者
  • msg.sig(bytes4):calldata的前4个字节(也就是函数标识符)
  • msg.value(uint):随消息发送的wei的数量

五丶Event

  • 用来触发EVM中的log记录,使用如下语句声明和使用
event X(<parameter types>) //定义
emit X(<parameter>) //使用
event Send(address sender, address receive, uint amount); //事件

function sent() public payable{
    
    
	//....
	emit Send(msg.sender, msg.receive,msg.value);//触发事件
	}

调用sent函数,会触发Send事件
返回一个事件:谁给谁转了多少钱

六丶控制结构

  • C++/js里面的大部分结构都有,包括 if,else,while,do,for,break,continue,return,? :
  • 没有goto
  • 在soldity中,其他类型是不会自动转换为bool的,所以if(1){}这样是不合法的

七丶Units

(1)EtherUnits

  • wei,szabo,finney,ether
  • 1 ether = 1000 finney = 106 szabo = 1018 wei

(2)TimeUnits

  • 一个数值后跟seconds,minutes,hours,days,weeks是一个时间单位,默认秒(1 == 1seconds)

如何要把一个变量转为单元,类似x * ether

八丶Contracts

  • 合约Contract是一个代码的基本组成部分,和class类似
  • 一个Contract里会包含状态变量,函数,函数修饰器和事件
  • Contract也有继承与多态

(1)状态变量

  • 储存在合约中的信息,如总量,个人的余额等等
contract C1{
    
    
	uint data; //State Variable
	}

data就是一个状态变量

(2)函数

function (<parameter types>) [internal | external | public] [pure | view | payable] [returns (<return types>)]
{
    
    }
  • view:一个函数如果不会改变状态(包括send ether)则可以被申明为view
  • pure:一个函数如果是view,并且不会从状态中读取数据,则可以被申明为pure
  • 如果一个函数什么都不return就相当于c++中的void 函数 不写returns即可
  • reutrn可以返回一个元组,用括号括起来
  • internal | external | public是不可选,必须写
  • pure | view | payable是可选的,可以不写
  • returns是可选的,可以不写

(3)Payable

  • 表示调用的时候可以发过来一个货币
  • msg.sender是发币地址,msg.value是数量
function deposit() payable returns(address addr,uint amount,bool success){
    
    
	return(msg.sender,msg.value,this.send(msg.value));
	}

没有申明可见性,默认是public
返回发送者地址,发了多少代币,是否发送成功
this代指本合约地址
这里是指sender向此合约打款

(4)visibility

  • 函数有四种可见性:external,public,internal,private
  • external表示只能从外部调用,如果想从内部调用,必须用this.f
  • public 则表示内外都可以
  • internal 可以被自己或衍生类调用
  • private则只能自己调用
  • 变量的visibility不能是external

internal ,private只是针对于外部合约而言,在区块链外部还是能查看相关数据的
visibility不写,默认为public

(5)构造函数

一个合约有至多一个构造函数,在构造时会执行一次

Contract A{
    
    
	bytes32 name;
	constructor(bytes32 _name)public{
    
    
		name = _name;
		}
	}

(6)Receive Ether

  • 一个合约有至多一个Receive ether函数,用如下语句声明。
  • receive() external payable{…}
  • 没有function关键字
  • 当收到ether时执行(.send()和.transfer())
//This contract keeps all Ether sent to it with no way 
//to get it back
contract Sink{
    
    
	event Received(address, uint);
	receive() external payable{
    
    
		emit Received(msg.sender, msg.value);
	}
}

contract Source{
    
    
	function sending(uint amount) internal payable {
    
    
		address payable x = address(Sink);
		x.transfer(10); // will call receive
	}
}

(7)fallback

  • 一个合约至多有一个fallback函数,fallback函数是缺省函数,当调用了一个该合约不存在的函数时会执行fallback。
  • 用如下语句声明,同样没有function关键词
  • fallback() external [payable]

(8)require

  • 预定义函数
  • require(bool condition)
  • require(bool condition,string message)
  • 如果条件不满足,会撤销更改(包括转账)

要求某种条件必须成立
如果不满足,就全部不执行,所有操作将会回退(撤销)

(9)函数修饰器function modifier

contract owned{
    
    
	address owner;
	mapping(address => bool) registeredAddresses;
	uint price;
	
	constructor()public {
    
    
		owner = msg.sender;
	}
	
	modifier onlyOwner{
    
    
		require(msg.sender == owner);
		_;//如果满足上述条件,函数将会在这里接着执行
	}
	
	modifier costs(uint price) {
    
    //modifier可以接受参数
		if(msg.value >= price){
    
    
			_;//满足条件,函数将会在这里接着执行
		}
	}
	
	function register() public payable costs(price){
    
    
		registeredAddressed[msg.sender] =true;
	}
	
	function changePrice(uint _price) public onlyOwner{
    
    
		price = _price;
	}
	
}
			

modifier中的_处,被修饰的函数将会在此执行

(10)继承

  • 用is来实现合约继承
  • 继承的子合约会继承父合约所有非private的东西,包括modifier
  • Contract A{…}
  • Contract B is A {…}
  • 如果要override一个函数,在被覆盖的函数声明时必须加virtual关键字,在覆盖的函数后加override
  • 如果希望能被在此override,也要加virtual关键字
  • 函数默认调用最衍生的类定义的函数
  • 如果要调用父类的函数,使用super.f()
  • 函数override的时候必须保持同样的可见性,或从external变成public
  • 另一个参数只能变得更加严格,即non-payable(也就是无参数)可以被override为view,view可以变成pure。payable是特殊的,必须保持为payable
contract Base{
    
    
	function foo() virtual external view{
    
    }
}

contract Middle is Base{
    
    }

contract Inherited is Middle{
    
    
	function foo() virtual override public pure{
    
    }
}

external -> public
view -> pure
符合override后的函数修饰

(11)Abstract Contracts

  • Abstract contracts是未实现的Contract。可以用来做父类
  • 用来使用什么功能,更广泛的父类
abstract contract A{
    
    
	function num() public pure virtual returns(uint);
}

contract B is A{
    
    
	function num() public pure override returns(uint){
    
    
		return 0;
	}
}

(12)Interface

  • 和Abstract Contract 差不多,但是更严格一点
  • 不能实现任何函数
  • 不能定义构造函数
  • 不能定义任何变量
  • 不能继承(可以被继承)

猜你喜欢

转载自blog.csdn.net/weixin_43402353/article/details/118447078