Wo werden schließlich Ethereum-Ereignisprotokolle gespeichert?

Hallo, es wurde schon oft geschrieben, aber wie ich beobachte, könnte keine der Antworten die richtige sein. Mich interessiert folgende Sache. Wenn ich das Ereignis in einem Smart Contract gemacht habe, wo wird es gespeichert? in Blockchain, wenn ja, wo genau? wenn nicht dort, vielleicht in Nodes? Ich baue eine seriöse App und muss dort viele Dinge speichern. also ich habe zum schluss noch 2 fragen.

1) Wo werden Protokolle genau gespeichert? 2) Wenn im Block-Header, können Sie beschreiben, wie ich diesen Protokollen vertrauen kann, die in das Front-End von web3.js gelangen?

Antworten (2)

Sie können den Protokollen vertrauen, da sie in ihrem jeweiligen Block gespeichert werden. Wenn ein Protokoll geändert wird, ändert es den Blockhash, die ReceiveRoot usw., genau wie bei Transaktionen. Der Merkle-Baum wäre nicht mehr derselbe.

Wenn ich also eine Funktion auf einer bestimmten Blockhöhe ausführe, ist die Quittung und damit das Protokoll auch Teil des Blocks auf dieser Höhe sowie meine Transaktion.

Um zu beantworten, wo sie genau gespeichert sind. In der Transaktionsquittung versuchen, wenn ich mich richtig erinnere.

Bildnachweis von https://medium.com/@preethikasireddy/how-does-ethereum-work-anyway-22d1df506369

Kopfzeile blockieren

Danke für die nette Erklärung. Alles klar. Ich würde Ihnen noch eine Frage stellen, wenn es Ihnen nichts ausmacht, hier zu antworten. OK? Was getan werden muss, ist Big Data. Wie Sie wissen, sind Smart Contracts aufgrund der Gaspreiserhöhung nicht für Big Data geeignet. Eine Lösung könnte also darin bestehen, Daten in IPFS oder Protokollen zu speichern. Wie man weiß, ist es viel besser, es in Protokollen zu speichern, weil es immer noch in Blockchain ist und das ist es, was die Leute mögen. Frage ist: Wenn ich dort viele Daten speichere, muss eines der Felder ausgeblendet werden, und nur ich könnte das bekommen. Niemand sollte zur Blockchain gehen und die Protokolle einsehen. Was denken Sie?
Sie können das Feld mit Ihrem öffentlichen Schlüssel verschlüsseln, sodass nur Ihr privater Schlüssel es entschlüsseln kann. Das Problem ist, ob der Verschlüsselungsalgorithmus jemals kollidiert und somit das Erraten privater Schlüssel möglich wird, da wir keine Daten aus einem System wie Ethereum/ipfs/swarm löschen können. Ich würde empfehlen, Swarm (bzz in Ethereum) über IPFS zu verwenden, da es stärker mit dem Ökosystem verflochten ist. Aber das ist nur eine persönliche Präferenz, nachdem Sie beide verwendet haben.

Wenn ein Vertrag ein Ereignis ausgibt, wird es in der StateDB-Struktur gespeichert:

// StateDBs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve:
// * Contracts
// * Accounts
type StateDB struct {
    db   Database
    trie Trie

    // This map holds 'live' objects, which will get modified while processing a state transition.
    stateObjects      map[common.Address]*stateObject
    stateObjectsDirty map[common.Address]struct{}

    // DB error.
    // State objects are used by the consensus core and VM which are
    // unable to deal with database-level errors. Any error that occurs
    // during a database read is memoized here and will eventually be returned
    // by StateDB.Commit.
    dbErr error

    // The refund counter, also used by state transitioning.
    refund uint64

    thash, bhash common.Hash
    txIndex      int
    logs         map[common.Hash][]*types.Log
    logSize      uint

    preimages map[common.Hash][]byte

    // Journal of state modifications. This is the backbone of
    // Snapshot and RevertToSnapshot.
    journal        *journal
    validRevisions []revision
    nextRevisionId int

    lock sync.Mutex
}

Dies ist das Mitglied, das die Daten in der obigen Struktur enthält:

    logs         map[common.Hash][]*types.Log

Während der Blockverarbeitung gibt jede Transaktion eine Quittung (mit Ereignisprotokollen) zurück und sie werden in einem Array gespeichert (von core/state_processor.go):

// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
    statedb.Prepare(tx.Hash(), block.Hash(), i)
    receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg)
    if err != nil {
        return nil, nil, 0, err
    }
    receipts = append(receipts, receipt)
    allLogs = append(allLogs, receipt.Logs...)
}

Sobald die Quittungen gesammelt wurden, berechnet der Konsensalgorithmus den Hash für alle Quittungen und fügt den resultierenden Hash in den Header des Blocks ein. Danach wird der Hash des Blocks generiert und an andere Knoten verteilt.

Der Vorgang zum Erstellen eines neuen Blocks ist hier ( core/types/block.go)

func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*Receipt) *Block {
    b := &Block{header: CopyHeader(header), td: new(big.Int)}

    // TODO: panic if len(txs) != len(receipts)
    if len(txs) == 0 {
        b.header.TxHash = EmptyRootHash
    } else {
        b.header.TxHash = DeriveSha(Transactions(txs))
        b.transactions = make(Transactions, len(txs))
        copy(b.transactions, txs)
    }

    if len(receipts) == 0 {
        b.header.ReceiptHash = EmptyRootHash
    } else {
        b.header.ReceiptHash = DeriveSha(Receipts(receipts))
        b.header.Bloom = CreateBloom(receipts)
    }

    if len(uncles) == 0 {
        b.header.UncleHash = EmptyUncleHash
    } else {
        b.header.UncleHash = CalcUncleHash(uncles)
        b.uncles = make([]*Header, len(uncles))
        for i := range uncles {
            b.uncles[i] = CopyHeader(uncles[i])
        }
    }

    return b
}

Dies ist die Zeile, die den Hash auf den Quittungen berechnet:

b.header.ReceiptHash = DeriveSha(Receipts(receipts))

Ereignisse werden als Teil der Struktur gespeichert Receipt:

// Receipt represents the results of a transaction.
type Receipt struct {
    // Consensus fields
    PostState         []byte `json:"root"`
    Status            uint64 `json:"status"`
    CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
    Bloom             Bloom  `json:"logsBloom"         gencodec:"required"`
    Logs              []*Log `json:"logs"              gencodec:"required"`

    // Implementation fields (don't reorder!)
    TxHash          common.Hash    `json:"transactionHash" gencodec:"required"`
    ContractAddress common.Address `json:"contractAddress"`
    GasUsed         uint64         `json:"gasUsed" gencodec:"required"`
}

Dies ist das Array mit den Ereignissen:

    Logs              []*Log `json:"logs"              gencodec:"required"`

Und das Ereignis ist definiert als:

// Log represents a contract log event. These events are generated by the LOG opcode and
// stored/indexed by the node.
type Log struct {
    // Consensus fields:
    // address of the contract that generated the event
    Address common.Address `json:"address" gencodec:"required"`
    // list of topics provided by the contract.
    Topics []common.Hash `json:"topics" gencodec:"required"`
    // supplied by the contract, usually ABI-encoded
    Data []byte `json:"data" gencodec:"required"`

    // Derived fields. These fields are filled in by the node
    // but not secured by consensus.
    // block in which the transaction was included
    BlockNumber uint64 `json:"blockNumber"`
    // hash of the transaction
    TxHash common.Hash `json:"transactionHash" gencodec:"required"`
    // index of the transaction in the block
    TxIndex uint `json:"transactionIndex" gencodec:"required"`
    // hash of the block in which the transaction was included
    BlockHash common.Hash `json:"blockHash"`
    // index of the log in the receipt
    Index uint `json:"logIndex" gencodec:"required"`

    // The Removed field is true if this log was reverted due to a chain reorganisation.
    // You must pay attention to this field if you receive logs through a filter query.
    Removed bool `json:"removed"`
}

Alle diese Daten werden im --datadir``/geth/chaindataVerzeichnis gespeichert

Sie können den Ereignisprotokollen vertrauen, da der Hash aller Quittungen im Hash des Blocks enthalten ist, sodass die Daten kryptografisch „versiegelt“ sind.

Falls Sie die Quittungen validieren möchten, erhalten Sie sie mit dieser Funktion:

receipts:=core.GetBlockReceipts(ethereum.ChainDb(), block.Hash(), block.NumberU64())`

Und den Hash erneut berechnen. Er muss mit dem ReceiptsHashdes Blockheaders übereinstimmen.

Ich hoffe, es ist jetzt klar, wie Events intern funktionieren.

Danke für die nette Erklärung. Alles klar. Ich würde Ihnen noch eine Frage stellen, wenn es Ihnen nichts ausmacht, hier zu antworten. OK? Was getan werden muss, ist Big Data. Wie Sie wissen, sind Smart Contracts aufgrund der Gaspreiserhöhung nicht für Big Data geeignet. Eine Lösung könnte also darin bestehen, Daten in IPFS oder Protokollen zu speichern. Wie man weiß, ist es viel besser, es in Protokollen zu speichern, weil es immer noch in Blockchain ist und das ist es, was die Leute mögen. Frage ist: Wenn ich dort viele Daten speichere, muss eines der Felder ausgeblendet werden, und nur ich könnte das bekommen. Niemand sollte zur Blockchain gehen und die Protokolle einsehen. Was denken Sie?
Das Konzept der Blockchain-Technologie besteht darin, dass die Daten öffentlich und für jedermann zugänglich sind. Die einzige Möglichkeit, private Daten in der Blockchain zu speichern, besteht also darin, sie zu verschlüsseln. Verschlüsselungsalgorithmen werden jedoch ständig durch fortschrittlichere Hardware und Fehler gebrochen, sodass das Risiko besteht, dass Ihre Daten in Zukunft öffentlich werden. Sie können Ihre privaten Daten in Ihrem eigenen Rechenzentrum speichern und den Hash dieser Daten auf Blockhcain veröffentlichen. Dies ist eine Möglichkeit zu beweisen, dass Sie sie nicht geändert haben, während Sie sie privat speichern.