mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
Added writing of genesis.Alloc on bootstrap, geth init will also fill the missing value
This commit is contained in:
parent
dd86f19df4
commit
09d66773bd
4 changed files with 137 additions and 0 deletions
|
|
@ -408,6 +408,34 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||
}
|
||||
}
|
||||
|
||||
if bc.logger != nil && bc.CurrentBlock().Number.Uint64() == 0 {
|
||||
rawAlloc, found := rawdb.ReadGenesisAlloc(bc.db)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set, use 'geth init' to set it")
|
||||
}
|
||||
|
||||
alloc := make(GenesisAlloc, len(rawAlloc))
|
||||
for _, account := range rawAlloc {
|
||||
var storage map[common.Hash]common.Hash
|
||||
if len(account.Storage) > 0 {
|
||||
storage = make(map[common.Hash]common.Hash, len(account.Storage))
|
||||
for _, entry := range account.Storage {
|
||||
storage[entry.Key] = entry.Value
|
||||
}
|
||||
}
|
||||
|
||||
alloc[account.Address] = GenesisAccount{
|
||||
Balance: account.Balance,
|
||||
Code: account.Code,
|
||||
Storage: storage,
|
||||
Nonce: account.Nonce,
|
||||
PrivateKey: account.PrivateKey,
|
||||
}
|
||||
}
|
||||
|
||||
bc.logger.OnGenesisBlock(bc.genesisBlock, alloc)
|
||||
}
|
||||
|
||||
// Load any existing snapshot, regenerating it if loading failed
|
||||
if bc.cacheConfig.SnapshotLimit > 0 {
|
||||
// If the chain was rewound past the snapshot persistent layer (causing
|
||||
|
|
|
|||
|
|
@ -371,10 +371,21 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
|
|||
if compatErr != nil && ((head.Number.Uint64() != 0 && compatErr.RewindToBlock != 0) || (head.Time != 0 && compatErr.RewindToTime != 0)) {
|
||||
return newcfg, stored, compatErr
|
||||
}
|
||||
|
||||
// Don't overwrite if the old is identical to the new
|
||||
if newData, _ := json.Marshal(newcfg); !bytes.Equal(storedData, newData) {
|
||||
rawdb.WriteChainConfig(db, stored, newcfg)
|
||||
}
|
||||
|
||||
// PR Review Question: Should we actually use same behavior as above and overwrite if the old is not identical to the new?
|
||||
// A new genesis alloc would lead to a new genesis block hash, so we should probably NOT overwrite unless block hash
|
||||
// is also affected in the flow above.
|
||||
//
|
||||
// We only write genesis alloc if the `genesis` is non-nil, which happen on blockchain boot and custom network.
|
||||
if genesis != nil && !rawdb.HasGenesisAlloc(db) {
|
||||
rawdb.WriteGenesisAlloc(db, toRawDBAccounts(genesis.Alloc))
|
||||
}
|
||||
|
||||
return newcfg, stored, nil
|
||||
}
|
||||
|
||||
|
|
@ -493,6 +504,8 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc
|
|||
if err := g.Alloc.flush(db, triedb, block.Hash(), bcLogger); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rawdb.WriteGenesisAlloc(db, toRawDBAccounts(g.Alloc))
|
||||
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
|
||||
rawdb.WriteBlock(db, block)
|
||||
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
|
||||
|
|
@ -504,6 +517,46 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc
|
|||
return block, nil
|
||||
}
|
||||
|
||||
func toRawDBAccounts(alloc GenesisAlloc) (out []rawdb.Account) {
|
||||
if len(alloc) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
out = make([]rawdb.Account, len(alloc))
|
||||
for addr, account := range alloc {
|
||||
out[i] = rawdb.Account{
|
||||
Address: addr,
|
||||
Code: account.Code,
|
||||
Storage: toRawDBAccountStorages(account.Storage),
|
||||
Balance: account.Balance,
|
||||
Nonce: account.Nonce,
|
||||
PrivateKey: account.PrivateKey,
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func toRawDBAccountStorages(in map[common.Hash]common.Hash) (out []rawdb.AccountStorage) {
|
||||
if len(in) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
out = make([]rawdb.AccountStorage, len(in))
|
||||
for key, value := range in {
|
||||
out[i] = rawdb.AccountStorage{
|
||||
Key: key,
|
||||
Value: value,
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||
// The block is committed as the canonical head block.
|
||||
// Note the state changes will be committed in hash-based scheme, use Commit
|
||||
|
|
|
|||
|
|
@ -761,6 +761,60 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block {
|
|||
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithWithdrawals(body.Withdrawals)
|
||||
}
|
||||
|
||||
// Account is an account in the state of the genesis block
|
||||
//
|
||||
// FIXME: This is a duplicate for now of core.GenesisAccount (and actually core.GenesisAlloc).
|
||||
type Account struct {
|
||||
Address common.Address `json:"address" gencodec:"required"`
|
||||
Code []byte `json:"code,omitempty"`
|
||||
Storage []AccountStorage `json:"storage,omitempty"`
|
||||
Balance *big.Int `json:"balance" gencodec:"required"`
|
||||
Nonce uint64 `json:"nonce,omitempty"`
|
||||
PrivateKey []byte `json:"secretKey,omitempty"` // for tests
|
||||
}
|
||||
|
||||
type AccountStorage struct {
|
||||
Key common.Hash `json:"key,omitempty"`
|
||||
Value common.Hash `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
// HasGenesisAlloc checks if a genesis allocation exists currently in the database
|
||||
func HasGenesisAlloc(db ethdb.Reader) (found bool) {
|
||||
found, _ = db.Has(genesisAllocKey)
|
||||
return
|
||||
}
|
||||
|
||||
// ReadGenesisalloc serializes the full initial genesis allocation into the database
|
||||
func ReadGenesisAlloc(db ethdb.Reader) (alloc []Account, found bool) {
|
||||
// We handle case where genesis alloc is not present, downstream code might decide differently
|
||||
// PR Review question: Should I check for specific Not Found Error? I did not see a common `error` in `ethdb`
|
||||
data, _ := db.Get(genesisAllocKey)
|
||||
|
||||
if len(data) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
alloc = []Account{}
|
||||
if err := rlp.Decode(bytes.NewReader(data), &alloc); err != nil {
|
||||
log.Crit("Failed to decode genesis alloc", "err", err)
|
||||
return nil, true
|
||||
}
|
||||
|
||||
return alloc, true
|
||||
}
|
||||
|
||||
// WriteGenesisAlloc serializes the full initial genesis allocation into the database
|
||||
func WriteGenesisAlloc(db ethdb.KeyValueWriter, alloc []Account) {
|
||||
data, err := rlp.EncodeToBytes(alloc)
|
||||
if err != nil {
|
||||
log.Crit("Failed to RLP encode alloc", "err", err)
|
||||
}
|
||||
|
||||
if err := db.Put(genesisAllocKey, data); err != nil {
|
||||
log.Crit("Failed to store genesis alloc", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteBlock serializes a block into the database, header and body separately.
|
||||
func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) {
|
||||
WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ var (
|
|||
transitionStatusKey = []byte("eth2-transition")
|
||||
|
||||
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
|
||||
genesisAllocKey = []byte("g") // genesisAllocKey (static key)
|
||||
|
||||
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
|
||||
headerTDSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
|
||||
headerHashSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
|
||||
|
|
|
|||
Loading…
Reference in a new issue