基于以太坊的智能合约开发

关键词: ETH, 区块链, 开发, 智能合约 状态: 进行中

小结:智能合约类似于定义各种结构体及方法,这些方法及对象将保存在区块链数据库中并将操作未来的数据库对象。

first helloworld

pragma solidity ^0.4.0;

contract helloword{
    string Myname = "name";
    function getName() public returns(string){
        return Myname;
    }
    function setName(string _name)public{
        Myname =  _name;
    }
}

/images/ETHContracts2020-03-16/Untitled.png

以太坊地址的本质

账户地址

外部账户地址0x5B38Da6a701c568545dCfcB03FcB875f56beddC4

合约地址0x0fC5025C764cE34df352757e82f7B5c4Df39A836

使用钱包转移资金

pragma solidity ^0.4.0;

contract payableTest{
    function pay() payable{ //payable 关键字使合约可接收转账,执行pay方法往合约转账
        
    }
    function getBalance() returns(uint){
        return this.balance; //获取合约账户金额,wei为单位,1eth=10的18次方的位
    }
    
}

执行pay方法通过外部账户往合约转帐

/images/ETHContracts2020-03-16/Untitled%201.png

this属性

this代表着合约地址

balance获取地址的金额

外部地址转账

pragma solidity ^0.4.0;

contract payableTest{
    function pay() payable{ //PayContracts同功能
        
    }
    function getMyBalance() returns(uint){
        return this.balance;
    }
    function getBalance(address _account) returns(uint){
        return _account.balance;
    }

    function transfer(address _account) payable{ //所有转账需要加上payable,往外部地址转账
        address account = _account;
        account.transfer(msg.value); //向指定账户转账
    }

		function PayContracts()payable{ //向本合约转账需要配合回滚函数,function ()payable
        this.transfer(msg.value);
    }
    
    function ()payable{ 
        
    }
}

以太坊中的全局属性

pragma solidity ^0.4.0;

contract grobal{
    function getSander()  returns(address){ //获取发送者
        return msg.sender;
    }
    
    
    function getBlockDifficulty()  returns(uint){ //获取当前块困难度
        return block.difficulty;
    }
    
    function getBlockMum() returns(uint){ //获取合约所在区块的id
        return block.number;
    }
    
    function getCoinbase()  returns(address){ //获取当前块是哪个矿工挖出的
        return block.coinbase;
    }
    
    
}
- msg
msg.sender(address) 消息发送者(当前调用)
msg.value (uint) 随消息发送的 wei 的数量
msg.data (bytes) 完整的 calldata
msg.gas (uint) 剩余 gas ,( 弃!)推荐使用gasleft()
msg.sig (bytes4) calldata 的前 4 字节(也就是函数标识符)
- tx
tx.gasprice (uint) 交易的 gas 价格
tx.origin (address) 交易发起者(完全的调用链)
- block
block.blockhash(uint blockNumber) (bytes32) 指定区块的区块哈希,仅可用于最新的 256 个区块且不包括当前区块,( 弃!)推荐使用blockhash(uint blockNumber)
block.coinbase (address): 挖出当前区块的矿工地址
block.difficulty (uint): 当前区块难度
block.gaslimit (uint): 当前区块 gas 限额
block.number (uint): 当前区块号
block.timestamp (uint): 自 unix epoch 起始当前区块以秒计的时间戳
- address
<address>.balance (uint256): 以 Wei 为单位的地址类型的余额。
<address payable>.transfer(uint256 amount): 向地址类型发送数量为 amount 的 Wei,失败时抛出异常,发送 2300 gas 的矿工费,不可调节。
<address payable>.send(uint256 amount) returns (bool):向地址类型发送数量为 amount 的 Wei,失败时返回 false,发送 2300 gas 的矿工费用,不可调节。
<address>.call(...) returns (bool): 发出低级函数 CALL,失败时返回 false,发送所有可用 gas,可调节。
<address>.callcode(...) returns (bool):已禁止使用。
<address>.delegatecall(...) returns (bool):发出低级函数 DELEGATECALL,失败时返回 false,发送所有可用 gas,可调节。
- alias
now (uint): 目前区块时间戳(block.timestamp)
blockhash(uint blockNumber)returns(bytes32) 指定区块的区块哈希,限制256个之内
gasleft() returns(uint) 剩余的 gas, (msg.gas)
staticcall()

转账尽量用transfer ,sand是底层函数,返回bool类型,比较危险。

Mapping映射

使用mapping制作注册和数据库功能

pragma solidity ^0.4.0;

contract maptest{
    //mapping
    mapping(address => uint) idmapping;
    mapping(uint => string) namemapping;
    uint sum = 1; //初始id,可设置为0,防止1号id被抢注册
    function register(string name){
        address account = msg.sender; 
        if (idmapping[account] == 0){ //判断注册者外部地址是否注册过平台,防止account一对多
            sum ++; //id默认加1
            idmapping[account] = sum;
            namemapping[sum] = name;
        }
    }

//方法可重写,使用不同参数获取数据
    function getName(uint id) returns(string){
        return namemapping[id];
    }
    function getName() returns(string){
        return namemapping[idmapping[msg.sender]];
    }
    function getName(address _address) returns(string){
        return namemapping[idmapping[_address]];
    }
    function getId() returns(uint){
        return idmapping[msg.sender];
    }
    function getId(address _address) returns(uint){
        return idmapping[_address];
    }
    
}

function修饰符

external 修饰符允许函数在函数外部调用,不允许函数被内部函数调用

使用间接方法调用this.test

pragma solidity ^0.4.0;

contract maptest{
    //mapping
    mapping(address => uint) idmapping;
    mapping(uint => string) namemapping;
    uint sum = 0;
    function register(string name){
        address account = msg.sender; 
        if (idmapping[account] == 0){
            sum ++;
            idmapping[account] = sum;
            namemapping[sum] = name;
        }
        
        
    }
    function getNameExternal(uint id) external returns(string){ //external 修饰,只允许外部调用
        return namemapping[id];
    }
    function getName(uint id) returns(string){ //间接调用external所修饰的方法
        return this.getNameExternal(id);
    }
    function getName() returns(string){
        return namemapping[idmapping[msg.sender]];
    }
    function getName(address _address) returns(string){
        return namemapping[idmapping[_address]];
    }
    function getId() returns(uint){
        return idmapping[msg.sender];
    }
    function getId(address _address) returns(uint){
        return idmapping[_address];
    }
    
}

contract externalTest{
    maptest m = new maptest(); //通过new一个函数进行调用
    function externalTestgetNameExternal(uint id) returns(string){
        return m.getNameExternal(id);
    }
}
contract mapson is maptest{ //通过继承方法中使用this调用
    function getName(uint id) returns(string){
        return this.getNameExternal(id);
    }
}

constant关键字

constant 在4.0中等价于 view,使用不消耗gas,在5.0中即将废弃

定义类似常量,定义后不允许修改

pragma solidity ^0.4.0;

contract addresstest{
    address public account;
    address public constant add = 0x617F2E2fD72FD9D5503197092aC168c91465E7f2;
    
    function getaddress() public returns(uint160){
        
        return uint160(account);
    }
    
}

合约中的构造函数

pragma solidity ^0.4.0;

contract constructTest{
    address public owner;
    uint private a;
    function constructTest(uint _a,uint _b){
        owner = msg.sender;
        a = _a;
    }
}

contract constructorTest{
    address owner;  //利用构造函数声明合约拥有者
    uint private a;
    constructor(uint _a,uint _b){ //在部署合约时会执行,constructor新的构造函数命名方式
        owner = msg.sender;  
        a = _a;
    }
}

modifier函数

pragma solidity ^0.4.0;

contract modifierTest{
    address owner;
    uint ownerID;
    constructor(){ 
        owner = msg.sender;  // 合约初始化语句,申明拥有者
    }
    
    modifier OnlyOwner{
        require(msg.sender == owner); //判断语句,如果false,则函数不会往下执行
        _; //动态添加语句处
    }
    
    function changeOwnerID(uint _num)OnlyOwner{ //将函数插入到OnlyOwner函数的_处执行
        ownerID = _num;
    }
}

modifier 常用在判断权限等判断语句,提升代码的重用性;

以下代码可模拟合约所有者设置任意用户的money,用户注册后改名需要花费10money

pragma solidity ^0.4.0;

contract modifierTest{
    address owner;
    uint ownerID;
    
    mapping(address => uint) idmapping;
    mapping(uint => string) namemapping;
    mapping(uint => uint) moneymapping;
    uint userid = 1;
    
    constructor(){ 
        owner = msg.sender;  // 合约初始化语句,申明拥有者
    }
    
    modifier HasMoney(uint needsMoney){
        require(moneymapping[idmapping[msg.sender]] > needsMoney); //判断语句,如果false,则函数不会往下执行
        _;
    }
    modifier OnlyOwner{
        require(msg.sender == owner); 
        _;
    }
    modifier hasNotRegister{
        require(idmapping[msg.sender] == 0); 
        _;
    }
    
    
    function register(string name)hasNotRegister{
            userid ++;
            idmapping[msg.sender] = userid;
            namemapping[userid] = name;
    }

    
    function changeOwnerID(uint _num)OnlyOwner{ //将函数插入到OnlyOwner函数的_处执行
        ownerID = _num;
    }
    
    function setMoney(uint _id,uint _money)OnlyOwner{ //管理员可修改用户金钱数量
        moneymapping[_id] = _money;
    }
    
    function getMoney()returns(uint){ //获取金钱
       return moneymapping[idmapping[msg.sender]];
    }
    
    function setName(string _name)HasMoney(10){//改名花费10money
        namemapping[idmapping[msg.sender]] = _name;
        moneymapping[idmapping[msg.sender]] = moneymapping[idmapping[msg.sender]] -10;
        
    }
    
    function getNameExternal(uint id) external returns(string){ //external 修饰,只允许外部调用
        return namemapping[id];
    }
    function getName(uint id) returns(string){ //间接调用external所修饰的方法
        return this.getNameExternal(id);
    }
    function getName() returns(string){
        return namemapping[idmapping[msg.sender]];
    }
    function getName(address _address) returns(string){
        return namemapping[idmapping[_address]];
    }
    function getId() returns(uint){
        return idmapping[msg.sender];
    }
    function getId(address _address) returns(uint){
        return idmapping[_address];
    }
    
}

合约的继承

is关键词,其他和其他语言差不多。

变量继承

internal/public 可被继承

external 没有external 修饰符

private 修饰私有

方法继承

internal 可被继承,不能外部调用,只允许内部调用

external 可以被继承,需要通过this调用

private 修饰私有

pure/view 修饰,不消耗gas

Getter

pragma solidity ^0.4.0;

contract getter{
    uint public num = 100;
    
    // function num() external view returns(uint){ //此部分代码等价于public。external只允许外部调用
    //     return num;
    // }
    
    function test()returns(uint){
        return this.num();//调用上述代码需添加this
    }
}

多重继承,多个继承靠后优先级大

销毁合约

pragma solidity ^0.4.0;

contract destruct{
    address owner;
    uint public money = 0;
    
    constructor(){
        owner = msg.sender;
    }
    
    function addmoney(){
        money+=100;

    }
    function forcecontract(){
        if(msg.sender == owner){
            selfdestruct(owner);
        }
    }
    
}

内存与存储

storage/memory

数组

/images/ETHContracts2020-03-16/Untitled%202.png

结构体

pragma solidity ^0.4.0;

contract structTest{
    
    struct person{
        uint id;
        string name;
    }

		struct person2{
        uint id;
        string name;
        // person2 p; //结构体不能包含本身,但是可以包含本身的可变长数组,以及mapping
        person2[] pArr; 
        mapping(uint => person2) pMap;
    }
    
    person p1;
    
    function addPerson() returns(uint,string){
        p1 = person({id:20,name:"name"}); //给区块链存储中的p1进行赋值
        person memory p2 = person(22,"name1");  //声明在memory接收
        
    }
    
}

结构体嵌套mapping赋值

pragma solidity ^0.4.0;

contract structTest{
    address owner;
    
    struct user{
        mapping(uint=>string) name;
        mapping(uint=>uint) balance;
    }
    
    mapping(address=>uint) id;
    
    constructor(){
        owner = msg.sender;
        id[msg.sender] =1;
    }
    
    modifier OnlyOwner{
        require(msg.sender == owner); 
        _;
    }
    
    user[] userArr;
    uint userid= 1;
    
    modifier hasNotRegister{
        require(id[msg.sender] == 0); 
        _;
    }
    
    function register(string _name) hasNotRegister{
        userid ++;
        // userArr[userid] = user();
        userArr[id[msg.sender]].name[id[msg.sender]]=_name;
        userArr[id[msg.sender]].balance[id[msg.sender]]=0;
    }
    
    function addMoney(address _address,uint _money)OnlyOwner{
        userArr[id[_address]].balance[id[_address]] = _money;
    }
}

版权声明: 本文除特别声明外,请勿转载。转载请附上原文链接及出处。

comments powered by Disqus