/ pure: 纯纯牛马 function addPure(uint256 _number) external pure returns(uint256 new_number){ new_number = _number + 1; }不会消耗gas对吧。传的不是状态变量
你的理解基本对了,但我们来更严谨、深入地回答这个问题。
✅ 你这段 pure
函数代码:
function addPure(uint256 _number) external pure returns(uint256 new_number) {new_number = _number + 1;
}
这是一个非常典型的 pure
函数:
-
✅ 不读取任何链上状态变量
-
✅ 不写入链上状态变量
-
✅ 只是计算输入值
_number + 1
,然后返回
❓会不会消耗 gas?
场景 | 是否消耗 gas | 原因解释 |
---|---|---|
用 call 调用(比如 Remix 蓝色按钮、本地调用) | ❌ 不消耗 | 函数在本地执行,不上链,不发交易 |
用 sendTransaction 发交易调用 | ✅ 会消耗 | 虽然函数是 pure ,但只要发了交易、上了链,就会消耗 gas(因为 EVM 要执行它) |
✅ 举例说明:
1. 使用 Remix 调用(或 web3/ethers call
):
const result = await contract.addPure(123); // ✅ 不消耗 gas
这是 本地仿真运行,不发交易,完全不花钱。适合做链下计算。
2. 使用 sendTransaction
方式调用:
await contract.addPure(123, { from: user });
就算函数是 pure
,因为你发了交易,EVM 还是要执行它、打包进区块,所以:
-
✅ 会消耗 gas(比如 21,000 ~ 30,000)
-
❌ 不会改链上状态
-
⚠️ 不推荐这么用,没意义还浪费 gas
🧠 小结:
函数类型 | pure |
---|---|
是否能读状态 | ❌ 不行 |
是否能改状态 | ❌ 不行 |
是否消耗 gas? | ✅ 发交易才消耗;❌ 用 call 就不消耗 |
🚀 一句话总结:
只要你调用pure/view
函数时用的是 call,不发交易,就不花 gas。
需要我帮你写一个对比:pure、view、write 三种函数并观察 Remix 上 gas 消耗差异的完整演示代码吗?
二、call和sendTransaction区别
你问得非常好!这是很多 Solidity 初学者在实际调用合约时都会混淆的核心概念。我们现在来彻底讲清楚什么是 sendTransaction
方式,以及为什么你写的那种方式就是。
✅ 先定义:什么是 sendTransaction?
在以太坊中:
sendTransaction
是指:向区块链发起一笔真实交易(transaction),从一个地址调用一个合约函数,消耗 gas,可能改变链上状态。
🔍 举个类比说明:
操作方式 | 类似于做什么 | 会不会上链 | 会不会花 gas | 使用函数类型 |
---|---|---|---|---|
call | 查看数据、模拟执行 | ❌ 否 | ❌ 否 | view / pure |
sendTransaction | 正式签名 + 发交易 + 广播 | ✅ 是 | ✅ 是(一定会) | non-view /任意 |
✅ 回到你的例子:
await contract.addPure(123, { from: user });
这行代码,在 web3.js 或 ethers.js 中,如果你用 await
调用了一个合约的函数,并且它不是 .call()
或 .staticCall()
,那么默认行为就是发起一笔真实交易,也就是 sendTransaction。
🧨 它其实等价于这样:
await contract.methods.addPure(123).send({ from: user });
-
这就会触发一笔链上交易
-
即使
addPure()
是pure
函数 -
你也会花 gas(比如 21,000)
-
但结果你无法直接拿到返回值,因为链上交易不返回值
⚠️ 非常重要的对比:
用法 | 是否发交易(sendTransaction) | 能不能返回结果 | 是否消耗 gas |
---|---|---|---|
contract.methods.foo().call() | ❌ 否(只读模拟) | ✅ 可以获取结果 | ❌ 不花钱 |
contract.methods.foo().send() | ✅ 是(发交易) | ❌ 无法直接获取 | ✅ 要花 gas |
✅ 正确方式:调用 pure
或 view
函数推荐用 .call()
const result = await contract.methods.addPure(123).call(); // ✅ 推荐方式
console.log(result); // 124
-
用
.call()
是本地调用,不会发交易 -
不会花钱
-
可以立刻获取返回值
✅ 总结一句话:
只要你用的是
.send()
或不带.call()
的 await 函数调用,并且指定了{ from: ... }
,那就是发了交易(sendTransaction
),会 上链、花 gas、不直接返回结果。
如果你想,我可以再写一段完整的 ethers.js 示例,对比 .call
和 .sendTransaction
两种方式的执行行为。需要吗?