github.com/iotexproject/iotex-core@v1.14.1-rc1/state/factory/workingsetstore.go (about)

     1  // Copyright (c) 2022 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package factory
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  
    12  	"github.com/iotexproject/go-pkgs/hash"
    13  	"go.uber.org/zap"
    14  
    15  	"github.com/pkg/errors"
    16  
    17  	"github.com/iotexproject/iotex-core/action/protocol"
    18  	"github.com/iotexproject/iotex-core/db"
    19  	"github.com/iotexproject/iotex-core/db/trie"
    20  	"github.com/iotexproject/iotex-core/db/trie/mptrie"
    21  	"github.com/iotexproject/iotex-core/pkg/log"
    22  	"github.com/iotexproject/iotex-core/pkg/util/byteutil"
    23  	"github.com/iotexproject/iotex-core/state"
    24  )
    25  
    26  type (
    27  	workingSetStore interface {
    28  		db.KVStoreBasic
    29  		Commit() error
    30  		States(string, [][]byte) ([][]byte, error)
    31  		Digest() hash.Hash256
    32  		Finalize(uint64) error
    33  		Snapshot() int
    34  		RevertSnapshot(int) error
    35  		ResetSnapshots()
    36  		ReadView(string) (interface{}, error)
    37  		WriteView(string, interface{}) error
    38  	}
    39  	stateDBWorkingSetStore struct {
    40  		view       protocol.View
    41  		flusher    db.KVStoreFlusher
    42  		readBuffer bool
    43  	}
    44  	factoryWorkingSetStore struct {
    45  		view      protocol.View
    46  		flusher   db.KVStoreFlusher
    47  		tlt       trie.TwoLayerTrie
    48  		trieRoots map[int][]byte
    49  	}
    50  )
    51  
    52  func newStateDBWorkingSetStore(view protocol.View, flusher db.KVStoreFlusher, readBuffer bool) workingSetStore {
    53  	return &stateDBWorkingSetStore{
    54  		flusher:    flusher,
    55  		view:       view,
    56  		readBuffer: readBuffer,
    57  	}
    58  }
    59  
    60  func newFactoryWorkingSetStore(view protocol.View, flusher db.KVStoreFlusher) (workingSetStore, error) {
    61  	tlt, err := newTwoLayerTrie(ArchiveTrieNamespace, flusher.KVStoreWithBuffer(), ArchiveTrieRootKey, true)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	return &factoryWorkingSetStore{
    67  		flusher:   flusher,
    68  		view:      view,
    69  		tlt:       tlt,
    70  		trieRoots: make(map[int][]byte),
    71  	}, nil
    72  }
    73  
    74  func (store *stateDBWorkingSetStore) Start(context.Context) error {
    75  	return nil
    76  }
    77  
    78  func (store *stateDBWorkingSetStore) Stop(context.Context) error {
    79  	return nil
    80  }
    81  
    82  func (store *stateDBWorkingSetStore) ReadView(name string) (interface{}, error) {
    83  	return store.view.Read(name)
    84  }
    85  
    86  func (store *stateDBWorkingSetStore) WriteView(name string, value interface{}) error {
    87  	return store.view.Write(name, value)
    88  }
    89  
    90  func (store *stateDBWorkingSetStore) Get(ns string, key []byte) ([]byte, error) {
    91  	data, err := store.flusher.KVStoreWithBuffer().Get(ns, key)
    92  	if err != nil {
    93  		if errors.Cause(err) == db.ErrNotExist {
    94  			return nil, errors.Wrapf(state.ErrStateNotExist, "failed to get state of ns = %x and key = %x", ns, key)
    95  		}
    96  		return nil, err
    97  	}
    98  	return data, nil
    99  }
   100  
   101  func (store *stateDBWorkingSetStore) Put(ns string, key []byte, value []byte) error {
   102  	store.flusher.KVStoreWithBuffer().MustPut(ns, key, value)
   103  	return nil
   104  }
   105  
   106  func (store *stateDBWorkingSetStore) Delete(ns string, key []byte) error {
   107  	store.flusher.KVStoreWithBuffer().MustDelete(ns, key)
   108  	return nil
   109  }
   110  
   111  func (store *stateDBWorkingSetStore) States(ns string, keys [][]byte) ([][]byte, error) {
   112  	if store.readBuffer {
   113  		return readStates(store.flusher.KVStoreWithBuffer(), ns, keys)
   114  	}
   115  	return readStates(store.flusher.BaseKVStore(), ns, keys)
   116  }
   117  
   118  func (store *stateDBWorkingSetStore) Digest() hash.Hash256 {
   119  	return hash.Hash256b(store.flusher.SerializeQueue())
   120  }
   121  
   122  func (store *stateDBWorkingSetStore) Finalize(height uint64) error {
   123  	// Persist current chain Height
   124  	store.flusher.KVStoreWithBuffer().MustPut(
   125  		AccountKVNamespace,
   126  		[]byte(CurrentHeightKey),
   127  		byteutil.Uint64ToBytes(height),
   128  	)
   129  	return nil
   130  }
   131  
   132  func (store *stateDBWorkingSetStore) Commit() error {
   133  	return store.flusher.Flush()
   134  }
   135  
   136  func (store *stateDBWorkingSetStore) Snapshot() int {
   137  	return store.flusher.KVStoreWithBuffer().Snapshot()
   138  }
   139  
   140  func (store *stateDBWorkingSetStore) RevertSnapshot(snapshot int) error {
   141  	return store.flusher.KVStoreWithBuffer().RevertSnapshot(snapshot)
   142  }
   143  
   144  func (store *stateDBWorkingSetStore) ResetSnapshots() {
   145  	store.flusher.KVStoreWithBuffer().ResetSnapshots()
   146  }
   147  
   148  func (store *factoryWorkingSetStore) Start(ctx context.Context) error {
   149  	return store.tlt.Start(ctx)
   150  }
   151  
   152  func (store *factoryWorkingSetStore) Stop(ctx context.Context) error {
   153  	return store.tlt.Stop(ctx)
   154  }
   155  
   156  func (store *factoryWorkingSetStore) ReadView(name string) (interface{}, error) {
   157  	return store.view.Read(name)
   158  }
   159  
   160  func (store *factoryWorkingSetStore) WriteView(name string, value interface{}) error {
   161  	return store.view.Write(name, value)
   162  }
   163  
   164  func (store *factoryWorkingSetStore) Get(ns string, key []byte) ([]byte, error) {
   165  	return readState(store.tlt, ns, key)
   166  }
   167  
   168  func (store *factoryWorkingSetStore) Put(ns string, key []byte, value []byte) error {
   169  	store.flusher.KVStoreWithBuffer().MustPut(ns, key, value)
   170  	nsHash := hash.Hash160b([]byte(ns))
   171  
   172  	return store.tlt.Upsert(nsHash[:], toLegacyKey(key), value)
   173  }
   174  
   175  func (store *factoryWorkingSetStore) Delete(ns string, key []byte) error {
   176  	store.flusher.KVStoreWithBuffer().MustDelete(ns, key)
   177  	nsHash := hash.Hash160b([]byte(ns))
   178  
   179  	err := store.tlt.Delete(nsHash[:], toLegacyKey(key))
   180  	if errors.Cause(err) == trie.ErrNotExist {
   181  		return errors.Wrapf(state.ErrStateNotExist, "key %x doesn't exist in namespace %x", key, nsHash)
   182  	}
   183  	return err
   184  }
   185  
   186  func (store *factoryWorkingSetStore) States(ns string, keys [][]byte) ([][]byte, error) {
   187  	values := [][]byte{}
   188  	if keys == nil {
   189  		iter, err := mptrie.NewLayerTwoLeafIterator(store.tlt, namespaceKey(ns), legacyKeyLen())
   190  		if err != nil {
   191  			return nil, err
   192  		}
   193  		for {
   194  			_, value, err := iter.Next()
   195  			if err == trie.ErrEndOfIterator {
   196  				break
   197  			}
   198  			if err != nil {
   199  				return nil, err
   200  			}
   201  			values = append(values, value)
   202  		}
   203  	} else {
   204  		for _, key := range keys {
   205  			value, err := readState(store.tlt, ns, key)
   206  			switch errors.Cause(err) {
   207  			case state.ErrStateNotExist:
   208  				values = append(values, nil)
   209  			case nil:
   210  				values = append(values, value)
   211  			default:
   212  				return nil, err
   213  			}
   214  		}
   215  	}
   216  	return values, nil
   217  }
   218  func (store *factoryWorkingSetStore) Digest() hash.Hash256 {
   219  	return hash.Hash256b(store.flusher.SerializeQueue())
   220  }
   221  
   222  func (store *factoryWorkingSetStore) Finalize(h uint64) error {
   223  	rootHash, err := store.tlt.RootHash()
   224  	if err != nil {
   225  		return err
   226  	}
   227  	store.flusher.KVStoreWithBuffer().MustPut(AccountKVNamespace, []byte(CurrentHeightKey), byteutil.Uint64ToBytes(h))
   228  	store.flusher.KVStoreWithBuffer().MustPut(ArchiveTrieNamespace, []byte(ArchiveTrieRootKey), rootHash)
   229  	// Persist the historical accountTrie's root hash
   230  	store.flusher.KVStoreWithBuffer().MustPut(
   231  		ArchiveTrieNamespace,
   232  		[]byte(fmt.Sprintf("%s-%d", ArchiveTrieRootKey, h)),
   233  		rootHash,
   234  	)
   235  	return nil
   236  }
   237  
   238  func (store *factoryWorkingSetStore) Commit() error {
   239  	_dbBatchSizelMtc.WithLabelValues().Set(float64(store.flusher.KVStoreWithBuffer().Size()))
   240  	return store.flusher.Flush()
   241  }
   242  
   243  func (store *factoryWorkingSetStore) Snapshot() int {
   244  	rh, err := store.tlt.RootHash()
   245  	if err != nil {
   246  		log.L().Panic("failed to do snapshot", zap.Error(err))
   247  	}
   248  	s := store.flusher.KVStoreWithBuffer().Snapshot()
   249  	store.trieRoots[s] = rh
   250  	return s
   251  }
   252  
   253  func (store *factoryWorkingSetStore) RevertSnapshot(snapshot int) error {
   254  	if err := store.flusher.KVStoreWithBuffer().RevertSnapshot(snapshot); err != nil {
   255  		return err
   256  	}
   257  	root, ok := store.trieRoots[snapshot]
   258  	if !ok {
   259  		// this should not happen, b/c we save the trie root on a successful return of Snapshot(), but check anyway
   260  		return errors.Wrapf(trie.ErrInvalidTrie, "failed to get trie root for snapshot = %d", snapshot)
   261  	}
   262  	return store.tlt.SetRootHash(root[:])
   263  }
   264  
   265  func (store *factoryWorkingSetStore) ResetSnapshots() {
   266  	store.flusher.KVStoreWithBuffer().ResetSnapshots()
   267  	store.trieRoots = make(map[int][]byte)
   268  }