Opcode

CALL 指令將 GAS 推入堆棧?

  • August 19, 2018

根據https://ethervm.io,執行 CALL 指令時,堆棧佈局如下:

[address, value, argOffset, argLen, retOffset, retLen]

所以 CALL 會從棧底彈出 6 個單詞來檢索必要的資訊。

但是當我查看這個 Solidity 程式碼的操作碼時:

contract Test {
   function withdraw() public {
       uint x = 123;
       msg.sender.call.value(x)();
   }
}

我可以看到相關的操作碼如下:

33  caller
90  swap1
82  dup3
90  swap1
60 00  push1    00
81  dup2
81  dup2
81  dup2
85  dup6
87  dup8
5a  gas
f1  call

我們可以看到,在 CALL 之前,GAS 將剩餘的氣體推入堆棧底部。但這改變了堆棧佈局,底部單詞不再是呼叫者地址。

這是否意味著來自https://ethervm.io的資訊不正確,或者我在這裡錯過了什麼?

謝謝!

是的,我認為這裡的https://ethervm.io/不正確。

來自黃皮書

因此操作數順序為:gas, to, value, in offset, in size, out offset, out size

有七個參數,氣體是堆棧中的最頂部。

JULIA還用七個參數對其進行了定義:

呼叫(g:u256,a:u256,v:u256,in:u256,insize:u256,out:u256,outsize:u256)-> r:u256

它執行 7pop秒,但在正常 EVM 跟踪期間這些彈出視窗不作為 OPCODES 可見,它們在Golang

自己看(core/vm/instructions.go

func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
   // Pop gas. The actual gas in in evm.callGasTemp.
   evm.interpreter.intPool.put(stack.pop())
   gas := evm.callGasTemp
   // Pop other call parameters.
   addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
   toAddr := common.BigToAddress(addr)
   value = math.U256(value)
   // Get the arguments from the memory.
   args := memory.Get(inOffset.Int64(), inSize.Int64())

   if value.Sign() != 0 {
       gas += params.CallStipend
   }
   ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
   if err != nil {
       stack.push(evm.interpreter.intPool.getZero())
   } else {
       stack.push(evm.interpreter.intPool.get().SetUint64(1))
   }
   if err == nil || err == errExecutionReverted {
       memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
   }
   contract.Gas += returnGas

   evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize)
   return ret, nil
}

pop定義為:

func (st *Stack) pop() (ret *big.Int) {
   ret = st.data[len(st.data)-1]
   st.data = st.data[:len(st.data)-1]
   return
}

引用自:https://ethereum.stackexchange.com/questions/56883