Filter, um die Ausgabe von Opcode-Daten nur auf Verträge/Funktionen zu beschränken, die vom lokalen Knoten aufgerufen werden

Nachdem ich die Datei " instructions.gogeth " geändert habe, kann ich die Ausführungszeit einzelner Opcodes sehen, sie sieht so aus:

Geben Sie hier die Bildbeschreibung ein

Meine Interpretation dieser Ausgabe ist, dass sie die Ausführung aller Verträge darstellt, von denen mein laufender Knoten hört, also alle Transaktionen des gesamten Netzwerks (ropsten testnet).

Die Änderungen, die ich am gethClient vorgenommen habe, sind hier:

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
}

Ich möchte diese Ausgabe irgendwie einschränken, sodass sie nur für Verträge/Funktionen angezeigt wird, die ich von meinem lokalen Knoten aus bereitstelle, dh diejenigen, die ich selbst anrufe.

Was ich jetzt suche, sind einige Gedanken darüber, wie man das macht – nicht einmal unbedingt eine Lösung – obwohl das großartig wäre – aber sogar Orte, an denen man anfangen kann – z. all diese Sachen, all diese Ideen wären sehr cool und hilfreich!

Antworten (2)

Ich lese immer wieder, dass vm die Quelle aufruft, aber ich kann keinen gültigen Weg finden, um die Ausführungszeit einer einzelnen Funktion (manchmal ein Aufruf einer anderen) zu berechnen. Wenn wir einen Vertrag bereitstellen, wird dadurch eine Transaktion erstellt, inputdas Attribut ist der Bytecode des Vertrags. Wenn wir eine Methode aufrufen, generieren Sie zuerst die Signatur der Methode (z. B.: 0xe079bdf1), finden Sie diese Methode dann anhand der Signatur und führen Sie sie aus. Die einzige Möglichkeit, eine Antwort zu erhalten, ist vm opcode, und ich hatte Solidity Assembly gelesen und viele Methodenaufrufe getestet, viele opcodes analysiert, aber ich kann keine Antwort finden, es ist so schwer für mich. Opcodes Anzeige folgt:

.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 

      ......

Vielleicht gibt es keine Antwort, vielleicht ist meine Analysemethode falsch. Wenn jemand die richtige Antwort weiß, sagen Sie es mir bitte. Hoffe es hilft~

Mann, was haltet ihr von dieser Idee
Probieren Sie es aus - ich habe meine Lösung als Awnser angegeben - was denken Sie?

Okay, na ja, es ist eine Art Hack, aber ... ich glaube, ich habe es verstanden. So geht's:

Mir wurde klar, dass wir jedes Mal, wenn wir einen Vertrag lokal aufrufen, was ich zu verfolgen versuche, in der Konsole in Form von davon hören "Submitted transaction":

Geben Sie hier die Bildbeschreibung ein

Was ich getan habe, war ein boolesches Flag in die Funktion zu setzen, die diesen Text hervorruft "Submitted transaction", dieser boolsche Wert ist sozusagen der " Einstiegspunkt/Gateway " für einen Wrapper des Zeiterfassungscodes.

So sieht es in der aus go-ethereum/core/vm/instructions.go, wo wir die Ausführungszeit verfolgen:

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
}

Ist also niedriger als der Code, der den Text go-ethereum/core/vm/instructions.goausspuckt, das ist in , weshalb wir dort den bool definieren. Wenn Sie versuchen, den bool in zu definieren , funktioniert es nicht."Submitted transaction"go-ethereum/internal/ethapi/api.gogo-ethereum/internal/ethapi/api.go

So setzen wir den 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
}

Endlich scheinen wir das zu haben, was im OP angegeben wurde, oder zumindest eine vernünftige Annäherung davon, dh:

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

Sie können den Code und meine Antwort darauf auf meinem GitHub auslesen !

Sehr interessant zu wissen, was ihr von dieser Lösung haltet.

Diese Art von Sachen ist super cool. Es gibt wahrscheinlich eine Menge Dinge, die Sie in ähnlicher Weise tun können, aber ich habe mich nie damit beschäftigt, weil ich nicht herausfinden konnte, wie ich meinen "Hack" vor aktualisiertem Code schützen kann. Gibt es „Hooks“ im Code, die es den Leuten ermöglichen, ihn zu „hacken“, oder muss man bei Upgrades einfach vorsichtig sein?
Ich denke, dies berechnet nur eine Opcode-Zeit, meistens enthält ein von einer Methode kompilierter Opcode viele opAddAnweisungen. und manchmal kann eine Methode viele andere Funktionen aufrufen usw.
Das stimmt. Ich habe es nur bei einem Funktionsaufruf ausprobiert. Hast du eine Idee, wie man es genauer machen kann?