entries.go 5.67 KB
Newer Older
1
package logs
2 3 4 5 6

import (
	"encoding/binary"
	"fmt"

7 8
	"github.com/ethereum/go-ethereum/common"

9
	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb"
10
	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
11 12
)

13
// searchCheckpoint is both a checkpoint for searching, as well as a checkpoint for sealing blocks.
14
type searchCheckpoint struct {
15 16 17 18
	blockNum uint64
	// seen logs *after* the seal of the mentioned block, i.e. not part of this block, but building on top of it.
	// There is at least one checkpoint per L2 block with logsSince == 0, i.e. the exact block boundary.
	logsSince uint32
19 20 21
	timestamp uint64
}

22
func newSearchCheckpoint(blockNum uint64, logsSince uint32, timestamp uint64) searchCheckpoint {
23 24
	return searchCheckpoint{
		blockNum:  blockNum,
25
		logsSince: logsSince,
26 27 28 29
		timestamp: timestamp,
	}
}

30 31 32
func newSearchCheckpointFromEntry(data Entry) (searchCheckpoint, error) {
	if data.Type() != TypeSearchCheckpoint {
		return searchCheckpoint{}, fmt.Errorf("%w: attempting to decode search checkpoint but was type %s", entrydb.ErrDataCorruption, data.Type())
33 34 35
	}
	return searchCheckpoint{
		blockNum:  binary.LittleEndian.Uint64(data[1:9]),
36
		logsSince: binary.LittleEndian.Uint32(data[9:13]),
37 38 39 40
		timestamp: binary.LittleEndian.Uint64(data[13:21]),
	}, nil
}

41 42
// encode creates a checkpoint entry
// type 0: "search checkpoint" <type><uint64 block number: 8 bytes><uint32 logsSince count: 4 bytes><uint64 timestamp: 8 bytes> = 21 bytes
43 44 45
func (s searchCheckpoint) encode() Entry {
	var data Entry
	data[0] = uint8(TypeSearchCheckpoint)
46
	binary.LittleEndian.PutUint64(data[1:9], s.blockNum)
47
	binary.LittleEndian.PutUint32(data[9:13], s.logsSince)
48 49 50 51 52
	binary.LittleEndian.PutUint64(data[13:21], s.timestamp)
	return data
}

type canonicalHash struct {
53
	hash common.Hash
54 55
}

56
func newCanonicalHash(hash common.Hash) canonicalHash {
57 58 59
	return canonicalHash{hash: hash}
}

60 61 62
func newCanonicalHashFromEntry(data Entry) (canonicalHash, error) {
	if data.Type() != TypeCanonicalHash {
		return canonicalHash{}, fmt.Errorf("%w: attempting to decode canonical hash but was type %s", entrydb.ErrDataCorruption, data.Type())
63
	}
64
	return newCanonicalHash(common.Hash(data[1:33])), nil
65 66
}

67 68 69
func (c canonicalHash) encode() Entry {
	var entry Entry
	entry[0] = uint8(TypeCanonicalHash)
70
	copy(entry[1:33], c.hash[:])
71 72 73 74
	return entry
}

type initiatingEvent struct {
75
	hasExecMsg bool
76
	logHash    common.Hash
77 78
}

79 80 81
func newInitiatingEventFromEntry(data Entry) (initiatingEvent, error) {
	if data.Type() != TypeInitiatingEvent {
		return initiatingEvent{}, fmt.Errorf("%w: attempting to decode initiating event but was type %s", entrydb.ErrDataCorruption, data.Type())
82
	}
83
	flags := data[1]
84
	return initiatingEvent{
85
		hasExecMsg: flags&eventFlagHasExecutingMessage != 0,
86
		logHash:    common.Hash(data[2:34]),
87 88 89
	}, nil
}

90
func newInitiatingEvent(logHash common.Hash, hasExecMsg bool) initiatingEvent {
91
	return initiatingEvent{
92 93 94
		hasExecMsg: hasExecMsg,
		logHash:    logHash,
	}
95 96 97
}

// encode creates an initiating event entry
98
// type 2: "initiating event" <type><flags><event-hash: 20 bytes> = 22 bytes
99 100 101
func (i initiatingEvent) encode() Entry {
	var data Entry
	data[0] = uint8(TypeInitiatingEvent)
102
	flags := byte(0)
103 104 105
	if i.hasExecMsg {
		flags = flags | eventFlagHasExecutingMessage
	}
106
	data[1] = flags
107
	copy(data[2:34], i.logHash[:])
108 109 110
	return data
}

111 112 113 114 115 116 117
type executingLink struct {
	chain     uint32
	blockNum  uint64
	logIdx    uint32
	timestamp uint64
}

118
func newExecutingLink(msg types.ExecutingMessage) (executingLink, error) {
119 120 121 122 123 124 125 126 127 128 129
	if msg.LogIdx > 1<<24 {
		return executingLink{}, fmt.Errorf("log idx is too large (%v)", msg.LogIdx)
	}
	return executingLink{
		chain:     msg.Chain,
		blockNum:  msg.BlockNum,
		logIdx:    msg.LogIdx,
		timestamp: msg.Timestamp,
	}, nil
}

130 131 132
func newExecutingLinkFromEntry(data Entry) (executingLink, error) {
	if data.Type() != TypeExecutingLink {
		return executingLink{}, fmt.Errorf("%w: attempting to decode executing link but was type %s", entrydb.ErrDataCorruption, data.Type())
133 134 135 136 137 138 139 140 141 142 143 144
	}
	timestamp := binary.LittleEndian.Uint64(data[16:24])
	return executingLink{
		chain:     binary.LittleEndian.Uint32(data[1:5]),
		blockNum:  binary.LittleEndian.Uint64(data[5:13]),
		logIdx:    uint32(data[13]) | uint32(data[14])<<8 | uint32(data[15])<<16,
		timestamp: timestamp,
	}, nil
}

// encode creates an executing link entry
// type 3: "executing link" <type><chain: 4 bytes><blocknum: 8 bytes><event index: 3 bytes><uint64 timestamp: 8 bytes> = 24 bytes
145 146 147
func (e executingLink) encode() Entry {
	var entry Entry
	entry[0] = uint8(TypeExecutingLink)
148 149 150 151 152 153 154 155 156 157 158 159
	binary.LittleEndian.PutUint32(entry[1:5], e.chain)
	binary.LittleEndian.PutUint64(entry[5:13], e.blockNum)

	entry[13] = byte(e.logIdx)
	entry[14] = byte(e.logIdx >> 8)
	entry[15] = byte(e.logIdx >> 16)

	binary.LittleEndian.PutUint64(entry[16:24], e.timestamp)
	return entry
}

type executingCheck struct {
160
	hash common.Hash
161 162
}

163
func newExecutingCheck(hash common.Hash) executingCheck {
164 165 166
	return executingCheck{hash: hash}
}

167 168 169
func newExecutingCheckFromEntry(data Entry) (executingCheck, error) {
	if data.Type() != TypeExecutingCheck {
		return executingCheck{}, fmt.Errorf("%w: attempting to decode executing check but was type %s", entrydb.ErrDataCorruption, data.Type())
170
	}
171
	return newExecutingCheck(common.Hash(data[1:33])), nil
172 173 174
}

// encode creates an executing check entry
175
// type 4: "executing check" <type><event-hash: 32 bytes> = 33 bytes
176 177 178
func (e executingCheck) encode() Entry {
	var entry Entry
	entry[0] = uint8(TypeExecutingCheck)
179
	copy(entry[1:33], e.hash[:])
180 181 182
	return entry
}

183 184 185
type paddingEntry struct{}

// encoding of the padding entry
186
// type 5: "padding" <type><padding: 33 bytes> = 34 bytes
187 188 189
func (e paddingEntry) encode() Entry {
	var entry Entry
	entry[0] = uint8(TypePadding)
190
	return entry
191
}