log_processor.go 2.67 KB
Newer Older
1
package processors
2 3 4 5 6

import (
	"context"
	"fmt"

7 8 9 10
	"github.com/ethereum/go-ethereum/common"
	ethTypes "github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"

11
	"github.com/ethereum-optimism/optimism/op-service/eth"
12
	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset"
13
	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
14 15 16
)

type LogStorage interface {
Axel Kingsley's avatar
Axel Kingsley committed
17
	SealBlock(chain types.ChainID, block eth.BlockRef) error
18 19 20
	AddLog(chain types.ChainID, logHash common.Hash, parentBlock eth.BlockID, logIdx uint32, execMsg *types.ExecutingMessage) error
}

21
type logProcessor struct {
22
	chain        types.ChainID
23
	logStore     LogStorage
24
	eventDecoder EventDecoderFn
25
	depSet       depset.ChainIndexFromID
26 27
}

28
func NewLogProcessor(chain types.ChainID, logStore LogStorage, depSet depset.ChainIndexFromID) LogProcessor {
29 30 31
	return &logProcessor{
		chain:        chain,
		logStore:     logStore,
32
		eventDecoder: DecodeExecutingMessageLog,
33
		depSet:       depSet,
34
	}
35 36
}

37 38
// ProcessLogs processes logs from a block and stores them in the log storage
// for any logs that are related to executing messages, they are decoded and stored
Axel Kingsley's avatar
Axel Kingsley committed
39
func (p *logProcessor) ProcessLogs(_ context.Context, block eth.BlockRef, rcpts ethTypes.Receipts) error {
40 41
	for _, rcpt := range rcpts {
		for _, l := range rcpt.Logs {
42 43
			// log hash represents the hash of *this* log as a potentially initiating message
			logHash := logToLogHash(l)
44
			// The log may be an executing message emitted by the CrossL2Inbox
45
			execMsg, err := p.eventDecoder(l, p.depSet)
46 47
			if err != nil {
				return fmt.Errorf("invalid log %d from block %s: %w", l.Index, block.ID(), err)
48 49 50
			}
			// executing messages have multiple entries in the database
			// they should start with the initiating message and then include the execution
51 52
			if err := p.logStore.AddLog(p.chain, logHash, block.ParentID(), uint32(l.Index), execMsg); err != nil {
				return fmt.Errorf("failed to add log %d from block %s: %w", l.Index, block.ID(), err)
53 54 55
			}
		}
	}
56
	if err := p.logStore.SealBlock(p.chain, block); err != nil {
57 58
		return fmt.Errorf("failed to seal block %s: %w", block.ID(), err)
	}
59 60 61
	return nil
}

62 63 64 65 66
// logToLogHash transforms a log into a hash that represents the log.
// it is the concatenation of the log's address and the hash of the log's payload,
// which is then hashed again. This is the hash that is stored in the log storage.
// The address is hashed into the payload hash to save space in the log storage,
// and because they represent paired data.
67
func logToLogHash(l *ethTypes.Log) common.Hash {
68 69
	payloadHash := crypto.Keccak256Hash(types.LogToMessagePayload(l))
	return types.PayloadHashToLogHash(payloadHash, l.Address)
70
}