|
|
-
- package state
-
- import (
- "bytes"
- "io"
- "io/ioutil"
- "time"
-
- acm "github.com/tendermint/tendermint/account"
- . "github.com/tendermint/go-common"
- dbm "github.com/tendermint/go-db"
- "github.com/tendermint/tendermint/events"
- "github.com/tendermint/go-merkle"
- ptypes "github.com/tendermint/tendermint/permission/types"
- . "github.com/tendermint/tendermint/state/types"
- "github.com/tendermint/tendermint/types"
- "github.com/tendermint/go-wire"
- )
-
- 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
- )
-
- //-----------------------------------------------------------------------------
-
- // NOTE: not goroutine-safe.
- type State struct {
- DB dbm.DB
- ChainID string
- LastBlockHeight int
- LastBlockHash []byte
- LastBlockParts types.PartSetHeader
- LastBlockTime time.Time
- BondedValidators *types.ValidatorSet
- LastBondedValidators *types.ValidatorSet
- UnbondingValidators *types.ValidatorSet
- accounts merkle.Tree // Shouldn't be accessed directly.
- validatorInfos merkle.Tree // Shouldn't be accessed directly.
- nameReg merkle.Tree // Shouldn't be accessed directly.
-
- evc events.Fireable // typically an events.EventCache
- }
-
- func LoadState(db dbm.DB) *State {
- s := &State{DB: db}
- buf := db.Get(stateKey)
- if len(buf) == 0 {
- return nil
- } else {
- r, n, err := bytes.NewReader(buf), new(int64), new(error)
- s.ChainID = wire.ReadString(r, n, err)
- s.LastBlockHeight = wire.ReadVarint(r, n, err)
- s.LastBlockHash = wire.ReadByteSlice(r, n, err)
- s.LastBlockParts = wire.ReadBinary(types.PartSetHeader{}, r, n, err).(types.PartSetHeader)
- s.LastBlockTime = wire.ReadTime(r, n, err)
- s.BondedValidators = wire.ReadBinary(&types.ValidatorSet{}, r, n, err).(*types.ValidatorSet)
- s.LastBondedValidators = wire.ReadBinary(&types.ValidatorSet{}, r, n, err).(*types.ValidatorSet)
- s.UnbondingValidators = wire.ReadBinary(&types.ValidatorSet{}, r, n, err).(*types.ValidatorSet)
- accountsHash := wire.ReadByteSlice(r, n, err)
- s.accounts = merkle.NewIAVLTree(wire.BasicCodec, acm.AccountCodec, defaultAccountsCacheCapacity, db)
- s.accounts.Load(accountsHash)
- validatorInfosHash := wire.ReadByteSlice(r, n, err)
- s.validatorInfos = merkle.NewIAVLTree(wire.BasicCodec, types.ValidatorInfoCodec, 0, db)
- s.validatorInfos.Load(validatorInfosHash)
- nameRegHash := wire.ReadByteSlice(r, n, err)
- s.nameReg = merkle.NewIAVLTree(wire.BasicCodec, NameRegCodec, 0, db)
- s.nameReg.Load(nameRegHash)
- if *err != nil {
- // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
- Exit(Fmt("Data has been corrupted or its spec has changed: %v\n", *err))
- }
- // TODO: ensure that buf is completely read.
- }
- return s
- }
-
- func (s *State) Save() {
- s.accounts.Save()
- s.validatorInfos.Save()
- s.nameReg.Save()
- buf, n, err := new(bytes.Buffer), new(int64), new(error)
- wire.WriteString(s.ChainID, buf, n, err)
- wire.WriteVarint(s.LastBlockHeight, buf, n, err)
- wire.WriteByteSlice(s.LastBlockHash, buf, n, err)
- wire.WriteBinary(s.LastBlockParts, buf, n, err)
- wire.WriteTime(s.LastBlockTime, buf, n, err)
- wire.WriteBinary(s.BondedValidators, buf, n, err)
- wire.WriteBinary(s.LastBondedValidators, buf, n, err)
- wire.WriteBinary(s.UnbondingValidators, buf, n, err)
- wire.WriteByteSlice(s.accounts.Hash(), buf, n, err)
- wire.WriteByteSlice(s.validatorInfos.Hash(), buf, n, err)
- wire.WriteByteSlice(s.nameReg.Hash(), buf, n, err)
- if *err != nil {
- PanicCrisis(*err)
- }
- 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,
- 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(),
- nameReg: s.nameReg.Copy(),
- evc: nil,
- }
- }
-
- // Returns a hash that represents the state data, excluding Last*
- func (s *State) Hash() []byte {
- return merkle.SimpleHashFromMap(map[string]interface{}{
- "BondedValidators": s.BondedValidators,
- "UnbondingValidators": s.UnbondingValidators,
- "Accounts": s.accounts,
- "ValidatorInfos": s.validatorInfos,
- "NameRegistry": s.nameReg,
- })
- }
-
- // Mutates the block in place and updates it with new state hash.
- func (s *State) ComputeBlockStateHash(block *types.Block) error {
- sCopy := s.Copy()
- // sCopy has no event cache in it, so this won't fire events
- err := execBlock(sCopy, block, types.PartSetHeader{})
- if err != nil {
- return err
- }
- // Set block.StateHash
- block.StateHash = sCopy.Hash()
- return nil
- }
-
- func (s *State) SetDB(db dbm.DB) {
- s.DB = db
- }
-
- //-------------------------------------
- // State.params
-
- func (s *State) GetGasLimit() int64 {
- return 1000000 // TODO
- }
-
- // State.params
- //-------------------------------------
- // State.accounts
-
- // 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) *acm.Account {
- _, acc := s.accounts.Get(address)
- if acc == nil {
- return nil
- }
- return acc.(*acm.Account).Copy()
- }
-
- // The account is copied before setting, so mutating it
- // afterwards has no side effects.
- // Implements Statelike
- func (s *State) UpdateAccount(account *acm.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()
- }
-
- // Set the accounts tree
- func (s *State) SetAccounts(accounts merkle.Tree) {
- s.accounts = accounts
- }
-
- // State.accounts
- //-------------------------------------
- // State.validators
-
- // The returned ValidatorInfo is a copy, so mutating it
- // has no side effects.
- func (s *State) GetValidatorInfo(address []byte) *types.ValidatorInfo {
- _, valInfo := s.validatorInfos.Get(address)
- if valInfo == nil {
- return nil
- }
- return valInfo.(*types.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 *types.ValidatorInfo) (updated bool) {
- return s.validatorInfos.Set(valInfo.Address, valInfo.Copy())
- }
-
- func (s *State) GetValidatorInfos() merkle.Tree {
- return s.validatorInfos.Copy()
- }
-
- func (s *State) unbondValidator(val *types.Validator) {
- // Move validator to UnbondingValidators
- val, removed := s.BondedValidators.Remove(val.Address)
- if !removed {
- PanicCrisis("Couldn't remove validator for unbonding")
- }
- val.UnbondHeight = s.LastBlockHeight + 1
- added := s.UnbondingValidators.Add(val)
- if !added {
- PanicCrisis("Couldn't add validator for unbonding")
- }
- }
-
- func (s *State) rebondValidator(val *types.Validator) {
- // Move validator to BondingValidators
- val, removed := s.UnbondingValidators.Remove(val.Address)
- if !removed {
- PanicCrisis("Couldn't remove validator for rebonding")
- }
- val.BondHeight = s.LastBlockHeight + 1
- added := s.BondedValidators.Add(val)
- if !added {
- PanicCrisis("Couldn't add validator for rebonding")
- }
- }
-
- func (s *State) releaseValidator(val *types.Validator) {
- // Update validatorInfo
- valInfo := s.GetValidatorInfo(val.Address)
- if valInfo == nil {
- PanicSanity("Couldn't find validatorInfo for release")
- }
- valInfo.ReleasedHeight = s.LastBlockHeight + 1
- s.SetValidatorInfo(valInfo)
-
- // Send coins back to UnbondTo outputs
- accounts, err := getOrMakeOutputs(s, nil, valInfo.UnbondTo)
- if err != nil {
- PanicSanity("Couldn't get or make unbondTo accounts")
- }
- adjustByOutputs(accounts, valInfo.UnbondTo)
- for _, acc := range accounts {
- s.UpdateAccount(acc)
- }
-
- // Remove validator from UnbondingValidators
- _, removed := s.UnbondingValidators.Remove(val.Address)
- if !removed {
- PanicCrisis("Couldn't remove validator for release")
- }
- }
-
- func (s *State) destroyValidator(val *types.Validator) {
- // Update validatorInfo
- valInfo := s.GetValidatorInfo(val.Address)
- if valInfo == nil {
- PanicSanity("Couldn't find validatorInfo for release")
- }
- 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 {
- PanicCrisis("Couldn't remove validator for destruction")
- }
- }
-
- }
-
- // Set the validator infos tree
- func (s *State) SetValidatorInfos(validatorInfos merkle.Tree) {
- s.validatorInfos = validatorInfos
- }
-
- // State.validators
- //-------------------------------------
- // State.storage
-
- func (s *State) LoadStorage(hash []byte) (storage merkle.Tree) {
- storage = merkle.NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 1024, s.DB)
- storage.Load(hash)
- return storage
- }
-
- // State.storage
- //-------------------------------------
- // State.nameReg
-
- func (s *State) GetNameRegEntry(name string) *types.NameRegEntry {
- _, value := s.nameReg.Get(name)
- if value == nil {
- return nil
- }
- entry := value.(*types.NameRegEntry)
- return entry.Copy()
- }
-
- func (s *State) UpdateNameRegEntry(entry *types.NameRegEntry) bool {
- return s.nameReg.Set(entry.Name, entry)
- }
-
- func (s *State) RemoveNameRegEntry(name string) bool {
- _, removed := s.nameReg.Remove(name)
- return removed
- }
-
- func (s *State) GetNames() merkle.Tree {
- return s.nameReg.Copy()
- }
-
- // Set the name reg tree
- func (s *State) SetNameReg(nameReg merkle.Tree) {
- s.nameReg = nameReg
- }
-
- func NameRegEncoder(o interface{}, w io.Writer, n *int64, err *error) {
- wire.WriteBinary(o.(*types.NameRegEntry), w, n, err)
- }
-
- func NameRegDecoder(r io.Reader, n *int64, err *error) interface{} {
- return wire.ReadBinary(&types.NameRegEntry{}, r, n, err)
- }
-
- var NameRegCodec = wire.Codec{
- Encode: NameRegEncoder,
- Decode: NameRegDecoder,
- }
-
- // State.nameReg
- //-------------------------------------
-
- // Implements events.Eventable. Typically uses events.EventCache
- func (s *State) SetFireable(evc events.Fireable) {
- s.evc = evc
- }
-
- //-----------------------------------------------------------------------------
- // Genesis
-
- func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) (*GenesisDoc, *State) {
- jsonBlob, err := ioutil.ReadFile(genDocFile)
- if err != nil {
- Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
- }
- genDoc := GenesisDocFromJSON(jsonBlob)
- return genDoc, MakeGenesisState(db, genDoc)
- }
-
- func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State {
- if len(genDoc.Validators) == 0 {
- Exit(Fmt("The genesis file has no validators"))
- }
-
- if genDoc.GenesisTime.IsZero() {
- genDoc.GenesisTime = time.Now()
- }
-
- // Make accounts state tree
- accounts := merkle.NewIAVLTree(wire.BasicCodec, acm.AccountCodec, defaultAccountsCacheCapacity, db)
- for _, genAcc := range genDoc.Accounts {
- perm := ptypes.ZeroAccountPermissions
- if genAcc.Permissions != nil {
- perm = *genAcc.Permissions
- }
- acc := &acm.Account{
- Address: genAcc.Address,
- PubKey: nil,
- Sequence: 0,
- Balance: genAcc.Amount,
- Permissions: perm,
- }
- accounts.Set(acc.Address, acc)
- }
-
- // global permissions are saved as the 0 address
- // so they are included in the accounts tree
- globalPerms := ptypes.DefaultAccountPermissions
- if genDoc.Params != nil && genDoc.Params.GlobalPermissions != nil {
- globalPerms = *genDoc.Params.GlobalPermissions
- // XXX: make sure the set bits are all true
- // Without it the HasPermission() functions will fail
- globalPerms.Base.SetBit = ptypes.AllPermFlags
- }
-
- permsAcc := &acm.Account{
- Address: ptypes.GlobalPermissionsAddress,
- PubKey: nil,
- Sequence: 0,
- Balance: 1337,
- Permissions: globalPerms,
- }
- accounts.Set(permsAcc.Address, permsAcc)
-
- // Make validatorInfos state tree && validators slice
- validatorInfos := merkle.NewIAVLTree(wire.BasicCodec, types.ValidatorInfoCodec, 0, db)
- validators := make([]*types.Validator, len(genDoc.Validators))
- for i, val := range genDoc.Validators {
- pubKey := val.PubKey
- address := pubKey.Address()
-
- // Make ValidatorInfo
- valInfo := &types.ValidatorInfo{
- Address: address,
- PubKey: pubKey,
- UnbondTo: make([]*types.TxOutput, len(val.UnbondTo)),
- FirstBondHeight: 0,
- FirstBondAmount: val.Amount,
- }
- for i, unbondTo := range val.UnbondTo {
- valInfo.UnbondTo[i] = &types.TxOutput{
- Address: unbondTo.Address,
- Amount: unbondTo.Amount,
- }
- }
- validatorInfos.Set(address, valInfo)
-
- // Make validator
- validators[i] = &types.Validator{
- Address: address,
- PubKey: pubKey,
- VotingPower: val.Amount,
- }
- }
-
- // Make namereg tree
- nameReg := merkle.NewIAVLTree(wire.BasicCodec, NameRegCodec, 0, db)
- // TODO: add names, contracts to genesis.json
-
- // IAVLTrees must be persisted before copy operations.
- accounts.Save()
- validatorInfos.Save()
- nameReg.Save()
-
- return &State{
- DB: db,
- ChainID: genDoc.ChainID,
- LastBlockHeight: 0,
- LastBlockHash: nil,
- LastBlockParts: types.PartSetHeader{},
- LastBlockTime: genDoc.GenesisTime,
- BondedValidators: types.NewValidatorSet(validators),
- LastBondedValidators: types.NewValidatorSet(nil),
- UnbondingValidators: types.NewValidatorSet(nil),
- accounts: accounts,
- validatorInfos: validatorInfos,
- nameReg: nameReg,
- }
- }
-
- func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numValidators int, randBonded bool, minBonded int64) (*State, []*acm.PrivAccount, []*types.PrivValidator) {
- db := dbm.NewMemDB()
- genDoc, privAccounts, privValidators := RandGenesisDoc(numAccounts, randBalance, minBalance, numValidators, randBonded, minBonded)
- s0 := MakeGenesisState(db, genDoc)
- s0.Save()
- return s0, privAccounts, privValidators
- }
|