github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/params/types/upgrade_cache.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/prefix"
     9  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    10  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    11  )
    12  
    13  var (
    14  	upgradeInfoPreifx = []byte("upgrade")
    15  	readyPrefix       = []byte("readyUpgrade")
    16  )
    17  
    18  type UpgradeCache struct {
    19  	storeKey *sdk.KVStoreKey
    20  	logger   log.Logger
    21  	cdc      *codec.Codec
    22  
    23  	readyLock        sync.Mutex
    24  	upgradeReadyMap  map[string][]func(UpgradeInfo)
    25  	infoLock         sync.Mutex
    26  	upgradeInfoCache map[string]UpgradeInfo
    27  }
    28  
    29  func NewUpgreadeCache(storeKey *sdk.KVStoreKey, logger log.Logger, cdc *codec.Codec) *UpgradeCache {
    30  	return &UpgradeCache{
    31  		storeKey: storeKey,
    32  		logger:   logger,
    33  		cdc:      cdc,
    34  
    35  		upgradeReadyMap:  make(map[string][]func(UpgradeInfo)),
    36  		upgradeInfoCache: make(map[string]UpgradeInfo),
    37  	}
    38  }
    39  
    40  func (uc *UpgradeCache) ReadUpgradeInfo(ctx sdk.Context, name string) (UpgradeInfo, error) {
    41  	if ctx.UseParamCache() {
    42  		info, exist := uc.readUpgradeInfo(name)
    43  		if exist {
    44  			return info, nil
    45  		}
    46  	}
    47  
    48  	info, err := readUpgradeInfoFromStore(ctx, name, uc.storeKey, uc.cdc)
    49  	if err != nil {
    50  		return info, err
    51  	}
    52  
    53  	uc.writeUpgradeInfo(info)
    54  	return info, nil
    55  }
    56  
    57  func (uc *UpgradeCache) ClaimReadyForUpgrade(name string, cb func(UpgradeInfo)) {
    58  	uc.writeClaim(name, cb)
    59  }
    60  
    61  func (uc *UpgradeCache) QueryReadyForUpgrade(name string) ([]func(UpgradeInfo), bool) {
    62  	return uc.readClaim(name)
    63  }
    64  
    65  func (uc *UpgradeCache) WriteUpgradeInfo(ctx sdk.Context, info UpgradeInfo, forceCover bool) sdk.Error {
    66  	if err := writeUpgradeInfoToStore(ctx, info, forceCover, uc.storeKey, uc.cdc, uc.logger); err != nil {
    67  		return err
    68  	}
    69  
    70  	// store is updated, remove the info from cache so
    71  	// makeing ReadUpgradeInfo to re-read from store.
    72  	uc.removeUpgradeInfo(info.Name)
    73  	return nil
    74  }
    75  
    76  func (uc *UpgradeCache) IsUpgradeExist(ctx sdk.Context, name string) bool {
    77  	store := getUpgradeStore(ctx, uc.storeKey)
    78  	return store.Has([]byte(name))
    79  }
    80  
    81  func (uc *UpgradeCache) IterateAllUpgradeInfo(ctx sdk.Context, cb func(info UpgradeInfo) (stop bool)) sdk.Error {
    82  	store := getUpgradeStore(ctx, uc.storeKey)
    83  	iterator := store.Iterator(nil, nil)
    84  	defer iterator.Close()
    85  
    86  	for ; iterator.Valid(); iterator.Next() {
    87  		data := iterator.Value()
    88  
    89  		var info UpgradeInfo
    90  		uc.cdc.MustUnmarshalJSON(data, &info)
    91  
    92  		if stop := cb(info); stop {
    93  			break
    94  		}
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func (uc *UpgradeCache) readUpgradeInfo(name string) (UpgradeInfo, bool) {
   101  	uc.infoLock.Lock()
   102  	defer uc.infoLock.Unlock()
   103  
   104  	info, ok := uc.upgradeInfoCache[name]
   105  	return info, ok
   106  }
   107  
   108  func (uc *UpgradeCache) removeUpgradeInfo(name string) {
   109  	uc.infoLock.Lock()
   110  	defer uc.infoLock.Unlock()
   111  
   112  	delete(uc.upgradeInfoCache, name)
   113  }
   114  
   115  func (uc *UpgradeCache) writeUpgradeInfo(info UpgradeInfo) {
   116  	uc.infoLock.Lock()
   117  	defer uc.infoLock.Unlock()
   118  
   119  	uc.upgradeInfoCache[info.Name] = info
   120  }
   121  
   122  func (uc *UpgradeCache) readClaim(name string) ([]func(UpgradeInfo), bool) {
   123  	uc.readyLock.Lock()
   124  	defer uc.readyLock.Unlock()
   125  
   126  	cb, ok := uc.upgradeReadyMap[name]
   127  	return cb, ok
   128  }
   129  
   130  func (uc *UpgradeCache) writeClaim(name string, cb func(UpgradeInfo)) {
   131  	uc.readyLock.Lock()
   132  	defer uc.readyLock.Unlock()
   133  
   134  	readies, ok := uc.upgradeReadyMap[name]
   135  	if !ok {
   136  		uc.upgradeReadyMap[name] = []func(UpgradeInfo){cb}
   137  	} else {
   138  		uc.upgradeReadyMap[name] = append(readies, cb)
   139  	}
   140  }
   141  
   142  func readUpgradeInfoFromStore(ctx sdk.Context, name string, skey *sdk.KVStoreKey, cdc *codec.Codec) (UpgradeInfo, sdk.Error) {
   143  	store := getUpgradeStore(ctx, skey)
   144  
   145  	data := store.Get([]byte(name))
   146  	if len(data) == 0 {
   147  		err := fmt.Errorf("upgrade '%s' is not exist", name)
   148  		return UpgradeInfo{}, err
   149  	}
   150  
   151  	var info UpgradeInfo
   152  	cdc.MustUnmarshalJSON(data, &info)
   153  	return info, nil
   154  }
   155  
   156  func writeUpgradeInfoToStore(ctx sdk.Context, info UpgradeInfo, forceCover bool, skey *sdk.KVStoreKey, cdc *codec.Codec, logger log.Logger) sdk.Error {
   157  	key := []byte(info.Name)
   158  
   159  	store := getUpgradeStore(ctx, skey)
   160  	if !forceCover && store.Has(key) {
   161  		logger.Error("upgrade proposal name has been exist", "proposal name", info.Name)
   162  		return sdk.ErrInternal(fmt.Sprintf("upgrade proposal name '%s' has been exist", info.Name))
   163  	}
   164  
   165  	data := cdc.MustMarshalJSON(info)
   166  	store.Set(key, data)
   167  
   168  	return nil
   169  }
   170  
   171  func getUpgradeStore(ctx sdk.Context, skey *sdk.KVStoreKey) sdk.KVStore {
   172  	return prefix.NewStore(ctx.KVStore(skey), upgradeInfoPreifx)
   173  }
   174  
   175  func readReadyFromStore(ctx sdk.Context, name string, skey *sdk.KVStoreKey) ([]byte, bool) {
   176  	store := getReadyStore(ctx, skey)
   177  	data := store.Get([]byte(name))
   178  	return data, len(data) != 0
   179  }
   180  
   181  func writeReadyToStore(ctx sdk.Context, name string, skey *sdk.KVStoreKey) {
   182  	store := getReadyStore(ctx, skey)
   183  	store.Set([]byte(name), []byte(name))
   184  }
   185  
   186  func getReadyStore(ctx sdk.Context, skey *sdk.KVStoreKey) sdk.KVStore {
   187  	return prefix.NewStore(ctx.KVStore(skey), readyPrefix)
   188  }