Newer
Older
acm "github.com/eris-ltd/eris-db/account"
ptypes "github.com/eris-ltd/eris-db/permission/types"
. "github.com/eris-ltd/eris-db/state/types"
txs "github.com/eris-ltd/eris-db/txs"
. "github.com/tendermint/go-common"
dbm "github.com/tendermint/go-db"
"github.com/tendermint/go-events"
"github.com/tendermint/go-merkle"
"github.com/tendermint/go-wire"
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(int), new(error)
s.ChainID = wire.ReadString(r, maxLoadStateElementSize, n, err)
s.LastBlockHash = wire.ReadByteSlice(r, maxLoadStateElementSize, n, err)
s.LastBlockParts = wire.ReadBinary(types.PartSetHeader{}, r, maxLoadStateElementSize, n, err).(types.PartSetHeader)
// s.BondedValidators = wire.ReadBinary(&types.ValidatorSet{}, r, maxLoadStateElementSize, n, err).(*types.ValidatorSet)
// s.LastBondedValidators = wire.ReadBinary(&types.ValidatorSet{}, r, maxLoadStateElementSize, n, err).(*types.ValidatorSet)
// s.UnbondingValidators = wire.ReadBinary(&types.ValidatorSet{}, r, maxLoadStateElementSize, n, err).(*types.ValidatorSet)
accountsHash := wire.ReadByteSlice(r, maxLoadStateElementSize, n, err)
s.accounts = merkle.NewIAVLTree(defaultAccountsCacheCapacity, db)
//validatorInfosHash := wire.ReadByteSlice(r, maxLoadStateElementSize, n, err)
//s.validatorInfos = merkle.NewIAVLTree(wire.BasicCodec, types.ValidatorInfoCodec, 0, db)
//s.validatorInfos.Load(validatorInfosHash)
nameRegHash := wire.ReadByteSlice(r, maxLoadStateElementSize, n, err)
// 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()
buf, n, err := new(bytes.Buffer), new(int), 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.validatorInfos.Hash(), buf, n, 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
}
Casey Kuhlman
committed
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.
_, accBytes, _ := s.accounts.Get(address)
if accBytes == nil {
}
// The account is copied before setting, so mutating it
// afterwards has no side effects.
// Implements Statelike
return s.accounts.Set(account.Address, acm.EncodeAccount(account))
}
// 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()
}
Casey Kuhlman
committed
// Set the accounts tree
func (s *State) SetAccounts(accounts merkle.Tree) {
s.accounts = accounts
}
// State.accounts
//-------------------------------------
// State.validators
// XXX: now handled by tendermint core
/*
// 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
}
}
// 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())
}
Casey Kuhlman
committed
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 {
}
val.UnbondHeight = s.LastBlockHeight + 1
added := s.UnbondingValidators.Add(val)
if !added {
func (s *State) rebondValidator(val *types.Validator) {
// Move validator to BondingValidators
val, removed := s.UnbondingValidators.Remove(val.Address)
if !removed {
}
val.BondHeight = s.LastBlockHeight + 1
added := s.BondedValidators.Add(val)
if !added {
func (s *State) releaseValidator(val *types.Validator) {
// Update validatorInfo
valInfo := s.GetValidatorInfo(val.Address)
if valInfo == nil {
}
valInfo.ReleasedHeight = s.LastBlockHeight + 1
s.SetValidatorInfo(valInfo)
// Send coins back to UnbondTo outputs
Casey Kuhlman
committed
accounts, err := getOrMakeOutputs(s, nil, valInfo.UnbondTo)
}
adjustByOutputs(accounts, valInfo.UnbondTo)
for _, acc := range accounts {
s.UpdateAccount(acc)
}
// Remove validator from UnbondingValidators
_, removed := s.UnbondingValidators.Remove(val.Address)
if !removed {
func (s *State) destroyValidator(val *types.Validator) {
// Update validatorInfo
valInfo := s.GetValidatorInfo(val.Address)
if valInfo == nil {
}
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 {
Casey Kuhlman
committed
// 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.Load(hash)
return storage
}
// State.storage
//-------------------------------------
// State.nameReg
func (s *State) GetNameRegEntry(name string) *txs.NameRegEntry {
_, valueBytes, _ := s.nameReg.Get([]byte(name))
if valueBytes == nil {
func DecodeNameRegEntry(entryBytes []byte) *txs.NameRegEntry {
var n int
var err error
value := NameRegCodec.Decode(bytes.NewBuffer(entryBytes), &n, &err)
return value.(*txs.NameRegEntry)
}
func (s *State) UpdateNameRegEntry(entry *txs.NameRegEntry) bool {
w := new(bytes.Buffer)
var n int
var err error
NameRegCodec.Encode(entry, w, &n, &err)
return s.nameReg.Set([]byte(entry.Name), w.Bytes())
}
func (s *State) RemoveNameRegEntry(name string) bool {
return removed
}
func (s *State) GetNames() merkle.Tree {
return s.nameReg.Copy()
}
Casey Kuhlman
committed
// Set the name reg tree
func (s *State) SetNameReg(nameReg merkle.Tree) {
s.nameReg = nameReg
}
func NameRegEncoder(o interface{}, w io.Writer, n *int, err *error) {
wire.WriteBinary(o.(*txs.NameRegEntry), w, n, err)
func NameRegDecoder(r io.Reader, n *int, err *error) interface{} {
return wire.ReadBinary(&txs.NameRegEntry{}, r, txs.MaxDataLength, n, err)
Encode: NameRegEncoder,
Decode: NameRegDecoder,
}
// State.nameReg
//-------------------------------------
// Implements events.Eventable. Typically uses events.EventCache
func (s *State) SetFireable(evc events.Fireable) {
s.evc = evc
}
//-----------------------------------------------------------------------------
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(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,
}
}
// 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, acm.EncodeAccount(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,
}
// TODO: add names, contracts to genesis.json
// IAVLTrees must be persisted before copy operations.
accounts.Save()
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,