1

Having modified the instructions.go file in geth I'm able to see the execution time of individual opcodes, it looks like this:

enter image description here

My interpretation of that output is that it represents the execution of all the contracts that my running node hears about, so then- all the transactions of the entire network (ropsten testnet).

The changes I made to the geth client are here:

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
}

What I'd like to do is somehow restrict that output so that it only displays for contracts/functions that I deploy from my local node, i.e. the ones that I call myself.

What I'm looking for now is, some thoughts about how to do that- not even necessarily a solution- although that would be great- but even, places to start- e.g. some code that corresponds to a similar filter/flag of sorts, all that kind of stuff, all those type of ideas would be very cool and helpful!

1

I read vm calling source again and again, but i can't find a valid way to computing single function(sometimes one call other) execute time. when we deploy a contract, this will create a transaction, input attribute is bytecode of contract, if we call a method, at first generate signature of method(for example:0xe079bdf1), then find this method by signature and execute. So the only way accquiring answer is vm opcode, and i had read Solidity Assembly and tested many method-calling, analyzed many opcodes, but i can't find an answer, it's so hard to me. opcodes ad follows:

.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 

      ......

Maybe there is no answer, maybe my analysis method is wrong. If someone knows correct answer, please tell me. Hope it helps~

0

alright, well- it's sort of a hack, but... I think I got it. Here's how it goes:

I realized that whenever we invoke a contract locally, which is what I'm trying to track, we hear about it in the console in the form of "Submitted transaction", like so:

enter image description here

What I did was put a boolean flag in the function that evokes that "Submitted transaction" text, this bool is the "entry point/gateway" so to speak, for a wrapper of the time-tracking code.

This is what it looks like in the go-ethereum/core/vm/instructions.go, where we track the execution time:

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
}

So go-ethereum/core/vm/instructions.go is lower level than the code that spits out the "Submitted transaction" text, that's in go-ethereum/internal/ethapi/api.go, which is why we define the bool there. If you try to define the bool in go-ethereum/internal/ethapi/api.go it doesn't work.

Here's how we set the bool in 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
}

So finally we seem to have what was specified in the OP, or at least a reasonable approximation of it, i.e.:

INFO [08-09|20:16:38] Submitted transaction                    fullhash=0xa55357ec2488604d580cbdc56373f40ea16dc4cb6aec0ea41a3836c696cc3c17 recipient=0x8705C513da621a16fd1dEFc9dE8aE7CDEAD01Fb8
execute opAdd consume =  1063

You can czech out the code, and my answer to it on my GitHub!

Very interested to know what you guys think of this solution.

  • 1
    This kind of stuff is super cool. There's probably a ton of stuff you can do in a similar vein, but I never dove in because I couldn't figure out how to protect my 'hack' from upgraded code. Are there 'hooks' in the code to allow people to 'hack' it, or do you just have to be careful about upgrades? – Thomas Jay Rush Aug 10 '17 at 0:57
  • 1
    I think this only computes one opcode time, most time, a method compiled opcode contains many opAdd instructions. and sometimes, a method may call many other function, etc. – BinGoBinBin Aug 10 '17 at 1:00
  • Yeah, true. I only tried it out on one function call. Do you have an idea of how to make it more accurate? – smatthewenglish Aug 10 '17 at 3:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.