123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- package mps
- import (
- "fmt"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/consensus"
- "github.com/ethereum/go-ethereum/core/privatecache"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
- )
- // chainReader contains methods to access local blockchain
- type chainReader interface {
- consensus.ChainReader
- CurrentBlock() *types.Block
- GetReceiptsByHash(hash common.Hash) types.Receipts
- }
- // UpgradeDB performs the following database operations to enable MPS support
- // 1. Construct and persist Empty Private State with empty accounts
- // 2. Construct and persist trie of root hashes of existing private states
- // 3. Update new mapping: block header root -> trie of private states root
- // 4. Once upgrade is complete update the ChainConfig.isMPS to true
- func UpgradeDB(db ethdb.Database, chain chainReader) error {
- currentBlockNumber := uint64(chain.CurrentBlock().Number().Int64())
- genesisHeader := chain.GetHeaderByNumber(0)
- privateStatesTrieRoot := rawdb.GetPrivateStatesTrieRoot(db, genesisHeader.Root)
- privateCacheProvider := privatecache.NewPrivateCacheProvider(db, nil, nil, false)
- mpsRepo, err := NewMultiplePrivateStateRepository(db, state.NewDatabase(db), privateStatesTrieRoot, privateCacheProvider)
- if err != nil {
- return err
- }
- emptyState, err := mpsRepo.DefaultState()
- if err != nil {
- return err
- }
- // pre-populate with dummy one as the state root is derived from block root hash
- privateState := &managedState{}
- mpsRepo.managedStates[types.DefaultPrivateStateIdentifier] = privateState
- for idx := uint64(1); idx <= currentBlockNumber; idx++ {
- header := chain.GetHeaderByNumber(idx)
- // TODO consider periodic reports instead of logging about each block
- fmt.Printf("Processing block %v with hash %v\n", idx, header.Hash().Hex())
- block := chain.GetBlock(header.Hash(), header.Number.Uint64())
- // update Empty Private State
- receipts := chain.GetReceiptsByHash(header.Hash())
- receiptsUpdated := false
- for txIdx, tx := range block.Transactions() {
- if tx.IsPrivate() && tx.To() == nil {
- // this is a contract creation transaction
- receipt := receipts[txIdx]
- accountAddress := receipt.ContractAddress
- emptyState.CreateAccount(accountAddress)
- emptyState.SetNonce(accountAddress, 1)
- emptyReceipt := &types.Receipt{
- PostState: receipt.PostState,
- Status: 1,
- CumulativeGasUsed: receipt.CumulativeGasUsed,
- Bloom: types.Bloom{},
- Logs: nil,
- TxHash: receipt.TxHash,
- ContractAddress: receipt.ContractAddress,
- GasUsed: receipt.GasUsed,
- BlockHash: receipt.BlockHash,
- BlockNumber: receipt.BlockNumber,
- TransactionIndex: receipt.TransactionIndex,
- }
- emptyReceipt.Bloom = types.CreateBloom(types.Receipts{emptyReceipt})
- emptyReceipt.PSReceipts = map[types.PrivateStateIdentifier]*types.Receipt{
- types.DefaultPrivateStateIdentifier: receipt,
- types.EmptyPrivateStateIdentifier: emptyReceipt}
- receipts[txIdx] = emptyReceipt
- receiptsUpdated = true
- }
- }
- if receiptsUpdated {
- batch := db.NewBatch()
- rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
- err := batch.Write()
- if err != nil {
- return err
- }
- }
- // update trie of private state roots and new mapping with block root hash
- privateState.stateRootProviderFunc = func(_ bool) (common.Hash, error) {
- return rawdb.GetPrivateStateRoot(db, header.Root), nil
- }
- err = mpsRepo.CommitAndWrite(chain.Config().IsEIP158(block.Number()), block)
- if err != nil {
- return err
- }
- }
- // update isMPS in the chain config
- config := chain.Config()
- config.IsMPS = true
- rawdb.WriteChainConfig(db, rawdb.ReadCanonicalHash(db, 0), config)
- fmt.Printf("MPS DB upgrade finished successfully.\n")
- return nil
- }
|