Изменив файл commands.gogeth
, я смог увидеть время выполнения отдельных опкодов, оно выглядит так:
Моя интерпретация этого вывода заключается в том, что он представляет собой выполнение всех контрактов, о которых слышит мой работающий узел, а значит, и всех транзакций всей сети (ropsten testnet).
Изменения, которые я внес в geth
клиент, находятся здесь:
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
}
Что я хотел бы сделать, так это каким-то образом ограничить этот вывод, чтобы он отображался только для контрактов/функций, которые я развертываю с моего локального узла, то есть тех, которые я вызываю сам.
То, что я ищу сейчас, это некоторые мысли о том, как это сделать - даже не обязательно решение - хотя это было бы здорово - но даже места для начала - например, некоторый код, который соответствует своего рода фильтру/флагу, все такие вещи, все эти идеи были бы очень крутыми и полезными!
Я снова и снова читаю источник вызова vm, но не могу найти правильный способ вычисления времени выполнения одной функции (иногда один вызов другого). когда мы развернем контракт, это создаст транзакцию, input
атрибутом является байт-код контракта, если мы вызываем метод, сначала генерируем подпись метода (например: 0xe079bdf1), затем находим этот метод по подписи и выполняем. Таким образом, единственный способ получить ответ - код операции vm, и я прочитал сборку Solidity и протестировал множество вызовов методов, проанализировал множество кодов операций, но не могу найти ответ, это так сложно для меня. объявление кодов операций следует:
.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
......
Может быть, ответа нет, может быть, мой метод анализа неверен. Если кто-то знает правильный ответ, подскажите. Надеюсь поможет~
ладно, это своего рода хак, но... кажется, я понял. Вот как это происходит:
Я понял, что всякий раз, когда мы вызываем контракт локально, что я и пытаюсь отследить, мы слышим об этом в консоли в виде, например "Submitted transaction"
:
Что я сделал, так это поместил логический флаг в функцию, которая вызывает этот "Submitted transaction"
текст, это логическое значение является, так сказать, « точкой входа / шлюзом » для оболочки кода отслеживания времени.
Вот как это выглядит в go-ethereum/core/vm/instructions.go
, где мы отслеживаем время выполнения:
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
}
Итак go-ethereum/core/vm/instructions.go
, это более низкий уровень, чем код, который выдает "Submitted transaction"
текст, который находится в go-ethereum/internal/ethapi/api.go
, поэтому мы определяем там логическое значение. Если вы попытаетесь определить в нем bool go-ethereum/internal/ethapi/api.go
, это не сработает.
Вот как мы устанавливаем bool 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
}
Итак, наконец, у нас есть то, что было указано в OP, или, по крайней мере, разумное приближение к нему, то есть:
INFO [08-09|20:16:38] Submitted transaction fullhash=0xa55357ec2488604d580cbdc56373f40ea16dc4cb6aec0ea41a3836c696cc3c17 recipient=0x8705C513da621a16fd1dEFc9dE8aE7CDEAD01Fb8
execute opAdd consume = 1063
Вы можете прочитать код и мой ответ на него на моем GitHub !
Очень интересно узнать, что вы, ребята, думаете об этом решении.
opAdd
инструкций. а иногда метод может вызывать множество других функций и т. д.
английский
английский