github.com/okex/exchain@v1.8.0/libs/tendermint/state/store.go (about) 1 package state 2 3 import ( 4 "bytes" 5 "fmt" 6 "strings" 7 8 "github.com/tendermint/go-amino" 9 10 abci "github.com/okex/exchain/libs/tendermint/abci/types" 11 tmmath "github.com/okex/exchain/libs/tendermint/libs/math" 12 tmos "github.com/okex/exchain/libs/tendermint/libs/os" 13 "github.com/okex/exchain/libs/tendermint/types" 14 dbm "github.com/okex/exchain/libs/tm-db" 15 "github.com/pkg/errors" 16 ) 17 18 const ( 19 // persist validators every valSetCheckpointInterval blocks to avoid 20 // LoadValidators taking too much time. 21 // https://github.com/tendermint/tendermint/pull/3438 22 // 100000 results in ~ 100ms to get 100 validators (see BenchmarkLoadValidators) 23 valSetCheckpointInterval = 100000 24 ) 25 26 //------------------------------------------------------------------------ 27 28 func calcValidatorsKey(height int64) []byte { 29 return []byte(fmt.Sprintf("validatorsKey:%v", height)) 30 } 31 32 func calcConsensusParamsKey(height int64) []byte { 33 return []byte(fmt.Sprintf("consensusParamsKey:%v", height)) 34 } 35 36 func calcABCIResponsesKey(height int64) []byte { 37 return []byte(fmt.Sprintf("abciResponsesKey:%v", height)) 38 } 39 40 // LoadStateFromDBOrGenesisFile loads the most recent state from the database, 41 // or creates a new one from the given genesisFilePath and persists the result 42 // to the database. 43 func LoadStateFromDBOrGenesisFile(stateDB dbm.DB, genesisFilePath string) (State, error) { 44 state := LoadState(stateDB) 45 if state.IsEmpty() { 46 var err error 47 state, err = MakeGenesisStateFromFile(genesisFilePath) 48 if err != nil { 49 return state, err 50 } 51 SaveState(stateDB, state) 52 } 53 54 return state, nil 55 } 56 57 // LoadStateFromDBOrGenesisDoc loads the most recent state from the database, 58 // or creates a new one from the given genesisDoc and persists the result 59 // to the database. 60 func LoadStateFromDBOrGenesisDoc(stateDB dbm.DB, genesisDoc *types.GenesisDoc) (State, error) { 61 state := LoadState(stateDB) 62 if state.IsEmpty() { 63 var err error 64 state, err = MakeGenesisState(genesisDoc) 65 if err != nil { 66 return state, err 67 } 68 SaveState(stateDB, state) 69 } 70 71 return state, nil 72 } 73 74 // LoadState loads the State from the database. 75 func LoadState(db dbm.DB) State { 76 return loadState(db, stateKey) 77 } 78 79 func loadState(db dbm.DB, key []byte) (state State) { 80 buf, err := db.Get(key) 81 if err != nil { 82 panic(err) 83 } 84 if len(buf) == 0 { 85 return state 86 } 87 88 err = cdc.UnmarshalBinaryBare(buf, &state) 89 if err != nil { 90 // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED 91 tmos.Exit(fmt.Sprintf(`LoadState: Data has been corrupted or its spec has changed: 92 %v\n`, err)) 93 } 94 // TODO: ensure that buf is completely read. 95 96 return state 97 } 98 99 // SaveState persists the State, the ValidatorsInfo, and the ConsensusParamsInfo to the database. 100 // This flushes the writes (e.g. calls SetSync). 101 func SaveState(db dbm.DB, state State) { 102 saveState(db, state, stateKey) 103 } 104 105 func saveState(db dbm.DB, state State, key []byte) { 106 nextHeight := state.LastBlockHeight + 1 107 // If first block, save validators for block 1. 108 if nextHeight == types.GetStartBlockHeight()+1 { 109 // This extra logic due to Tendermint validator set changes being delayed 1 block. 110 // It may get overwritten due to InitChain validator updates. 111 lastHeightVoteChanged := types.GetStartBlockHeight() + 1 112 saveValidatorsInfo(db, nextHeight, lastHeightVoteChanged, state.Validators) 113 } 114 // Save next validators. 115 saveValidatorsInfo(db, nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators) 116 // Save next consensus params. 117 saveConsensusParamsInfo(db, nextHeight, state.LastHeightConsensusParamsChanged, state.ConsensusParams) 118 db.SetSync(key, state.Bytes()) 119 } 120 121 //------------------------------------------------------------------------ 122 123 // ABCIResponses retains the responses 124 // of the various ABCI calls during block processing. 125 // It is persisted to disk for each height before calling Commit. 126 type ABCIResponses struct { 127 DeliverTxs []*abci.ResponseDeliverTx `json:"deliver_txs"` 128 EndBlock *abci.ResponseEndBlock `json:"end_block"` 129 BeginBlock *abci.ResponseBeginBlock `json:"begin_block"` 130 } 131 132 func (arz ABCIResponses) AminoSize(cdc *amino.Codec) int { 133 size := 0 134 for _, tx := range arz.DeliverTxs { 135 txSize := tx.AminoSize(cdc) 136 size += 1 + amino.UvarintSize(uint64(txSize)) + txSize 137 } 138 if arz.EndBlock != nil { 139 endBlockSize := arz.EndBlock.AminoSize(cdc) 140 size += 1 + amino.UvarintSize(uint64(endBlockSize)) + endBlockSize 141 } 142 if arz.BeginBlock != nil { 143 beginBlockSize := arz.BeginBlock.AminoSize(cdc) 144 size += 1 + amino.UvarintSize(uint64(beginBlockSize)) + beginBlockSize 145 } 146 return size 147 } 148 149 func (arz ABCIResponses) MarshalToAmino(cdc *amino.Codec) ([]byte, error) { 150 var buf bytes.Buffer 151 buf.Grow(arz.AminoSize(cdc)) 152 err := arz.MarshalAminoTo(cdc, &buf) 153 if err != nil { 154 return nil, err 155 } 156 return buf.Bytes(), nil 157 } 158 159 func (arz ABCIResponses) MarshalAminoTo(cdc *amino.Codec, buf *bytes.Buffer) error { 160 var err error 161 // field 1 162 for i := 0; i < len(arz.DeliverTxs); i++ { 163 const pbKey = 1<<3 | 2 164 buf.WriteByte(pbKey) 165 txSize := arz.DeliverTxs[i].AminoSize(cdc) 166 err = amino.EncodeUvarintToBuffer(buf, uint64(txSize)) 167 if err != nil { 168 return err 169 } 170 lenBeforeData := buf.Len() 171 err = arz.DeliverTxs[i].MarshalAminoTo(cdc, buf) 172 if err != nil { 173 return err 174 } 175 if buf.Len()-lenBeforeData != txSize { 176 return amino.NewSizerError(arz.DeliverTxs[i], buf.Len()-lenBeforeData, txSize) 177 } 178 } 179 // field 2 180 if arz.EndBlock != nil { 181 const pbKey = 2<<3 | 2 182 buf.WriteByte(pbKey) 183 endBlockSize := arz.EndBlock.AminoSize(cdc) 184 err = amino.EncodeUvarintToBuffer(buf, uint64(endBlockSize)) 185 if err != nil { 186 return err 187 } 188 lenBeforeData := buf.Len() 189 err = arz.EndBlock.MarshalAminoTo(cdc, buf) 190 if err != nil { 191 return err 192 } 193 if buf.Len()-lenBeforeData != endBlockSize { 194 return amino.NewSizerError(arz.EndBlock, buf.Len()-lenBeforeData, endBlockSize) 195 } 196 } 197 // field 3 198 if arz.BeginBlock != nil { 199 const pbKey = 3<<3 | 2 200 buf.WriteByte(pbKey) 201 beginBlockSize := arz.BeginBlock.AminoSize(cdc) 202 err = amino.EncodeUvarintToBuffer(buf, uint64(beginBlockSize)) 203 if err != nil { 204 return err 205 } 206 lenBeforeData := buf.Len() 207 err = arz.BeginBlock.MarshalAminoTo(cdc, buf) 208 if err != nil { 209 return err 210 } 211 if buf.Len()-lenBeforeData != beginBlockSize { 212 return amino.NewSizerError(arz.BeginBlock, buf.Len()-lenBeforeData, beginBlockSize) 213 } 214 } 215 216 return nil 217 } 218 219 // UnmarshalFromAmino unmarshal data from amino bytes. 220 func (arz *ABCIResponses) UnmarshalFromAmino(cdc *amino.Codec, data []byte) error { 221 var dataLen uint64 = 0 222 var subData []byte 223 224 for { 225 data = data[dataLen:] 226 if len(data) == 0 { 227 break 228 } 229 pos, pbType, err := amino.ParseProtoPosAndTypeMustOneByte(data[0]) 230 if err != nil { 231 return err 232 } 233 data = data[1:] 234 235 if pbType == amino.Typ3_ByteLength { 236 var n int 237 dataLen, n, _ = amino.DecodeUvarint(data) 238 239 data = data[n:] 240 if len(data) < int(dataLen) { 241 return errors.New("not enough data") 242 } 243 subData = data[:dataLen] 244 } 245 246 switch pos { 247 case 1: 248 var resDeliverTx *abci.ResponseDeliverTx = nil 249 if len(subData) != 0 { 250 resDeliverTx = &abci.ResponseDeliverTx{} 251 err := resDeliverTx.UnmarshalFromAmino(cdc, subData) 252 if err != nil { 253 return err 254 } 255 } 256 arz.DeliverTxs = append(arz.DeliverTxs, resDeliverTx) 257 258 case 2: 259 eBlock := &abci.ResponseEndBlock{} 260 if len(subData) != 0 { 261 err := eBlock.UnmarshalFromAmino(cdc, subData) 262 if err != nil { 263 return err 264 } 265 } 266 arz.EndBlock = eBlock 267 268 case 3: 269 bBlock := &abci.ResponseBeginBlock{} 270 if len(subData) != 0 { 271 err := bBlock.UnmarshalFromAmino(cdc, subData) 272 if err != nil { 273 return err 274 } 275 } 276 arz.BeginBlock = bBlock 277 278 default: 279 return fmt.Errorf("unexpect feild num %d", pos) 280 } 281 } 282 return nil 283 } 284 285 // PruneStates deletes states between the given heights (including from, excluding to). It is not 286 // guaranteed to delete all states, since the last checkpointed state and states being pointed to by 287 // e.g. `LastHeightChanged` must remain. The state at to must also exist. 288 // 289 // The from parameter is necessary since we can't do a key scan in a performant way due to the key 290 // encoding not preserving ordering: https://github.com/tendermint/tendermint/issues/4567 291 // This will cause some old states to be left behind when doing incremental partial prunes, 292 // specifically older checkpoints and LastHeightChanged targets. 293 func PruneStates(db dbm.DB, from int64, to int64) error { 294 if from <= 0 || to <= 0 { 295 return fmt.Errorf("from height %v and to height %v must be greater than 0", from, to) 296 } 297 if from >= to { 298 return fmt.Errorf("from height %v must be lower than to height %v", from, to) 299 } 300 valInfo := loadValidatorsInfo(db, to) 301 if valInfo == nil { 302 return fmt.Errorf("validators at height %v not found", to) 303 } 304 paramsInfo := loadConsensusParamsInfo(db, to) 305 if paramsInfo == nil { 306 return fmt.Errorf("consensus params at height %v not found", to) 307 } 308 309 keepVals := make(map[int64]bool) 310 if valInfo.ValidatorSet == nil { 311 keepVals[valInfo.LastHeightChanged] = true 312 keepVals[lastStoredHeightFor(to, valInfo.LastHeightChanged)] = true // keep last checkpoint too 313 } 314 keepParams := make(map[int64]bool) 315 if paramsInfo.ConsensusParams.Equals(&types.ConsensusParams{}) { 316 keepParams[paramsInfo.LastHeightChanged] = true 317 } 318 319 batch := db.NewBatch() 320 defer batch.Close() 321 pruned := uint64(0) 322 var err error 323 324 // We have to delete in reverse order, to avoid deleting previous heights that have validator 325 // sets and consensus params that we may need to retrieve. 326 for h := to - 1; h >= from; h-- { 327 // For heights we keep, we must make sure they have the full validator set or consensus 328 // params, otherwise they will panic if they're retrieved directly (instead of 329 // indirectly via a LastHeightChanged pointer). 330 if keepVals[h] { 331 v := loadValidatorsInfo(db, h) 332 if v.ValidatorSet == nil { 333 v.ValidatorSet, err = LoadValidators(db, h) 334 if err != nil { 335 return err 336 } 337 v.LastHeightChanged = h 338 batch.Set(calcValidatorsKey(h), v.Bytes()) 339 } 340 } else { 341 batch.Delete(calcValidatorsKey(h)) 342 } 343 344 if keepParams[h] { 345 p := loadConsensusParamsInfo(db, h) 346 if p.ConsensusParams.Equals(&types.ConsensusParams{}) { 347 p.ConsensusParams, err = LoadConsensusParams(db, h) 348 if err != nil { 349 return err 350 } 351 p.LastHeightChanged = h 352 batch.Set(calcConsensusParamsKey(h), p.Bytes()) 353 } 354 } else { 355 batch.Delete(calcConsensusParamsKey(h)) 356 } 357 358 batch.Delete(calcABCIResponsesKey(h)) 359 pruned++ 360 361 // avoid batches growing too large by flushing to database regularly 362 if pruned%1000 == 0 && pruned > 0 { 363 err := batch.Write() 364 if err != nil { 365 return err 366 } 367 batch.Close() 368 batch = db.NewBatch() 369 defer batch.Close() 370 } 371 } 372 373 err = batch.WriteSync() 374 if err != nil { 375 return err 376 } 377 378 return nil 379 } 380 381 // NewABCIResponses returns a new ABCIResponses 382 func NewABCIResponses(block *types.Block) *ABCIResponses { 383 resDeliverTxs := make([]*abci.ResponseDeliverTx, len(block.Data.Txs)) 384 if len(block.Data.Txs) == 0 { 385 // This makes Amino encoding/decoding consistent. 386 resDeliverTxs = nil 387 } 388 return &ABCIResponses{ 389 DeliverTxs: resDeliverTxs, 390 } 391 } 392 393 // Bytes serializes the ABCIResponse using go-amino. 394 func (arz *ABCIResponses) Bytes() []byte { 395 bz, err := arz.MarshalToAmino(cdc) 396 if err != nil { 397 return cdc.MustMarshalBinaryBare(arz) 398 } 399 return bz 400 } 401 402 func (arz *ABCIResponses) ResultsHash() []byte { 403 results := types.NewResults(arz.DeliverTxs) 404 return results.Hash() 405 } 406 func (arz *ABCIResponses) String() string { 407 str := strings.Builder{} 408 results := types.NewResults(arz.DeliverTxs) 409 for _, v := range results { 410 str.WriteString(fmt.Sprintf("code:%d,msg:=%s\n", v.Code, v.Data.String())) 411 } 412 return str.String() 413 } 414 415 // LoadABCIResponses loads the ABCIResponses for the given height from the database. 416 // This is useful for recovering from crashes where we called app.Commit and before we called 417 // s.Save(). It can also be used to produce Merkle proofs of the result of txs. 418 func LoadABCIResponses(db dbm.DB, height int64) (*ABCIResponses, error) { 419 buf, err := db.Get(calcABCIResponsesKey(height)) 420 if err != nil { 421 return nil, err 422 } 423 if len(buf) == 0 { 424 return nil, ErrNoABCIResponsesForHeight{height} 425 } 426 427 abciResponses := new(ABCIResponses) 428 err = cdc.UnmarshalBinaryBare(buf, abciResponses) 429 if err != nil { 430 // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED 431 tmos.Exit(fmt.Sprintf(`LoadABCIResponses: Data has been corrupted or its spec has 432 changed: %v\n`, err)) 433 } 434 // TODO: ensure that buf is completely read. 435 436 return abciResponses, nil 437 } 438 439 // SaveABCIResponses persists the ABCIResponses to the database. 440 // This is useful in case we crash after app.Commit and before s.Save(). 441 // Responses are indexed by height so they can also be loaded later to produce 442 // Merkle proofs. 443 // 444 // Exposed for testing. 445 func SaveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) { 446 db.SetSync(calcABCIResponsesKey(height), abciResponses.Bytes()) 447 } 448 449 //----------------------------------------------------------------------------- 450 451 // ValidatorsInfo represents the latest validator set, or the last height it changed 452 type ValidatorsInfo struct { 453 ValidatorSet *types.ValidatorSet 454 LastHeightChanged int64 455 } 456 457 // Bytes serializes the ValidatorsInfo using go-amino. 458 func (valInfo *ValidatorsInfo) Bytes() []byte { 459 return cdc.MustMarshalBinaryBare(valInfo) 460 } 461 462 // LoadValidators loads the ValidatorSet for a given height. 463 // Returns ErrNoValSetForHeight if the validator set can't be found for this height. 464 func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) { 465 valSet, _, err := LoadValidatorsWithStoredHeight(db, height) 466 return valSet, err 467 } 468 469 // LoadValidators loads the ValidatorSet for a given height. plus the last LastHeightChanged 470 // Returns ErrNoValSetForHeight if the validator set can't be found for this height. 471 func LoadValidatorsWithStoredHeight(db dbm.DB, height int64) (*types.ValidatorSet, int64, error) { 472 valInfo := loadValidatorsInfo(db, height) 473 if valInfo == nil { 474 return nil, -1, ErrNoValSetForHeight{height} 475 } 476 if valInfo.ValidatorSet == nil { 477 lastStoredHeight := lastStoredHeightFor(height, valInfo.LastHeightChanged) 478 valInfo2 := loadValidatorsInfo(db, lastStoredHeight) 479 if valInfo2 == nil || valInfo2.ValidatorSet == nil { 480 panic( 481 fmt.Sprintf("Couldn't find validators at height %d (height %d was originally requested)", 482 lastStoredHeight, 483 height, 484 ), 485 ) 486 } 487 valInfo2.ValidatorSet.IncrementProposerPriority(int(height - lastStoredHeight)) // mutate 488 valInfo = valInfo2 489 } 490 491 return valInfo.ValidatorSet, valInfo.LastHeightChanged, nil 492 } 493 494 func lastStoredHeightFor(height, lastHeightChanged int64) int64 { 495 checkpointHeight := height - height%valSetCheckpointInterval 496 return tmmath.MaxInt64(checkpointHeight, lastHeightChanged) 497 } 498 499 // CONTRACT: Returned ValidatorsInfo can be mutated. 500 func loadValidatorsInfo(db dbm.DB, height int64) *ValidatorsInfo { 501 buf, err := db.Get(calcValidatorsKey(height)) 502 if err != nil { 503 panic(err) 504 } 505 if len(buf) == 0 { 506 return nil 507 } 508 509 v := new(ValidatorsInfo) 510 err = cdc.UnmarshalBinaryBare(buf, v) 511 if err != nil { 512 // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED 513 tmos.Exit(fmt.Sprintf(`LoadValidators: Data has been corrupted or its spec has changed: 514 %v\n`, err)) 515 } 516 // TODO: ensure that buf is completely read. 517 518 return v 519 } 520 521 // saveValidatorsInfo persists the validator set. 522 // 523 // `height` is the effective height for which the validator is responsible for 524 // signing. It should be called from s.Save(), right before the state itself is 525 // persisted. 526 func saveValidatorsInfo(db dbm.DB, height, lastHeightChanged int64, valSet *types.ValidatorSet) { 527 if !IgnoreSmbCheck && lastHeightChanged > height { 528 panic("LastHeightChanged cannot be greater than ValidatorsInfo height") 529 } 530 valInfo := &ValidatorsInfo{ 531 LastHeightChanged: lastHeightChanged, 532 } 533 // Only persist validator set if it was updated or checkpoint height (see 534 // valSetCheckpointInterval) is reached. 535 if height == lastHeightChanged || height%valSetCheckpointInterval == 0 { 536 valInfo.ValidatorSet = valSet 537 } 538 db.Set(calcValidatorsKey(height), valInfo.Bytes()) 539 } 540 541 //----------------------------------------------------------------------------- 542 543 // ConsensusParamsInfo represents the latest consensus params, or the last height it changed 544 type ConsensusParamsInfo struct { 545 ConsensusParams types.ConsensusParams 546 LastHeightChanged int64 547 } 548 549 // Bytes serializes the ConsensusParamsInfo using go-amino. 550 func (params ConsensusParamsInfo) Bytes() []byte { 551 return cdc.MustMarshalBinaryBare(params) 552 } 553 554 // LoadConsensusParams loads the ConsensusParams for a given height. 555 func LoadConsensusParams(db dbm.DB, height int64) (types.ConsensusParams, error) { 556 empty := types.ConsensusParams{} 557 558 paramsInfo := loadConsensusParamsInfo(db, height) 559 if paramsInfo == nil { 560 return empty, ErrNoConsensusParamsForHeight{height} 561 } 562 563 if paramsInfo.ConsensusParams.Equals(&empty) { 564 paramsInfo2 := loadConsensusParamsInfo(db, paramsInfo.LastHeightChanged) 565 if paramsInfo2 == nil { 566 panic( 567 fmt.Sprintf( 568 "Couldn't find consensus params at height %d as last changed from height %d", 569 paramsInfo.LastHeightChanged, 570 height, 571 ), 572 ) 573 } 574 paramsInfo = paramsInfo2 575 } 576 577 return paramsInfo.ConsensusParams, nil 578 } 579 580 func loadConsensusParamsInfo(db dbm.DB, height int64) *ConsensusParamsInfo { 581 buf, err := db.Get(calcConsensusParamsKey(height)) 582 if err != nil { 583 panic(err) 584 } 585 if len(buf) == 0 { 586 return nil 587 } 588 589 paramsInfo := new(ConsensusParamsInfo) 590 err = cdc.UnmarshalBinaryBare(buf, paramsInfo) 591 if err != nil { 592 // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED 593 tmos.Exit(fmt.Sprintf(`LoadConsensusParams: Data has been corrupted or its spec has changed: 594 %v\n`, err)) 595 } 596 // TODO: ensure that buf is completely read. 597 598 return paramsInfo 599 } 600 601 // saveConsensusParamsInfo persists the consensus params for the next block to disk. 602 // It should be called from s.Save(), right before the state itself is persisted. 603 // If the consensus params did not change after processing the latest block, 604 // only the last height for which they changed is persisted. 605 func saveConsensusParamsInfo(db dbm.DB, nextHeight, changeHeight int64, params types.ConsensusParams) { 606 paramsInfo := &ConsensusParamsInfo{ 607 LastHeightChanged: changeHeight, 608 } 609 if changeHeight == nextHeight { 610 paramsInfo.ConsensusParams = params 611 } 612 db.Set(calcConsensusParamsKey(nextHeight), paramsInfo.Bytes()) 613 }