英文:
Golang: pass boolean flag from function in file/sub-directory A, to function in file/sub-directory B
问题
以下是要翻译的内容:
以下函数位于文件夹go-ethereum/core/vm/instructions.go中:
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
    // 开始执行时间跟踪
    var startTime = time.Now().UnixNano()
    x, y := stack.pop(), stack.pop()
    stack.push(math.U256(x.Add(x, y)))
    evm.interpreter.intPool.put(y)
    // 记录执行时间
    fmt.Println("execute opAdd consume =", (time.Now().UnixNano() - startTime))
    return nil, nil
}
这个函数的目的是输出以太坊虚拟机执行操作码opAdd的执行时间,它的外观如下:
然而,我想要的是只有在我本地发起的程序在我的自己的网络节点上运行时才显示这些信息。
以下是文件go-ethereum/internal/ethapi/api.go中的一个函数:
// SendRawTransaction将已签名的交易添加到交易池中。
// 发送者负责对交易进行签名并使用正确的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
}
这个函数只在将交易提交到网络时执行,并在终端窗口的控制台中输出Submitted transaction。
是否有办法从go-ethereum/internal/ethapi/api.go传递一个布尔标志到go-ethereum/core/vm/instructions.go,就在它输出Submitted transaction之前,这样我就可以执行操作码执行时间记录功能?
编辑:
从文件go-ethereum/internal/ethapi/api.go中:
// submitTransaction是一个辅助函数,将tx提交到txPool并记录一条消息。
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 {
        // 用于操作码执行时间跟踪的标志
        vm.OpcodeTrigger = true
        log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
    }
    return tx.Hash(), nil
}
以及从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) {
    // 在检查中包装日志记录
    if OpcodeTrigger {
        // 开始执行时间跟踪
        var startTime = time.Now().UnixNano()
    }
    x, y := stack.pop(), stack.pop()
    stack.push(math.U256(x.Add(x, y)))
    evm.interpreter.intPool.put(y)
    // 在检查中包装日志记录
    if OpcodeTrigger {
        // 现在将布尔标志设置回false
        OpcodeTrigger = false
        // 记录执行时间
        fmt.Println("execute opAdd consume =", (time.Now().UnixNano() - startTime))
    }
    return nil, nil
}
英文:
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
}
答案1
得分: 2
要控制是否在instructions.go中输出时间信息,可以在文件instructions.go中添加一个布尔变量(例如):
var Debug bool
然后在日志记录部分进行检查:
if Debug {
   // 记录执行时间
   fmt.Println("execute opAdd consume =", (time.Now().UnixNano() - startTime))
}
然后在某个地方设置它(例如在你的api pkg中):
import ".../core/vm"
vm.Debug = true
这种方法在并发情况下不安全,因此需要在启动时根据条件设置一次,或者使用互斥锁进行保护。虽然这种方法不太理想,但作为一个快速的解决方案,你可以这样做(抱歉,我对这个特定的代码库不太熟悉)。
我不清楚opAdd是如何被你的其他代码触发的,如果它是直接调用的,你当然可以在函数中添加一个参数来控制调用点的输出,这将更好。
通常情况下,你可以选择以下方式之一:
- 将是否进行调试作为参数传递给函数调用opAdd。
 - 在启动时设置一个全局的调试级别,以控制是否进行日志记录或全局日志记录级别,并且这将影响所有这类跟踪。
 
它们在这里有一个日志包,我不知道为什么这里没有使用它:
https://github.com/ethereum/go-ethereum/blob/master/log/logger.go
编辑:
我会始终分配startTime,但如果你希望避免这样做,你需要在顶层声明它,将其与你上面的代码进行比较:
// 在检查中进行日志记录
var startTime time.Time
if OpcodeTrigger {
    // 开始执行时间跟踪
    startTime = time.Now().UnixNano()
}
注意:如果这是并发的,你应该在vm pkg中添加一个互斥锁,并且只能使用一个函数对OpCodeTrigger进行更改,该函数在访问时使用mu.Lock进行包装。在这一点上,你可能会开始思考是否有更好的方法来做到这一点 ![]()
如果你再次遇到困难,最好在像forum.golangbridge.org这样的论坛上提问,因为stackoverflow不适合进行详细的来回交流。
英文:
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:
- Pass in whether to debug or not to the function call opAdd
 - 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。




评论