以太坊GAS相关知识

准备工作

1、三个账户,eth.account[0]为默认账户,挖矿所得的奖励都会进入到这个账户

> eth.getBalance(eth.accounts[0])
736031150000000000000
> eth.getBalance(eth.accounts[1])
500050000000000000
> eth.getBalance(eth.accounts[2])
500050000000000000

普通交易所需的gas

> eth.estimateGas({from:eth.accounts[1], to: eth.accounts[2], value:50000000000000})
21001
> eth.gasPrice
20000000000

如上,显示这笔account[1] => account[2] 的交易需要21001 gas(estimateGas用于计算交易所需gas), 当前的gasPrice为 20000000000(gasPrice获取到的值),下面来验证一下
给账户1解锁,发送这笔交易,并开启挖矿打包

> eth.sendTransaction({from:eth.accounts[1], to: eth.accounts[2], value:50000000000000})
I0318 00:24:21.360815 internal/ethapi/api.go:1143] Tx(0x33b58084a35e99245b9c931204a0d161b9d00f9fae5ffb307aff29f200e5cd30) to: 0x49fbd70ca9f90972806c375a111d08950d203f96
"0x33b58084a35e99245b9c931204a0d161b9d00f9fae5ffb307aff29f200e5cd30"

待交易被打包后

> eth.getBalance(eth.accounts[1])
499580000000000000
> eth.getBalance(eth.accounts[2])
500100000000000000

由 cost = gas * gasPrice , ( 账户1减少的资产 - 账户2增加的资产)/ gasPrice = 消耗的gas,即以下公式应该是成立的

(500050000000000000 - 499580000000000000) - (500100000000000000 - 500050000000000000) = 21001 * 20000000000 = 420020000000000 

然而 细心的同学应该会发现,这个公式并不能成功,21001 这个数字怎么看怎么别扭,如果减1 这个公式就成功了!!!继续
查看这笔交易的明细

> eth.getTransactionReceipt("0x33b58084a35e99245b9c931204a0d161b9d00f9fae5ffb307aff29f200e5cd30")
{
  blockHash: "0x8e411163367bc42a70ecc230d05dd2038afe0dccfab29c8a718a57bdbea0b2fa",
  blockNumber: 134,
  contractAddress: null,
  cumulativeGasUsed: 21000,
  from: "0x27c649b7c4f66cfaedb99d6b38527db4deda6f41",
  gasUsed: 21000,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0x2008f134f3328e48d4d05919666a5924767b00b286cf1ff27b7956654d5b6482",
  to: "0x49fbd70ca9f90972806c375a111d08950d203f96",
  transactionHash: "0x33b58084a35e99245b9c931204a0d161b9d00f9fae5ffb307aff29f200e5cd30",
  transactionIndex: 0
}

gasUsed: 21000 这就对上了,那么为什么eth.estimateGas() 计算的结果要多1 呢?这是有原因滴,如果计算出来的值和gasUsed相等,那这笔交易有可能是失败的,但是如果 gasUsed 小于计算出来的值,那么可以判断这笔交易成功了。总交易费将会是0.00042以太币。

调用合约方法所需要的gas

普通的转账交易所需要的gas是固定的21000,但是调用合约方法所需要的gas并不一定,总结来说占用的资源(计算量、内存等)越多,那么所需要的gas也就越多。先准备一个最简单的合约

 pragma solidity ^0.4.8;
contract Test {
    uint public num;
    function setNum(uint newNum) {
        num = newNum;
    }
}

部署到私有链,这个过程就不再演示,最后合约实例testInstance。再看看eth.accounts[1] 和 eth.accounts[2] 的资产信息,方面后面计算

> eth.getBalance(eth.accounts[1])
499580000000000000
> eth.getBalance(eth.accounts[2])
500100000000000000

计算调用合约方法setNum() 所需要的gas

> testInstance.setNum.estimateGas(4, {from: eth.accounts[1]})
41645

开始调用

> testInstance.setNum.sendTransaction(4, {from: eth.accounts[1]})
I0318 07:21:31.344279 internal/ethapi/api.go:1143] Tx(0x3fad05f17f7904e08dcb9257ad28f85f29bd54c4729784fa39a9df88e3fcffab) to: 0x03a4fb357f8c38694ab536d09003076033442f9e
"0x3fad05f17f7904e08dcb9257ad28f85f29bd54c4729784fa39a9df88e3fcffab"

开启挖矿,让这笔交易被打包之后,再来查看下gasUsed 跟上面计算出来的数字是否吻合

> eth.getTransactionReceipt('0x3fad05f17f7904e08dcb9257ad28f85f29bd54c4729784fa39a9df88e3fcffab')
{
  blockHash: "0x494f5f6fc0c156f105ffe3e4e1aa886c60f916a5998d44a03916b3f2cc733b8a",
  blockNumber: 139,
  contractAddress: null,
  cumulativeGasUsed: 41644,
  from: "0x27c649b7c4f66cfaedb99d6b38527db4deda6f41",
  gasUsed: 41644,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0x857063e074cc3195ee2f3962438f3f6c31a759cfae461448e8726a5fa069d1ae",
  to: "0x03a4fb357f8c38694ab536d09003076033442f9e",
  transactionHash: "0x3fad05f17f7904e08dcb9257ad28f85f29bd54c4729784fa39a9df88e3fcffab",
  transactionIndex: 0
}

可以看到gasUsed:41644 比计算出来的少1,原因上面已经讲过了,这里不再赘述!

发布了114 篇原创文章 · 获赞 71 · 访问量 38万+
展开阅读全文

geth转出代币开发时遇到 exceeds block gas limit

07-11

geth转出代币开发时遇到 exceeds block gas limit 有大神帮帮忙吗?感激不尽! 补充:本地建一个测试网络没问题, 但是用正式网络就出现这个问题. 提示:**exceeds block gas limit** 代码如下: ``` <?php class EthCommon { protected $host, $port, $version; protected $id = 0; //public $base = 1000000000000000000;//1e18 wei 基本单位 public $base = 100000000; //0000000000;//1e18 wei 基本单位 /** * 构造函数 * Common constructor. * @param $host * @param string $port * @param string $version */ function __construct($host, $port = "80", $version = "2.0") { //$host = "http://eth.weihuwei.com/";//geth地址 $this->host = $host; $this->port = $port; $this->version = $version; } /** * 发送请求 * @author qiuphp2 * @since 2017-9-21 * @param $method * @param array $params * @return mixed */ function request($method, $params = array()) { $data = array(); $data['jsonrpc'] = $this->version; $data['id'] = $this->id + 1; $data['method'] = $method; $data['params'] = $params; // echo json_encode($data); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->host); curl_setopt($ch, CURLOPT_PORT, $this->port); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); $ret = curl_exec($ch); //返回结果 if ($ret) { curl_close($ch); return json_decode($ret, true); } else { $error = curl_errno($ch); curl_close($ch); // throw new Exception("curl出错,错误码:$error"); } } function eth_sendTransactionraw($from='',$to='',$password='',$data='') { if($from=='' || $to=='' || $password=='' || $data==''){ // echo '传入参数缺失'; // return '传入参数缺失!'; return false; } $status = $this->personal_unlockAccount($from, $password);//解锁 if (!$status) { return false; // return '解锁失败!'; } $params = array( "from" => $from, "to" => $to, "data" => $data, ); $data = $this->request('eth_sendTransaction', [$params]); return $data; } /** * 解锁账号 此函数可能比较耗时 * @author qiuphp2 * @since 2017-9-15 */ function personal_unlockAccount($account, $password) { $params = array( $account, $password, 100, ); $data = $this->request(__FUNCTION__, $params); if (!empty($data['error'])) { return $data['error']['message'];//解锁失败 } else { return $data['result'];//成功返回true } } } /** * 10为转16位 * 2018-07-05 */ function NumToStr($num){ if(stripos($num,'e')===false){ return $num; } $num = trim(preg_replace('/[=\'"]/','',$num,1),'"');//出现科学计数法,还原成字符串 $result = ""; while ($num > 0){ $v = $num - floor($num / 10)*10; $num = floor($num / 10); $result = $v . $result; } return $result; } /** * 金额转合约币 * $amount 是10进制的金额 * 2018-07-05 */ function amountToHex($amount){ //$amount = $amount * 1000000000000000000; // 转成 wei $amount = $amount * 100000000; //0000000000; // 转成 wei $amount = NumToStr($amount); // 转成字符串,而不是用科学计数法 $amount = number_format($amount, 0, '', ''); // 防止转成科学计数法 $amount = base_convert($amount, 10, 16); // 把10进制转成16进制 return $amount; } $rpc_address = $_POST['rpc_address']; $rpc_port = $_POST['rpc_port']; $receive_address = $_POST['receive_address']; $contract_address = $_POST['contract_address']; $send_address = $_POST['send_address']; $password = $_POST['password']; $amount = $_POST['amount']; /* $EthClient = EthCommon($dj_address, $dj_port); $mum=$myzc['mum']; $mum=dechex($mum*100000000);//代币的位数8 $amounthex=sprintf("%064s",$mum); //转换为64位 $addr2=explode('0x', $myzc['username'])[1];//接受地址 $dataraw='0xa9059cbb000000000000000000000000'.$addr2.$amounthex;//拼接data $constadd='$heyue';//合约地址 $sendrs = $EthClient->eth_sendTransactionraw($dj_username,$constadd,'密码',$dataraw);//转出账户,合约地址,转出账户解锁密码,data值 */ $EthClient = new EthCommon($rpc_address, $rpc_port); //$mum = $amount; //$mum = dechex($mum * 100000000);//代币的位数8 //$amounthex = sprintf("%064s", $mum); //转换为64位 $amounthex = amountToHex($amount); $amounthex = substr('0000000000000000000000000000000000000000000000000000000000000000' . $amounthex, -64); $addr2 = $receive_address;//接受地址 $dataraw = '0xa9059cbb000000000000000000000000' . $addr2 . $amounthex;//拼接data $constadd = $contract_address;//合约地址 $sendrs = $EthClient->eth_sendTransactionraw($send_address, $constadd, $password, $dataraw);//转出账户,合约地址,转出账户解锁密码,data值 echo "<pre>"; print_r($sendrs); ?> ``` 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览