The following function lives in the folder go-ethereum/core/vm/instructions.go
:
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
}
it's meant to output the execution time of the opcode opAdd
in the execution of the Ethereum virtual machine, which looks like this:
However, what I'd like to do is have this information only display when it's running a programme that I've initiated locally, on my own network node.
Here is a function in the file go-ethereum/internal/ethapi/api.go
:
// SendRawTransaction will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce.
func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (string, error) {
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return "", err
}
if err := s.b.SendTx(ctx, tx); err != nil {
return "", err
}
signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
if tx.To() == nil {
from, err := types.Sender(signer, tx)
if err != nil {
return "", err
}
addr := crypto.CreateAddress(from, tx.Nonce())
log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
} else {
log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
}
return tx.Hash().Hex(), nil
}
This function only executes when one submits a transaction to the network, and outputs Submitted transaction
in the terminal window's console.
Is there a way that I could pass a boolean flag from go-ethereum/internal/ethapi/api.go
to go-ethereum/core/vm/instructions.go
, right before it outputs Submitted transaction
so that I could execute the opcode execution time catalouging functionality?
EDIT
From the file 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
}
and from go-ethereum/core/vm/instructions.go
:
var (
OpcodeTrigger bool
bigZero = new(big.Int)
)
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
var 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
}
To control whether timing information is output in instructions.go, yes you could add a boolean variable to the file instructions.go (perhaps something like):
var Debug bool
and wrap the logging in a check on it:
if Debug {
// log ellapsed execution time
fmt.Println("execute opAdd consume = ",(time.Now().UnixNano() - startTime))
}
and then set it somewhere (for example in your api pkg) with
import ".../core/vm"
vm.Debug = true
this is not goroutine safe so would have to be set once on startup depending on conditions or protected with a mutex. It's also pretty horrible but as a quick hack to see it work you could do this (sorry not familiar with this particular code base) .
I'm not clear on how opAdd is triggered by your other code if it was directly called you could of course just add a parameter to the function to control the output from the calling site, this would be preferable.
Normally this sort of thing you'd either:
They do have a log package, I don't know why it's not used here:
https://github.com/ethereum/go-ethereum/blob/master/log/logger.go
EDIT
I would just always allocate startTime , but if you wish to avoid that, you need to declare it at the top level, compare this to your code above:
// wrap the logging in a check
var startTime time.Time
if OpcodeTrigger {
// begin execution time tracking
startTime = time.Now().UnixNano();
}
NB if this is concurrent at all you should be adding a mutex to the vm pkg and only mutating OpCodeTrigger with a function which wraps the access with a mu.Lock - at that point you might start to ask yourself if there are better ways to do this :)
Better if you get stuck again to ask on a forum like forum.golangbridge.org as stackoverflow is not designed for extensive back and forth.