Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
164832c
WIP
pompon0 Aug 4, 2026
7a8d996
roughly compiles
pompon0 Aug 4, 2026
74243c4
snapshot
pompon0 Aug 4, 2026
bec2480
streaming
pompon0 Aug 4, 2026
1b5a061
GlobalRange in AppProposal
pompon0 Aug 4, 2026
027ed62
fixes types tests
pompon0 Aug 4, 2026
0892f8d
data fixes
pompon0 Aug 4, 2026
0f43cb1
codex AppQC in BlockDB
pompon0 Aug 4, 2026
f5f12b7
robust tracking
pompon0 Aug 5, 2026
5e11a5d
pushing AppQCs
pompon0 Aug 5, 2026
921892c
reverted metrics
pompon0 Aug 5, 2026
5434911
WIP
pompon0 Aug 6, 2026
566d110
addresses codex review
pompon0 Aug 6, 2026
9c12d28
fmt
pompon0 Aug 6, 2026
5d195ee
fixed data tests
pompon0 Aug 6, 2026
bd863e5
pruned avail tests
pompon0 Aug 6, 2026
d7af2d1
some fixes
pompon0 Aug 6, 2026
519733f
some test fixes
pompon0 Aug 7, 2026
85efdec
appProposal persistence.
pompon0 Aug 7, 2026
00fe049
test fixes
pompon0 Aug 7, 2026
7fc04f0
uniform coverage of blockDB data types
pompon0 Aug 7, 2026
ea1df5c
consistent recent floor
pompon0 Aug 7, 2026
06bcfd5
simplifications
pompon0 Aug 7, 2026
fe34f24
WIP
pompon0 Aug 7, 2026
90d264f
floor
pompon0 Aug 7, 2026
8ad2882
more precise status
pompon0 Aug 7, 2026
cd348cd
floor fixed
pompon0 Aug 7, 2026
063e606
test fixes
pompon0 Aug 7, 2026
c9ac367
codex test fixes
pompon0 Aug 7, 2026
cc64f08
removed persistedBlockStart
pompon0 Aug 7, 2026
1c2f9b1
p2p tests still fail
pompon0 Aug 7, 2026
94369ac
should be fine
pompon0 Aug 7, 2026
9114624
voting only on persisted apphashes
pompon0 Aug 7, 2026
1344285
simplified db
pompon0 Aug 7, 2026
febf53e
fix from codex
pompon0 Aug 7, 2026
ddddac9
simplified readRecent()
pompon0 Aug 7, 2026
86bacf6
simplified
pompon0 Aug 7, 2026
b59451f
removed useless tests
pompon0 Aug 7, 2026
6b67803
simplified inmem blockDB
pompon0 Aug 7, 2026
a7aaa69
Option[Status]
pompon0 Aug 7, 2026
882a8a5
rename done
pompon0 Aug 10, 2026
6262ca2
WIP
pompon0 Aug 10, 2026
520f74d
fixed data.State.First()
pompon0 Aug 10, 2026
388c57d
applied comments WIP
pompon0 Aug 10, 2026
7a9bd64
fixed
pompon0 Aug 10, 2026
b1da655
anchor excluded from the avail state
pompon0 Aug 10, 2026
55a22ad
addressed comments
pompon0 Aug 10, 2026
9c7ebf6
Merge remote-tracking branch 'origin/main' into gprusak-appqc
pompon0 Aug 10, 2026
50066c8
removed stupid shit
pompon0 Aug 10, 2026
ff4a03c
test fix
pompon0 Aug 10, 2026
0fc5236
removed race condition
pompon0 Aug 10, 2026
5785a55
fixed test
pompon0 Aug 10, 2026
84c42bf
applied claude comments
pompon0 Aug 11, 2026
34b20ab
typo
pompon0 Aug 11, 2026
19d1d79
buf
pompon0 Aug 11, 2026
dc776b0
stricter rules for pushing AppHash
pompon0 Aug 11, 2026
6d9af6b
adapted the weakened WAL semantics
pompon0 Aug 11, 2026
8b8d526
applied claude comments
pompon0 Aug 11, 2026
779b058
added test for out-of-order PushAppHash
pompon0 Aug 11, 2026
d4e2c2c
more precise old apphash dropping criterion
pompon0 Aug 11, 2026
9ac7ed8
another test
pompon0 Aug 11, 2026
bfe6137
Re-run checks
pompon0 Aug 11, 2026
674210d
Merge remote-tracking branch 'origin/main' into gprusak-appqc
pompon0 Aug 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
938 changes: 467 additions & 471 deletions sei-db/ledger_db/block/block_db_test.go

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions sei-db/ledger_db/block/blocksim/block_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,19 +170,11 @@ func (g *BlockGenerator) buildFullCommitQC() (*types.FullCommitQC, []*types.Bloc

viewSpec := types.ViewSpec{CommitQC: prev, Epoch: types.NewEpoch(0, types.OpenRoadRange(), genesisTime, committee, 0)}
leader := committee.Leader(viewSpec.View())
appQC := func() utils.Option[*types.AppQC] {
if n := viewSpec.NextGlobalBlock(); n > 0 {
p := types.NewAppProposal(n-1, viewSpec.View().Index, types.AppHash(g.rand.Bytes(hashSizeBytes)), viewSpec.Epoch.EpochIndex())
return utils.Some(g.fakeAppQC(p))
}
return utils.None[*types.AppQC]()
}()
proposal := utils.OrPanic1(types.NewProposalForTesting(
committee,
viewSpec,
time.Now(),
laneQCs,
appQC,
g.fakeSig(leader),
))
commitVote := types.NewCommitVote(proposal.Proposal().Msg())
Expand Down
31 changes: 8 additions & 23 deletions sei-db/ledger_db/block/blocksim/blocksim.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,29 +178,11 @@ func NewBlockSim(
// countExistingState scans the ledger to count the persisted blocks and QCs,
// exercising the replay path at startup.
func countExistingState(db types.BlockDB) (blocks int, qcs int, err error) {
it, err := db.Iterator(0)
suffix, err := db.ReadSuffix()
if err != nil {
return 0, 0, fmt.Errorf("failed to open ledger iterator: %w", err)
return 0, 0, fmt.Errorf("failed to read suffix ledger data: %w", err)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] countExistingState now returns the size of the recovery suffix, not the whole ledger, but the doc comment above still says "scans the ledger to count the persisted blocks and QCs, exercising the replay path at startup". Since blockCount/qcCount are reported to the operator at line 106, the numbers now mean something different from what the benchmark previously printed — worth either renaming to countSuffixState or updating the comment so the output isn't misread.

}
defer func() { _ = it.Close() }()
for {
pos, ok, err := it.Next()
if err != nil {
return 0, 0, fmt.Errorf("failed to advance ledger iterator: %w", err)
}
if !ok {
break
}
if pos.QC.QC().GlobalRange().First == pos.Number {
// The scan entered a new QC's range.
qcs++
}
// Presence comes off the position, so counting never reads a block value.
if pos.HasBlock {
blocks++
}
}
return blocks, qcs, nil
return len(suffix.Blocks), len(suffix.CommitQCs), nil
Comment thread
pompon0 marked this conversation as resolved.
}

// recoverResumeState reads the persisted tail so the benchmark resumes appending
Expand All @@ -218,8 +200,11 @@ func recoverResumeState(
prev := tmutils.None[*types.CommitQC]()
highest := tmutils.None[uint64]()

status := db.Status()
if status.NextBlock > 0 {
status, ok := db.Status().Get()
if !ok {
return prev, highest, nil
}
Comment thread
pompon0 marked this conversation as resolved.
if status.NextBlock > status.First {
highest = tmutils.Some(uint64(status.NextBlock - 1))
}
if status.NextQC > 0 {
Expand Down
88 changes: 81 additions & 7 deletions sei-db/ledger_db/block/littblock/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ import (
// - kindBlock 'b' + 8-byte big-endian GlobalBlockNumber (block primary key)
// - kindBlockHash 'h' + 32-byte header hash (block hash alias)
// - kindQC 'q' + 8-byte big-endian GlobalBlockNumber (QC primary + covered aliases)
// - kindAppQC 'a' + 8-byte big-endian GlobalBlockNumber (AppQC primary + covered aliases)
// - kindAppProp 'p' + 8-byte big-endian GlobalBlockNumber (AppProposal primary + covered aliases)
const (
kindAppQC byte = 'a'
kindBlock byte = 'b'
kindBlockHash byte = 'h'
kindAppProp byte = 'p'
Comment thread
pompon0 marked this conversation as resolved.
kindQC byte = 'q'
)

Expand All @@ -32,8 +36,8 @@ func encodeKey(n types.GlobalBlockNumber) []byte {
}

// decodeKey decodes an 8-byte value produced by encodeKey.
func decodeKey(b []byte) types.GlobalBlockNumber {
return types.GlobalBlockNumber(binary.BigEndian.Uint64(b))
func decodeKey(b [8]byte) types.GlobalBlockNumber {
return types.GlobalBlockNumber(binary.BigEndian.Uint64(b[:]))
}

// blockKey returns the primary key under which a block at number n is stored.
Expand All @@ -53,15 +57,28 @@ func qcKey(n types.GlobalBlockNumber) []byte {
return append([]byte{kindQC}, encodeKey(n)...)
}

// appQCKey returns the key for AppQC number n — used both for an AppQC's
// primary key and for each covered-number alias.
func appQCKey(n types.GlobalBlockNumber) []byte {
return append([]byte{kindAppQC}, encodeKey(n)...)
}

// appProposalKey returns the key for AppProposal number n — used both for an
// AppProposal's primary key and for each covered-number alias.
func appProposalKey(n types.GlobalBlockNumber) []byte {
return append([]byte{kindAppProp}, encodeKey(n)...)
}

// keyKind returns the kind prefix byte of a stored key.
func keyKind(key []byte) byte {
return key[0]
}

// decodeNumberKey decodes the GlobalBlockNumber from a kindBlock or kindQC key
// (i.e. a key whose prefix is followed by an 8-byte big-endian number).
// decodeNumberKey decodes the GlobalBlockNumber from a kindBlock, kindQC, or
// kindAppQC key (i.e. a key whose prefix is followed by an 8-byte big-endian
// number). Panics if key is not 9 bytes (1B kind + 8B GlobalBlockNumber).
func decodeNumberKey(key []byte) types.GlobalBlockNumber {
return decodeKey(key[1:])
return decodeKey([8]byte(key[1:]))
}

// Serialization version for blocks.
Expand All @@ -70,6 +87,12 @@ const blockSerializationVersion byte = 1
// Serialization version for QCs.
const qcSerializationVersion byte = 1

// Serialization version for AppQCs.
const appQCSerializationVersion byte = 1

// Serialization version for AppProposals.
const appProposalSerializationVersion byte = 1

// blockValuePrefixLen is the fixed header preceding a block's proto bytes: one
// version byte followed by the 8-byte big-endian GlobalBlockNumber.
const blockValuePrefixLen = 1 + 8
Expand Down Expand Up @@ -124,8 +147,8 @@ func encodeQC(qc *types.FullCommitQC) []byte {
// so deriving from the encoded fields is what makes a QC's range identical
// before and after a round trip through the table.
func coveredRange(qc *types.FullCommitQC) (types.GlobalBlockNumber, types.GlobalBlockNumber) {
first := qc.QC().GlobalRange().First
return first, first + types.GlobalBlockNumber(len(qc.Headers()))
gr := qc.QC().GlobalRange()
return gr.First, gr.Next
}

// decodeQC unmarshals a FullCommitQC from the value produced by encodeQC.
Expand All @@ -142,3 +165,54 @@ func decodeQC(value []byte) (*types.FullCommitQC, error) {
}
return qc, nil
}

// encodeAppProposal marshals an AppProposal to the bytes stored as its table
// value, framed as [version:1][proto(AppProposal)].
func encodeAppProposal(appProposal *types.AppProposal) []byte {
proto := types.AppProposalConv.Marshal(appProposal)
value := make([]byte, 0, 1+len(proto))
value = append(value, appProposalSerializationVersion)
value = append(value, proto...)
return value
}

// decodeAppProposal unmarshals an AppProposal from the value produced by
// encodeAppProposal.
func decodeAppProposal(value []byte) (*types.AppProposal, error) {
if len(value) < 1 {
return nil, fmt.Errorf("appProposal value too short: %d bytes", len(value))
}
if value[0] != appProposalSerializationVersion {
return nil, fmt.Errorf("unsupported appProposal serialization version %d", value[0])
}
appProposal, err := types.AppProposalConv.Unmarshal(value[1:])
if err != nil {
return nil, fmt.Errorf("failed to unmarshal appProposal: %w", err)
}
return appProposal, nil
}

// encodeAppQC marshals an AppQC to the bytes stored as its table value,
// framed as [version:1][proto(AppQC)].
func encodeAppQC(appQC *types.AppQC) []byte {
proto := types.AppQCConv.Marshal(appQC)
value := make([]byte, 0, 1+len(proto))
value = append(value, appQCSerializationVersion)
value = append(value, proto...)
return value
}

// decodeAppQC unmarshals an AppQC from the value produced by encodeAppQC.
func decodeAppQC(value []byte) (*types.AppQC, error) {
if len(value) < 1 {
return nil, fmt.Errorf("appQC value too short: %d bytes", len(value))
}
if value[0] != appQCSerializationVersion {
return nil, fmt.Errorf("unsupported appQC serialization version %d", value[0])
}
appQC, err := types.AppQCConv.Unmarshal(value[1:])
if err != nil {
return nil, fmt.Errorf("failed to unmarshal appQC: %w", err)
}
return appQC, nil
}
2 changes: 1 addition & 1 deletion sei-db/ledger_db/block/littblock/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestKeyRoundTrip(t *testing.T) {
for _, n := range cases {
key := encodeKey(n)
require.Len(t, key, 8, "key must be 8 bytes")
require.Equal(t, n, decodeKey(key))
require.Equal(t, n, decodeKey([8]byte(key)))
}
}

Expand Down
Loading
Loading