El siguiente fragmento de código es una parte constitutiva del instructions.go
archivo, donde viven todos nuestros lieblings opCodes
.
// make log instruction function
func makeLog(size int) executionFunc {
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
topics := make([]common.Hash, size)
mStart, mSize := stack.pop(), stack.pop()
for i := 0; i < size; i++ {
topics[i] = common.BigToHash(stack.pop())
}
d := memory.Get(mStart.Int64(), mSize.Int64())
evm.StateDB.AddLog(&types.Log{
Address: contract.Address(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
// core/state doesn't know the current block number.
BlockNumber: evm.BlockNumber.Uint64(),
})
evm.interpreter.intPool.put(mStart, mSize)
return nil, nil
}
}
// make push instruction function
func makePush(size uint64, pushByteSize int) executionFunc {
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
codeLen := len(contract.Code)
startMin := codeLen
if int(*pc+1) < startMin {
startMin = int(*pc + 1)
}
endMin := codeLen
if startMin+pushByteSize < endMin {
endMin = startMin + pushByteSize
}
integer := evm.interpreter.intPool.get()
stack.push(integer.SetBytes(common.RightPadBytes(contract.Code[startMin:endMin], pushByteSize)))
*pc += size
return nil, nil
}
}
// make push instruction function
func makeDup(size int64) executionFunc {
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.dup(evm.interpreter.intPool, int(size))
return nil, nil
}
}
// make swap instruction function
func makeSwap(size int64) executionFunc {
// switch n + 1 otherwise n would be swapped with n
size += 1
return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
stack.swap(int(size))
return nil, nil
}
La pregunta es, ¿son estos make log instruction functions
mismos códigos de operación?
Si lo son, ¿por qué no se llaman así?
Si no, ¿qué están haciendo viviendo en el archivo con todos los opCodes
?
No estoy seguro de haber entendido completamente su pregunta, pero aquí están mis observaciones...
Los códigos de operación manejados por las cuatro make*
funciones que enumera difieren de los otros códigos de operación de EVM en que cada uno es parte de familias de códigos de operación más amplias:
makeLog()
maneja códigos de operación LOG0
a través deLOG4
makePush()
maneja códigos de operación PUSH1
a través dePUSH32
makeDup()
maneja códigos de operación DUP1
a través deDUP16
makeSwap()
maneja códigos de operación SWAP1
a través deSWAP16
Esto difiere de las otras funciones en el archivo, cada una de las cuales maneja solo un código de operación único, junto con sus operandos de pila.
Además, los LOG*
códigos de operación son particularmente inusuales ya que cada uno consume una cantidad diferente de operandos de la pila: LOG0
consume 2, LOG4
consume 6. Por lo tanto, esto también debe abordarse.
Al final, la función devuelta por cada una de las make*()
metafunciones realizará el trabajo de un único código de operación y, por lo tanto, estará en pie de igualdad con las demás funciones del archivo.