github.com/iotexproject/iotex-core@v1.14.1-rc1/state/factory/factory.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  	"strconv"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/pkg/errors"
    16  	"github.com/prometheus/client_golang/prometheus"
    17  	"go.uber.org/zap"
    18  
    19  	"github.com/iotexproject/go-pkgs/cache"
    20  	"github.com/iotexproject/go-pkgs/hash"
    21  	"github.com/iotexproject/iotex-address/address"
    22  
    23  	"github.com/iotexproject/iotex-core/action"
    24  	"github.com/iotexproject/iotex-core/action/protocol"
    25  	"github.com/iotexproject/iotex-core/action/protocol/execution/evm"
    26  	"github.com/iotexproject/iotex-core/action/protocol/staking"
    27  	"github.com/iotexproject/iotex-core/actpool"
    28  	"github.com/iotexproject/iotex-core/blockchain"
    29  	"github.com/iotexproject/iotex-core/blockchain/block"
    30  	"github.com/iotexproject/iotex-core/blockchain/genesis"
    31  	"github.com/iotexproject/iotex-core/db"
    32  	"github.com/iotexproject/iotex-core/db/batch"
    33  	"github.com/iotexproject/iotex-core/db/trie"
    34  	"github.com/iotexproject/iotex-core/pkg/lifecycle"
    35  	"github.com/iotexproject/iotex-core/pkg/log"
    36  	"github.com/iotexproject/iotex-core/pkg/prometheustimer"
    37  	"github.com/iotexproject/iotex-core/pkg/tracer"
    38  	"github.com/iotexproject/iotex-core/pkg/util/byteutil"
    39  	"github.com/iotexproject/iotex-core/state"
    40  )
    41  
    42  const (
    43  	// AccountKVNamespace is the bucket name for account
    44  	AccountKVNamespace = "Account"
    45  	// ArchiveNamespacePrefix is the prefix of the buckets storing history data
    46  	ArchiveNamespacePrefix = "Archive"
    47  	// CurrentHeightKey indicates the key of current factory height in underlying DB
    48  	CurrentHeightKey = "currentHeight"
    49  	// ArchiveTrieNamespace is the bucket for the latest state view
    50  	ArchiveTrieNamespace = "AccountTrie"
    51  	// ArchiveTrieRootKey indicates the key of accountTrie root hash in underlying DB
    52  	ArchiveTrieRootKey = "archiveTrieRoot"
    53  )
    54  
    55  var (
    56  	// ErrNotSupported is the error that the statedb is not for archive mode
    57  	ErrNotSupported = errors.New("not supported")
    58  	// ErrNoArchiveData is the error that the node have no archive data
    59  	ErrNoArchiveData = errors.New("no archive data")
    60  
    61  	_dbBatchSizelMtc = prometheus.NewGaugeVec(
    62  		prometheus.GaugeOpts{
    63  			Name: "iotex_db_batch_size",
    64  			Help: "DB batch size",
    65  		},
    66  		[]string{},
    67  	)
    68  
    69  	//DefaultConfig is the default config for state factory
    70  	DefaultConfig = Config{
    71  		Chain:   blockchain.DefaultConfig,
    72  		Genesis: genesis.Default,
    73  	}
    74  )
    75  
    76  func init() {
    77  	prometheus.MustRegister(_dbBatchSizelMtc)
    78  }
    79  
    80  type (
    81  	// Factory defines an interface for managing states
    82  	Factory interface {
    83  		lifecycle.StartStopper
    84  		protocol.StateReader
    85  		Register(protocol.Protocol) error
    86  		Validate(context.Context, *block.Block) error
    87  		// NewBlockBuilder creates block builder
    88  		NewBlockBuilder(context.Context, actpool.ActPool, func(action.Envelope) (*action.SealedEnvelope, error)) (*block.Builder, error)
    89  		SimulateExecution(context.Context, address.Address, *action.Execution) ([]byte, *action.Receipt, error)
    90  		ReadContractStorage(context.Context, address.Address, []byte) ([]byte, error)
    91  		PutBlock(context.Context, *block.Block) error
    92  		DeleteTipBlock(context.Context, *block.Block) error
    93  		StateAtHeight(uint64, interface{}, ...protocol.StateOption) error
    94  		StatesAtHeight(uint64, ...protocol.StateOption) (state.Iterator, error)
    95  	}
    96  
    97  	// factory implements StateFactory interface, tracks changes to account/contract and batch-commits to DB
    98  	factory struct {
    99  		lifecycle                lifecycle.Lifecycle
   100  		mutex                    sync.RWMutex
   101  		cfg                      Config
   102  		registry                 *protocol.Registry
   103  		currentChainHeight       uint64
   104  		saveHistory              bool
   105  		twoLayerTrie             trie.TwoLayerTrie // global state trie, this is a read only trie
   106  		dao                      db.KVStore        // the underlying DB for account/contract storage
   107  		timerFactory             *prometheustimer.TimerFactory
   108  		workingsets              cache.LRUCache // lru cache for workingsets
   109  		protocolView             protocol.View
   110  		skipBlockValidationOnPut bool
   111  		ps                       *patchStore
   112  	}
   113  
   114  	// Config contains the config for factory
   115  	Config struct {
   116  		Chain   blockchain.Config
   117  		Genesis genesis.Genesis
   118  	}
   119  )
   120  
   121  // GenerateConfig generates the factory config
   122  func GenerateConfig(chain blockchain.Config, g genesis.Genesis) Config {
   123  	return Config{
   124  		Chain:   chain,
   125  		Genesis: g,
   126  	}
   127  }
   128  
   129  // Option sets Factory construction parameter
   130  type Option func(*factory, *Config) error
   131  
   132  // RegistryOption sets the registry in state db
   133  func RegistryOption(reg *protocol.Registry) Option {
   134  	return func(sf *factory, cfg *Config) error {
   135  		sf.registry = reg
   136  		return nil
   137  	}
   138  }
   139  
   140  // SkipBlockValidationOption skips block validation on PutBlock
   141  func SkipBlockValidationOption() Option {
   142  	return func(sf *factory, cfg *Config) error {
   143  		sf.skipBlockValidationOnPut = true
   144  		return nil
   145  	}
   146  }
   147  
   148  // DefaultTriePatchOption loads patchs
   149  func DefaultTriePatchOption() Option {
   150  	return func(sf *factory, cfg *Config) (err error) {
   151  		sf.ps, err = newPatchStore(cfg.Chain.TrieDBPatchFile)
   152  		return
   153  	}
   154  }
   155  
   156  // NewFactory creates a new state factory
   157  func NewFactory(cfg Config, dao db.KVStore, opts ...Option) (Factory, error) {
   158  	sf := &factory{
   159  		cfg:                cfg,
   160  		currentChainHeight: 0,
   161  		registry:           protocol.NewRegistry(),
   162  		saveHistory:        cfg.Chain.EnableArchiveMode,
   163  		protocolView:       protocol.View{},
   164  		workingsets:        cache.NewThreadSafeLruCache(int(cfg.Chain.WorkingSetCacheSize)),
   165  		dao:                dao,
   166  	}
   167  
   168  	for _, opt := range opts {
   169  		if err := opt(sf, &cfg); err != nil {
   170  			log.S().Errorf("Failed to execute state factory creation option %p: %v", opt, err)
   171  			return nil, err
   172  		}
   173  	}
   174  	timerFactory, err := prometheustimer.New(
   175  		"iotex_statefactory_perf",
   176  		"Performance of state factory module",
   177  		[]string{"topic", "chainID"},
   178  		[]string{"default", strconv.FormatUint(uint64(cfg.Chain.ID), 10)},
   179  	)
   180  	if err != nil {
   181  		log.L().Error("Failed to generate prometheus timer factory.", zap.Error(err))
   182  	}
   183  	sf.timerFactory = timerFactory
   184  
   185  	return sf, nil
   186  }
   187  
   188  func (sf *factory) Start(ctx context.Context) error {
   189  	ctx = protocol.WithRegistry(ctx, sf.registry)
   190  	err := sf.dao.Start(ctx)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	if sf.twoLayerTrie, err = newTwoLayerTrie(ArchiveTrieNamespace, sf.dao, ArchiveTrieRootKey, true); err != nil {
   195  		return errors.Wrap(err, "failed to generate accountTrie from config")
   196  	}
   197  	if err := sf.twoLayerTrie.Start(ctx); err != nil {
   198  		return err
   199  	}
   200  	// check factory height
   201  	h, err := sf.dao.Get(AccountKVNamespace, []byte(CurrentHeightKey))
   202  	switch errors.Cause(err) {
   203  	case nil:
   204  		sf.currentChainHeight = byteutil.BytesToUint64(h)
   205  		// start all protocols
   206  		if sf.protocolView, err = sf.registry.StartAll(ctx, sf); err != nil {
   207  			return err
   208  		}
   209  	case db.ErrNotExist:
   210  		if err = sf.dao.Put(AccountKVNamespace, []byte(CurrentHeightKey), byteutil.Uint64ToBytes(0)); err != nil {
   211  			return errors.Wrap(err, "failed to init factory's height")
   212  		}
   213  		// start all protocols
   214  		if sf.protocolView, err = sf.registry.StartAll(ctx, sf); err != nil {
   215  			return err
   216  		}
   217  		ctx = protocol.WithBlockCtx(
   218  			ctx,
   219  			protocol.BlockCtx{
   220  				BlockHeight:    0,
   221  				BlockTimeStamp: time.Unix(sf.cfg.Genesis.Timestamp, 0),
   222  				Producer:       sf.cfg.Chain.ProducerAddress(),
   223  				GasLimit:       sf.cfg.Genesis.BlockGasLimitByHeight(0),
   224  			})
   225  		ctx = protocol.WithFeatureCtx(ctx)
   226  		// init the state factory
   227  		if err := sf.createGenesisStates(ctx); err != nil {
   228  			return errors.Wrap(err, "failed to create genesis states")
   229  		}
   230  	default:
   231  		return err
   232  	}
   233  	return sf.lifecycle.OnStart(ctx)
   234  }
   235  
   236  func (sf *factory) Stop(ctx context.Context) error {
   237  	sf.mutex.Lock()
   238  	defer sf.mutex.Unlock()
   239  	if err := sf.dao.Stop(ctx); err != nil {
   240  		return err
   241  	}
   242  	sf.workingsets.Clear()
   243  	return sf.lifecycle.OnStop(ctx)
   244  }
   245  
   246  // Height returns factory's height
   247  func (sf *factory) Height() (uint64, error) {
   248  	sf.mutex.RLock()
   249  	defer sf.mutex.RUnlock()
   250  	height, err := sf.dao.Get(AccountKVNamespace, []byte(CurrentHeightKey))
   251  	if err != nil {
   252  		return 0, errors.Wrap(err, "failed to get factory's height from underlying DB")
   253  	}
   254  	return byteutil.BytesToUint64(height), nil
   255  }
   256  
   257  func (sf *factory) newWorkingSet(ctx context.Context, height uint64) (*workingSet, error) {
   258  	span := tracer.SpanFromContext(ctx)
   259  	span.AddEvent("factory.newWorkingSet")
   260  	defer span.End()
   261  
   262  	g := genesis.MustExtractGenesisContext(ctx)
   263  	flusher, err := db.NewKVStoreFlusher(
   264  		sf.dao,
   265  		batch.NewCachedBatch(),
   266  		sf.flusherOptions(!g.IsEaster(height))...,
   267  	)
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  	store, err := newFactoryWorkingSetStore(sf.protocolView, flusher)
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  	if err := store.Start(ctx); err != nil {
   276  		return nil, err
   277  	}
   278  	for _, p := range sf.ps.Get(height) {
   279  		if p.Type == _Delete {
   280  			if err := store.Delete(p.Namespace, p.Key); err != nil {
   281  				return nil, err
   282  			}
   283  		} else {
   284  			if err := store.Put(p.Namespace, p.Key, p.Value); err != nil {
   285  				return nil, err
   286  			}
   287  		}
   288  	}
   289  
   290  	return newWorkingSet(height, store), nil
   291  }
   292  
   293  func (sf *factory) flusherOptions(preEaster bool) []db.KVStoreFlusherOption {
   294  	opts := []db.KVStoreFlusherOption{
   295  		db.SerializeFilterOption(func(wi *batch.WriteInfo) bool {
   296  			if wi.Namespace() == ArchiveTrieNamespace {
   297  				return true
   298  			}
   299  			if wi.Namespace() != evm.CodeKVNameSpace && wi.Namespace() != staking.CandsMapNS {
   300  				return false
   301  			}
   302  			return preEaster
   303  		}),
   304  		db.SerializeOption(func(wi *batch.WriteInfo) []byte {
   305  			if preEaster {
   306  				return wi.SerializeWithoutWriteType()
   307  			}
   308  			return wi.Serialize()
   309  		}),
   310  	}
   311  	if sf.saveHistory {
   312  		opts = append(opts, db.FlushTranslateOption(func(wi *batch.WriteInfo) *batch.WriteInfo {
   313  			if wi.WriteType() == batch.Delete && wi.Namespace() == ArchiveTrieNamespace {
   314  				return nil
   315  			}
   316  			return wi
   317  		}))
   318  	}
   319  
   320  	return opts
   321  }
   322  
   323  func (sf *factory) Register(p protocol.Protocol) error {
   324  	return p.Register(sf.registry)
   325  }
   326  
   327  func (sf *factory) Validate(ctx context.Context, blk *block.Block) error {
   328  	ctx = protocol.WithRegistry(ctx, sf.registry)
   329  	key := generateWorkingSetCacheKey(blk.Header, blk.Header.ProducerAddress())
   330  	ws, isExist, err := sf.getFromWorkingSets(ctx, key)
   331  	if err != nil {
   332  		return err
   333  	}
   334  	if !isExist {
   335  		if err := ws.ValidateBlock(ctx, blk); err != nil {
   336  			return errors.Wrap(err, "failed to validate block with workingset in factory")
   337  		}
   338  		sf.putIntoWorkingSets(key, ws)
   339  	}
   340  	receipts, err := ws.Receipts()
   341  	if err != nil {
   342  		return err
   343  	}
   344  	blk.Receipts = receipts
   345  	return nil
   346  }
   347  
   348  // NewBlockBuilder returns block builder which hasn't been signed yet
   349  func (sf *factory) NewBlockBuilder(
   350  	ctx context.Context,
   351  	ap actpool.ActPool,
   352  	sign func(action.Envelope) (*action.SealedEnvelope, error),
   353  ) (*block.Builder, error) {
   354  	sf.mutex.Lock()
   355  	ctx = protocol.WithRegistry(ctx, sf.registry)
   356  	ws, err := sf.newWorkingSet(ctx, sf.currentChainHeight+1)
   357  	sf.mutex.Unlock()
   358  	if err != nil {
   359  		return nil, errors.Wrap(err, "Failed to obtain working set from state factory")
   360  	}
   361  	postSystemActions := make([]*action.SealedEnvelope, 0)
   362  	unsignedSystemActions, err := ws.generateSystemActions(ctx)
   363  	if err != nil {
   364  		return nil, err
   365  	}
   366  	for _, elp := range unsignedSystemActions {
   367  		se, err := sign(elp)
   368  		if err != nil {
   369  			return nil, err
   370  		}
   371  		postSystemActions = append(postSystemActions, se)
   372  	}
   373  	blkBuilder, err := ws.CreateBuilder(ctx, ap, postSystemActions, sf.cfg.Chain.AllowedBlockGasResidue)
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  
   378  	blkCtx := protocol.MustGetBlockCtx(ctx)
   379  	key := generateWorkingSetCacheKey(blkBuilder.GetCurrentBlockHeader(), blkCtx.Producer.String())
   380  	sf.putIntoWorkingSets(key, ws)
   381  	return blkBuilder, nil
   382  }
   383  
   384  // SimulateExecution simulates a running of smart contract operation, this is done off the network since it does not
   385  // cause any state change
   386  func (sf *factory) SimulateExecution(
   387  	ctx context.Context,
   388  	caller address.Address,
   389  	ex *action.Execution,
   390  ) ([]byte, *action.Receipt, error) {
   391  	ctx, span := tracer.NewSpan(ctx, "factory.SimulateExecution")
   392  	defer span.End()
   393  
   394  	sf.mutex.Lock()
   395  	ws, err := sf.newWorkingSet(ctx, sf.currentChainHeight+1)
   396  	sf.mutex.Unlock()
   397  	if err != nil {
   398  		return nil, nil, errors.Wrap(err, "failed to obtain working set from state factory")
   399  	}
   400  
   401  	return evm.SimulateExecution(ctx, ws, caller, ex)
   402  }
   403  
   404  // ReadContractStorage reads contract's storage
   405  func (sf *factory) ReadContractStorage(ctx context.Context, contract address.Address, key []byte) ([]byte, error) {
   406  	sf.mutex.Lock()
   407  	ws, err := sf.newWorkingSet(ctx, sf.currentChainHeight+1)
   408  	sf.mutex.Unlock()
   409  	if err != nil {
   410  		return nil, errors.Wrap(err, "failed to generate working set from state factory")
   411  	}
   412  	return evm.ReadContractStorage(ctx, ws, contract, key)
   413  }
   414  
   415  // PutBlock persists all changes in RunActions() into the DB
   416  func (sf *factory) PutBlock(ctx context.Context, blk *block.Block) error {
   417  	sf.mutex.Lock()
   418  	timer := sf.timerFactory.NewTimer("Commit")
   419  	sf.mutex.Unlock()
   420  	defer timer.End()
   421  	producer := blk.PublicKey().Address()
   422  	if producer == nil {
   423  		return errors.New("failed to get address")
   424  	}
   425  	g := genesis.MustExtractGenesisContext(ctx)
   426  	ctx = protocol.WithBlockCtx(
   427  		protocol.WithRegistry(ctx, sf.registry),
   428  		protocol.BlockCtx{
   429  			BlockHeight:    blk.Height(),
   430  			BlockTimeStamp: blk.Timestamp(),
   431  			GasLimit:       g.BlockGasLimitByHeight(blk.Height()),
   432  			Producer:       producer,
   433  		},
   434  	)
   435  	ctx = protocol.WithFeatureCtx(ctx)
   436  	key := generateWorkingSetCacheKey(blk.Header, blk.Header.ProducerAddress())
   437  	ws, isExist, err := sf.getFromWorkingSets(ctx, key)
   438  	if err != nil {
   439  		return err
   440  	}
   441  	if !isExist {
   442  		// regenerate workingset
   443  		if !sf.skipBlockValidationOnPut {
   444  			err = ws.ValidateBlock(ctx, blk)
   445  		} else {
   446  			err = ws.Process(ctx, blk.RunnableActions().Actions())
   447  		}
   448  		if err != nil {
   449  			log.L().Error("Failed to update state.", zap.Error(err))
   450  			return err
   451  		}
   452  	}
   453  	sf.mutex.Lock()
   454  	defer sf.mutex.Unlock()
   455  	receipts, err := ws.Receipts()
   456  	if err != nil {
   457  		return err
   458  	}
   459  	blk.Receipts = receipts
   460  	h, _ := ws.Height()
   461  	if sf.currentChainHeight+1 != h {
   462  		// another working set with correct version already committed, do nothing
   463  		return fmt.Errorf(
   464  			"current state height %d + 1 doesn't match working set height %d",
   465  			sf.currentChainHeight, h,
   466  		)
   467  	}
   468  
   469  	if err := ws.Commit(ctx); err != nil {
   470  		return err
   471  	}
   472  	rh, err := sf.dao.Get(ArchiveTrieNamespace, []byte(ArchiveTrieRootKey))
   473  	if err != nil {
   474  		return err
   475  	}
   476  	if err := sf.twoLayerTrie.SetRootHash(rh); err != nil {
   477  		return err
   478  	}
   479  	sf.currentChainHeight = h
   480  
   481  	return nil
   482  }
   483  
   484  func (sf *factory) DeleteTipBlock(_ context.Context, _ *block.Block) error {
   485  	return errors.Wrap(ErrNotSupported, "cannot delete tip block from factory")
   486  }
   487  
   488  // StateAtHeight returns a confirmed state at height -- archive mode
   489  func (sf *factory) StateAtHeight(height uint64, s interface{}, opts ...protocol.StateOption) error {
   490  	sf.mutex.RLock()
   491  	defer sf.mutex.RUnlock()
   492  	cfg, err := processOptions(opts...)
   493  	if err != nil {
   494  		return err
   495  	}
   496  	if cfg.Keys != nil {
   497  		return errors.Wrap(ErrNotSupported, "Read state with keys option has not been implemented yet")
   498  	}
   499  	if height > sf.currentChainHeight {
   500  		return errors.Errorf("query height %d is higher than tip height %d", height, sf.currentChainHeight)
   501  	}
   502  	return sf.stateAtHeight(height, cfg.Namespace, cfg.Key, s)
   503  }
   504  
   505  // StatesAtHeight returns a set states in the state factory at height -- archive mode
   506  func (sf *factory) StatesAtHeight(height uint64, opts ...protocol.StateOption) (state.Iterator, error) {
   507  	sf.mutex.RLock()
   508  	defer sf.mutex.RUnlock()
   509  	if height > sf.currentChainHeight {
   510  		return nil, errors.Errorf("query height %d is higher than tip height %d", height, sf.currentChainHeight)
   511  	}
   512  	return nil, errors.Wrap(ErrNotSupported, "Read historical states has not been implemented yet")
   513  }
   514  
   515  // State returns a confirmed state in the state factory
   516  func (sf *factory) State(s interface{}, opts ...protocol.StateOption) (uint64, error) {
   517  	sf.mutex.RLock()
   518  	defer sf.mutex.RUnlock()
   519  	cfg, err := processOptions(opts...)
   520  	if err != nil {
   521  		return 0, err
   522  	}
   523  	if cfg.Keys != nil {
   524  		return 0, errors.Wrap(ErrNotSupported, "Read state with keys option has not been implemented yet")
   525  	}
   526  	value, err := sf.dao.Get(cfg.Namespace, cfg.Key)
   527  	if err != nil {
   528  		if errors.Cause(err) == db.ErrNotExist {
   529  			return sf.currentChainHeight, errors.Wrapf(state.ErrStateNotExist, "failed to get state of ns = %x and key = %x", cfg.Namespace, cfg.Key)
   530  		}
   531  		return sf.currentChainHeight, err
   532  	}
   533  
   534  	return sf.currentChainHeight, state.Deserialize(s, value)
   535  }
   536  
   537  // State returns a set states in the state factory
   538  func (sf *factory) States(opts ...protocol.StateOption) (uint64, state.Iterator, error) {
   539  	sf.mutex.RLock()
   540  	defer sf.mutex.RUnlock()
   541  	cfg, err := processOptions(opts...)
   542  	if err != nil {
   543  		return 0, nil, err
   544  	}
   545  	if cfg.Key != nil {
   546  		return sf.currentChainHeight, nil, errors.Wrap(ErrNotSupported, "Read states with key option has not been implemented yet")
   547  	}
   548  	values, err := readStates(sf.dao, cfg.Namespace, cfg.Keys)
   549  	if err != nil {
   550  		return 0, nil, err
   551  	}
   552  
   553  	return sf.currentChainHeight, state.NewIterator(values), nil
   554  }
   555  
   556  // ReadView reads the view
   557  func (sf *factory) ReadView(name string) (interface{}, error) {
   558  	return sf.protocolView.Read(name)
   559  }
   560  
   561  //======================================
   562  // private trie constructor functions
   563  //======================================
   564  
   565  func (sf *factory) rootHash() ([]byte, error) {
   566  	return sf.twoLayerTrie.RootHash()
   567  }
   568  
   569  func namespaceKey(ns string) []byte {
   570  	h := hash.Hash160b([]byte(ns))
   571  	return h[:]
   572  }
   573  
   574  func readState(tlt trie.TwoLayerTrie, ns string, key []byte) ([]byte, error) {
   575  	ltKey := toLegacyKey(key)
   576  	data, err := tlt.Get(namespaceKey(ns), ltKey)
   577  	if err != nil {
   578  		if errors.Cause(err) == trie.ErrNotExist {
   579  			return nil, errors.Wrapf(state.ErrStateNotExist, "failed to get state of ns = %x and key = %x", ns, key)
   580  		}
   581  		return nil, err
   582  	}
   583  
   584  	return data, nil
   585  }
   586  
   587  func toLegacyKey(input []byte) []byte {
   588  	key := hash.Hash160b(input)
   589  	return key[:]
   590  }
   591  
   592  func legacyKeyLen() int {
   593  	return 20
   594  }
   595  
   596  func (sf *factory) stateAtHeight(height uint64, ns string, key []byte, s interface{}) error {
   597  	if !sf.saveHistory {
   598  		return ErrNoArchiveData
   599  	}
   600  	tlt, err := newTwoLayerTrie(ArchiveTrieNamespace, sf.dao, fmt.Sprintf("%s-%d", ArchiveTrieRootKey, height), false)
   601  	if err != nil {
   602  		return errors.Wrapf(err, "failed to generate trie for %d", height)
   603  	}
   604  	if err := tlt.Start(context.Background()); err != nil {
   605  		return err
   606  	}
   607  	defer tlt.Stop(context.Background())
   608  
   609  	value, err := readState(tlt, ns, key)
   610  	if err != nil {
   611  		return err
   612  	}
   613  	return state.Deserialize(s, value)
   614  }
   615  
   616  func (sf *factory) createGenesisStates(ctx context.Context) error {
   617  	ws, err := sf.newWorkingSet(ctx, 0)
   618  	if err != nil {
   619  		return errors.Wrap(err, "failed to obtain working set from state factory")
   620  	}
   621  	// add Genesis states
   622  	if err := ws.CreateGenesisStates(ctx); err != nil {
   623  		return err
   624  	}
   625  
   626  	return ws.Commit(ctx)
   627  }
   628  
   629  // getFromWorkingSets returns (workingset, true) if it exists in a cache, otherwise generates new workingset and return (ws, false)
   630  func (sf *factory) getFromWorkingSets(ctx context.Context, key hash.Hash256) (*workingSet, bool, error) {
   631  	sf.mutex.RLock()
   632  	defer sf.mutex.RUnlock()
   633  	if data, ok := sf.workingsets.Get(key); ok {
   634  		if ws, ok := data.(*workingSet); ok {
   635  			// if it is already validated, return workingset
   636  			return ws, true, nil
   637  		}
   638  		return nil, false, errors.New("type assertion failed to be WorkingSet")
   639  	}
   640  	ws, err := sf.newWorkingSet(ctx, sf.currentChainHeight+1)
   641  	if err != nil {
   642  		return nil, false, errors.Wrap(err, "failed to obtain working set from state factory")
   643  	}
   644  	return ws, false, nil
   645  }
   646  
   647  func (sf *factory) putIntoWorkingSets(key hash.Hash256, ws *workingSet) {
   648  	sf.mutex.Lock()
   649  	defer sf.mutex.Unlock()
   650  	sf.workingsets.Add(key, ws)
   651  }