Golang:将布尔标志从文件/子目录A中的函数传递到文件/子目录B中的函数

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:

enter image description here

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

enter image description here

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:

  1. Pass in whether to debug or not to the function call opAdd
  2. Set a global debugging level on startup once to control whether logging takes place or at what level globally and this would affect all such tracing.

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.