/ 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
兩種方式的執行行為。需要嗎?