文章目录
- 一、ubuntu安装
- 二、FISCO BCOS安装
- 五、 WeBASE安装
- 5.1 WeBASE简介
- 5.2 节点前置服务搭建
- 5.3 调用HelloWorld合约
- 七、Solidity极简入门
- 7.1. 值类型
- 7.2. 变量数据存储和作用域
- 7.3. 函数
- 7.4 控制流
- 7.5 数组&映射
- 7.6 结构体
- 7.7 修饰符
- 7.8 事件
- 7.9 面向对象
- 7.10 抽象合约
- 7.11接口合约
- 7.12 库合约
- 九、案例
- 9.1 权限控制合约
- 9.2 投票合约
- 9.3 拍卖合约
一、ubuntu安装
# ubuntu系统下载
https://releases.ubuntu.com/18.04.6/
##虚拟机安装好后 root密码用普通用户登录
#sudo passwd初始化
# 替换镜像源
mv /etc/apt/sources.list /etc/apt/sources.list.backup
# 新建源 参考国内源文档
https://developer.aliyun.com/mirror/ubuntu/
# 操作如下
vim /etc/apt/aources.list
.........
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
.........
# 更新apt源表
apt update
apt upgrade
二、FISCO BCOS安装
FISCO BCOS 2.0 技术文档
https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/
环境安装:
# 不安装,则start.all会报错:Cannot open file:../crypto/rand/randfile
apt install -y openssl curl
# 不安装 bash console/start.sh 会报错Failed to connect to all the nodes!
apt install -y default-jdk
安装包下载
#借梯子下载好相关的包
#build_chain.sh
https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/v2.11.0/build_chain.sh
# fisco-bcos build_chain.sh脚本中需要的二进制文件
https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/v2.11.0/fisco-bcos.tar.gz
# console download_console.sh 脚本中需要的文件
https://github.com/FISCO-BCOS/console/releases/download/v2.9.2/console.tar.gz
执行
# 安装
bash build_chain.sh -l 127.0.0.1:3 -e ./fisco-bcos
bash nodes/127.0.0.1/start_all.sh
# 查看
tail -f nodes/127.0.0.1/node0/log/log_2024092819.29.log |grep +++
tail -f nodes/127.0.0.1/node0/log/log_2024092819.29.log |grep connect
# 控制台安装
tar -xf console.tar.gz
cp -r nodes/127.0.0.1/sdk/* console/conf/
cp -n console/conf/config-example.toml console/conf/config.toml
bash console/start.sh
五、 WeBASE安装
5.1 WeBASE简介
WeBASE(WeBank Blockchain Application Software Extension)是在区块链应用和FISCO-BCOS节点之间搭建的一套通用组件。围绕交易、合约、密钥管理,数据,可视化管理来设计各个模块,开发者可以根据业务所需,选择子系统进行部署。WeBASE屏蔽了区块链底层的复杂度,降低开发者的门槛,大幅提高区块链应用的开发效率,包含节点前置、节点管理、交易链路,数据导出,Web管理平台等子系统
5.2 节点前置服务搭建
vim ~/.bashrc
# 增加 JAVA_HOME 提示报错:java_home不存在
readlink -f $(which java)
.........
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
.........
source ~/.bashrc
echo $JAVA_HOME
## webase-front.zip
https://osp-1257653870.cos.ap-guangzhou.myqcloud.com/WeBASE/releases/download/v1.5.5/webase-front.zip
unzip webase-front.zip
cd webase-front
cp ../nodes/127.0.0.1/sdk/* ./conf/
bash start.sh
bash status.sh
tail -f log/WeBASE-Front.log |grep success
http://localhost:5002/WeBASE-Front
也可以使用在线开发环境:
https://remix.ethereum.org/
5.3 调用HelloWorld合约
HelloWorld合约已经内置于控制台中,位于控制台目录contracts/solidity/HelloWorld.sol
pragma solidity>=0.4.24 <0.6.11;
contract HelloWorld {
string name;
constructor() public {
name = "Hello, World!";
}
function get() public view returns (string memory) {
return name;
}
function set(string memory n) public {
name = n;
}
}
# 在控制台输入以下指令 部署成功则返回合约地址
[group:1]> deploy HelloWorld
# 调用get接口获取name变量 此处的合约地址是deploy指令返回的地址
[group:1]>call HelloWorld 0xa2bf59b4ca0952464b393947990eaa2e25870587 get
# 调用set设置name
[group:1]>call HelloWorld 0xa2bf59b4ca0952464b393947990eaa2e25870587 set "Hello, FISCO BCOS"
七、Solidity极简入门
Solidity是一门为实现智能合约而创建的面向对象的高级编程语言。 智能合约是管理以太坊中账户行为的程序。
Solidity 是一种面向以太坊虚拟机 (EVM) 的 带花括号的语言。 它受 C++,Python 和 JavaScript 的影响。您可以在 语言的影响因素 部分中找到更多有关 Solidity 受哪些语言启发的细节
7.1. 值类型
pragma solidity 0.6.10;
contract ValueType {
string _string = "Hello Web3!";
//布尔型
bool _bool = true;
bool _bool1 = !_bool; // 取非
bool _bool2 = _bool && _bool1; //与
bool _bool3 = _bool || _bool1; //或
bool _bool4 = _bool == _bool1; //相等
bool _bool5 = _bool != _bool1; //不相等
//整数
int _int = -1; // 整数
uint _uint = 1; // 正整数 uint=uint256
uint _num = 17;
uint _num1 = _num +2; // 加
uint _num2 = _num/3; //除取整
uint _num3 = _num%5; //取余
uint _num4 = _num*3; //乘
uint _num5 = _num**2; //指数
//地址
address public _address = 0xfBbe31cb73D23Ae79771157c2Bb7C45Cce7C1E18;
// 固定长度 Array
uint[8] _array1;
address[100] _array3;
//定长字节数组
//长度为1的字节类型
bytes1 A = 0x01;
//byte是bytes1的别名
byte B =0x01;
//长度为2的字节类型
bytes2 C= 0xaabb;
bytes1[32] _array2;
bytes32 _bytes32 = "hellowold";
bytes1 _bytes1 = _bytes32[0];
// 可变长度 Array
uint[] array4;
address[] array6;
//bytes比较特殊,是数组,不用加[]
//可以使用bytes或bytes1[]。bytes 比 bytes1[] 省gas
bytes1[] array5;
bytes array7;
// 初始值
//如果你在变量声明后添加了public关键字,
//那么这个变量将自动生成一个与变量名相同的函数,
//该函数用于获取这个变量的值
bool public _bool_c; // false
string public _string_c; // ""
int public _int_c; // 0
uint public _uint_c; // 0
address public _address_c;
// 0x0000000000000000000000000000000000000000 (或 address(0))
//枚举 类比bool
enum ActionSet { Buy, Hold, Sell}
ActionSet public _enum_c; // 默认值第1个内容Buy的索引0
function fi() internal{} // internal空白函数
function fe() external{} // external空白函数
}
常量
pragma solidity 0.6.10;
contract ConstantTest {
// constant变量必须在声明的时候初始化,之后不能改变
uint256 constant CONSTANT_NUM = 10;
string constant CONSTANT_STRING = "0xAA";
bytes constant CONSTANT_BYTES = "WTF";
address constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000;
// immutable变量可以在constructor里初始化,之后不能改变
uint256 public immutable IMMUTABLE_NUM = 9999999999;
address public immutable IMMUTABLE_ADDRESS;
uint256 public immutable IMMUTABLE_TEST;
// 利用constructor初始化immutable变量,因此可以利用
constructor() public {
IMMUTABLE_ADDRESS = address(this);
IMMUTABLE_TEST = test();
}
//利用了test()函数给IMMUTABLE_TEST初始化为9
function test() public pure returns(uint256){
uint256 what = 9;
return(what);
}
}
枚举和结构体
//可以理解bool的扩展。
pragma solidity 0.6.10;
contract Enum {
enum Status{
None,running,stopping,spendding
}
struct Order{
address buyer;
Status status;
}
Status status = Status.running;
//枚举可以显式地和 uint 相互转换
function get() external returns(Status) {
return status;//1
}
function set(Status _status) external{
status = _status;
}
}
7.2. 变量数据存储和作用域
引用类型(Reference Type):包括数组(array)和结构体(struct),由于这类变量比较复杂,占用存储空间大,我们在使用时必须要声明数据存储的位置。
Solidity数据存储位置有三类:storage,memory和calldata。不同存储位置的gas成本不同。storage类型的数据存在链上,类似计算机的硬盘,消耗gas多;memory和calldata类型的临时存在内存里,消耗gas少。大致用法:
storage:合约里的状态变量默认都是storage,存储在链上。
memory:函数里的参数和临时变量一般用memory,存储在内存中,不上链。尤其是如果返回数据类型是变长的情况下,必须加memory修饰,例如:string,
bytes, array和自定义结构。calldata:和memory类似,存储在内存中,不上链。与memory的不同点在于calldata变量不能修改(immutable),一般用于函数的参数。
pragma solidity 0.6.10;
contract StorageScope{
uint[] x = [1,2,3]; // 状态变量:数组 x
function fStorage() public{
//声明一个storage的变量 xStorage,指向x。修改xStorage也会影响x
//storage存储
uint[] storage xStorage = x;
xStorage[0] = 100;
}
function get() public returns (uint){
return x[0];
}
// memory存储
function g(uint[3] memory _data) public pure {
// ...
}
}
Solidity中变量按作用域划分有三种,分别是状态变量(state variable),局部变量(local variable)和全局变量(global variable)
状态变量是数据存储在链上的变量,所有合约内函数都可以访问,gas消耗高。状态变量在合约内、函数外声明
局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。局部变量的数据存.储在内存里,不上链,gas低.
全局变量是全局范围工作的变量,都是solidity预留关键字。他们可以在函数内不声明直接使用:
pragma solidity 0.6.10;
contract StorageScope{
uint public m = 1;
uint public y;
string public z;
function foo() external{
// 可以在函数里更改状态变量的值
m = 5;
y = 2;
z = "0xAA";
}
//局部变量是仅在函数执行过程中有效的变量,函数退出后,变量无效。
//局部变量的数据存储在内存里,不上链,gas低。
function bar() external returns(uint){
uint xx = 1;
uint yy = 3;
uint zz = xx + yy;
return(zz);
}
//全局变量是全局范围工作的变量,都是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);
}
}
7.3. 函数
注意 1:合约中定义的函数需要明确指定可见性,它们没有默认值。
注意 2:public|private|internal也可用于修饰状态变量。public变量会自动生成同名的getter函数,用于查询数值。未标明可见性类型的状态变量,默认为internal
function //关键字开头
//函数名 输入到函数的变量类型和名称
<function name> ( <parameter types>)
//public:内部和外部均可见。
//private:只能从本合约内部访问,继承的合约也不能使用。
//external:只能从合约外部访问(但内部可以通过 this.f() 来调用,f是函数名)。
//internal: 只能从合约内部访问,继承的合约可以用
{internal|external|public|private}
//pure,中文意思是“纯”,这里可以理解为”纯打酱油的”。pure 函数既不能读取也不能写入链上的状态变量。
//view,“看”,这里可以理解为“看客”。view函数能读取但也不能写入状态变量。
//非 pure 或 view 的函数既可以读取也可以写入状态变量。
[pure|view|payable]
[returns(<return types>)]
函数返回值
returns:跟在函数名后面,用于声明返回的变量类型及变量名。 return:用于函数主体中,返回指定的变量。
pragma solidity 0.6.10 ;
contract FunctionTypes {
int num = 99;
//function <function name>(<parameter types>) {internal|external|public|private}
//[pure|view|payable] [returns (<return types>)] 方括号中的是可写可不写的关键字
// pure: 纯纯牛马
function addPure(uint256 _number) external pure returns(uint256 new_number){
new_number = _number + 1;
}
function addView() external view returns (int) {
int newnum = num +1;
return newnum;
}
function add() external returns (int) {
int num = num +1;
return num;
}
//需要读num值 view
function viewFunc() external view returns(int){
return num;
}
// 不需要读写num
function pureFunc() external pure returns (int){
return 3+7;
}
// internal: 内部函数
function minus() internal {
num = num - 1;
}
// 合约内的函数可以调用内部函数
function minusCall() external returns(int) {
minus();
return num;
}
// 返回多个变量
function returnMultiple() public returns(uint256, bool, uint256[3] memory,address,address){
return(1, true, [uint256(1),2,5],address(this),address(0));
}
// 命名式返回
function returnNamed() public returns(uint256 _number, bool _bool, uint256[3] memory _array){
_number = 2;
_bool = false;
_array = [uint256(3),2,1];
}
// 命名式返回,依然支持return
function returnNamed2() public pure returns(uint256 _number, bool _bool, uint256[3] memory _array){
return(1, true, [uint256(1),2,5]);
}
}
例:计算合约
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.10;
contract Counter {
int num ;
function inc() external returns (int){
num = num +1;
return num;
//return num +1;//num+1 是另一局部变量,会不自增。
}
//如下 只加1 不更新的.
function in+1() external returns (int x){
x = num +1;
}
function dec() external returns (int){
num = num -1;
return num;
}
}
例:地址变量使用
//声明solidity版本为0.6.10
pragma solidity 0.6.10;
//定义合约
contract AddrTest {
//定义address类型全局变量
address addr;
//部署合约时设置addr值
constructor() public{
addr =0x018020B71d0cACB421483efa5104fD2a8DAe9728;
}
function getValue() public returns(address){
return addr;
}
//合约地址 和 0
function getAddress() public returns(address,address){
return (address(this),address(0));
}
}
7.4 控制流
条件选择
pragma solidity 0.6.10;
contract fenzhi{
function test(bool condition)public returns(string memory){
//单个条件判断
if(condition)
{return "condition true";}
return "condition false";
}
function test2(bool condition) public returns(string memory){
//当条件不满足时,执行else语句
if(condition){
return "condition true";
} else {
return "condition false";
}
}
function test3(bool condition, bool condition2) public returns (string memory){
//else语句可以结合if连续判断
if(condition){
return "condition true";
}
else if(condition2){
return"condition2 true";
} else {
return "all false";
}
}
function test5(bool condition)public returns(string memory){
//条件?条件为true时的返回:条件为false时的返回
string memory x=condition ?"condition ture":"condition false";
return x;
}
function test6(bool condition, bool condition2) public returns (string memory){
//先判断condtion,condition为true执行大括号语句,否则执行else
if(condition){
//再判断condition2
if(condition2){
return "condition2 true";
} else{
return "condition2 false";
}
} else {
return "condition false";
}
}
}
循环
pragma solidity 0.6.10;
contract ForAndWhere {
function forexam() external returns (int) {
int sum;
for (int condition =1; condition<=10;condition++){
//写在执行语句前面,跳过后面的语句
if (condition ==5){
continue;
}
//写在执行语句前面,跳出循环
if (condition ==9){
break;
}
sum+=condition;
}
return sum;//31=1+2+3+4+6+7+8
}
function where() external returns (int){
int _n=1;
where (_n <10){
//code
_n++;
}
}
}
7.5 数组&映射
数组
pragma solidity 0.6.10;
contract ArrayTest{
//动态数组
int[] public nums = [1,2,3];
//定长数组
int[3] public numsFix =[4,5,6];
function example() external returns (uint[] memory,uint){
nums.push(4);//[1,2,3,4]
nums[2] = 66; // [1,2,66,4]
delete nums[1];//[1,0,66,4] //位置没有删
nums.pop();// [1,0,66]
uint len = nums.length;
//对于memory修饰的动态数组,可以用new操作符来创建,
//但是必须声明长度,并且声明后长度不能改变
uint[] memory a = new uint[](5);
//如果创建的是动态数组,你需要一个一个元素的赋值。
a[0] =1;
return (a,len);
}
// 查看数组
function returnArray() external view returns( int[] memory){
return nums;
}
// 删除元素
function remove(uint _index) public {
for (uint i = _index; i< nums.length-1;i++){
nums[i] = nums[i+1];
}
nums.pop();
}
}
异常
require(_owners[tokenId] == msg.sender, "Transfer Not Owner");
assert(_owners[tokenId] == msg.sender);
数组方法
pragma solidity 0.6.10;
//定义Test6合约
contract Array_ {
//个ages变量,类型为uint类型阳,并在声明时初始化值
uint[] public ages =[10,11,12];
//在数组未尾添加空元素
function pushEmpty() public {
ages.push();
}
//在数组未尾添加指定元素
function pushAge(uint age)public {
ages.push(age);
}
//删除数组未尾元素
function popAge() public {
ages.pop();
}
//将指定索引的元素设置为0值
function deleteAge(uint index) public {
delete ages[index];
}
function getAges() public returns(uint[] memory){
return ages;
}
function getLength() public returns(uint){
return ages.length;
}
// 查看数组
function returnArray() external view returns(uint[] memory){
return ages;
}
// 删除元素:1. 前面不变 后面往前移,删最后一个。
function remove1(uint _index) public {
require (_index < ages.length,"index out of band");
for (uint i = _index; i< ages.length-1;i++){
ages[i] = ages[i+1];
}
ages.pop();
}
// 删除元素:2.最后一个数替换后删。不考虑顺序。
function remove2 (uint _index) external {
require (_index<ages.length,"index out of band");
ages[_index] = ages[ages.length-1];
ages.pop();
}
//测试,当检查条件不成立的时候,就会抛出异常
function test() external view {
assert (ages.length==3);
assert (ages[0]==1);
}
}
字节数组
pragma solidity 0.6.10;
contract arry_char{
//初始化A,类型为字节数组
bytes public A;
//初始化B,类型为字节数组
bytes public B= "hellw";
//初始化C,字符串
string public c= "world";
//bytes类型使用push删除元素
function pushA(byte b)public {
A.push(b);
}
//bvtes类型使用pop删除元素
function popA()public {
A.pop();
}
//bytes类型修改指定索引元素
function changeB()public {
B[4]= "o";
}
//string类型不能获取长度或修改指定索引元素
function errFunc()public {
//C.length;
// C[0] = "a"
}
}
映射
pragma solidity 0.6.10;
contract Test_mapping {
//声明全局变量users,类型为mapping键为uint类型,值为string类型
mapping(uint=>string)public users;
// 设置用户名
function setuser(uint userID, string memory name) public {
users[userID]= name;
}
// 获取用户名
function getuser(uint userID)public returns(string memory){
return users[userID];
}
// 删除用户
function deleteuser(uint userID)public {
delete users[userID];
}
}
数组和映射组合快速判断。
pragma solidity 0.6.10;
contract IterableMapping{
mapping (address=>uint) balances;
mapping (address=>bool) inserted;
address[] keys;
function set(address _key, uint _val) external {
balances[_key]= _val;
if (!inserted[_key]){
inserted[_key] = true;//可以快速判断存在
keys.push(_key);
}
}
//数组长度
function getSize() external view returns (uint){
return keys.length;
}
// 第一个值
function getFirst() external view returns (uint){
return balances[keys[0]];
}
}
7.6 结构体
pragma solidity 0.6.10;
contract Structs{
struct Car{
string model;
uint year;
address owner;
}
Car c;
Car[] cs;
mapping (address=>Car[]) carbyown;
function example() external {
//初始化
Car memory benchi = Car("benchi",1984,msg.sender);
Car memory baoma = Car({year:1999,model:"baoma",owner:msg.sender});
Car memory aodi;
aodi.model ="aodi";
aodi.year = 2000;
aodi.owner=msg.sender;
cs.push(benchi);
cs.push(baoma);
cs.push(aodi);
//使用storage指向cs修改
Car storage c=cs[0];
c.year = 1985;
delete c.model;
}
// 返回第值
function returnstruct(uint _i) external view returns(uint,string memory,address){
return (cs[_i].year,cs[_i].model,cs[_i].owner);
}
}
//声明soliditv版本为0.6.10
pragma solidity 0.6.10;
contract Test_struct{
//定义枚举类型
enum gender {
male, female
}
//定义结构体类型
struct user {
uint ID;// 用户ID
string name; //用户名
gender _gender;//用户性别
}
//声明全局变量user,变量类型为
user public _user;//创建用户
function createUser(uint userID, string memory name, bool isFemale) public{
_user =user(userID,name,gender.male);
if(isFemale){
_user._gender =gender.female;
}
}
//更新用户名
function updateUserName(string memory name) public {
_user.name = name;
}
//获取用户性别
function getUserGender() public returns(string memory){
if(_user._gender == gender.male){
return"男";
}
return"女";
}
}
7.7 修饰符
pragma solidity 0.6.10;
contract ModifyTest {
address public owner;
// 创建合约时初始化owner变量
uint x;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require (owner==msg.sender,"只允许合约创建者操作");
_;
}
modifier compare(uint x,uint y) {
// if(x>y){
// _;
// }
require (x>y,"小于Y");
_;
}
// function test() public onlyOwner returns(uint){
// return x+1;
// }
function test(uint x) public onlyOwner compare(x,9) returns(uint){
return x+1;
}
}
使用lihui部署并调用合约test()函数,输入9,提示错误。
使用lihui部署并调用合约test()函数,输入10,返回11。
使用lihui创建合约,使用test用户调用test(),提示“只允许“
7.8 事件
pragma solidity 0.6.10;
contract EventTest{
event testLog(uint x,string y);
function test(uint a, string memory b) public {
emit testLog(a,b);
}
event message (address _from, address _to, string _message);
function sendMessage(address _to, string memory _message) external {
emit message(msg.sender, _to, _message);
}
}
通过合约管理-在线工具-Event查看
7.9 面向对象
pragma solidity 0.6.10;
contract Object {
string name;
uint age;
//构造函数,初始化
constructor (string memory _name,uint _age) public {
name = _name;
age = _age;
}
function get() external view returns(string memory,uint){
return (name,age);
}
}
部署时就需要初始化
继承
pragma solidity 0.6.10;
contract Animal {
string name;
uint age;
// 构造函数
constructor (string memory _name,uint _age) public {
name = _name;
age = _age;
}
function get_name() public view returns(string memory){
return name;
}
function get_age() public view returns (uint){
return age;
}
}
pragma solidity 0.6.10;
import "./Animal.sol";
contract Dog is Animal{
constructor(string memory _name, uint _age) Animal(_name, _age) public{
}
//使用super话用父合约中的petName座
function dogName() public view returns(string memory){
return super.get_name();
}
//通过指定合约名调用父合约中的getAge函数
function dogAge() public view returns(uint){
return Animal.get_age();
}
}
直接使用父类方法和自写方法一样。
多继承
pragma solidity 0.6.10;
contract Pet {
// 和人玩耍
function play()public view returns(string memory){
return "play with people";
}
//陪伴人
function accompany()public returns(string memory){
return "accompany with people";
}
}
pragma solidity 0.6.10;
import "./Animal.sol";
import "./Pet.sol";
// is Pet 则继承Pet方法
contract CatPet is Animal,Pet{
//构造函数继承的两种方式
//contract CatPet is Animal("cat",22),Pet{
constructor(string memory _name, uint _age) Animal(_name, _age) public{
}
//使用super话用父合约中的petName座
function dogName() public view returns(string memory){
return super.get_name();
}
//通过指定合约名调用父合约中的getAge函数
function dogAge() public view returns(uint){
return Animal.get_age();
}
}
new 创建合约
//在NewPet中引用Pet, 并使用new 关键字创建
pragma solidity 0.6.10;
import "./Pet.sol";
contract NewPet {
address petaddr;
function deploy() public returns(address){
Pet pt = new Pet();
petaddr=address(pt);
return petaddr;
}
function get() public view returns (string memory){
return Pet(petaddr).play();
}
}
方法覆盖
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.10;
contract A {
function foo() external view virtual returns(string memory){
return "A";
}
function bar() external view returns(string memory){
return "ab";
}
}
pragma solidity 0.6.10;
import "./A.sol";
contract B is A {
function foo() external view virtual override returns(string memory){
return "Ba";
}
}
pragma solidity 0.6.10;
import "./B.sol";
contract C is B {
function foo() external view override returns(string memory){
return "Cb";
}
}
7.10 抽象合约
pragma solidity 0.6.10;
abstract contract A {
function foo() external view virtual returns(string memory){
return "A";
}
function bar() external view returns(string memory){
return "ab";
}
function virt(uint x,uint y) public virtual returns (uint);
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.10;
import "./A.sol";
contract B is A {
function foo() external view virtual override returns(string memory){
return "Ba";
}
function virt(uint _x,uint _y) public override returns (uint){
return _x+_y;
}
}
7.11接口合约
7.12 库合约
pragma solidity 0.6.10;
library Librar {
function max(int x,int y) internal pure returns (int){
return x>y?x:y;//取最大值
}
function find(int[] storage arr,int t) internal view returns(uint){
for (uint i =0;i<arr.length;i++){
if (arr[i] ==t) return i;
}//查找值
revert ("no find");
}
}
contract Library {
function test(int x,int y) external view returns (int){
return Librar.max(x,y);//调用库函数
}
using Librar for *;//简化库函数调用
function test2(int x,int y) external view returns(int){
return x.max(y);
}
int[] arr = [1,2,3,6];
function testfind() external view returns(uint){
return arr.find(2);
}
}
九、案例
9.1 权限控制合约
pragma solidity 0.6.10;
contract AcessContract {
event GrantRole(bytes32 indexed _role, address indexed _account);
//role=>account=>bool
mapping (bytes32=>mapping(address=>bool)) public roles;
bytes32 private constant ADMIN = keccak256(abi.encodePacked("ADMIN"));
bytes32 private constant USER = keccak256(abi.encodePacked("USER"));
//升级权限
function grantRole(bytes32 _role,address _account) internal {
roles[_role][_account] = true;
emit GrantRole(_role,_account);
}
//取消权限
function evokeRole(bytes32 _role,address _account) internal {
roles[_role][_account] = false ;
emit GrantRole(_role,_account);
}
modifier onlyRole(bytes32 _role){
require (roles[_role][msg.sender],"not auth");
_;
}
constructor() public {
grantRole(ADMIN,msg.sender);
}
// ADMIN才能修改
function grantRoleW(bytes32 _role,address _account) external onlyRole(ADMIN) {
grantRole(_role,_account);
}
}
9.2 投票合约
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;
contract ballot{
// 选民
struct Voter{
uint weight; //权重
bool voted; //是否已投票
string proposalName;//
address delegate;// 被委托人
}
//提案
struct Proposal{
string name;//提案名
uint voteCout;//投票数
}
//主持人
address public chairPerson;
//存储所有选民
mapping(address=>Voter) public voters;
//存储所有提案
Proposal[] public proposals;
//是否在投票中
bool voting = true;
//修饰符,只有主持人可以操作
modifier onlychairPerson() {
require(chairPerson == msg.sender,"只有主持人可以操作");
_;
}
// 修饰符,只有投票正在中可以操作
modifier onlyproposals(){
require(voting,"投票已结束");
_;
}
//创建合约 传入提案名
constructor(string[] memory proposalNames) public{
//合约创建者为主持人
chairPerson = msg.sender;
// 给主持人赋权
voters[msg.sender].weight =1;
// 添加提案到数组
for (uint i =0;i<proposalNames.length;i++){
proposals.push(
//Proposal(proposalNames[i],0));
Proposal({name:proposalNames[i],voteCout:0})
);
}
}
//内部使用工具 根据提案名获取索引
function getProposalIndexByName(string memory _name) private view returns(uint){
for (uint i = 0; i<proposals.length;i++){
if (keccak256(abi.encodePacked(_name)) == keccak256(abi.encodePacked(proposals[i].name))){
return i;
}
}
revert("未找到");
}
//授权某个选民进行投票
function approveToVote(address voteradd) public onlychairPerson onlyproposals {
require (voters[voteradd].voted == false,"已投票");
require (voters[voteradd].weight ==0,"已赋权");
voters[voteradd].weight =1;
}
// 投票给某提案
function vote(string memory _proposalName) public onlyproposals{
Voter storage sender = voters[msg.sender];
require (sender.voted == false,"已投票");
sender.voted=true;
sender.proposalName= _proposalName;
uint i= getProposalIndexByName(_proposalName);
proposals[i].voteCout += sender.weight;
}
// 停止投票
function stoped() public onlychairPerson {
voting=false;
}
// 将投票权委托给指定用户,并跟随指定用户的投票
function delegate(address delegateAddr) public onlyproposals {
//获取操作用户
Voter storage sender = voters[msg.sender];
require (sender.voted == false,"已投票");
require(delegateAddr!=msg.sender,"自己不能自己委托" );
//委托是可以传递的,可能形成闭环让合约卡住
while (voters[delegateAddr].delegate!=address(0)){
delegateAddr =voters[delegateAddr].delegate;
require(delegateAddr!= msg.sender,"不能循环委托");
}
//设置为已投票
sender.voted=true;
sender.delegate = delegateAddr;
//获取被委托人
Voter storage d = voters[delegateAddr];
if (d.voted){
//若被委托人投过票,则直接增加票数
uint i = getProposalIndexByName(d.proposalName);
proposals[i].voteCout+=sender.weight;
} else {
// 若被委托人没投过票,增加被委托人票数
d.weight += sender.weight;
}
}
//获取投票最多的提案
function getMax() public view returns (string memory winName){
uint maxVote=0;
for (uint i = 0; i<proposals.length;i++){
if(proposals[i].voteCout >maxVote){
maxVote = proposals[i].voteCout;
winName = proposals[i].name;
}
}
return winName;
}
}
通过代码了解联邦选举流程
pragma solidity 0.6.10;
pragma experimental ABIEncoderV2;
contract ballot2{
struct Area{
string name; //选取名称
uint weight; // 选区计票权重
mapping(string=>uint) Proposal;// 该区投票情况
}
//投票人
struct Voter{
uint weight; //权重
bool voted; //是否已投票
string proposalName;//
string areaName;// 选区名
}
//提案
struct Proposal{
string name;//提案名
uint voteCout;//投票数
}
//主持人
address public chairPerson;
//存储所有选民
mapping(address=>Voter) public voters;
//存储所有提案
Proposal[] public proposals;
//存储所有的选区
Area[] areas;
//是否在投票中
bool voting = true;
//修饰符,只有主持人可以操作
modifier onlychairPerson() {
require(chairPerson == msg.sender,"只有主持人可以操作");
_;
}
// 修饰符,只有投票正在中可以操作
modifier onlyproposals(){
require(voting,"投票已结束");
_;
}
//创建合约 传入提案名和主持人所在地区
constructor(string[] memory proposalNames,string memory chairPersonArea) public{
//合约创建者为主持人
chairPerson = msg.sender;
// 给主持人赋权
voters[msg.sender].weight =1;
// 设置主持人所在区域
voters[chairPerson].areaName = chairPersonArea;
// 添加提案到数组
for (uint i =0;i<proposalNames.length;i++){
proposals.push(
//Proposal(proposalNames[i],0));
Proposal({name:proposalNames[i],voteCout:0})
);
}
}
//内部使用工具 根据提案名获取索引
function getProposalIndexByName(string memory _name) public view returns(uint){
for (uint i = 0; i<proposals.length;i++){
if (keccak256(abi.encodePacked(_name)) == keccak256(abi.encodePacked(proposals[i].name))){
return i;
}
}
revert("未找到");
}
//内部使用工具 根据提小区获取索引
function getAreaIndexByName(string memory _name) public view returns(uint){
for (uint i = 0; i<areas.length;i++){
if (keccak256(abi.encodePacked(_name)) == keccak256(abi.encodePacked(areas[i].name))){
return i;
}
}
revert("未找到");
}
// 添加小区
function addArea(string memory _name,uint _weight) public onlychairPerson onlyproposals{
areas.push(
Area({name:_name,weight:_weight})
);
}
//授权某个选民进行投票,并设置选民所在地区
function approveToVote(address voteradd,string memory _areaname) public onlychairPerson onlyproposals {
require (voters[voteradd].voted == false,"已投票");
require (voters[voteradd].weight ==0,"已赋权");
voters[voteradd].weight =1;
voters[voteradd].areaName = _areaname;
}
// 投票给某提案
function vote(string memory _proposalName) public onlyproposals{
Voter storage sender = voters[msg.sender];
require (sender.voted == false,"已投票");
sender.voted=true;
sender.proposalName= _proposalName;
uint areai= getAreaIndexByName(sender.areaName);
//获取选民选区,增加对应投票
areas[areai].Proposal[_proposalName] += sender.weight;
}
// 停止投票
function stoped() public onlychairPerson {
voting=false;
}
//获取区域最大投票和权重
function getAreaMax(string memory _areaname) public view returns (string memory winName,uint){
uint maxVote=0;
// 获取指定区域
uint areai= getAreaIndexByName(_areaname);
Area storage a = areas[areai];
for (uint i = 0; i<proposals.length;i++){
uint ProposalCount = a.Proposal[proposals[i].name];
if(ProposalCount>maxVote){
maxVote = ProposalCount;
winName = proposals[i].name;
}
}
return (winName,a.weight);
}
//将每个区的票相加
function areaTotel() public onlyproposals {
string memory winName;
uint winWeight;
for (uint i =0;i<areas.length;i++){
(winName,winWeight) = getAreaMax(areas[i].name);
uint indexi = getProposalIndexByName(winName);
proposals[i].voteCout += winWeight;
}
}
//获取投票最多的提案
function getMax() public view returns (string memory winName){
uint maxVote=0;
for (uint i = 0; i<proposals.length;i++){
if(proposals[i].voteCout >maxVote){
maxVote = proposals[i].voteCout;
winName = proposals[i].name;
}
}
return winName;
}
}
9.3 拍卖合约
pragma solidity 0.6.10;
contract Auction{
//拍卖收益人
address public beneficiary;
//拍卖结束的时间戳(毫秒)
uint public auctionEnd;
//当前出价最高者和最高金额
address public highestBidder;
uint public highestBid;
//参与拍卖用户余额
mapping (address=>uint) public balance;
//最高出价变更EVENT
event HighestBidIncreased(address bidder,uint amount);
//初始化拍卖,传入拍卖时间(秒)和收益人地址
constructor (address _beneficiary, uint _biddingtime) public{
beneficiary = _beneficiary;
auctionEnd = now+_biddingtime*1000;
}
//存入余额
function deposit(uint _value) public{
balance[msg.sender] += _value;
}
//取出余额
function withdraw() public returns(uint) {
uint valueNow =balance[msg.sender];
balance[msg.sender]=0;
return valueNow;
}
// 竞拍出价
function bid (uint _value) public {
require(now<=auctionEnd,"拍卖时间结束");
require(balance[msg.sender]>=highestBid,"余额不足");
require(_value > highestBid,"当前价低于最高价");
// 将余额返还给之前最高者
balance[highestBidder]+=highestBid;
// 当前最高者减余额
balance[msg.sender]-= _value;
//更新最高者,发送event
highestBidder = msg.sender;
highestBid = _value;
emit HighestBidIncreased(msg.sender,_value);
}
function stopAuction() public {
require(now>auctionEnd,"拍卖时间未到");
balance[beneficiary]+=highestBid;
}
}
// 声明 solidity 版本为 0.6.10
pragma solidity 0.6.10;
// 定义 Auction 合约
contract Auction2{
//拍卖结构体,存储盲拍的散列和保证金
struct Bid{
bytes32 blindedBid;
uint margin;
}
//拍卖受益人
address public beneficiary;
// 拍卖结束的时间戳
uint public biddingEnd;
// 出价披露结束的时间戳
uint public revealEnd;
// 参数拍卖的用户
mapping(address =>Bid) public bids;
//当前出价最高者和最高金额
address public highestBidder;
uint public highestBid;
// 参与拍卖用户的余额
mapping(address=>uint) balance;
// 修饰符,限制操作时间必须小于 time
modifier onlyBefore(uint time){
require(now<time);
_;
}
// 修饰符,限制操作时间必须大于 time
modifier onlyAfter(uint time){
require(now>time);
_;
}
// 初始化拍卖,传入拍卖持续时间(秒),出价披露持续时间(秒),受益人地址
constructor(uint biddingTime,uint revealTime,address beneficiary)public{
beneficiary=beneficiary;
biddingEnd =now+biddingTime*1000;
revealEnd =biddingEnd +revealTime*1000;
}
// 存入余额
function deposit(uint value)public {
balance[msg.sender]+=value;
}
//取出余额
function withdraw()public returns(uint){
uint value =balance[msg.sender];
balance[msg.sender]=0;
return value;
}
// 工具函数,供用户计算哈希(该函数不会在区块链上留下日志)
function bidTool(uint value, string memory secret)public view returns(bytes32){
return keccak256(abi.encodePacked(value,secret));
}
//盲拍,传入盲拍哈希值和保证金
function blindedBid(bytes32 blindedBid, uint value) public onlyBefore(biddingEnd){
require(balance[msg.sender]>= value,"余额不足");
balance[msg.sender]-= value;
Bid storage bid= bids[msg.sender];
require(bid.margin ==0,"只能出价一次");
bids[msg.sender]= Bid({blindedBid:blindedBid,margin:value});
}
// 判断 value 是否为最高出价,更新当前最高价和出价用户
function placeBid(address bidder, uint value)internal returns (bool success){
if(value<= highestBid){return false;}
if(highestBid !=0 ){balance[highestBidder]+=highestBid;}
highestBid =value;
highestBidder=bidder;
return true;
}
//披露价格,验证哈希值,正确则执行出价流程
function reveal(uint value, string memory secret) public onlyAfter(biddingEnd) onlyBefore(revealEnd){
Bid storage bid= bids[msg.sender];
uint refund = bid.margin;
if(bid.blindedBid != keccak256(abi.encodePacked(value, secret))){
return;
}
//只能披露一次价格
if(bid.blindedBid ==bytes32(0)){
return;
}
bool isHighest=placeBid(msg.sender,value);
if(isHighest){
refund -= value;
}
//将盲拍哈希设置为空
bid.blindedBid=bytes32(0);
balance[msg.sender]+= refund;
}
//结束拍卖,将拍卖所得转给受益人
function stopAuction()public{
require(now>= biddingEnd,"拍卖还未到结束时间");
balance[beneficiary]+= highestBid;
}
}