区块链-智能合约Solidity编程
文章目录
- 一、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=uint256uint _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;// 固定长度 Arrayuint[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];// 可变长度 Arrayuint[] array4;address[] array6;//bytes比较特殊,是数组,不用加[]//可以使用bytes或bytes1[]。bytes 比 bytes1[] 省gasbytes1[] array5;bytes array7; // 初始值 //如果你在变量声明后添加了public关键字,//那么这个变量将自动生成一个与变量名相同的函数,//该函数用于获取这个变量的值bool public _bool_c; // falsestring public _string_c; // ""int public _int_c; // 0uint public _uint_c; // 0address public _address_c; // 0x0000000000000000000000000000000000000000 (或 address(0))//枚举 类比boolenum ActionSet { Buy, Hold, Sell}ActionSet public _enum_c; // 默认值第1个内容Buy的索引0function 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初始化为9function 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]; // 状态变量:数组 xfunction 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值 viewfunction viewFunc() external view returns(int){return num;}// 不需要读写numfunction 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];}// 命名式返回,依然支持returnfunction 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;}//合约地址 和 0function 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执行大括号语句,否则执行elseif(condition){//再判断condition2if(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;// 用户IDstring 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=>boolmapping (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;//最高出价变更EVENTevent 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;//更新最高者,发送eventhighestBidder = 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;// 修饰符,限制操作时间必须小于 timemodifier onlyBefore(uint time){require(now<time);_;}// 修饰符,限制操作时间必须大于 timemodifier 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;}
}
相关文章:
区块链-智能合约Solidity编程
文章目录 一、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 抽象合…...
VS Code创建VUE项目(一)工具安装与项目创建
一.安装与配置npm 1.下载安装Node.js 安装Node.js 下载地址: Node.js — 在任何地方运行 JavaScript (nodejs.org)或下载 | Node.js 中文网 下载后一步步安装就好(安装过程基本一路直接“NEXT”就可以了,直到Finished)&#x…...
cudnn8编译caffe过程(保姆级图文全过程,涵盖各种报错及解决办法)
众所周知,caffe是个较老的框架,而且只支持到cudnn7,但是笔者在复现ds-slam过程中又必须编译caffe,我的cuda版本是11.4,最低只支持到8.2.4,故没办法,只能编译了 在此记录过程、报错及解决办法如下; 首先安装依赖: sudo apt-get install git sudo apt-get install lib…...
Docker安装Nginx
前提:Docker已安装好,本人使用的为自带docker的云服务器,docker常用命令已掌握,yjj为在根目录创建的一个文件夹,可自行修改对应的目录。 1、安装镜像,可去dockerhub上面找,一般都是组件名称。do…...
大数据治理:构建新时代数据生态的关键
摘要 随着信息技术的飞速发展和数字化浪潮的席卷,大数据已成为当今社会的核心资源。如何有效治理大数据,不仅关系到数据资源的利用效率,还对隐私保护、网络安全和社会秩序产生深远影响。本文深入探讨了大数据治理的概念、面临的挑战以及治理框架的构建,从技术、法律和伦理等…...
Leetcode 1223 LCA of Deepest TreeNode
题意,找到所有最深的叶子节点的LCA https://leetcode.com/problems/lowest-common-ancestor-of-deepest-leaves/description/ 第一个想法是模块的想法, LCA 找到所有最深的叶子节点两两组合 可行,但是算法复杂度很高而且你先要从顶到下,再从…...
C++从入门到起飞之——红黑树 全方位剖析!
🌈个人主页:秋风起,再归来~🔥系列专栏:C从入门到起飞 🔖克心守己,律己则安 目录 1. 红⿊树的概念 2. 红⿊树的实现 2.1 构建整体框架 2.2 红黑树的插入 2.3 红黑树的验证 2.4 红黑树…...
Java基于SSM微信小程序物流仓库管理系统设计与实现(lw+数据库+讲解等)
选题背景 随着社会的发展,社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景,运用软件工程原理和开发方法,它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…...
[LeetCode] 733. 图像渲染
题目描述: 有一幅以 m x n 的二维整数数组表示的图画 image ,其中 image[i][j] 表示该图画的像素值大小。你也被给予三个整数 sr , sc 和 color 。你应该从像素 image[sr][sc] 开始对图像进行上色 填充 。 为了完成 上色工作: 从初始像素…...
智能EDA小白从0开始 —— DAY23 PyAether深度解析与技术展望
引言:技术革新与行业需求的碰撞 在半导体行业快速发展的今天,芯片设计的复杂性和对效率的要求日益提升。传统的芯片设计工具和方法已经难以满足当前行业的需求,特别是在面对大规模、高性能芯片的设计时,设计师们面临着前所未有的…...
从深海探测到海洋强国:数字孪生助力海洋装备跨越式发展
海洋广袤无垠,蕴藏着丰富的资源。近现代以来,人类使用各种手段探索海洋探索,广袤无垠的海洋与人类的生活越来越紧密,至少10亿人口摄入的蛋白质来自海洋,全球超过90%的货物、数据信息交流在海洋中转;海洋中丰…...
架构师备考-背诵精华(系统质量属性)
系统质量属性 根据GB/T 16260.1 定义,从管理角度对软件系统质量进行度量,可将影响软件质量的主要因素划分为6种维度特性包括:功能性、可靠性、易用性、效率、维护性、可移植性 功能性 适合性、准确性、互操作性、依从性、安全性 可靠性 容错…...
Pycharm下载安装教程(详细步骤)+汉化设置教程
今天讲解的是Pycharm安装教程和配置汉化设置,希望能够帮助到大家。 创作不易,还请各位同学三连点赞!!收藏!!转发!!! 对于刚入门学习Python还找不到方向的小伙伴可以试试…...
网络安全入门
网络安全入门是指学习和了解网络安全基础知识和技术的入门阶段。网络安全是指保护计算机系统、网络和数据免受未经授权的访问、使用、泄露、破坏以及其他威胁的技术和措施。 要入门网络安全,可以按照以下步骤进行: 了解网络安全基本概念:学习…...
你真的了解Canvas吗--解密十【ZRender篇】
目录 👊🏻入口 动画讲解二 Animator Element Transformable graphic 总结 书接上篇你真的了解Canvas吗--解密九【ZRender篇】由于一个bug的篇幅需要续写这个下篇,不过那块的bug内容对我们这篇要讲的动画也是息息相关的,因为Transformable这个类主要就是和变换相…...
mac安装brew时踩坑解决方案
安装包 mac上如果按照git等工具可能会使用brew,例如使用:$ brew install git命令,如果电脑没有按照brew,则会提示:zsh: command not found: brew 解决方案 需要我们打开brew的官网https://brew.sh/,复制…...
基于Handsontable.js + Excel.js实现表格预览和导出功能(公式渲染)
本文记录在html中基于Handsontable.js Excel.js实现表格预览、导出、带公式单元格渲染功能,在这里我们在html中实现,当然也可以在vue、react等框架中使用npm下载导入依赖文件。 Handsontable官方文档 一、开发前的准备引入相关依赖库 <!DOCTYPE ht…...
重学SpringBoot3-集成Redis(十三)之点排行榜实现
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-集成Redis(十三)之点排行榜实现 1. 为什么选择 Redis 来实现排行榜?2. 项目环境准备2.1. 添加依赖2.2. 配置 Redis 连…...
Java 中方法参数传递的陷阱
前言 在编程过程中,我们经常会遇到一些看似简单却容易出错的问题。本文将通过一个具体的例子,探讨 Java 中方法参数传递的陷阱,并提供详细的解决方法。希望这篇文章能帮助你在未来的开发中避免类似的错误。 问题背景 假设我们的任务是计算…...
哪家云电脑便宜又好用?ToDesk云电脑、顺网云、达龙云全方位评测
陈老老老板🤴 🧙♂️本文专栏:生活(主要讲一下自己生活相关的内容)生活就像海洋,只有意志坚强的人,才能到达彼岸。 🧙♂️本文简述:讲一下市面上云电脑的对比。 🧙♂️上一篇文…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
