upgrade_db.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package mps
  2. import (
  3. "fmt"
  4. "github.com/ethereum/go-ethereum/common"
  5. "github.com/ethereum/go-ethereum/consensus"
  6. "github.com/ethereum/go-ethereum/core/privatecache"
  7. "github.com/ethereum/go-ethereum/core/rawdb"
  8. "github.com/ethereum/go-ethereum/core/state"
  9. "github.com/ethereum/go-ethereum/core/types"
  10. "github.com/ethereum/go-ethereum/ethdb"
  11. )
  12. // chainReader contains methods to access local blockchain
  13. type chainReader interface {
  14. consensus.ChainReader
  15. CurrentBlock() *types.Block
  16. GetReceiptsByHash(hash common.Hash) types.Receipts
  17. }
  18. // UpgradeDB performs the following database operations to enable MPS support
  19. // 1. Construct and persist Empty Private State with empty accounts
  20. // 2. Construct and persist trie of root hashes of existing private states
  21. // 3. Update new mapping: block header root -> trie of private states root
  22. // 4. Once upgrade is complete update the ChainConfig.isMPS to true
  23. func UpgradeDB(db ethdb.Database, chain chainReader) error {
  24. currentBlockNumber := uint64(chain.CurrentBlock().Number().Int64())
  25. genesisHeader := chain.GetHeaderByNumber(0)
  26. privateStatesTrieRoot := rawdb.GetPrivateStatesTrieRoot(db, genesisHeader.Root)
  27. privateCacheProvider := privatecache.NewPrivateCacheProvider(db, nil, nil, false)
  28. mpsRepo, err := NewMultiplePrivateStateRepository(db, state.NewDatabase(db), privateStatesTrieRoot, privateCacheProvider)
  29. if err != nil {
  30. return err
  31. }
  32. emptyState, err := mpsRepo.DefaultState()
  33. if err != nil {
  34. return err
  35. }
  36. // pre-populate with dummy one as the state root is derived from block root hash
  37. privateState := &managedState{}
  38. mpsRepo.managedStates[types.DefaultPrivateStateIdentifier] = privateState
  39. for idx := uint64(1); idx <= currentBlockNumber; idx++ {
  40. header := chain.GetHeaderByNumber(idx)
  41. // TODO consider periodic reports instead of logging about each block
  42. fmt.Printf("Processing block %v with hash %v\n", idx, header.Hash().Hex())
  43. block := chain.GetBlock(header.Hash(), header.Number.Uint64())
  44. // update Empty Private State
  45. receipts := chain.GetReceiptsByHash(header.Hash())
  46. receiptsUpdated := false
  47. for txIdx, tx := range block.Transactions() {
  48. if tx.IsPrivate() && tx.To() == nil {
  49. // this is a contract creation transaction
  50. receipt := receipts[txIdx]
  51. accountAddress := receipt.ContractAddress
  52. emptyState.CreateAccount(accountAddress)
  53. emptyState.SetNonce(accountAddress, 1)
  54. emptyReceipt := &types.Receipt{
  55. PostState: receipt.PostState,
  56. Status: 1,
  57. CumulativeGasUsed: receipt.CumulativeGasUsed,
  58. Bloom: types.Bloom{},
  59. Logs: nil,
  60. TxHash: receipt.TxHash,
  61. ContractAddress: receipt.ContractAddress,
  62. GasUsed: receipt.GasUsed,
  63. BlockHash: receipt.BlockHash,
  64. BlockNumber: receipt.BlockNumber,
  65. TransactionIndex: receipt.TransactionIndex,
  66. }
  67. emptyReceipt.Bloom = types.CreateBloom(types.Receipts{emptyReceipt})
  68. emptyReceipt.PSReceipts = map[types.PrivateStateIdentifier]*types.Receipt{
  69. types.DefaultPrivateStateIdentifier: receipt,
  70. types.EmptyPrivateStateIdentifier: emptyReceipt}
  71. receipts[txIdx] = emptyReceipt
  72. receiptsUpdated = true
  73. }
  74. }
  75. if receiptsUpdated {
  76. batch := db.NewBatch()
  77. rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
  78. err := batch.Write()
  79. if err != nil {
  80. return err
  81. }
  82. }
  83. // update trie of private state roots and new mapping with block root hash
  84. privateState.stateRootProviderFunc = func(_ bool) (common.Hash, error) {
  85. return rawdb.GetPrivateStateRoot(db, header.Root), nil
  86. }
  87. err = mpsRepo.CommitAndWrite(chain.Config().IsEIP158(block.Number()), block)
  88. if err != nil {
  89. return err
  90. }
  91. }
  92. // update isMPS in the chain config
  93. config := chain.Config()
  94. config.IsMPS = true
  95. rawdb.WriteChainConfig(db, rawdb.ReadCanonicalHash(db, 0), config)
  96. fmt.Printf("MPS DB upgrade finished successfully.\n")
  97. return nil
  98. }