Solidity
EVM 如何找到被呼叫函式的入口?
我閱讀了 go-ethereum 的原始碼,對 EVM 如何找到被呼叫函式的入口感到困惑。正如規範所說,事務中的數據欄位指定函式和參數。因此,在我的理解中,特定的功能應該在 EVM 中執行,並帶有相關的輸入數據,而不是整個合約程式碼。但是,我找不到相關的程式碼。在執行循環中,PC 從 0 開始:
pc = uint64(0) // program counter for ; ; instrCount++ { // Get the memory location of pc op = contract.GetOp(pc) // calculate the new memory size and gas price for the current executing opcode newMemSize, cost, err = calculateGasAndSize(evm.env, contract, caller, op, statedb, mem, stack) if err != nil { return nil, err } // Use the calculated gas. When insufficient gas is present, use all gas and return an // Out Of Gas error if !contract.UseGas(cost) { return nil, OutOfGasError } // Resize the memory calculated previously mem.Resize(newMemSize.Uint64()) // Add a log message if evm.cfg.Debug { evm.logger.captureState(pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), nil) } if opPtr := evm.jumpTable[op]; opPtr.valid { if opPtr.fn != nil { opPtr.fn(instruction{}, &pc, evm.env, contract, mem, stack) } else { switch op { case PC: opPc(instruction{data: new(big.Int).SetUint64(pc)}, &pc, evm.env, contract, mem, stack) case JUMP: if err := jump(pc, stack.pop()); err != nil { return nil, err } continue case JUMPI: pos, cond := stack.pop(), stack.pop() if cond.Cmp(common.BigTrue) >= 0 { if err := jump(pc, pos); err != nil { return nil, err } continue } case RETURN: offset, size := stack.pop(), stack.pop() ret := mem.GetPtr(offset.Int64(), size.Int64()) return ret, nil case SUICIDE: opSuicide(instruction{}, nil, evm.env, contract, mem, stack) fallthrough case STOP: // Stop the contract return nil, nil } } } else { return nil, fmt.Errorf("Invalid opcode %x", op) } pc++ }
那麼EVM是如何執行具體功能的呢?
具體功能應該在 EVM 中使用相關的輸入數據執行,而不是整個合約程式碼
- EVM 將執行合約程式碼。 EVM 只執行字節碼,對函式一無所知。Solidity、Serpent 和 web3.js 實現相同的應用程序二進制介面,這就是函式和數據的編碼方式:什麼是 ABI,為什麼需要它與合約互動?
- EVM 編譯器根據 ABI**生成模擬功能的合約程式碼。**這是一個例子。
例子
對於遵循 ABI 的函式,編譯器的工作是生成正確的 EVM 字節碼。
一個非常粗略的範例,僅用於概念目的,EVM 編譯器將生成的“跳轉表”字節碼:
method_id = first 4 bytes of msg.data if method_id == 0x25d8dcf2 jump to 0x11 if method_id == 0xaabbccdd jump to 0x22 if method_id == 0xffaaccee jump to 0x33 other code <- Solidity fallback function code could be here 0x11: code for function with method id 0x25d8dcf2 0x22: code for function with method id 0xaabbccdd 0x33: code for function with method id 0xffaaccee
可以看到
msg.data
(Method ID 是 ABI 給出的術語)的前 4 個字節用於檢查跳轉到哪個函式並執行。從範例中,您還可以看到,您可以讓自己的編譯器生成具有不同邏輯的字節碼(也許您想使用 msg.data 的前 8 個字節),但是呼叫者必須遵循這些約定,而不是簡單地使用像 web3.js 這樣的庫。
範例來自: