Solidity 进阶编程 | 注意一下合约中的细节

举报
小生凡一 发表于 2021/10/15 23:21:24 2021/10/15
【摘要】 目录 1. 内置的全局变量2. 错误处理3. 访问函数4. 创建合约5. 合约继承6. 修饰器modifier最后 补充知识: 转账的话是与部署者无关,与交易者有关!gas是以太坊网络中的...

补充知识:

  1. 转账的话是与部署者无关,与交易者有关!
  2. gas是以太坊网络中的一个计量单位,是为了对算力消耗进行量化而设计的指标,也就是说有了gas这个计算单位,我们可以方便的计算出用户完成一笔交易需要支出多少gas费用,矿工完成一个区块的打包确认能收到多少gas报酬。
    请添加图片描述

1. 内置的全局变量

  • msg.sender:

获取调用者地址,下面的例子是部署者调用了,所以是部署者的地址,
比如a账户部署,但是是使用b账户调用下getOwner的话,那么这个时候的owner就是b账户的地址了。

pragma solidity 0.4.22;
contract Owner {
    address public owner;
    function getOwner() public {
        owner = msg.sender;   // 获取调用者的地址
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • msg.value:

可以接收payable修饰的转账金额,单位:wei,必须要有payable

可以用接收的value进行判断限制,比如转账金额必须在某个范围,balance做不到

pragma solidity 0.4.22;
contract Value {
    uint256 public money;
    function getValue() public payable {
        money = msg.value;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果加if判断:

pragma solidity 0.4.22;

contract Value {
    uint256 public money;
    function getValue() public payable {
        if( msg.value == 666) {  // 转钱金额为666wei才赋值 
            money = msg.value;
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注意:需要转钱,注意单位默认是wei

内置的全局变量 简称 类型
blockhash 哈希值 byte32
block.coinbase 当前块矿工的地址 address
block.difficulty 当前块的难度 uint
block.gaslimi 当前块的gaslimit uint
block.number 当前块的块号 uint
block.timestamp 当前块的时间戳 uint
gasleft() 剩余的gas uint
msg.sender 调用者的地址 address
msg.value 转账的金额(单位:wei) uint
msg.data 完整的调用数据 calldata bytes
now 当前块的时间戳 uint(和block.timestamp相同)
tx.gasprice 交易的gas价格 uint
tx.origin 交易的发送者 address

请添加图片描述

2. 错误处理

  • require:
    require 式的异常不会消耗任何 gas,官方推荐使用require,相当于if {throw},没有else的
    最终底层触发的也是assert式的错误
require(msg.value == 666);    // 如果不满足则报错,否则继续往下执行

  
 
  • 1

类似于下面的:注意条件正好是相反的

if (msg.value <= 6 * 10 ** 18)  {
    // todo 涉及到错误处理
    throw;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • assert:
    即使有错误,也会执行并扣除gas
assert(msg.value == 666 );    // 如果不满足则报错,否则继续往下执行

  
 
  • 1
  • revert():处理更复杂逻辑的场景,比如if/else
if (msg.value <= 6 * 10 ** 18){
    revert();
} else {
    b = 666;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • require(条件); 如果满足条件则继续往下执行,如果不满足则报错,不扣除gas,推荐使用
  • assert(条件); assert扣除gas,不推荐使用
  • revert(): 负责逻辑中使用,if(条件){revert();}else{…}

3. 访问函数

原来要返回一个变量,得写个函数返回

pragma solidity 0.4.22;
contract Hello {
    string name = "hallen";
    function get_name() public view returns(string){
        return name;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果用public修饰了变量,会生成一个同名的访问函数,可以直接访问

pragma solidity 0.4.22;
contract Fan {
    string public name = "fanone";
    function getName() public view returns(string){
        return name;
        // return this.data(); 合约内部使用this也是要调用访问函数的
    }
}
contract One {
    function getHelloName() public view returns (string){
        Fan h = new Fan();   // 地址直接强转合约类型
        return h.name();    // 这里必须加括号,是个访问函数
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4. 创建合约

  • new : 返回的是地址,需要转合约类型
    初始化合约的时候用到这种方式
Fan h = new Fan();  // 把地址直接强转为合约类型

  
 
  • 1

和java有点像
合约变量(Fan public h),此时是空的,需要赋值地址才能使用,否则报错
合约类型作为参数的场景用到这种方式

Fan public h;
// 函数中赋值
address addr = new Fan();
h = Fan(addr); // 赋值地址

  
 
  • 1
  • 2
  • 3
  • 4

转账语法:
h.get_money.value(20).gas(800)();

h必须是赋值地址后的合约对象

pragma solidity 0.4.24;
contract Test1{
    // 获取转账钱
    function contractGetMoney() public payable{
    }
    // 查看余额
    function getBalance() public view returns(uint256){
        return address(this).balance;
    }
}
contract Test2 {
    // 查看余额
    function getBalance() public view returns(uint256){
        return address(this).balance;
    }
    // 获取转账钱
    function contractGetMoney()public payable{
    }
    // transfer:谁调用就给谁转钱
    Test1 public t1;
    function getAddr(address addr) public{
        t1 = Test1(addr);
    }
    // 转钱给Test1合约
    function payToT1() public{
        t1.contract_get_money.value(5 * 10 **18).gas(200)();
    }
    // 付钱得用payable修饰,使用匿名函数
    function () public payable {}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

5. 合约继承

  • 使用is关键字,多个父合约用逗号隔开
    contract 合约名 is 父合约1,父合约2,… {}
    constract Cat is Animail,Lactation{} // Lactation:哺乳动物
    如果两个父合约中有相同的函数,则遵循最远继承原则(继承顺序,Animail最近,Lactation最远,所以是Lactation中的)

6. 修饰器modifier

在函数执行前检查是否满足前置条件,满足条件才执行函数

pragma solidity 0.4.22;
contract Value {
    uint256 public money;
    modifier check_money(){
        require(msg.value == 10);
        _;  // 修饰的代码,指进入函数后的所有代码
    }
    function get_value() public payable check_money{  // check_money就是前面定义的修饰器
        money = msg.value;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

可以结合构造函数,判断是不是管理员(部署者),只有是管理员才可以访问的函数可以加修饰器

pragma solidity 0.4.22;
contract Value {
    address public owner;
    uint256 public money;
    constructor() public{
        owner = msg.sender;
    }
    modifier check_owner(){
        require(msg.sender == owner);
        _;   // 修饰的代码,指进入函数后的所有代码
    }
    function get_value() public payable check_money{
        money = msg.value;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最后

小生凡一,期待你的关注。
在这里插入图片描述

文章来源: blog.csdn.net,作者:小生凡一,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_45304503/article/details/118979085

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。