Skip to content

Commit f535624

Browse files
authored
Merge pull request #372 from SiaFoundation/min-reorg
chain: Add MinReorgIndex
2 parents 1e58a5a + 5ee5683 commit f535624

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

chain/manager.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,23 @@ func (m *Manager) BestIndex(height uint64) (types.ChainIndex, bool) {
137137
return m.store.BestIndex(height)
138138
}
139139

140+
// MinReorgIndex returns the index on the best chain below which the manager
141+
// cannot perform a reorg.
142+
func (m *Manager) MinReorgIndex() types.ChainIndex {
143+
m.mu.Lock()
144+
defer m.mu.Unlock()
145+
index := m.tipState.Index
146+
for index.Height > 0 {
147+
prevIndex, ok := m.store.BestIndex(index.Height - 1)
148+
_, _, ok2 := m.store.Block(prevIndex.ID)
149+
if !ok || !ok2 {
150+
break
151+
}
152+
index = prevIndex
153+
}
154+
return index
155+
}
156+
140157
// History returns a set of block IDs that span the best chain, beginning with
141158
// the 10 most-recent blocks, and subsequently spaced exponentionally farther
142159
// apart until reaching the genesis block.

chain/manager_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,70 @@ func TestNewDBStoreAtCheckpoint(t *testing.T) {
480480
}
481481
})
482482
}
483+
484+
func TestMinReorgIndex(t *testing.T) {
485+
n, genesisBlock := TestnetZen()
486+
genesisBlock.Transactions = nil
487+
n.InitialTarget = types.BlockID{0xFF}
488+
n.BlockInterval = time.Second
489+
n.MaturityDelay = 5
490+
n.HardforkDevAddr.Height = 1
491+
n.HardforkTax.Height = 1
492+
n.HardforkStorageProof.Height = 1
493+
n.HardforkOak.Height = 1
494+
n.HardforkASIC.Height = 1
495+
n.HardforkFoundation.Height = 1
496+
n.HardforkV2.AllowHeight = 1
497+
n.HardforkV2.RequireHeight = 1
498+
n.HardforkV2.FinalCutHeight = 1
499+
500+
// mine to checkpoint
501+
cs := n.GenesisState()
502+
b := genesisBlock
503+
var blocks []types.Block
504+
for range 20 {
505+
cs, _ = consensus.ApplyBlock(cs, b, consensus.V1BlockSupplement{}, time.Time{})
506+
b = types.Block{
507+
ParentID: cs.Index.ID,
508+
Timestamp: types.CurrentTimestamp(),
509+
MinerPayouts: []types.SiacoinOutput{{
510+
Value: cs.BlockReward(),
511+
Address: types.VoidAddress,
512+
}},
513+
}
514+
findBlockNonce(cs, &b)
515+
blocks = append(blocks, b)
516+
}
517+
checkpointState, _ := consensus.ApplyBlock(cs, b, consensus.V1BlockSupplement{}, time.Time{})
518+
519+
// initialize manager at checkpoint
520+
store, tipState, err := NewDBStoreAtCheckpoint(NewMemDB(), cs, b, nil)
521+
if err != nil {
522+
t.Fatal(err)
523+
}
524+
cm := NewManager(store, tipState)
525+
// min reorg index should be at checkpoint
526+
if minReorg := cm.MinReorgIndex(); minReorg != checkpointState.Index {
527+
t.Fatal("unexpected min reorg index:", minReorg, "expected:", checkpointState.Index)
528+
}
529+
530+
// reinitialize at genesis
531+
store, tipState, err = NewDBStore(NewMemDB(), n, genesisBlock, nil)
532+
if err != nil {
533+
t.Fatal(err)
534+
}
535+
cm = NewManager(store, tipState)
536+
if minReorg := cm.MinReorgIndex(); minReorg.ID != genesisBlock.ID() {
537+
t.Fatal("unexpected min reorg index:", minReorg, "expected:", genesisBlock.ID())
538+
}
539+
// add intervening blocks
540+
if err := cm.AddBlocks(blocks); err != nil {
541+
t.Fatal(err)
542+
} else if cm.Tip() != checkpointState.Index {
543+
t.Fatal("tip mismatch:", cm.Tip(), "expected:", checkpointState.Index)
544+
}
545+
// min reorg index should still be at genesis
546+
if minReorg := cm.MinReorgIndex(); minReorg.ID != genesisBlock.ID() {
547+
t.Fatal("unexpected min reorg index:", minReorg, "expected:", genesisBlock.ID())
548+
}
549+
}

0 commit comments

Comments
 (0)