1. Gas 介绍
在 Solidity 和以太坊中,gas 是一个非常重要的概念。它是衡量在以太坊区块链上执行交易或运行智能合约所需的计算工作量的单位。基本上,每一次在以太坊网络中执行某种操作,如交易或合约调用,都需要消耗一定数量的 gas。
以下是关于 gas 的介绍:
- 计算费用:Gas 被用于计算在以太坊区块链上执行操作的费用。每种操作都需要不同数量的 gas,具体取决于操作的复杂性。例如,执行简单的算术操作消耗的 gas 将少于创建或调用智能合约所需的 gas。
- 防止无限循环:Gas 机制还可以防止智能合约中的无限循环。因为每次操作都需要 gas,如果一个合约试图进行无限操作,它最终会用尽所有的 gas 并停止执行。
- 交易费用:执行交易或调用合约的用户需要支付 gas 费用,这是他们为以太坊网络提供的计算资源付费的方式。这也被称为“矿工费”,因为这些费用会支付给执行交易的矿工。费用是通过将 gas 价格(以 ether 或 Gwei 衡量)乘以交易消耗的 gas 数量来计算的。
- Gas Limit:每个交易都有一个 gas 限制,即交易愿意支付的最大 gas 数量。如果交易消耗的 gas 超过这个限制,交易会被回滚,但已消耗的 gas 不会退还。
- Gas Price:Gas 的价格不是固定的,而是由市场决定的。当网络很忙时,由于用户竞争网络资源,通常会推高 gas 价格。用户可以选择支付更高的 gas 价格来增加他们的交易被快速打包的概率。
在以太坊网络中,除了每个交易有一个 gas limit(交易可消耗的最大 gas 数量)外,每个区块也有一个 gas limit,即 “block gas limit”。这是在单个区块中可以包含的 gas 总量的上限。换句话说,所有区块中的交易消耗的 gas 的总和不能超过这个 limit:
- 区块大小的限制:Block gas limit 实际上限制了区块的大小,因为更多的交易或更复杂的交易需要更多的 gas。通过这种方式,以太坊网络中每个区块的大小被控制在一定范围内,以维持网络的健康运行。
- 根据网络条件自动调整:Block gas limit 不是固定的,而是可以根据网络的需要进行自动调整的。例如,如果区块链的前一个区块已经满了,区块链协议将增加 block gas limit。反之,如果区块很低,block gas limit 会被降低。
- 矿工投票:实际上,矿工在开采新区块时可以对下一个区块的 gas limit 进行投票。然后将这个值按照一定算法进行调整,以决定下一个区块的 gas limit。
除了对以太坊网络的整体性能进行限制,block gas limit 还可以防止某些“大”交易大量消耗网络资源的情况,从而保护网络免受潜在的 DDoS 攻击。同时,用户也需要知道这个限制,以便根据当前网络条件合理设置他们的交易 gas limit。
2. 使用示例
2.1 获取 gas price
我们可以使用web3.js
来获取 gas price:
import { Web3 } from 'web3';
//private RPC endpoint
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_INFURA_ID');
// get the current gas price
await web3.eth.getGasPrice();
2.2 错误示范:合约中使用死循环耗尽 gas
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
contract ForeverTest {
uint256 public i = 0;
// 当发送的所有 gas 被用尽时,会导致你的交易失败。
// 状态更改将被撤销。
// 已消耗的 gas 不会退还。
// Remix测试会报错:
// transact to ForeverTest.forever errored: Error occurred: out of gas.
// out of gas
// The transaction ran out of gas. Please increase the Gas Limit.
function forever() public {
while (true) {
i += 1;
}
}
}
2.3 gas 计量单位
wei
是以太坊网络中最小的货币单位,wei是以太坊的基础单位。1 ether
等于1e18 wei
。然而,对于大多数的交易和智能合约,通常使用的计量单位是Gwei
,这更方便于理解和计算。1 Gwei
相当于1e9 wei
。当支付以太坊网络的交易费用或矿工费时,通常会看到的单位就是Gwei。
web3.js
中提供了两个函数来进行ether
与wei
之间的转换:
console.log(web3.utils.fromWei("1", "ether"));
// 0.000000000000000001
console.log(web3.utils.toWei("1", "ether"));
// 1_000_000_000_000_000_000
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特