You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

660 lines
18 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package state
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "time"
  7. "github.com/tendermint/tendermint/account"
  8. "github.com/tendermint/tendermint/binary"
  9. blk "github.com/tendermint/tendermint/block"
  10. . "github.com/tendermint/tendermint/common"
  11. dbm "github.com/tendermint/tendermint/db"
  12. "github.com/tendermint/tendermint/merkle"
  13. )
  14. var (
  15. stateKey = []byte("stateKey")
  16. minBondAmount = uint64(1) // TODO adjust
  17. defaultAccountsCacheCapacity = 1000 // TODO adjust
  18. unbondingPeriodBlocks = uint(60 * 24 * 365) // TODO probably better to make it time based.
  19. validatorTimeoutBlocks = uint(10) // TODO adjust
  20. )
  21. //-----------------------------------------------------------------------------
  22. type InvalidTxError struct {
  23. Tx blk.Tx
  24. Reason error
  25. }
  26. func (txErr InvalidTxError) Error() string {
  27. return fmt.Sprintf("Invalid tx: [%v] reason: [%v]", txErr.Tx, txErr.Reason)
  28. }
  29. //-----------------------------------------------------------------------------
  30. // NOTE: not goroutine-safe.
  31. type State struct {
  32. DB dbm.DB
  33. LastBlockHeight uint
  34. LastBlockHash []byte
  35. LastBlockParts blk.PartSetHeader
  36. LastBlockTime time.Time
  37. BondedValidators *ValidatorSet
  38. UnbondingValidators *ValidatorSet
  39. accounts merkle.Tree // Shouldn't be accessed directly.
  40. validatorInfos merkle.Tree // Shouldn't be accessed directly.
  41. }
  42. func LoadState(db dbm.DB) *State {
  43. s := &State{DB: db}
  44. buf := db.Get(stateKey)
  45. if len(buf) == 0 {
  46. return nil
  47. } else {
  48. r, n, err := bytes.NewReader(buf), new(int64), new(error)
  49. s.LastBlockHeight = binary.ReadUvarint(r, n, err)
  50. s.LastBlockHash = binary.ReadByteSlice(r, n, err)
  51. s.LastBlockParts = binary.ReadBinary(blk.PartSetHeader{}, r, n, err).(blk.PartSetHeader)
  52. s.LastBlockTime = binary.ReadTime(r, n, err)
  53. s.BondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
  54. s.UnbondingValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
  55. accountsHash := binary.ReadByteSlice(r, n, err)
  56. s.accounts = merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db)
  57. s.accounts.Load(accountsHash)
  58. validatorInfosHash := binary.ReadByteSlice(r, n, err)
  59. s.validatorInfos = merkle.NewIAVLTree(binary.BasicCodec, ValidatorInfoCodec, 0, db)
  60. s.validatorInfos.Load(validatorInfosHash)
  61. if *err != nil {
  62. panic(*err)
  63. }
  64. // TODO: ensure that buf is completely read.
  65. }
  66. return s
  67. }
  68. // Save this state into the db.
  69. func (s *State) Save() {
  70. s.accounts.Save()
  71. s.validatorInfos.Save()
  72. buf, n, err := new(bytes.Buffer), new(int64), new(error)
  73. binary.WriteUvarint(s.LastBlockHeight, buf, n, err)
  74. binary.WriteByteSlice(s.LastBlockHash, buf, n, err)
  75. binary.WriteBinary(s.LastBlockParts, buf, n, err)
  76. binary.WriteTime(s.LastBlockTime, buf, n, err)
  77. binary.WriteBinary(s.BondedValidators, buf, n, err)
  78. binary.WriteBinary(s.UnbondingValidators, buf, n, err)
  79. binary.WriteByteSlice(s.accounts.Hash(), buf, n, err)
  80. binary.WriteByteSlice(s.validatorInfos.Hash(), buf, n, err)
  81. if *err != nil {
  82. panic(*err)
  83. }
  84. s.DB.Set(stateKey, buf.Bytes())
  85. }
  86. func (s *State) Copy() *State {
  87. return &State{
  88. DB: s.DB,
  89. LastBlockHeight: s.LastBlockHeight,
  90. LastBlockHash: s.LastBlockHash,
  91. LastBlockParts: s.LastBlockParts,
  92. LastBlockTime: s.LastBlockTime,
  93. BondedValidators: s.BondedValidators.Copy(),
  94. UnbondingValidators: s.UnbondingValidators.Copy(),
  95. accounts: s.accounts.Copy(),
  96. validatorInfos: s.validatorInfos.Copy(),
  97. }
  98. }
  99. // The accounts from the TxInputs must either already have
  100. // account.PubKey.(type) != PubKeyNil, (it must be known),
  101. // or it must be specified in the TxInput. If redeclared,
  102. // the TxInput is modified and input.PubKey set to PubKeyNil.
  103. func (s *State) GetOrMakeAccounts(ins []*blk.TxInput, outs []*blk.TxOutput) (map[string]*account.Account, error) {
  104. accounts := map[string]*account.Account{}
  105. for _, in := range ins {
  106. // Account shouldn't be duplicated
  107. if _, ok := accounts[string(in.Address)]; ok {
  108. return nil, blk.ErrTxDuplicateAddress
  109. }
  110. acc := s.GetAccount(in.Address)
  111. if acc == nil {
  112. return nil, blk.ErrTxInvalidAddress
  113. }
  114. // PubKey should be present in either "account" or "in"
  115. if _, isNil := acc.PubKey.(account.PubKeyNil); isNil {
  116. if _, isNil := in.PubKey.(account.PubKeyNil); isNil {
  117. return nil, blk.ErrTxUnknownPubKey
  118. }
  119. if !bytes.Equal(in.PubKey.Address(), acc.Address) {
  120. return nil, blk.ErrTxInvalidPubKey
  121. }
  122. acc.PubKey = in.PubKey
  123. } else {
  124. in.PubKey = account.PubKeyNil{}
  125. }
  126. accounts[string(in.Address)] = acc
  127. }
  128. for _, out := range outs {
  129. // Account shouldn't be duplicated
  130. if _, ok := accounts[string(out.Address)]; ok {
  131. return nil, blk.ErrTxDuplicateAddress
  132. }
  133. acc := s.GetAccount(out.Address)
  134. // output account may be nil (new)
  135. if acc == nil {
  136. acc = &account.Account{
  137. Address: out.Address,
  138. PubKey: account.PubKeyNil{},
  139. Sequence: 0,
  140. Balance: 0,
  141. }
  142. }
  143. accounts[string(out.Address)] = acc
  144. }
  145. return accounts, nil
  146. }
  147. func (s *State) ValidateInputs(accounts map[string]*account.Account, signBytes []byte, ins []*blk.TxInput) (total uint64, err error) {
  148. for _, in := range ins {
  149. acc := accounts[string(in.Address)]
  150. if acc == nil {
  151. panic("ValidateInputs() expects account in accounts")
  152. }
  153. // Check TxInput basic
  154. if err := in.ValidateBasic(); err != nil {
  155. return 0, err
  156. }
  157. // Check signatures
  158. if !acc.PubKey.VerifyBytes(signBytes, in.Signature) {
  159. return 0, blk.ErrTxInvalidSignature
  160. }
  161. // Check sequences
  162. if acc.Sequence+1 != in.Sequence {
  163. return 0, blk.ErrTxInvalidSequence
  164. }
  165. // Check amount
  166. if acc.Balance < in.Amount {
  167. return 0, blk.ErrTxInsufficientFunds
  168. }
  169. // Good. Add amount to total
  170. total += in.Amount
  171. }
  172. return total, nil
  173. }
  174. func (s *State) ValidateOutputs(outs []*blk.TxOutput) (total uint64, err error) {
  175. for _, out := range outs {
  176. // Check TxOutput basic
  177. if err := out.ValidateBasic(); err != nil {
  178. return 0, err
  179. }
  180. // Good. Add amount to total
  181. total += out.Amount
  182. }
  183. return total, nil
  184. }
  185. func (s *State) AdjustByInputs(accounts map[string]*account.Account, ins []*blk.TxInput) {
  186. for _, in := range ins {
  187. acc := accounts[string(in.Address)]
  188. if acc == nil {
  189. panic("AdjustByInputs() expects account in accounts")
  190. }
  191. if acc.Balance < in.Amount {
  192. panic("AdjustByInputs() expects sufficient funds")
  193. }
  194. acc.Balance -= in.Amount
  195. acc.Sequence += 1
  196. }
  197. }
  198. func (s *State) AdjustByOutputs(accounts map[string]*account.Account, outs []*blk.TxOutput) {
  199. for _, out := range outs {
  200. acc := accounts[string(out.Address)]
  201. if acc == nil {
  202. panic("AdjustByOutputs() expects account in accounts")
  203. }
  204. acc.Balance += out.Amount
  205. }
  206. }
  207. // If the tx is invalid, an error will be returned.
  208. // Unlike AppendBlock(), state will not be altered.
  209. func (s *State) ExecTx(tx_ blk.Tx) error {
  210. // TODO: do something with fees
  211. fees := uint64(0)
  212. // Exec tx
  213. switch tx_.(type) {
  214. case *blk.SendTx:
  215. tx := tx_.(*blk.SendTx)
  216. accounts, err := s.GetOrMakeAccounts(tx.Inputs, tx.Outputs)
  217. if err != nil {
  218. return err
  219. }
  220. signBytes := account.SignBytes(tx)
  221. inTotal, err := s.ValidateInputs(accounts, signBytes, tx.Inputs)
  222. if err != nil {
  223. return err
  224. }
  225. outTotal, err := s.ValidateOutputs(tx.Outputs)
  226. if err != nil {
  227. return err
  228. }
  229. if outTotal > inTotal {
  230. return blk.ErrTxInsufficientFunds
  231. }
  232. fee := inTotal - outTotal
  233. fees += fee
  234. // Good! Adjust accounts
  235. s.AdjustByInputs(accounts, tx.Inputs)
  236. s.AdjustByOutputs(accounts, tx.Outputs)
  237. s.UpdateAccounts(accounts)
  238. return nil
  239. case *blk.BondTx:
  240. tx := tx_.(*blk.BondTx)
  241. valInfo := s.GetValidatorInfo(tx.PubKey.Address())
  242. if valInfo != nil {
  243. // TODO: In the future, check that the validator wasn't destroyed,
  244. // add funds, merge UnbondTo outputs, and unbond validator.
  245. return errors.New("Adding coins to existing validators not yet supported")
  246. }
  247. accounts, err := s.GetOrMakeAccounts(tx.Inputs, nil)
  248. if err != nil {
  249. return err
  250. }
  251. signBytes := account.SignBytes(tx)
  252. inTotal, err := s.ValidateInputs(accounts, signBytes, tx.Inputs)
  253. if err != nil {
  254. return err
  255. }
  256. if err := tx.PubKey.ValidateBasic(); err != nil {
  257. return err
  258. }
  259. outTotal, err := s.ValidateOutputs(tx.UnbondTo)
  260. if err != nil {
  261. return err
  262. }
  263. if outTotal > inTotal {
  264. return blk.ErrTxInsufficientFunds
  265. }
  266. fee := inTotal - outTotal
  267. fees += fee
  268. // Good! Adjust accounts
  269. s.AdjustByInputs(accounts, tx.Inputs)
  270. s.UpdateAccounts(accounts)
  271. // Add ValidatorInfo
  272. s.SetValidatorInfo(&ValidatorInfo{
  273. Address: tx.PubKey.Address(),
  274. PubKey: tx.PubKey,
  275. UnbondTo: tx.UnbondTo,
  276. FirstBondHeight: s.LastBlockHeight + 1,
  277. FirstBondAmount: outTotal,
  278. })
  279. // Add Validator
  280. added := s.BondedValidators.Add(&Validator{
  281. Address: tx.PubKey.Address(),
  282. PubKey: tx.PubKey,
  283. BondHeight: s.LastBlockHeight + 1,
  284. VotingPower: outTotal,
  285. Accum: 0,
  286. })
  287. if !added {
  288. panic("Failed to add validator")
  289. }
  290. return nil
  291. case *blk.UnbondTx:
  292. tx := tx_.(*blk.UnbondTx)
  293. // The validator must be active
  294. _, val := s.BondedValidators.GetByAddress(tx.Address)
  295. if val == nil {
  296. return blk.ErrTxInvalidAddress
  297. }
  298. // Verify the signature
  299. signBytes := account.SignBytes(tx)
  300. if !val.PubKey.VerifyBytes(signBytes, tx.Signature) {
  301. return blk.ErrTxInvalidSignature
  302. }
  303. // tx.Height must be greater than val.LastCommitHeight
  304. if tx.Height <= val.LastCommitHeight {
  305. return errors.New("Invalid unbond height")
  306. }
  307. // Good!
  308. s.unbondValidator(val)
  309. return nil
  310. case *blk.RebondTx:
  311. tx := tx_.(*blk.RebondTx)
  312. // The validator must be inactive
  313. _, val := s.UnbondingValidators.GetByAddress(tx.Address)
  314. if val == nil {
  315. return blk.ErrTxInvalidAddress
  316. }
  317. // Verify the signature
  318. signBytes := account.SignBytes(tx)
  319. if !val.PubKey.VerifyBytes(signBytes, tx.Signature) {
  320. return blk.ErrTxInvalidSignature
  321. }
  322. // tx.Height must be equal to the next height
  323. if tx.Height != s.LastBlockHeight+1 {
  324. return errors.New("Invalid rebond height")
  325. }
  326. // Good!
  327. s.rebondValidator(val)
  328. return nil
  329. case *blk.DupeoutTx:
  330. tx := tx_.(*blk.DupeoutTx)
  331. // Verify the signatures
  332. _, accused := s.BondedValidators.GetByAddress(tx.Address)
  333. voteASignBytes := account.SignBytes(&tx.VoteA)
  334. voteBSignBytes := account.SignBytes(&tx.VoteB)
  335. if !accused.PubKey.VerifyBytes(voteASignBytes, tx.VoteA.Signature) ||
  336. !accused.PubKey.VerifyBytes(voteBSignBytes, tx.VoteB.Signature) {
  337. return blk.ErrTxInvalidSignature
  338. }
  339. // Verify equivocation
  340. // TODO: in the future, just require one vote from a previous height that
  341. // doesn't exist on this chain.
  342. if tx.VoteA.Height != tx.VoteB.Height {
  343. return errors.New("DupeoutTx heights don't match")
  344. }
  345. if tx.VoteA.Type == blk.VoteTypeCommit && tx.VoteA.Round < tx.VoteB.Round {
  346. // Check special case.
  347. // Validators should not sign another vote after committing.
  348. } else {
  349. if tx.VoteA.Round != tx.VoteB.Round {
  350. return errors.New("DupeoutTx rounds don't match")
  351. }
  352. if tx.VoteA.Type != tx.VoteB.Type {
  353. return errors.New("DupeoutTx types don't match")
  354. }
  355. if bytes.Equal(tx.VoteA.BlockHash, tx.VoteB.BlockHash) {
  356. return errors.New("DupeoutTx blockhashes shouldn't match")
  357. }
  358. }
  359. // Good! (Bad validator!)
  360. s.destroyValidator(accused)
  361. return nil
  362. default:
  363. panic("Unknown Tx type")
  364. }
  365. }
  366. func (s *State) unbondValidator(val *Validator) {
  367. // Move validator to UnbondingValidators
  368. val, removed := s.BondedValidators.Remove(val.Address)
  369. if !removed {
  370. panic("Couldn't remove validator for unbonding")
  371. }
  372. val.UnbondHeight = s.LastBlockHeight + 1
  373. added := s.UnbondingValidators.Add(val)
  374. if !added {
  375. panic("Couldn't add validator for unbonding")
  376. }
  377. }
  378. func (s *State) rebondValidator(val *Validator) {
  379. // Move validator to BondingValidators
  380. val, removed := s.UnbondingValidators.Remove(val.Address)
  381. if !removed {
  382. panic("Couldn't remove validator for rebonding")
  383. }
  384. val.BondHeight = s.LastBlockHeight + 1
  385. added := s.BondedValidators.Add(val)
  386. if !added {
  387. panic("Couldn't add validator for rebonding")
  388. }
  389. }
  390. func (s *State) releaseValidator(val *Validator) {
  391. // Update validatorInfo
  392. valInfo := s.GetValidatorInfo(val.Address)
  393. if valInfo == nil {
  394. panic("Couldn't find validatorInfo for release")
  395. }
  396. valInfo.ReleasedHeight = s.LastBlockHeight + 1
  397. s.SetValidatorInfo(valInfo)
  398. // Send coins back to UnbondTo outputs
  399. accounts, err := s.GetOrMakeAccounts(nil, valInfo.UnbondTo)
  400. if err != nil {
  401. panic("Couldn't get or make unbondTo accounts")
  402. }
  403. s.AdjustByOutputs(accounts, valInfo.UnbondTo)
  404. s.UpdateAccounts(accounts)
  405. // Remove validator from UnbondingValidators
  406. _, removed := s.UnbondingValidators.Remove(val.Address)
  407. if !removed {
  408. panic("Couldn't remove validator for release")
  409. }
  410. }
  411. func (s *State) destroyValidator(val *Validator) {
  412. // Update validatorInfo
  413. valInfo := s.GetValidatorInfo(val.Address)
  414. if valInfo == nil {
  415. panic("Couldn't find validatorInfo for release")
  416. }
  417. valInfo.DestroyedHeight = s.LastBlockHeight + 1
  418. valInfo.DestroyedAmount = val.VotingPower
  419. s.SetValidatorInfo(valInfo)
  420. // Remove validator
  421. _, removed := s.BondedValidators.Remove(val.Address)
  422. if !removed {
  423. _, removed := s.UnbondingValidators.Remove(val.Address)
  424. if !removed {
  425. panic("Couldn't remove validator for destruction")
  426. }
  427. }
  428. }
  429. // "checkStateHash": If false, instead of checking the resulting
  430. // state.Hash() against blk.StateHash, it *sets* the blk.StateHash.
  431. // (used for constructing a new proposal)
  432. // NOTE: If an error occurs during block execution, state will be left
  433. // at an invalid state. Copy the state before calling AppendBlock!
  434. func (s *State) AppendBlock(block *blk.Block, blockPartsHeader blk.PartSetHeader, checkStateHash bool) error {
  435. // Basic block validation.
  436. err := block.ValidateBasic(s.LastBlockHeight, s.LastBlockHash, s.LastBlockParts, s.LastBlockTime)
  437. if err != nil {
  438. return err
  439. }
  440. // Validate block Validation.
  441. if block.Height == 1 {
  442. if len(block.Validation.Commits) != 0 {
  443. return errors.New("Block at height 1 (first block) should have no Validation commits")
  444. }
  445. } else {
  446. if uint(len(block.Validation.Commits)) != s.BondedValidators.Size() {
  447. return errors.New("Invalid block validation size")
  448. }
  449. var sumVotingPower uint64
  450. s.BondedValidators.Iterate(func(index uint, val *Validator) bool {
  451. commit := block.Validation.Commits[index]
  452. if commit.IsZero() {
  453. return false
  454. } else {
  455. vote := &blk.Vote{
  456. Height: block.Height - 1,
  457. Round: commit.Round,
  458. Type: blk.VoteTypeCommit,
  459. BlockHash: block.LastBlockHash,
  460. BlockParts: block.LastBlockParts,
  461. }
  462. if val.PubKey.VerifyBytes(account.SignBytes(vote), commit.Signature) {
  463. sumVotingPower += val.VotingPower
  464. return false
  465. } else {
  466. log.Warn(Fmt("Invalid validation signature.\nval: %v\nvote: %v", val, vote))
  467. err = errors.New("Invalid validation signature")
  468. return true
  469. }
  470. }
  471. })
  472. if err != nil {
  473. return err
  474. }
  475. if sumVotingPower <= s.BondedValidators.TotalVotingPower()*2/3 {
  476. return errors.New("Insufficient validation voting power")
  477. }
  478. }
  479. // Commit each tx
  480. for _, tx := range block.Data.Txs {
  481. err := s.ExecTx(tx)
  482. if err != nil {
  483. return InvalidTxError{tx, err}
  484. }
  485. }
  486. // Update Validator.LastCommitHeight as necessary.
  487. for i, commit := range block.Validation.Commits {
  488. if commit.IsZero() {
  489. continue
  490. }
  491. _, val := s.BondedValidators.GetByIndex(uint(i))
  492. if val == nil {
  493. panic(Fmt("Failed to fetch validator at index %v", i))
  494. }
  495. val.LastCommitHeight = block.Height - 1
  496. updated := s.BondedValidators.Update(val)
  497. if !updated {
  498. panic("Failed to update validator LastCommitHeight")
  499. }
  500. }
  501. // If any unbonding periods are over,
  502. // reward account with bonded coins.
  503. toRelease := []*Validator{}
  504. s.UnbondingValidators.Iterate(func(index uint, val *Validator) bool {
  505. if val.UnbondHeight+unbondingPeriodBlocks < block.Height {
  506. toRelease = append(toRelease, val)
  507. }
  508. return false
  509. })
  510. for _, val := range toRelease {
  511. s.releaseValidator(val)
  512. }
  513. // If any validators haven't signed in a while,
  514. // unbond them, they have timed out.
  515. toTimeout := []*Validator{}
  516. s.BondedValidators.Iterate(func(index uint, val *Validator) bool {
  517. if val.LastCommitHeight+validatorTimeoutBlocks < block.Height {
  518. toTimeout = append(toTimeout, val)
  519. }
  520. return false
  521. })
  522. for _, val := range toTimeout {
  523. s.unbondValidator(val)
  524. }
  525. // Increment validator AccumPowers
  526. s.BondedValidators.IncrementAccum(1)
  527. // Check or set blk.StateHash
  528. stateHash := s.Hash()
  529. if checkStateHash {
  530. // State hash should match
  531. if !bytes.Equal(stateHash, block.StateHash) {
  532. return Errorf("Invalid state hash. Got %X, block says %X",
  533. stateHash, block.StateHash)
  534. }
  535. } else {
  536. // Set the state hash.
  537. if block.StateHash != nil {
  538. panic("Cannot overwrite block.StateHash")
  539. }
  540. block.StateHash = stateHash
  541. }
  542. s.LastBlockHeight = block.Height
  543. s.LastBlockHash = block.Hash()
  544. s.LastBlockParts = blockPartsHeader
  545. s.LastBlockTime = block.Time
  546. return nil
  547. }
  548. // The returned Account is a copy, so mutating it
  549. // has no side effects.
  550. func (s *State) GetAccount(address []byte) *account.Account {
  551. _, acc := s.accounts.Get(address)
  552. if acc == nil {
  553. return nil
  554. }
  555. return acc.(*account.Account).Copy()
  556. }
  557. // The returned Account is a copy, so mutating it
  558. // has no side effects.
  559. func (s *State) GetAccounts() merkle.Tree {
  560. return s.accounts.Copy()
  561. }
  562. // The account is copied before setting, so mutating it
  563. // afterwards has no side effects.
  564. func (s *State) UpdateAccount(account *account.Account) {
  565. s.accounts.Set(account.Address, account.Copy())
  566. }
  567. // The accounts are copied before setting, so mutating it
  568. // afterwards has no side effects.
  569. func (s *State) UpdateAccounts(accounts map[string]*account.Account) {
  570. for _, acc := range accounts {
  571. s.accounts.Set(acc.Address, acc.Copy())
  572. }
  573. }
  574. // The returned ValidatorInfo is a copy, so mutating it
  575. // has no side effects.
  576. func (s *State) GetValidatorInfo(address []byte) *ValidatorInfo {
  577. _, valInfo := s.validatorInfos.Get(address)
  578. if valInfo == nil {
  579. return nil
  580. }
  581. return valInfo.(*ValidatorInfo).Copy()
  582. }
  583. // Returns false if new, true if updated.
  584. // The valInfo is copied before setting, so mutating it
  585. // afterwards has no side effects.
  586. func (s *State) SetValidatorInfo(valInfo *ValidatorInfo) (updated bool) {
  587. return s.validatorInfos.Set(valInfo.Address, valInfo.Copy())
  588. }
  589. // Returns a hash that represents the state data,
  590. // excluding LastBlock*
  591. func (s *State) Hash() []byte {
  592. hashables := []merkle.Hashable{
  593. s.BondedValidators,
  594. s.UnbondingValidators,
  595. s.accounts,
  596. s.validatorInfos,
  597. }
  598. return merkle.HashFromHashables(hashables)
  599. }