Skip to content

Commit c686485

Browse files
core: only compute state root once (#30299)
This PR refactors the genesis initialization a bit, s.th. we only compute the blockhash once instead of twice as before (during hashAlloc and flushAlloc) This will significantly reduce the amount of memory allocated during genesis init --------- Co-authored-by: Gary Rong <[email protected]>
1 parent 2b9d198 commit c686485

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

core/genesis.go

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
145145
return statedb.Commit(0, false)
146146
}
147147

148-
// flushAlloc is very similar with hash, but the main difference is all the generated
149-
// states will be persisted into the given database. Also, the genesis state
150-
// specification will be flushed as well.
151-
func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database, blockhash common.Hash) error {
148+
// flushAlloc is very similar with hash, but the main difference is all the
149+
// generated states will be persisted into the given database.
150+
func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database) (common.Hash, error) {
152151
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
153152
if err != nil {
154-
return err
153+
return common.Hash{}, err
155154
}
156155
for addr, account := range *ga {
157156
if account.Balance != nil {
@@ -167,21 +166,15 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
167166
}
168167
root, err := statedb.Commit(0, false)
169168
if err != nil {
170-
return err
169+
return common.Hash{}, err
171170
}
172171
// Commit newly generated states into disk if it's not empty.
173172
if root != types.EmptyRootHash {
174173
if err := triedb.Commit(root, true); err != nil {
175-
return err
174+
return common.Hash{}, err
176175
}
177176
}
178-
// Marshal the genesis state specification and persist.
179-
blob, err := json.Marshal(ga)
180-
if err != nil {
181-
return err
182-
}
183-
rawdb.WriteGenesisStateSpec(db, blockhash, blob)
184-
return nil
177+
return root, nil
185178
}
186179

187180
func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) {
@@ -426,6 +419,11 @@ func (g *Genesis) ToBlock() *types.Block {
426419
if err != nil {
427420
panic(err)
428421
}
422+
return g.toBlockWithRoot(root)
423+
}
424+
425+
// toBlockWithRoot constructs the genesis block with the given genesis state root.
426+
func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
429427
head := &types.Header{
430428
Number: new(big.Int).SetUint64(g.Number),
431429
Nonce: types.EncodeNonce(g.Nonce),
@@ -482,8 +480,7 @@ func (g *Genesis) ToBlock() *types.Block {
482480
// Commit writes the block and state of a genesis specification to the database.
483481
// The block is committed as the canonical head block.
484482
func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) {
485-
block := g.ToBlock()
486-
if block.Number().Sign() != 0 {
483+
if g.Number != 0 {
487484
return nil, errors.New("can't commit genesis block with number > 0")
488485
}
489486
config := g.Config
@@ -493,15 +490,22 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
493490
if err := config.CheckConfigForkOrder(); err != nil {
494491
return nil, err
495492
}
496-
if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength {
493+
if config.Clique != nil && len(g.ExtraData) < 32+crypto.SignatureLength {
497494
return nil, errors.New("can't start clique chain without signers")
498495
}
499-
// All the checks has passed, flushAlloc the states derived from the genesis
500-
// specification as well as the specification itself into the provided
501-
// database.
502-
if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil {
496+
// flush the data to disk and compute the state root
497+
root, err := flushAlloc(&g.Alloc, db, triedb)
498+
if err != nil {
499+
return nil, err
500+
}
501+
block := g.toBlockWithRoot(root)
502+
503+
// Marshal the genesis state specification and persist.
504+
blob, err := json.Marshal(g.Alloc)
505+
if err != nil {
503506
return nil, err
504507
}
508+
rawdb.WriteGenesisStateSpec(db, block.Hash(), blob)
505509
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
506510
rawdb.WriteBlock(db, block)
507511
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)

0 commit comments

Comments
 (0)