tendermint/state/state.go

232 lines
5.7 KiB
Go
Raw Normal View History

package state
import (
"bytes"
"errors"
"sync"
"time"
. "github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/blocks"
2014-10-04 19:16:49 -07:00
. "github.com/tendermint/tendermint/db"
"github.com/tendermint/tendermint/merkle"
)
var (
2014-10-07 00:43:34 -07:00
ErrStateInvalidSequenceNumber = errors.New("Error State invalid sequence number")
ErrStateInvalidValidationStateHash = errors.New("Error State invalid ValidationStateHash")
ErrStateInvalidAccountStateHash = errors.New("Error State invalid AccountStateHash")
stateKey = []byte("stateKey")
)
2014-10-06 21:28:49 -07:00
type accountBalanceCodec struct{}
func (abc accountBalanceCodec) Write(accBal interface{}) (accBalBytes []byte, err error) {
w := new(bytes.Buffer)
_, err = accBal.(*AccountBalance).WriteTo(w)
return w.Bytes(), err
}
func (abc accountBalanceCodec) Read(accBalBytes []byte) (interface{}, error) {
n, err, r := new(int64), new(error), bytes.NewBuffer(accBalBytes)
return ReadAccountBalance(r, n, err), *err
}
//-----------------------------------------------------------------------------
2014-10-07 00:43:34 -07:00
// TODO: make it unsafe, remove mtx, and export fields?
type State struct {
2014-10-06 21:28:49 -07:00
mtx sync.Mutex
db DB
height uint32 // Last known block height
blockHash []byte // Last known block hash
commitTime time.Time
accountBalances *merkle.TypedTree
validators *ValidatorSet
}
2014-10-06 21:28:49 -07:00
func GenesisState(db DB, genesisTime time.Time, accBals []*AccountBalance) *State {
2014-10-04 19:16:49 -07:00
2014-10-06 21:28:49 -07:00
// TODO: Use "uint64Codec" instead of BasicCodec
accountBalances := merkle.NewTypedTree(merkle.NewIAVLTree(db), BasicCodec, accountBalanceCodec{})
2014-10-04 19:16:49 -07:00
validators := map[uint64]*Validator{}
2014-10-06 21:28:49 -07:00
for _, accBal := range accBals {
accountBalances.Set(accBal.Id, accBal)
validators[accBal.Id] = &Validator{
Account: accBal.Account,
2014-10-04 19:16:49 -07:00
BondHeight: 0,
2014-10-06 21:28:49 -07:00
VotingPower: accBal.Balance,
2014-10-04 19:16:49 -07:00
Accum: 0,
}
}
validatorSet := NewValidatorSet(validators)
return &State{
2014-10-06 21:28:49 -07:00
db: db,
height: 0,
blockHash: nil,
commitTime: genesisTime,
accountBalances: accountBalances,
validators: validatorSet,
2014-10-04 19:16:49 -07:00
}
2014-10-03 17:59:54 -07:00
}
2014-10-04 19:16:49 -07:00
func LoadState(db DB) *State {
s := &State{db: db}
buf := db.Get(stateKey)
if len(buf) == 0 {
2014-10-03 17:59:54 -07:00
return nil
} else {
reader := bytes.NewReader(buf)
var n int64
var err error
s.height = ReadUInt32(reader, &n, &err)
s.commitTime = ReadTime(reader, &n, &err)
2014-09-11 22:44:59 -07:00
s.blockHash = ReadByteSlice(reader, &n, &err)
2014-10-06 21:28:49 -07:00
accountBalancesHash := ReadByteSlice(reader, &n, &err)
s.accountBalances = merkle.NewTypedTree(merkle.LoadIAVLTreeFromHash(db, accountBalancesHash), BasicCodec, accountBalanceCodec{})
2014-09-14 15:37:32 -07:00
var validators = map[uint64]*Validator{}
for reader.Len() > 0 {
validator := ReadValidator(reader, &n, &err)
2014-09-14 15:37:32 -07:00
validators[validator.Id] = validator
}
2014-09-14 15:37:32 -07:00
s.validators = NewValidatorSet(validators)
if err != nil {
panic(err)
}
}
return s
}
// Save this state into the db.
2014-09-11 10:55:32 -07:00
// For convenience, the commitTime (required by ConsensusAgent)
// is saved here.
func (s *State) Save(commitTime time.Time) {
s.mtx.Lock()
defer s.mtx.Unlock()
s.commitTime = commitTime
2014-10-06 21:28:49 -07:00
s.accountBalances.Tree.Save()
var buf bytes.Buffer
var n int64
var err error
WriteUInt32(&buf, s.height, &n, &err)
WriteTime(&buf, commitTime, &n, &err)
2014-09-11 22:44:59 -07:00
WriteByteSlice(&buf, s.blockHash, &n, &err)
2014-10-06 21:28:49 -07:00
WriteByteSlice(&buf, s.accountBalances.Tree.Hash(), &n, &err)
for _, validator := range s.validators.Map() {
WriteBinary(&buf, validator, &n, &err)
}
if err != nil {
panic(err)
}
s.db.Set(stateKey, buf.Bytes())
}
func (s *State) Copy() *State {
s.mtx.Lock()
defer s.mtx.Unlock()
return &State{
2014-10-06 21:28:49 -07:00
db: s.db,
height: s.height,
commitTime: s.commitTime,
blockHash: s.blockHash,
accountBalances: s.accountBalances.Copy(),
validators: s.validators.Copy(),
}
}
2014-09-11 22:44:59 -07:00
// If the tx is invalid, an error will be returned.
2014-10-06 21:28:49 -07:00
// Unlike AppendBlock(), state will not be altered.
func (s *State) ExecTx(tx Tx) error {
s.mtx.Lock()
defer s.mtx.Unlock()
2014-10-06 21:28:49 -07:00
return s.execTx(tx)
2014-09-11 22:44:59 -07:00
}
2014-10-06 21:28:49 -07:00
func (s *State) execTx(tx Tx) error {
/*
// Get the signer's incr
signerId := tx.Signature().SignerId
if mem.state.AccountSequence(signerId) != tx.Sequence() {
return ErrStateInvalidSequenceNumber
}
*/
2014-10-03 17:59:54 -07:00
// XXX commit the tx
2014-10-06 21:28:49 -07:00
panic("Implement ExecTx()")
return nil
}
2014-09-11 22:44:59 -07:00
// NOTE: If an error occurs during block execution, state will be left
// at an invalid state. Copy the state before calling Commit!
2014-10-06 21:28:49 -07:00
func (s *State) AppendBlock(b *Block) error {
s.mtx.Lock()
defer s.mtx.Unlock()
2014-09-11 22:44:59 -07:00
// Basic block validation.
err := b.ValidateBasic(s.height, s.blockHash)
if err != nil {
return err
}
// Commit each tx
for _, tx := range b.Data.Txs {
2014-10-06 21:28:49 -07:00
err := s.execTx(tx)
2014-09-11 22:44:59 -07:00
if err != nil {
return err
}
}
2014-10-07 00:43:34 -07:00
// Increment validator AccumPowers
2014-09-08 16:27:58 -07:00
s.validators.IncrementAccum()
2014-10-07 00:43:34 -07:00
// State hashes should match
if !bytes.Equal(s.validators.Hash(), b.ValidationStateHash) {
return ErrStateInvalidValidationStateHash
}
if !bytes.Equal(s.accountBalances.Tree.Hash(), b.AccountStateHash) {
return ErrStateInvalidAccountStateHash
}
2014-10-06 21:28:49 -07:00
s.height = b.Height
s.blockHash = b.Hash()
return nil
}
func (s *State) Height() uint32 {
s.mtx.Lock()
defer s.mtx.Unlock()
return s.height
}
func (s *State) CommitTime() time.Time {
s.mtx.Lock()
defer s.mtx.Unlock()
return s.commitTime
}
2014-10-07 00:43:34 -07:00
// The returned ValidatorSet gets mutated upon s.ExecTx() and s.AppendBlock().
// Caller should copy the returned set before mutating.
func (s *State) Validators() *ValidatorSet {
s.mtx.Lock()
defer s.mtx.Unlock()
return s.validators
}
2014-10-07 00:43:34 -07:00
func (s *State) BlockHash() []byte {
s.mtx.Lock()
defer s.mtx.Unlock()
return s.blockHash
}
2014-10-06 21:28:49 -07:00
func (s *State) AccountBalance(accountId uint64) *AccountBalance {
s.mtx.Lock()
defer s.mtx.Unlock()
2014-10-06 21:28:49 -07:00
accBal := s.accountBalances.Get(accountId)
if accBal == nil {
return nil
}
2014-10-06 21:28:49 -07:00
return accBal.(*AccountBalance)
}