通学智能合约系列--地址交易<下>

Posted 通学技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通学智能合约系列--地址交易<下>相关的知识,希望对你有一定的参考价值。

大家好,通学技术,学通技术,欢迎大家继续跟我一起学习智能合约系列。

5.以太坊中的全局属性

上节内容的最后,我们提出了一个问题,msg.value是什么?

不多卖关子,在solidity中,我们称之为全局变量,这里与我们java,python等语言中全局变量不同,更像是以太坊系统提供给我们的一种系统变量,以方便我们更好地进行转账交易或查询区块链信息等操作。

这里我们重点介绍几个比较重要的以太坊全局变量

pragma solidity ^0.4.16;

contract globleTest{

   function getSender() view returns(address){
      return msg.sender;
   }
   
   function getDifficulty() view returns(uint){
       return block.difficulty;
   }
   
   function getBlockNumber() view returns(uint){
       return block.number;
   }
   
   function getCoinbase() view returns(address){
       return block.coinbase;
   }
 
}

编译部署执行方法后,我们会得到以下结果:

在这里插入图片描述

这里上面主要说了四个全局变量,分别是获取发送者地址、获取当前区块的难度

获取挖出当前区块的矿工地址,获取区块高度。我们后面会经常用到。我几个概念我们可以先简单理解为:

  • ​ 发送者地址:就是谁给你转钱了。或者是 你给你自己钱包里面的银行卡存钱了。
  • ​ 当前区块的难度:就是假如我给你转钱了,要让所有人相信,区块链网络索要耗费的资源
  • ​ 挖出当前区块的矿工地址: 就是这个矿工帮你记账了 ,系统是不是应该奖励一下他。
  • ​ 当前块号的高度: 就是该笔区块是整个区块链中的第几环咯。

关于以太坊的全局变量,我们这里罗列一下,大家可以自行测试。

block.blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希——仅可用于最新的 256 个区块且不包括当前区块;而 blocks 从 0.4.22 版本开始已经不推荐使用,由 blockhash(uint blockNumber) 代替

block.coinbase (address): 挖出当前区块的矿工地址

block.difficulty (uint): 当前区块难度

block.gaslimit (uint): 当前区块 gas 限额

block.number (uint): 当前区块号

block.timestamp (uint): 自 unix epoch 起始当前区块以秒计的时间戳

gasleft() returns (uint256):剩余的 gas

msg.data (bytes): 完整的 calldata

msg.gas (uint): 剩余 gas - 自 0.4.21 版本开始已经不推荐使用,由 gesleft() 代替

msg.sender (address): 消息发送者(当前调用)

msg.sig (bytes4): calldata 的前 4 字节(也就是函数标识符)

msg.value (uint): 随消息发送的 wei 的数量

now (uint): 目前区块时间戳(block.timestamp)

tx.gasprice (uint): 交易的 gas 价格

tx.origin (address): 交易发起者(完全的调用链)

6.转账误操作

在上面的内容中,具体为2.2.1节及4.4.2节中,我们介绍了两种转账方式,并且说明了两者没有什么差别。这里我们把这个内容再放到一起对比下。

pragma solidity ^0.4.16;

contract payableTest{
   
   // callable函数
   function () payable{
   
   }

   // 方式一 可以直接通过外部输入给合约转账 等同于方式二
   function pay() payable{
      
   }
   
   // 方式二 通过外部输入给合约转账 等同于方式一 
   // 注意:使用this关键字 必须写callback函数
   function pay2() payable{
   	   this.transfer(msg.value);
   }
   
   // 方式三 直接给合约转账 
   function pay3() payable{
   	   this.transfer(10 ether);
   }
   
   // 方式四 给其他账户转账 
   function pay4() payable{
       address account = 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
       // account.transfer(10 ether);
       account.transfer(msg.value);
   
   }
   
}

这里我们可以看到方式一、二、三都可以给合约账户进行转账,而方式四则可以指定账户进行转账。

不过在给其他账户进行转账的时候,我们需要注意一点 ,下面来看看:

   // 方式五 给其他账户转账 (慎用 容易引起误操作)
   // 必须给运行界面—>交易金额 设置初始转账金额 不能为0
   function pay5() payable{
       address account = 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
       account.transfer(10 ether);
   }

如果运行界面->交易金额为0时,会报错如下:

transact to payableTest.pay5 errored: VM error: revert.
revert	The transaction has been reverted to the initial state.
Note: The constructor should be payable if you send value.	Debug the transaction to get more information

如果我们设置了初始交易金额 ,则会得到以下结果:

在这里插入图片描述

相信小伙伴们,经过这一小节的练习,转账操作理解会更深刻一些。

7.底层send方法

我们上节内容可以看到,在我们调用transfer方法时,如果说外部输入的交易金额 为0时,则会发生报错。而这里有一个不报错的方法,你想不想用呢?

function sendTest() payable{
       address account = 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
       account.send(10 ether);
   }

但是呢?send方法在执行时会有一些风险:

  • 调用递归不能超过1024
  • 如果gas不够,执行会失败

所以使用send方法,要检查成功与否,我们可以根据其返回值是true还是false进行后续操作,但不建议。

 function sendTest() payable returns(bool){
       address account = 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
       return account.send(10 ether);
   }

transfer相对于send方法来说,更加安全,推荐使用。正所谓印证了那句话,人生苦短,我用transfer.

8.mapping映射–哈希表

这节课内容,视频所举的例子,个人觉得有些牵强,所以按照一下思路,进行讲解。

经过前面的学习,我们都知道,我们运行环境里面的当前账号,就相当于一个数字钱包地址。在以太坊上,我们都可以有一个唯一的钱包地址,那么怎么把这个钱包和我们的身份关联起来呢?在solidity的世界里,我们的身份又怎么和我们的姓名关联起来呢?

如果有小伙伴接触过java,肯定都学过hashMap,面试的必考点之一。我们知道HashMap是可以通过key-value的形式去描述一种绑定关系,那么在solidity的世界里,是不是也存在这样一种数据结构呢?

答案是显然的。就是我们的mapping.

pragma solidity ^0.4.16;

contract mappingTest{
  // 映射 一个钱包地址对应一个个人身份id 
  mapping(address => uint) idMapping;
  // 映射 一个个人身份id地址对应一个个人姓名
  mapping(uint => string) nameMapping;
  
  
  uint id = 1;
  // 给某某人提供以太钱包 
  function offerWallet(string name) {
      
      address account = msg.sender;
      // 先给某某人分配一个身份id,然后将钱包绑定到某某人的身份id上
      idMapping[account] = id;
      // 然后在将个人id与个人姓名进行映射绑定
      nameMapping[id] = name;
      
      id++;
     
  }
  // 根据地质获取身份id
  function getIdByAddress(address account) view returns(uint){
      
      return idMapping[account];
  }
  // 根据id获取个人姓名
  function getNameById(uint id) view returns(string){
      
      return nameMapping[id];
  }
   
}

编译部署后,我们依次执行以下方法,会得到下图所示:

在这里插入图片描述

至此,就解决我们前面提出的问题啦。

以上是关于通学智能合约系列--地址交易<下>的主要内容,如果未能解决你的问题,请参考以下文章

通学智能合约系列--地址交易<上>

通学智能合约系列--地址交易<上>

通学智能合约系列(二十)--结构体<下>

通学智能合约系列(二十一)--结构体<下>

通学智能合约系列(二十一)--结构体<下>

通学智能合约系列(十六)--合约的继承