Después de haber modificado el archivo instrucciones.gogeth
, puedo ver el tiempo de ejecución de los códigos de operación individuales, se ve así:
Mi interpretación de esa salida es que representa la ejecución de todos los contratos de los que escucha mi nodo en ejecución, entonces, todas las transacciones de toda la red (ropsten testnet).
Los cambios que hice en el geth
cliente están aquí:
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// begin execution time tracking
var startTime = time.Now().UnixNano();
x, y := stack.pop(), stack.pop()
stack.push(math.U256(x.Add(x, y)))
evm.interpreter.intPool.put(y)
// log ellapsed execution time
fmt.Println("execute opAdd consume = ",(time.Now().UnixNano() - startTime))
return nil, nil
}
Lo que me gustaría hacer es restringir de alguna manera esa salida para que solo se muestre para contratos/funciones que implemento desde mi nodo local, es decir, los que yo mismo llamo.
Lo que estoy buscando ahora es, algunas ideas sobre cómo hacer eso, ni siquiera necesariamente una solución, aunque eso sería genial, pero incluso, lugares para comenzar, por ejemplo, algún código que corresponda a un tipo de filtro/bandera similar, ¡Todo ese tipo de cosas, todo ese tipo de ideas serían geniales y útiles!
Leí la fuente de llamada de vm una y otra vez, pero no puedo encontrar una forma válida de calcular el tiempo de ejecución de una sola función (a veces una llamada a otra). cuando implementamos un contrato, esto creará una transacción, el input
atributo es el código de bytes del contrato, si llamamos a un método, primero genera la firma del método (por ejemplo: 0xe079bdf1), luego encuentra este método por firma y ejecuta. Entonces, la única forma de obtener la respuesta es vm opcode, y había leído Solidity Assembly y probado muchas llamadas a métodos, analizado muchos códigos de operación, pero no puedo encontrar una respuesta, es muy difícil para mí. El anuncio de códigos de operación sigue:
.data
0:
.code
PUSH 60 contract Wallet {\n
mappin...
PUSH 40 contract Wallet {\n
mappin...
MSTORE contract Wallet {\n
mappin...
PUSH 0 contract Wallet {\n
mappin...
CALLDATALOAD contract Wallet {\n
mappin...
PUSH 100000000000000000000000000000000000000000000000000000000 contract Wallet {\n
mappin...
SWAP1 contract Wallet {\n
mappin...
DIV contract Wallet {\n
mappin...
PUSH FFFFFFFF contract Wallet {\n
mappin...
AND
......
Tal vez no haya respuesta, tal vez mi método de análisis sea incorrecto. Si alguien sabe la respuesta correcta, por favor dígame. Espero que ayude ~
bien, bueno, es una especie de truco, pero... creo que lo entendí. Así es como funciona:
Me di cuenta de que cada vez que invocamos un contrato localmente, que es lo que estoy tratando de rastrear, lo escuchamos en la consola en forma de "Submitted transaction"
, así:
Lo que hice fue poner una bandera booleana en la función que evoca ese "Submitted transaction"
texto, este booleano es el " punto de entrada/puerta de enlace ", por así decirlo, para un envoltorio del código de seguimiento de tiempo.
Así es como se ve en el go-ethereum/core/vm/instructions.go
, donde rastreamos el tiempo de ejecución:
var (
bigZero = new(big.Int)
startTime = time.Now().UnixNano();
)
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
// wrap the logging in a check
if OpcodeTrigger {
// begin execution time tracking
startTime = time.Now().UnixNano();
}
x, y := stack.pop(), stack.pop()
stack.push(math.U256(x.Add(x, y)))
evm.interpreter.intPool.put(y)
// wrap the logging in a check
if OpcodeTrigger {
// now set the boolean flag back to false
OpcodeTrigger = false
// log ellapsed execution time
fmt.Println("execute opAdd consume = ",(time.Now().UnixNano() - startTime))
}
return nil, nil
}
Por lo tanto, go-ethereum/core/vm/instructions.go
es un nivel más bajo que el código que escupe el "Submitted transaction"
texto, eso está en go-ethereum/internal/ethapi/api.go
, por lo que definimos el bool allí. Si intenta definir el bool en go-ethereum/internal/ethapi/api.go
él, no funciona.
Así es como configuramos el bool en go-ethereum/internal/ethapi/api.go
:
// submitTransaction is a helper function that submits tx to txPool and logs a message.
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
if err := b.SendTx(ctx, tx); err != nil {
return common.Hash{}, err
}
if tx.To() == nil {
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
from, _ := types.Sender(signer, tx)
addr := crypto.CreateAddress(from, tx.Nonce())
log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
} else {
// flag for opcode execution time tracking
vm.OpcodeTrigger = true
log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
}
return tx.Hash(), nil
}
Entonces, finalmente, parece que tenemos lo que se especificó en el OP, o al menos una aproximación razonable, es decir:
INFO [08-09|20:16:38] Submitted transaction fullhash=0xa55357ec2488604d580cbdc56373f40ea16dc4cb6aec0ea41a3836c696cc3c17 recipient=0x8705C513da621a16fd1dEFc9dE8aE7CDEAD01Fb8
execute opAdd consume = 1063
¡Puedes sacar el código y mi respuesta en mi GitHub !
Muy interesado en saber lo que ustedes piensan de esta solución.
opAdd
instrucciones. y, a veces, un método puede llamar a muchas otras funciones, etc.
smatthewenglish
smatthewenglish