github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/chains_info.go (about)

     1  package core
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math/big"
     7  	"os"
     8  	"strings"
     9  	"sync"
    10  
    11  	ep "github.com/neatlab/neatio/chain/consensus/neatcon/epoch"
    12  	"github.com/neatlab/neatio/chain/core/state"
    13  	"github.com/neatlab/neatio/chain/log"
    14  	"github.com/neatlab/neatio/utilities/common"
    15  	"github.com/neatlab/neatio/utilities/common/math"
    16  	"github.com/neatlib/crypto-go"
    17  	dbm "github.com/neatlib/db-go"
    18  	"github.com/neatlib/wire-go"
    19  )
    20  
    21  const (
    22  	OFFICIAL_MINIMUM_VALIDATORS = 1
    23  	OFFICIAL_MINIMUM_DEPOSIT    = "50000000000000000000000"
    24  )
    25  
    26  type CoreChainInfo struct {
    27  	db dbm.DB
    28  
    29  	Owner   common.Address
    30  	ChainId string
    31  
    32  	MinValidators    uint16
    33  	MinDepositAmount *big.Int
    34  	StartBlock       *big.Int
    35  	EndBlock         *big.Int
    36  
    37  	JoinedValidators []JoinedValidator
    38  
    39  	EpochNumber uint64
    40  
    41  	DepositInMainChain    *big.Int
    42  	DepositInSideChain    *big.Int
    43  	WithdrawFromSideChain *big.Int
    44  	WithdrawFromMainChain *big.Int
    45  }
    46  
    47  type JoinedValidator struct {
    48  	PubKey        crypto.PubKey
    49  	Address       common.Address
    50  	DepositAmount *big.Int
    51  }
    52  
    53  type ChainInfo struct {
    54  	CoreChainInfo
    55  
    56  	Epoch *ep.Epoch
    57  }
    58  
    59  const (
    60  	chainInfoKey  = "CHAIN"
    61  	ethGenesisKey = "ETH_GENESIS"
    62  	ntcGenesisKey = "NTC_GENESIS"
    63  )
    64  
    65  var allChainKey = []byte("AllChainID")
    66  
    67  const specialSep = ";"
    68  
    69  var mtx sync.RWMutex
    70  
    71  func calcCoreChainInfoKey(chainId string) []byte {
    72  	return []byte(chainInfoKey + ":" + chainId)
    73  }
    74  
    75  func calcEpochKey(number uint64, chainId string) []byte {
    76  	return []byte(chainInfoKey + fmt.Sprintf("-%v-%s", number, chainId))
    77  }
    78  
    79  func calcETHGenesisKey(chainId string) []byte {
    80  	return []byte(ethGenesisKey + ":" + chainId)
    81  }
    82  
    83  func calcNTCGenesisKey(chainId string) []byte {
    84  	return []byte(ntcGenesisKey + ":" + chainId)
    85  }
    86  
    87  func GetChainInfo(db dbm.DB, chainId string) *ChainInfo {
    88  	mtx.RLock()
    89  	defer mtx.RUnlock()
    90  
    91  	cci := loadCoreChainInfo(db, chainId)
    92  	if cci == nil {
    93  		return nil
    94  	}
    95  
    96  	ci := &ChainInfo{
    97  		CoreChainInfo: *cci,
    98  	}
    99  
   100  	epoch := loadEpoch(db, cci.EpochNumber, chainId)
   101  	if epoch != nil {
   102  		ci.Epoch = epoch
   103  	}
   104  
   105  	log.Debugf("LoadChainInfo(), chainInfo is: %v\n", ci)
   106  
   107  	return ci
   108  }
   109  
   110  func SaveChainInfo(db dbm.DB, ci *ChainInfo) error {
   111  	mtx.Lock()
   112  	defer mtx.Unlock()
   113  
   114  	log.Debugf("ChainInfo Save(), info is: (%v)\n", ci)
   115  
   116  	err := saveCoreChainInfo(db, &ci.CoreChainInfo)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	if ci.Epoch != nil {
   122  		err = saveEpoch(db, ci.Epoch, ci.ChainId)
   123  		if err != nil {
   124  			return err
   125  		}
   126  	}
   127  
   128  	saveId(db, ci.ChainId)
   129  
   130  	return nil
   131  }
   132  
   133  func SaveFutureEpoch(db dbm.DB, futureEpoch *ep.Epoch, chainId string) error {
   134  	mtx.Lock()
   135  	defer mtx.Unlock()
   136  
   137  	if futureEpoch != nil {
   138  		err := saveEpoch(db, futureEpoch, chainId)
   139  		if err != nil {
   140  			return err
   141  		}
   142  	}
   143  	return nil
   144  }
   145  
   146  func loadCoreChainInfo(db dbm.DB, chainId string) *CoreChainInfo {
   147  
   148  	cci := CoreChainInfo{db: db}
   149  	buf := db.Get(calcCoreChainInfoKey(chainId))
   150  	if len(buf) == 0 {
   151  		return nil
   152  	} else {
   153  		r, n, err := bytes.NewReader(buf), new(int), new(error)
   154  		wire.ReadBinaryPtr(&cci, r, 0, n, err)
   155  		if *err != nil {
   156  
   157  			log.Debugf("LoadChainInfo: Data has been corrupted or its spec has changed: %v", *err)
   158  			os.Exit(1)
   159  		}
   160  	}
   161  	return &cci
   162  }
   163  
   164  func saveCoreChainInfo(db dbm.DB, cci *CoreChainInfo) error {
   165  
   166  	db.SetSync(calcCoreChainInfoKey(cci.ChainId), wire.BinaryBytes(*cci))
   167  	return nil
   168  }
   169  
   170  func (cci *CoreChainInfo) TotalDeposit() *big.Int {
   171  	sum := big.NewInt(0)
   172  	for _, v := range cci.JoinedValidators {
   173  		sum.Add(sum, v.DepositAmount)
   174  	}
   175  	return sum
   176  }
   177  
   178  func loadEpoch(db dbm.DB, number uint64, chainId string) *ep.Epoch {
   179  	epochBytes := db.Get(calcEpochKey(number, chainId))
   180  	return ep.FromBytes(epochBytes)
   181  }
   182  
   183  func saveEpoch(db dbm.DB, epoch *ep.Epoch, chainId string) error {
   184  
   185  	db.SetSync(calcEpochKey(epoch.Number, chainId), epoch.Bytes())
   186  	return nil
   187  }
   188  
   189  func (ci *ChainInfo) GetEpochByBlockNumber(blockNumber uint64) *ep.Epoch {
   190  	mtx.RLock()
   191  	defer mtx.RUnlock()
   192  
   193  	if blockNumber < 0 {
   194  		return ci.Epoch
   195  	} else {
   196  		epoch := ci.Epoch
   197  		if epoch == nil {
   198  			return nil
   199  		}
   200  		if blockNumber >= epoch.StartBlock && blockNumber <= epoch.EndBlock {
   201  			return epoch
   202  		}
   203  
   204  		if blockNumber > epoch.EndBlock {
   205  			ep := loadEpoch(ci.db, epoch.Number+1, ci.ChainId)
   206  			return ep
   207  		}
   208  
   209  		number := epoch.Number
   210  		for {
   211  			if number == 0 {
   212  				break
   213  			}
   214  			number--
   215  
   216  			ep := loadEpoch(ci.db, number, ci.ChainId)
   217  			if ep == nil {
   218  				return nil
   219  			}
   220  
   221  			if blockNumber >= ep.StartBlock && blockNumber <= ep.EndBlock {
   222  				return ep
   223  			}
   224  		}
   225  	}
   226  	return nil
   227  }
   228  
   229  func saveId(db dbm.DB, chainId string) {
   230  
   231  	buf := db.Get(allChainKey)
   232  
   233  	if len(buf) == 0 {
   234  		db.SetSync(allChainKey, []byte(chainId))
   235  		log.Debugf("ChainInfo SaveId(), chainId is: %s", chainId)
   236  	} else {
   237  
   238  		strIdArr := strings.Split(string(buf), specialSep)
   239  
   240  		found := false
   241  		for _, id := range strIdArr {
   242  			if id == chainId {
   243  				found = true
   244  				break
   245  			}
   246  		}
   247  
   248  		if !found {
   249  			strIdArr = append(strIdArr, chainId)
   250  			strIds := strings.Join(strIdArr, specialSep)
   251  			db.SetSync(allChainKey, []byte(strIds))
   252  
   253  			log.Debugf("ChainInfo SaveId(), strIds is: %s", strIds)
   254  		}
   255  	}
   256  }
   257  
   258  func GetSideChainIds(db dbm.DB) []string {
   259  	mtx.RLock()
   260  	defer mtx.RUnlock()
   261  
   262  	buf := db.Get(allChainKey)
   263  
   264  	log.Debugf("Get side chain IDs, buf is %v, len is %d", buf, len(buf))
   265  
   266  	if len(buf) == 0 {
   267  		return []string{}
   268  	}
   269  
   270  	return strings.Split(string(buf), specialSep)
   271  }
   272  
   273  func CheckSideChainRunning(db dbm.DB, chainId string) bool {
   274  	ids := GetSideChainIds(db)
   275  
   276  	for _, id := range ids {
   277  		if id == chainId {
   278  			return true
   279  		}
   280  	}
   281  
   282  	return false
   283  }
   284  
   285  func SaveChainGenesis(db dbm.DB, chainId string, ethGenesis, ntcGenesis []byte) {
   286  	mtx.Lock()
   287  	defer mtx.Unlock()
   288  
   289  	db.SetSync(calcETHGenesisKey(chainId), ethGenesis)
   290  
   291  	db.SetSync(calcNTCGenesisKey(chainId), ntcGenesis)
   292  }
   293  
   294  func LoadChainGenesis(db dbm.DB, chainId string) (ethGenesis, ntcGenesis []byte) {
   295  	mtx.RLock()
   296  	defer mtx.RUnlock()
   297  
   298  	ethGenesis = db.Get(calcETHGenesisKey(chainId))
   299  	ntcGenesis = db.Get(calcNTCGenesisKey(chainId))
   300  	return
   301  }
   302  
   303  var pendingChainMtx sync.Mutex
   304  
   305  var pendingChainIndexKey = []byte("PENDING_CHAIN_IDX")
   306  
   307  func calcPendingChainInfoKey(chainId string) []byte {
   308  	return []byte("PENDING_CHAIN:" + chainId)
   309  }
   310  
   311  type pendingIdxData struct {
   312  	ChainID string
   313  	Start   *big.Int
   314  	End     *big.Int
   315  }
   316  
   317  func GetPendingSideChainData(db dbm.DB, chainId string) *CoreChainInfo {
   318  
   319  	pendingChainByteSlice := db.Get(calcPendingChainInfoKey(chainId))
   320  	if pendingChainByteSlice != nil {
   321  		var cci CoreChainInfo
   322  		wire.ReadBinaryBytes(pendingChainByteSlice, &cci)
   323  		return &cci
   324  	}
   325  
   326  	return nil
   327  }
   328  
   329  func CreatePendingSideChainData(db dbm.DB, cci *CoreChainInfo) {
   330  	storePendingSideChainData(db, cci, true)
   331  }
   332  
   333  func UpdatePendingSideChainData(db dbm.DB, cci *CoreChainInfo) {
   334  	storePendingSideChainData(db, cci, false)
   335  }
   336  
   337  func storePendingSideChainData(db dbm.DB, cci *CoreChainInfo, create bool) {
   338  	pendingChainMtx.Lock()
   339  	defer pendingChainMtx.Unlock()
   340  
   341  	db.SetSync(calcPendingChainInfoKey(cci.ChainId), wire.BinaryBytes(*cci))
   342  
   343  	if create {
   344  
   345  		var idx []pendingIdxData
   346  		pendingIdxByteSlice := db.Get(pendingChainIndexKey)
   347  		if pendingIdxByteSlice != nil {
   348  			wire.ReadBinaryBytes(pendingIdxByteSlice, &idx)
   349  		}
   350  
   351  		for _, v := range idx {
   352  			if v.ChainID == cci.ChainId {
   353  				return
   354  			}
   355  		}
   356  
   357  		idx = append(idx, pendingIdxData{cci.ChainId, cci.StartBlock, cci.EndBlock})
   358  		db.SetSync(pendingChainIndexKey, wire.BinaryBytes(idx))
   359  	}
   360  }
   361  
   362  func DeletePendingSideChainData(db dbm.DB, chainId string) {
   363  	pendingChainMtx.Lock()
   364  	defer pendingChainMtx.Unlock()
   365  
   366  	db.DeleteSync(calcPendingChainInfoKey(chainId))
   367  }
   368  
   369  func GetSideChainForLaunch(db dbm.DB, height *big.Int, stateDB *state.StateDB) (readyForLaunch []string, newPendingIdxBytes []byte, deleteSideChainIds []string) {
   370  	pendingChainMtx.Lock()
   371  	defer pendingChainMtx.Unlock()
   372  
   373  	var idx []pendingIdxData
   374  	pendingIdxByteSlice := db.Get(pendingChainIndexKey)
   375  	if pendingIdxByteSlice != nil {
   376  		wire.ReadBinaryBytes(pendingIdxByteSlice, &idx)
   377  	}
   378  
   379  	if len(idx) == 0 {
   380  		return
   381  	}
   382  
   383  	newPendingIdx := idx[:0]
   384  
   385  	for _, v := range idx {
   386  		if v.Start.Cmp(height) > 0 {
   387  
   388  			newPendingIdx = append(newPendingIdx, v)
   389  		} else if v.End.Cmp(height) < 0 {
   390  
   391  			cci := GetPendingSideChainData(db, v.ChainID)
   392  			for _, jv := range cci.JoinedValidators {
   393  				stateDB.SubSideChainDepositBalance(jv.Address, v.ChainID, jv.DepositAmount)
   394  				stateDB.AddBalance(jv.Address, jv.DepositAmount)
   395  			}
   396  
   397  			officialMinimumDeposit := math.MustParseBig256(OFFICIAL_MINIMUM_DEPOSIT)
   398  			stateDB.AddBalance(cci.Owner, officialMinimumDeposit)
   399  			stateDB.SubChainBalance(cci.Owner, officialMinimumDeposit)
   400  			if stateDB.GetChainBalance(cci.Owner).Sign() != 0 {
   401  				log.Error("the chain balance is not 0 when create chain failed, watch out!!!")
   402  			}
   403  
   404  			deleteSideChainIds = append(deleteSideChainIds, v.ChainID)
   405  
   406  		} else {
   407  
   408  			cci := GetPendingSideChainData(db, v.ChainID)
   409  			if len(cci.JoinedValidators) >= int(cci.MinValidators) && cci.TotalDeposit().Cmp(cci.MinDepositAmount) >= 0 {
   410  
   411  				for _, jv := range cci.JoinedValidators {
   412  
   413  					stateDB.SubSideChainDepositBalance(jv.Address, v.ChainID, jv.DepositAmount)
   414  					stateDB.AddChainBalance(cci.Owner, jv.DepositAmount)
   415  				}
   416  
   417  				readyForLaunch = append(readyForLaunch, v.ChainID)
   418  			} else {
   419  				newPendingIdx = append(newPendingIdx, v)
   420  			}
   421  		}
   422  	}
   423  
   424  	if len(newPendingIdx) != len(idx) {
   425  
   426  		newPendingIdxBytes = wire.BinaryBytes(newPendingIdx)
   427  
   428  	}
   429  
   430  	return
   431  }
   432  
   433  func ProcessPostPendingData(db dbm.DB, newPendingIdxBytes []byte, deleteSideChainIds []string) {
   434  	pendingChainMtx.Lock()
   435  	defer pendingChainMtx.Unlock()
   436  
   437  	for _, id := range deleteSideChainIds {
   438  		db.DeleteSync(calcPendingChainInfoKey(id))
   439  	}
   440  
   441  	if newPendingIdxBytes != nil {
   442  		db.SetSync(pendingChainIndexKey, newPendingIdxBytes)
   443  	}
   444  }