Skip to content

Commit 522cdfd

Browse files
committed
Support migration
1 parent c90d21b commit 522cdfd

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

block/internal/executing/executor.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,12 @@ func (e *Executor) initializeState() error {
270270
e.logger.Info().Uint64("height", state.LastBlockHeight).
271271
Str("chain_id", state.ChainID).Msg("initialized state")
272272

273+
// Migrate any old-style pending block (stored at height N+1 via SaveBlockData
274+
// with empty signature) to the new metadata-key format.
275+
if err := e.migrateLegacyPendingBlock(e.ctx); err != nil {
276+
return fmt.Errorf("failed to migrate legacy pending block: %w", err)
277+
}
278+
273279
// Determine sync target: use Raft height if node is behind Raft consensus
274280
syncTargetHeight := state.LastBlockHeight
275281
if e.raftNode != nil {

block/internal/executing/pending.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package executing
22

33
import (
44
"context"
5+
"crypto/sha256"
56
"errors"
67
"fmt"
78

89
"github.com/evstack/ev-node/pkg/store"
910
"github.com/evstack/ev-node/types"
11+
"github.com/ipfs/go-datastore"
1012
ds "github.com/ipfs/go-datastore"
1113
)
1214

@@ -87,3 +89,60 @@ func (e *Executor) deletePendingBlock(ctx context.Context, batch store.Batch) er
8789
}
8890
return nil
8991
}
92+
93+
// migrateLegacyPendingBlock detects old-style pending blocks that were stored
94+
// at height N+1 via SaveBlockData with an empty signature (pre-upgrade format)
95+
// and migrates them to the new metadata-key format (m/pending_header, m/pending_data).
96+
//
97+
// This prevents double-signing when a node is upgraded: without migration the
98+
// new code would not find the pending block and would create+sign a new one at
99+
// the same height.
100+
func (e *Executor) migrateLegacyPendingBlock(ctx context.Context) error {
101+
candidateHeight := e.getLastState().LastBlockHeight + 1
102+
pendingHeader, pendingData, err := e.store.GetBlockData(ctx, candidateHeight)
103+
if err != nil {
104+
if !errors.Is(err, datastore.ErrNotFound) {
105+
return fmt.Errorf("get block data: %w", err)
106+
}
107+
return nil
108+
}
109+
if len(pendingHeader.Signature) != 0 {
110+
return errors.New("pending block with signatures found")
111+
}
112+
// Migrate: write header+data to the new metadata keys.
113+
if err := e.savePendingBlock(ctx, pendingHeader, pendingData); err != nil {
114+
return fmt.Errorf("save migrated pending block: %w", err)
115+
}
116+
117+
// Clean up old-style keys.
118+
batch, err := e.store.NewBatch(ctx)
119+
if err != nil {
120+
return fmt.Errorf("create cleanup batch: %w", err)
121+
}
122+
123+
headerBytes, err := pendingHeader.MarshalBinary()
124+
if err != nil {
125+
return fmt.Errorf("marshal header for hash: %w", err)
126+
}
127+
headerHash := sha256.Sum256(headerBytes)
128+
129+
for _, key := range []string{
130+
store.GetHeaderKey(candidateHeight),
131+
store.GetDataKey(candidateHeight),
132+
store.GetSignatureKey(candidateHeight),
133+
store.GetIndexKey(headerHash[:]),
134+
} {
135+
if err := batch.Delete(ds.NewKey(key)); err != nil {
136+
return fmt.Errorf("delete legacy key %s: %w", key, err)
137+
}
138+
}
139+
140+
if err := batch.Commit(); err != nil {
141+
return fmt.Errorf("commit cleanup batch: %w", err)
142+
}
143+
144+
e.logger.Info().
145+
Uint64("height", candidateHeight).
146+
Msg("migrated legacy pending block to metadata format")
147+
return nil
148+
}

pkg/store/keys.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,24 @@ const (
3434
heightPrefix = "t"
3535
)
3636

37-
func getHeaderKey(height uint64) string {
37+
func GetHeaderKey(height uint64) string {
3838
return GenerateKey([]string{headerPrefix, strconv.FormatUint(height, 10)})
3939
}
4040

41-
func getDataKey(height uint64) string {
41+
func getHeaderKey(height uint64) string { return GetHeaderKey(height) }
42+
43+
func GetDataKey(height uint64) string {
4244
return GenerateKey([]string{dataPrefix, strconv.FormatUint(height, 10)})
4345
}
4446

45-
func getSignatureKey(height uint64) string {
47+
func getDataKey(height uint64) string { return GetDataKey(height) }
48+
49+
func GetSignatureKey(height uint64) string {
4650
return GenerateKey([]string{signaturePrefix, strconv.FormatUint(height, 10)})
4751
}
4852

53+
func getSignatureKey(height uint64) string { return GetSignatureKey(height) }
54+
4955
func getStateAtHeightKey(height uint64) string {
5056
return GenerateKey([]string{statePrefix, strconv.FormatUint(height, 10)})
5157
}
@@ -54,10 +60,12 @@ func GetMetaKey(key string) string {
5460
return GenerateKey([]string{metaPrefix, key})
5561
}
5662

57-
func getIndexKey(hash types.Hash) string {
63+
func GetIndexKey(hash types.Hash) string {
5864
return GenerateKey([]string{indexPrefix, hash.String()})
5965
}
6066

67+
func getIndexKey(hash types.Hash) string { return GetIndexKey(hash) }
68+
6169
func getHeightKey() string {
6270
return GenerateKey([]string{heightPrefix})
6371
}

0 commit comments

Comments
 (0)