tendermint/state/state.go

354 lines
10 KiB
Go
Raw Normal View History

package state
import (
"bytes"
2015-05-22 13:53:10 -07:00
"io"
"time"
2015-04-01 17:30:16 -07:00
"github.com/tendermint/tendermint/account"
"github.com/tendermint/tendermint/binary"
2015-06-16 21:16:58 -07:00
. "github.com/tendermint/tendermint/common"
2015-04-01 17:30:16 -07:00
dbm "github.com/tendermint/tendermint/db"
2015-04-13 18:26:41 -07:00
"github.com/tendermint/tendermint/events"
2015-04-01 17:30:16 -07:00
"github.com/tendermint/tendermint/merkle"
"github.com/tendermint/tendermint/types"
)
var (
stateKey = []byte("stateKey")
minBondAmount = int64(1) // TODO adjust
defaultAccountsCacheCapacity = 1000 // TODO adjust
unbondingPeriodBlocks = int(60 * 24 * 365) // TODO probably better to make it time based.
validatorTimeoutBlocks = int(10) // TODO adjust
)
2014-10-06 21:28:49 -07:00
//-----------------------------------------------------------------------------
2014-10-07 01:05:54 -07:00
// NOTE: not goroutine-safe.
type State struct {
DB dbm.DB
ChainID string
LastBlockHeight int
LastBlockHash []byte
LastBlockParts types.PartSetHeader
LastBlockTime time.Time
BondedValidators *ValidatorSet
LastBondedValidators *ValidatorSet
UnbondingValidators *ValidatorSet
accounts merkle.Tree // Shouldn't be accessed directly.
validatorInfos merkle.Tree // Shouldn't be accessed directly.
2015-05-22 13:53:10 -07:00
nameReg merkle.Tree // Shouldn't be accessed directly.
2015-04-13 18:26:41 -07:00
2015-04-15 23:40:27 -07:00
evc events.Fireable // typically an events.EventCache
}
func LoadState(db dbm.DB) *State {
2014-10-07 01:05:54 -07:00
s := &State{DB: db}
buf := db.Get(stateKey)
if len(buf) == 0 {
2014-10-03 17:59:54 -07:00
return nil
} else {
r, n, err := bytes.NewReader(buf), new(int64), new(error)
s.ChainID = binary.ReadString(r, n, err)
s.LastBlockHeight = binary.ReadVarint(r, n, err)
s.LastBlockHash = binary.ReadByteSlice(r, n, err)
s.LastBlockParts = binary.ReadBinary(types.PartSetHeader{}, r, n, err).(types.PartSetHeader)
s.LastBlockTime = binary.ReadTime(r, n, err)
s.BondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
s.LastBondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
s.UnbondingValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
accountsHash := binary.ReadByteSlice(r, n, err)
s.accounts = merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db)
s.accounts.Load(accountsHash)
validatorInfosHash := binary.ReadByteSlice(r, n, err)
s.validatorInfos = merkle.NewIAVLTree(binary.BasicCodec, ValidatorInfoCodec, 0, db)
s.validatorInfos.Load(validatorInfosHash)
2015-05-22 13:53:10 -07:00
nameRegHash := binary.ReadByteSlice(r, n, err)
s.nameReg = merkle.NewIAVLTree(binary.BasicCodec, NameRegCodec, 0, db)
s.nameReg.Load(nameRegHash)
if *err != nil {
2015-06-16 21:16:58 -07:00
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
Exit(Fmt("Data has been corrupted or its spec has changed: %v\n", *err))
}
2014-10-11 21:27:58 -07:00
// TODO: ensure that buf is completely read.
}
return s
}
func (s *State) Save() {
s.accounts.Save()
2014-12-17 01:37:13 -08:00
s.validatorInfos.Save()
2015-05-22 13:53:10 -07:00
s.nameReg.Save()
buf, n, err := new(bytes.Buffer), new(int64), new(error)
binary.WriteString(s.ChainID, buf, n, err)
binary.WriteVarint(s.LastBlockHeight, buf, n, err)
binary.WriteByteSlice(s.LastBlockHash, buf, n, err)
binary.WriteBinary(s.LastBlockParts, buf, n, err)
binary.WriteTime(s.LastBlockTime, buf, n, err)
binary.WriteBinary(s.BondedValidators, buf, n, err)
binary.WriteBinary(s.LastBondedValidators, buf, n, err)
binary.WriteBinary(s.UnbondingValidators, buf, n, err)
binary.WriteByteSlice(s.accounts.Hash(), buf, n, err)
binary.WriteByteSlice(s.validatorInfos.Hash(), buf, n, err)
2015-05-22 13:53:10 -07:00
binary.WriteByteSlice(s.nameReg.Hash(), buf, n, err)
if *err != nil {
2015-06-16 21:16:58 -07:00
// SOMETHING HAS GONE HORRIBLY WRONG
panic(*err)
}
2014-10-07 01:05:54 -07:00
s.DB.Set(stateKey, buf.Bytes())
}
// CONTRACT:
// Copy() is a cheap way to take a snapshot,
// as if State were copied by value.
func (s *State) Copy() *State {
return &State{
DB: s.DB,
ChainID: s.ChainID,
LastBlockHeight: s.LastBlockHeight,
LastBlockHash: s.LastBlockHash,
LastBlockParts: s.LastBlockParts,
LastBlockTime: s.LastBlockTime,
2015-03-20 05:47:52 -07:00
BondedValidators: s.BondedValidators.Copy(), // TODO remove need for Copy() here.
LastBondedValidators: s.LastBondedValidators.Copy(), // That is, make updates to the validator set
UnbondingValidators: s.UnbondingValidators.Copy(), // copy the valSet lazily.
accounts: s.accounts.Copy(),
validatorInfos: s.validatorInfos.Copy(),
2015-05-22 13:53:10 -07:00
nameReg: s.nameReg.Copy(),
2015-04-17 13:18:50 -07:00
evc: nil,
}
}
// Returns a hash that represents the state data, excluding Last*
func (s *State) Hash() []byte {
hashables := []merkle.Hashable{
s.BondedValidators,
s.UnbondingValidators,
s.accounts,
s.validatorInfos,
2015-05-22 13:53:10 -07:00
s.nameReg,
2014-10-07 23:11:04 -07:00
}
2015-06-18 20:19:39 -07:00
return merkle.SimpleHashFromHashables(hashables)
}
// Mutates the block in place and updates it with new state hash.
2015-06-05 14:15:40 -07:00
func (s *State) ComputeBlockStateHash(block *types.Block) error {
sCopy := s.Copy()
2015-04-15 23:40:27 -07:00
// sCopy has no event cache in it, so this won't fire events
err := execBlock(sCopy, block, types.PartSetHeader{})
if err != nil {
return err
2015-03-18 01:27:16 -07:00
}
// Set block.StateHash
block.StateHash = sCopy.Hash()
2015-03-18 01:27:16 -07:00
return nil
}
//-------------------------------------
// State.accounts
2015-06-16 21:16:58 -07:00
// Returns nil if account does not exist with given address.
// The returned Account is a copy, so mutating it
// has no side effects.
// Implements Statelike
func (s *State) GetAccount(address []byte) *account.Account {
_, acc := s.accounts.Get(address)
if acc == nil {
return nil
}
return acc.(*account.Account).Copy()
}
// The account is copied before setting, so mutating it
// afterwards has no side effects.
// Implements Statelike
func (s *State) UpdateAccount(account *account.Account) bool {
return s.accounts.Set(account.Address, account.Copy())
}
// Implements Statelike
func (s *State) RemoveAccount(address []byte) bool {
_, removed := s.accounts.Remove(address)
return removed
}
// The returned Account is a copy, so mutating it
// has no side effects.
func (s *State) GetAccounts() merkle.Tree {
return s.accounts.Copy()
}
// State.accounts
//-------------------------------------
// State.validators
// The returned ValidatorInfo is a copy, so mutating it
// has no side effects.
func (s *State) GetValidatorInfo(address []byte) *ValidatorInfo {
_, valInfo := s.validatorInfos.Get(address)
if valInfo == nil {
2014-10-12 21:14:10 -07:00
return nil
}
return valInfo.(*ValidatorInfo).Copy()
}
// Returns false if new, true if updated.
// The valInfo is copied before setting, so mutating it
// afterwards has no side effects.
func (s *State) SetValidatorInfo(valInfo *ValidatorInfo) (updated bool) {
return s.validatorInfos.Set(valInfo.Address, valInfo.Copy())
2014-10-12 21:14:10 -07:00
}
func (s *State) unbondValidator(val *Validator) {
// Move validator to UnbondingValidators
val, removed := s.BondedValidators.Remove(val.Address)
2014-10-12 21:14:10 -07:00
if !removed {
2015-06-16 21:16:58 -07:00
// SOMETHING HAS GONE HORRIBLY WRONG
panic("Couldn't remove validator for unbonding")
2014-10-12 21:14:10 -07:00
}
val.UnbondHeight = s.LastBlockHeight + 1
2014-10-12 21:14:10 -07:00
added := s.UnbondingValidators.Add(val)
if !added {
2015-06-16 21:16:58 -07:00
// SOMETHING HAS GONE HORRIBLY WRONG
panic("Couldn't add validator for unbonding")
2014-10-12 21:14:10 -07:00
}
}
func (s *State) rebondValidator(val *Validator) {
// Move validator to BondingValidators
val, removed := s.UnbondingValidators.Remove(val.Address)
if !removed {
2015-06-16 21:16:58 -07:00
// SOMETHING HAS GONE HORRIBLY WRONG
panic("Couldn't remove validator for rebonding")
}
val.BondHeight = s.LastBlockHeight + 1
added := s.BondedValidators.Add(val)
if !added {
2015-06-16 21:16:58 -07:00
// SOMETHING HAS GONE HORRIBLY WRONG
panic("Couldn't add validator for rebonding")
}
}
func (s *State) releaseValidator(val *Validator) {
// Update validatorInfo
valInfo := s.GetValidatorInfo(val.Address)
2015-06-16 21:16:58 -07:00
// SANITY CHECK
if valInfo == nil {
panic("Couldn't find validatorInfo for release")
2014-10-12 21:14:10 -07:00
}
2015-06-16 21:16:58 -07:00
// SANITY CHECK END
valInfo.ReleasedHeight = s.LastBlockHeight + 1
s.SetValidatorInfo(valInfo)
// Send coins back to UnbondTo outputs
2015-06-16 21:16:58 -07:00
// SANITY CHECK
2015-05-12 17:40:19 -07:00
accounts, err := getOrMakeOutputs(s, nil, valInfo.UnbondTo)
if err != nil {
panic("Couldn't get or make unbondTo accounts")
}
2015-06-16 21:16:58 -07:00
// SANITY CHECK END
adjustByOutputs(accounts, valInfo.UnbondTo)
for _, acc := range accounts {
s.UpdateAccount(acc)
}
// Remove validator from UnbondingValidators
_, removed := s.UnbondingValidators.Remove(val.Address)
2014-10-12 21:14:10 -07:00
if !removed {
2015-06-16 21:16:58 -07:00
// SOMETHING HAS GONE HORRIBLY WRONG
panic("Couldn't remove validator for release")
}
}
func (s *State) destroyValidator(val *Validator) {
// Update validatorInfo
valInfo := s.GetValidatorInfo(val.Address)
2015-06-16 21:16:58 -07:00
// SANITY CHECK
if valInfo == nil {
panic("Couldn't find validatorInfo for release")
}
2015-06-16 21:16:58 -07:00
// SANITY CHECK END
valInfo.DestroyedHeight = s.LastBlockHeight + 1
valInfo.DestroyedAmount = val.VotingPower
s.SetValidatorInfo(valInfo)
// Remove validator
_, removed := s.BondedValidators.Remove(val.Address)
if !removed {
_, removed := s.UnbondingValidators.Remove(val.Address)
if !removed {
2015-06-16 21:16:58 -07:00
// SOMETHING HAS GONE HORRIBLY WRONG
panic("Couldn't remove validator for destruction")
}
2014-10-07 23:11:04 -07:00
}
}
// State.validators
//-------------------------------------
// State.storage
2015-01-11 14:27:46 -08:00
func (s *State) LoadStorage(hash []byte) (storage merkle.Tree) {
storage = merkle.NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 1024, s.DB)
storage.Load(hash)
return storage
2014-12-17 01:37:13 -08:00
}
// State.storage
//-------------------------------------
2015-05-22 13:53:10 -07:00
// State.nameReg
func (s *State) GetNameRegEntry(name string) *types.NameRegEntry {
2015-05-22 13:53:10 -07:00
_, value := s.nameReg.Get(name)
if value == nil {
return nil
}
entry := value.(*types.NameRegEntry)
return entry.Copy()
2015-05-22 13:53:10 -07:00
}
func (s *State) UpdateNameRegEntry(entry *types.NameRegEntry) bool {
return s.nameReg.Set(entry.Name, entry)
}
func (s *State) RemoveNameRegEntry(name string) bool {
2015-05-22 13:53:10 -07:00
_, removed := s.nameReg.Remove(name)
return removed
}
func (s *State) GetNames() merkle.Tree {
return s.nameReg.Copy()
}
func NameRegEncoder(o interface{}, w io.Writer, n *int64, err *error) {
binary.WriteBinary(o.(*types.NameRegEntry), w, n, err)
}
func NameRegDecoder(r io.Reader, n *int64, err *error) interface{} {
return binary.ReadBinary(&types.NameRegEntry{}, r, n, err)
}
var NameRegCodec = binary.Codec{
Encode: NameRegEncoder,
Decode: NameRegDecoder,
}
// State.nameReg
//-------------------------------------
2015-04-15 23:40:27 -07:00
// Implements events.Eventable. Typically uses events.EventCache
func (s *State) SetFireable(evc events.Fireable) {
s.evc = evc
2015-04-13 18:26:41 -07:00
}
//-----------------------------------------------------------------------------
2014-10-07 23:11:04 -07:00
type InvalidTxError struct {
Tx types.Tx
Reason error
}
func (txErr InvalidTxError) Error() string {
2015-06-16 21:16:58 -07:00
return Fmt("Invalid tx: [%v] reason: [%v]", txErr.Tx, txErr.Reason)
}