1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package processors
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/common"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
)
type LogStorage interface {
SealBlock(chain types.ChainID, block eth.BlockRef) error
AddLog(chain types.ChainID, logHash common.Hash, parentBlock eth.BlockID, logIdx uint32, execMsg *types.ExecutingMessage) error
}
type logProcessor struct {
chain types.ChainID
logStore LogStorage
eventDecoder EventDecoderFn
depSet depset.ChainIndexFromID
}
func NewLogProcessor(chain types.ChainID, logStore LogStorage, depSet depset.ChainIndexFromID) LogProcessor {
return &logProcessor{
chain: chain,
logStore: logStore,
eventDecoder: DecodeExecutingMessageLog,
depSet: depSet,
}
}
// 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
func (p *logProcessor) ProcessLogs(_ context.Context, block eth.BlockRef, rcpts ethTypes.Receipts) error {
for _, rcpt := range rcpts {
for _, l := range rcpt.Logs {
// log hash represents the hash of *this* log as a potentially initiating message
logHash := logToLogHash(l)
// The log may be an executing message emitted by the CrossL2Inbox
execMsg, err := p.eventDecoder(l, p.depSet)
if err != nil {
return fmt.Errorf("invalid log %d from block %s: %w", l.Index, block.ID(), err)
}
// executing messages have multiple entries in the database
// they should start with the initiating message and then include the execution
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)
}
}
}
if err := p.logStore.SealBlock(p.chain, block); err != nil {
return fmt.Errorf("failed to seal block %s: %w", block.ID(), err)
}
return nil
}
// 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.
func logToLogHash(l *ethTypes.Log) common.Hash {
payloadHash := crypto.Keccak256Hash(types.LogToMessagePayload(l))
return types.PayloadHashToLogHash(payloadHash, l.Address)
}