package downloader import ( "fmt" "sync" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/trie" ) // governanceDB is backed by memory db for fast sync. // it implements core.GovernanceStateDB type governanceStateDB struct { db ethdb.Database headRoot common.Hash headHeight uint64 height2Root map[uint64]common.Hash mu sync.Mutex } func (g *governanceStateDB) State() (*state.StateDB, error) { return state.New(g.headRoot, state.NewDatabase(g.db)) } func (g *governanceStateDB) StateAt(height uint64) (*state.StateDB, error) { root, exists := g.height2Root[height] if !exists { return nil, fmt.Errorf("Governance state not ready, height: %d", height) } return state.New(root, state.NewDatabase(g.db)) } func (g *governanceStateDB) StoreState(s *types.GovState) { g.mu.Lock() defer g.mu.Unlock() log.Debug("Store state", "height", s.Number.Uint64()) // Store the height -> root mapping. g.height2Root[s.Number.Uint64()] = s.Root // Store the account. for _, node := range s.Proof { g.db.Put(crypto.Keccak256(node), node) } // Store the storage. triedb := trie.NewDatabase(g.db) t, err := trie.New(common.Hash{}, triedb) if err != nil { panic(err) } for _, kv := range s.Storage { t.TryUpdate(kv[0], kv[1]) } t.Commit(nil) triedb.Commit(t.Hash(), false) if s.Number.Uint64() > g.headHeight { log.Debug("Governance head root changed", "number", s.Number.Uint64()) g.headRoot = s.Root g.headHeight = s.Number.Uint64() } } // This is a governance for fast sync type governance struct { *core.Governance db *governanceStateDB } func newGovernance(headState *types.GovState) *governance { db := ethdb.NewMemDatabase() govStateDB := &governanceStateDB{ db: db, headRoot: headState.Root, headHeight: headState.Number.Uint64(), height2Root: make(map[uint64]common.Hash), } govStateDB.StoreState(headState) return &governance{ Governance: core.NewGovernance(govStateDB), db: govStateDB, } } func (g *governance) StoreState(s *types.GovState) { g.db.StoreState(s) }