github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/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 "github.com/neatio-net/crypto-go" 12 dbm "github.com/neatio-net/db-go" 13 ep "github.com/neatio-net/neatio/chain/consensus/neatcon/epoch" 14 "github.com/neatio-net/neatio/chain/core/state" 15 "github.com/neatio-net/neatio/chain/log" 16 "github.com/neatio-net/neatio/utilities/common" 17 "github.com/neatio-net/neatio/utilities/common/math" 18 "github.com/neatio-net/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 }