Go-ethereum 源碼解析之 core/types/log.go

Go-ethereum 源碼解析之 core/types/log.go

package types

import (
    "io"

    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/common/hexutil"
    "github.com/ethereum/go-ethereum/rlp"
)

//go:generate gencodec -type Log -field-override logMarshaling -out gen_log_json.go

// 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"`
}

type logMarshaling struct {
    Data        hexutil.Bytes
    BlockNumber hexutil.Uint64
    TxIndex     hexutil.Uint
    Index       hexutil.Uint
}

type rlpLog struct {
    Address common.Address
    Topics  []common.Hash
    Data    []byte
}

type rlpStorageLog struct {
    Address     common.Address
    Topics      []common.Hash
    Data        []byte
    BlockNumber uint64
    TxHash      common.Hash
    TxIndex     uint
    BlockHash   common.Hash
    Index       uint
}

// EncodeRLP implements rlp.Encoder.
func (l *Log) EncodeRLP(w io.Writer) error {
    return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
}

// DecodeRLP implements rlp.Decoder.
func (l *Log) DecodeRLP(s *rlp.Stream) error {
    var dec rlpLog
    err := s.Decode(&dec)
    if err == nil {
        l.Address, l.Topics, l.Data = dec.Address, dec.Topics, dec.Data
    }
    return err
}

// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
// a log including non-consensus fields.
type LogForStorage Log

// EncodeRLP implements rlp.Encoder.
func (l *LogForStorage) EncodeRLP(w io.Writer) error {
    return rlp.Encode(w, rlpStorageLog{
        Address:     l.Address,
        Topics:      l.Topics,
        Data:        l.Data,
        BlockNumber: l.BlockNumber,
        TxHash:      l.TxHash,
        TxIndex:     l.TxIndex,
        BlockHash:   l.BlockHash,
        Index:       l.Index,
    })
}

// DecodeRLP implements rlp.Decoder.
func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error {
    var dec rlpStorageLog
    err := s.Decode(&dec)
    if err == nil {
        *l = LogForStorage{
            Address:     dec.Address,
            Topics:      dec.Topics,
            Data:        dec.Data,
            BlockNumber: dec.BlockNumber,
            TxHash:      dec.TxHash,
            TxIndex:     dec.TxIndex,
            BlockHash:   dec.BlockHash,
            Index:       dec.Index,
        }
    }
    return err
}

Appendix A. 總體批注

文件 core/types/log.go 中主要定義了數(shù)據(jù)結(jié)構(gòu) Log,用于表示合約的一個日志事件。

數(shù)據(jù)結(jié)構(gòu) Log 中包含共識字段和派生字段兩部分。

- 由數(shù)據(jù)結(jié)構(gòu) logMarshaling 表示某些字段的 JSON 編碼。
- 共識字段支持 RLP 編碼,由數(shù)據(jù)結(jié)構(gòu) rlpLog 表示。
- 數(shù)據(jù)結(jié)構(gòu) logMarshaling、rlpLog、rlpStorageLog 是流形式。
- 通過方法 EncodeRLP() 編碼 Log。
- 通過方法 DecodeRLP() 解碼 Log。

數(shù)據(jù)結(jié)構(gòu) LogForStorage 只是 Log 的封裝器,便于與數(shù)據(jù)結(jié)構(gòu) rlpStorageLog 進行映射。
- 通過方法 EncodeRLP() 編碼由 LogForStorage 臨時構(gòu)建的 rlpStorageLog。
- 通過方法 DecodeRLP() 解碼成臨時的 rlpStorageLog,再還原出 LogForStorage。

Appendix B. 詳細批注

type Log struct

Log 表示合約的一個日志事件。 這些事件由 LOG 操作碼生成并且由節(jié)點存儲和索引。

// Consensus fields:
Address common.Address:    生成事件的合約地址
Topics []common.Hash:      由合約提供的主題列表
Data []byte:               由合約提供,通常是 ABI 編碼的

// Derived fields. These fields are filled in by the node
// but not secured by consensus.
BlockNumber uint64:        事務(wù)所屬的區(qū)塊
TxHash common.Hash:        事務(wù)的哈希
TxIndex uint:              事務(wù)在區(qū)塊中的索引
BlockHash common.Hash:     事務(wù)所屬的區(qū)塊的哈希
Index uint:                Log 在 Receipt 中的索引

Removed bool:              如果由于鏈重新組織導致 Log 被恢復則此字段為 true。如果是通過過濾器查詢接收此日志,則必須小心此字段。
  1. func (l *Log) EncodeRLP(w io.Writer) error
    方法 EncodeRLP() 實現(xiàn)了 rlp.Encoder 接口,并將 Log 的共識字段扁平化成 RLP 流。

將 Log 的 RLP 編碼寫入到參數(shù) w 中。

- 具體的實現(xiàn)是調(diào)用函數(shù) rlp.Encode() 完成的。
  1. func (l *Log) DecodeRLP(s *rlp.Stream) error
    方法 DecodeRLP() 實現(xiàn)了 rlp.Decoder 接口,并從 RLP 流中加載 Log 的共識字段。

從參數(shù) s 中加載共識字段。

- 具體的實現(xiàn)是調(diào)用方法 rlp.Stream.Decode() 完成的。

type logMarshaling struct

Log 的 JSON 編碼。

各字段的意義同 Log 中的同名字段。

- Data        hexutil.Bytes:   
- BlockNumber hexutil.Uint64:  
- TxIndex     hexutil.Uint:    
- Index       hexutil.Uint:    

type rlpLog struct

Log 的 RLP 編碼。

各字段的意義同 Log 中的同名字段。

- Address common.Address
- Topics  []common.Hash
- Data    []byte

type rlpStorageLog struct

Log RLP 編碼后的存儲結(jié)構(gòu),包含了 Log 的大部分字段。

各字段的意義同 Log 中的同名字段。

- Address     common.Address
- Topics      []common.Hash
- Data        []byte
- BlockNumber uint64
- TxHash      common.Hash
- TxIndex     uint
- BlockHash   common.Hash
- Index       uint

type LogForStorage Log

LogForStorage 是 Log 的封裝器,用于扁平化和分析 Log 的整個內(nèi)容,而不僅僅是原始的共識字段。

  1. func (l *LogForStorage) EncodeRLP(w io.Writer) error
    方法 EncodeRLP() 實現(xiàn)了 rlp.Encoder 接口,并將 LogForStorage 的所有字段扁平化成 RLP 流。

將 LogForStorage 的 RLP 編碼寫入到參數(shù) w 中。

- 具體的實現(xiàn)是調(diào)用函數(shù) rlp.Encode() 完成的。
- 將臨時創(chuàng)建的 rlpStorageLog 編碼成 RLP 流。
  1. func (l *LogForStorage) DecodeRLP(s *rlp.Stream) error
    方法 DecodeRLP() 實現(xiàn)了 rlp.Decoder 接口,并從 RLP 流中加載 LogForStorage 的所有字段。

從參數(shù) s 中同時加載共識字段和實現(xiàn)字段。

- 具體的實現(xiàn)是調(diào)用方法 rlp.Stream.Decode() 完成的。
- 從解碼后的 receiptStorageRLP 中還原其它字段。

Reference

  1. https://github.com/ethereum/go-ethereum/blob/master/core/types/log.go

Contributor

  1. Windstamp
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容