-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathapply_genesis.go
More file actions
140 lines (125 loc) · 4.51 KB
/
Copy pathapply_genesis.go
File metadata and controls
140 lines (125 loc) · 4.51 KB
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package gossip
import (
"errors"
"fmt"
"github.com/Fantom-foundation/go-opera/inter/iblockproc"
"github.com/Fantom-foundation/go-opera/inter/ibr"
"github.com/Fantom-foundation/go-opera/inter/ier"
"github.com/Fantom-foundation/go-opera/opera/genesis"
"github.com/Fantom-foundation/go-opera/utils/dbutil/autocompact"
"github.com/Fantom-foundation/lachesis-base/kvdb/batched"
"github.com/ethereum/go-ethereum/common"
"github.com/syndtr/goleveldb/leveldb/opt"
)
// ApplyGenesis writes initial state.
func (s *Store) ApplyGenesis(g genesis.Genesis) (err error) {
// use batching wrapper for hot tables
unwrap := s.WrapTablesAsBatched()
defer unwrap()
// write epochs
var topEr *ier.LlrIdxFullEpochRecord
g.Epochs.ForEach(func(er ier.LlrIdxFullEpochRecord) bool {
if er.EpochState.Rules.NetworkID != g.NetworkID || er.EpochState.Rules.Name != g.NetworkName {
err = errors.New("network ID/name mismatch")
return false
}
if topEr == nil {
topEr = &er
}
s.WriteFullEpochRecord(er)
return true
})
if err != nil {
return err
}
if topEr == nil {
return errors.New("no ERs in genesis")
}
var prevEs *iblockproc.EpochState
s.ForEachHistoryBlockEpochState(func(bs iblockproc.BlockState, es iblockproc.EpochState) bool {
s.WriteUpgradeHeight(bs, es, prevEs)
prevEs = &es
return true
})
s.SetBlockEpochState(topEr.BlockState, topEr.EpochState)
s.FlushBlockEpochState()
// write blocks
var lastBlock ibr.LlrIdxFullBlockRecord
g.Blocks.ForEach(func(br ibr.LlrIdxFullBlockRecord) bool {
s.WriteFullBlockRecord(br)
if br.Idx > lastBlock.Idx {
lastBlock = br
}
return true
})
// write EVM items
liveReader, err := g.FwsLiveSection.GetReader()
if err != nil {
s.Log.Info("Fantom World State Live data not available in the genesis", "err", err)
}
if liveReader != nil { // has S5 section - import S5 data
s.Log.Info("Importing Fantom World State Live data from genesis")
err = s.evm.ImportLiveWorldState(liveReader)
if err != nil {
return fmt.Errorf("failed to import Fantom World State data from genesis; %v", err)
}
// import S5 archive
archiveReader, _ := g.FwsArchiveSection.GetReader()
if archiveReader != nil { // has archive section
s.Log.Info("Importing Fantom World State Archive data from genesis")
err = s.evm.ImportArchiveWorldState(archiveReader)
if err != nil {
return fmt.Errorf("failed to import Fantom World State Archive data from genesis; %v", err)
}
} else { // no archive section - initialize archive from the live section
s.Log.Info("No archive in the genesis file - initializing the archive from the live state", "blockNum", lastBlock.Idx)
liveToArchiveReader, err := g.FwsLiveSection.GetReader() // second reader of the same section for the archive import
if err != nil {
return fmt.Errorf("failed to get second FWS section reader; %v", err)
}
err = s.evm.InitializeArchiveWorldState(liveToArchiveReader, uint64(lastBlock.Idx))
if err != nil {
return fmt.Errorf("failed to import Fantom World State data from genesis; %v", err)
}
}
} else { // no S5 section in the genesis file
// Import legacy EVM genesis section
err = s.evm.ImportLegacyEvmData(g.RawEvmItems, uint64(lastBlock.Idx), common.Hash(lastBlock.Root))
if err != nil {
return fmt.Errorf("import of legacy genesis data into StateDB failed; %v", err)
}
}
if err := s.evm.Open(); err != nil {
return fmt.Errorf("unable to open EvmStore to check imported state: %w", err)
}
if err := s.evm.CheckLiveStateHash(lastBlock.Idx, lastBlock.Root); err != nil {
return fmt.Errorf("checking imported live state failed: %w", err)
} else {
s.Log.Info("StateDB imported successfully, stateRoot matches", "index", lastBlock.Idx, "root", lastBlock.Root)
}
// write LLR state
s.setLlrState(LlrState{
LowestEpochToDecide: topEr.Idx + 1,
LowestEpochToFill: topEr.Idx + 1,
LowestBlockToDecide: topEr.BlockState.LastBlock.Idx + 1,
LowestBlockToFill: topEr.BlockState.LastBlock.Idx + 1,
})
s.FlushLlrState()
s.SetGenesisID(g.GenesisID)
s.SetGenesisBlockIndex(topEr.BlockState.LastBlock.Idx)
return nil
}
func (s *Store) WrapTablesAsBatched() (unwrap func()) {
origTables := s.table
batchedBlocks := batched.Wrap(autocompact.Wrap2M(s.table.Blocks, opt.GiB, 16*opt.GiB, false, "blocks"))
s.table.Blocks = batchedBlocks
batchedBlockHashes := batched.Wrap(s.table.BlockHashes)
s.table.BlockHashes = batchedBlockHashes
unwrapEVM := s.evm.WrapTablesAsBatched()
return func() {
unwrapEVM()
_ = batchedBlocks.Flush()
_ = batchedBlockHashes.Flush()
s.table = origTables
}
}