昨天介紹完,create
系列,今天介紹剩下的系統操作指令,這幾個指令可以執行其他合約的指令,這次也順便介紹 return
、revert
和selfdestruct
。
CALL
(0xF1)CALL
指令允許一個合約調用另一個合約的功能。它會從當前合約轉移指定的以太幣到目標合約,並執行目標合約的代碼。此指令還允許合約讀取和寫入存儲,並返回數據。
def _call(self, txn):
gas = self.evm.stack.pop()
to = self.evm.stack.pop()
value = self.evm.stack.pop()
mem_start = self.evm.stack.pop()
mem_length = self.evm.stack.pop()
returndata_start = self.evm.stack.pop()
returndata_length = self.evm.stack.pop()
data = self.evm.memory[mem_start: mem_start + mem_length]
source = self.getAccount(txn.caller)
target = self.getAccount(hex(to))
source['balance'] -= value
target['balance'] += value
# skip build tx and send tx
self.evm.excute(target['code'])
evm = EVM(target['code'])
evm.memory = data
evm.execute()
self.evm.memory[returndata_start:returndata_start + returndata_length] = evm.stack
CALLCODE
(0xF2)CALLCODE
與 CALL
類似,但它在調用者的上下文中執行目標合約的代碼。這意味著它使用調用者的存儲和餘額,而不是被調用合約的存儲和餘額。
def callcode(self):
self._call()
DELEGATECALL
(0xF4)DELEGATECALL
指令允許一個合約在其自己的上下文中執行另一個合約的代碼。這意味著它使用調用者的存儲、餘額和消息發送者,而不是被調用合約的這些值。
def delegatecall(self, txn):
gas = self.evm.stack.pop()
to = self.evm.stack.pop()
mem_start = self.evm.stack.pop()
mem_length = self.evm.stack.pop()
returndata_start = self.evm.stack.pop()
returndata_length = self.evm.stack.pop()
data = self.evm.memory[mem_start: mem_start + mem_length]
target = self.getAccount(hex(to))
# skip build tx and send tx
self.evm.excute(target['code'])
evm = EVM(target['code'])
evm.memory = data
evm.storage = self.evm.storage
evm.execute()
self.evm.memory[returndata_start:returndata_start + returndata_length] = evm.stack
STATICCALL
(0xFA)STATICCALL
指令與 CALL
類似,但它只能進行讀取操作,不能修改存儲或轉移以太幣。這確保了調用的純粹性,因為它不會改變任何狀態。
def staticcall(self):
gas = self.evm.stack.pop()
to = self.evm.stack.pop()
mem_start = self.evm.stack.pop()
mem_length = self.evm.stack.pop()
returndata_start = self.evm.stack.pop()
returndata_length = self.evm.stack.pop()
data = self.evm.memory[mem_start: mem_start + mem_length]
target = self.getAccount(hex(to))
self.evm.excute(target['code'])
self.evm.memory[returndata_start:returndata_start + returndata_length] = self.evm.stack
RETURN
(0xF3)RETURN
指令允許合約返回數據給調用者。它結束當前的合約執行,並返回指定的數據。
def _return(self):
mem_start = self.evm.stack.pop()
mem_length = self.evm.stack.pop()
self.evm.stack = self.evm.memory[mem_start: mem_start + mem_length]
REVERT
(0xFD)REVERT
指令允許合約在遇到錯誤時終止執行,並退還所有未使用的 Gas。它還允許合約返回一個錯誤消息,說明為什麼操作失敗。
def revert(self):
mem_start = self.evm.stack.pop()
mem_length = self.evm.stack.pop()
self.evm.stack = self.evm.memory[mem_start: mem_start + mem_length]
self.success = False
SELFDESTRUCT
(0xFF)SELFDESTRUCT
指令允許合約銷毀自己,並將其餘額發送到指定的地址。一旦合約自毀,它的代碼和存儲將從區塊鏈上永久刪除,並且不能再次調用或恢復。
def selfdestruct(self, txn):
to = self.evm.stack.pop()
target = self.getAccount(hex(to))
self.evm.balance[txn.thisAddr] += target['balance']
target['balance'] = 0
這些系統操作為智能合約提供了與外部世界交互的能力,並允許它們執行各種複雜的操作。理解這些指令的工作原理和用途對於 Ethereum 智能合約開發至關重要。