...
This commit is contained in:
parent
8facbdf809
commit
b73b7a54c7
|
@ -55,6 +55,6 @@ func (db *LevelDB) Print() {
|
|||
for iter.Next() {
|
||||
key := iter.Key()
|
||||
value := iter.Value()
|
||||
fmt.Printf("[%x]:\t[%x]", key, value)
|
||||
fmt.Printf("[%X]:\t[%X]\n", key, value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,6 @@ func (db *MemDB) Delete(key []byte) {
|
|||
|
||||
func (db *MemDB) Print() {
|
||||
for key, value := range db.db {
|
||||
fmt.Printf("[%x]:\t[%x]", []byte(key), value)
|
||||
fmt.Printf("[%X]:\t[%X]\n", []byte(key), value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ func (t *IAVLTree) Copy() Tree {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// TODO: make TypedTree work with the underlying tree to cache the decoded value.
|
||||
type TypedTree struct {
|
||||
Tree Tree
|
||||
keyCodec Codec
|
||||
|
@ -183,6 +184,14 @@ func (t *TypedTree) Remove(key interface{}) (interface{}, error) {
|
|||
return value, err
|
||||
}
|
||||
|
||||
func (t *TypedTree) Copy() *TypedTree {
|
||||
return &TypedTree{
|
||||
Tree: t.Tree.Copy(),
|
||||
keyCodec: t.keyCodec,
|
||||
valueCodec: t.valueCodec,
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
type nodeElement struct {
|
||||
|
|
112
state/state.go
112
state/state.go
|
@ -18,40 +18,55 @@ var (
|
|||
stateKey = []byte("stateKey")
|
||||
)
|
||||
|
||||
type State struct {
|
||||
mtx sync.Mutex
|
||||
db DB
|
||||
height uint32 // Last known block height
|
||||
blockHash []byte // Last known block hash
|
||||
commitTime time.Time
|
||||
accounts merkle.Tree
|
||||
validators *ValidatorSet
|
||||
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 GenesisState(db DB, genesisTime time.Time, accountBalances []*AccountBalance) *State {
|
||||
func (abc accountBalanceCodec) Read(accBalBytes []byte) (interface{}, error) {
|
||||
n, err, r := new(int64), new(error), bytes.NewBuffer(accBalBytes)
|
||||
return ReadAccountBalance(r, n, err), *err
|
||||
}
|
||||
|
||||
accounts := merkle.NewIAVLTree(db)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
type State struct {
|
||||
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
|
||||
}
|
||||
|
||||
func GenesisState(db DB, genesisTime time.Time, accBals []*AccountBalance) *State {
|
||||
|
||||
// TODO: Use "uint64Codec" instead of BasicCodec
|
||||
accountBalances := merkle.NewTypedTree(merkle.NewIAVLTree(db), BasicCodec, accountBalanceCodec{})
|
||||
validators := map[uint64]*Validator{}
|
||||
|
||||
for _, account := range accountBalances {
|
||||
// XXX make codec merkle tree.
|
||||
//accounts.Set(account.Id, BinaryBytes(account))
|
||||
validators[account.Id] = &Validator{
|
||||
Account: account.Account,
|
||||
for _, accBal := range accBals {
|
||||
accountBalances.Set(accBal.Id, accBal)
|
||||
validators[accBal.Id] = &Validator{
|
||||
Account: accBal.Account,
|
||||
BondHeight: 0,
|
||||
VotingPower: account.Balance,
|
||||
VotingPower: accBal.Balance,
|
||||
Accum: 0,
|
||||
}
|
||||
}
|
||||
validatorSet := NewValidatorSet(validators)
|
||||
|
||||
return &State{
|
||||
db: db,
|
||||
height: 0,
|
||||
blockHash: nil,
|
||||
commitTime: genesisTime,
|
||||
accounts: accounts,
|
||||
validators: validatorSet,
|
||||
db: db,
|
||||
height: 0,
|
||||
blockHash: nil,
|
||||
commitTime: genesisTime,
|
||||
accountBalances: accountBalances,
|
||||
validators: validatorSet,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,8 +82,8 @@ func LoadState(db DB) *State {
|
|||
s.height = ReadUInt32(reader, &n, &err)
|
||||
s.commitTime = ReadTime(reader, &n, &err)
|
||||
s.blockHash = ReadByteSlice(reader, &n, &err)
|
||||
accountsMerkleRoot := ReadByteSlice(reader, &n, &err)
|
||||
s.accounts = merkle.LoadIAVLTreeFromHash(db, accountsMerkleRoot)
|
||||
accountBalancesHash := ReadByteSlice(reader, &n, &err)
|
||||
s.accountBalances = merkle.NewTypedTree(merkle.LoadIAVLTreeFromHash(db, accountBalancesHash), BasicCodec, accountBalanceCodec{})
|
||||
var validators = map[uint64]*Validator{}
|
||||
for reader.Len() > 0 {
|
||||
validator := ReadValidator(reader, &n, &err)
|
||||
|
@ -89,14 +104,14 @@ func (s *State) Save(commitTime time.Time) {
|
|||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
s.commitTime = commitTime
|
||||
s.accounts.Save()
|
||||
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)
|
||||
WriteByteSlice(&buf, s.blockHash, &n, &err)
|
||||
WriteByteSlice(&buf, s.accounts.Hash(), &n, &err)
|
||||
WriteByteSlice(&buf, s.accountBalances.Tree.Hash(), &n, &err)
|
||||
for _, validator := range s.validators.Map() {
|
||||
WriteBinary(&buf, validator, &n, &err)
|
||||
}
|
||||
|
@ -110,24 +125,24 @@ func (s *State) Copy() *State {
|
|||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
return &State{
|
||||
db: s.db,
|
||||
height: s.height,
|
||||
commitTime: s.commitTime,
|
||||
blockHash: s.blockHash,
|
||||
accounts: s.accounts.Copy(),
|
||||
validators: s.validators.Copy(),
|
||||
db: s.db,
|
||||
height: s.height,
|
||||
commitTime: s.commitTime,
|
||||
blockHash: s.blockHash,
|
||||
accountBalances: s.accountBalances.Copy(),
|
||||
validators: s.validators.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// If the tx is invalid, an error will be returned.
|
||||
// Unlike CommitBlock(), state will not be altered.
|
||||
func (s *State) CommitTx(tx Tx) error {
|
||||
// Unlike AppendBlock(), state will not be altered.
|
||||
func (s *State) ExecTx(tx Tx) error {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
return s.commitTx(tx)
|
||||
return s.execTx(tx)
|
||||
}
|
||||
|
||||
func (s *State) commitTx(tx Tx) error {
|
||||
func (s *State) execTx(tx Tx) error {
|
||||
/*
|
||||
// Get the signer's incr
|
||||
signerId := tx.Signature().SignerId
|
||||
|
@ -136,13 +151,13 @@ func (s *State) commitTx(tx Tx) error {
|
|||
}
|
||||
*/
|
||||
// XXX commit the tx
|
||||
panic("Implement CommitTx()")
|
||||
panic("Implement ExecTx()")
|
||||
return nil
|
||||
}
|
||||
|
||||
// NOTE: If an error occurs during block execution, state will be left
|
||||
// at an invalid state. Copy the state before calling Commit!
|
||||
func (s *State) CommitBlock(b *Block) error {
|
||||
func (s *State) AppendBlock(b *Block) error {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
|
@ -154,14 +169,15 @@ func (s *State) CommitBlock(b *Block) error {
|
|||
|
||||
// Commit each tx
|
||||
for _, tx := range b.Data.Txs {
|
||||
err := s.commitTx(tx)
|
||||
err := s.execTx(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// After all state has been mutated, finally increment validators.
|
||||
s.validators.IncrementAccum()
|
||||
s.height = b.Height
|
||||
s.blockHash = b.Hash()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -184,18 +200,12 @@ func (s *State) Validators() *ValidatorSet {
|
|||
return s.validators
|
||||
}
|
||||
|
||||
func (s *State) AccountBalance(accountId uint64) (*AccountBalance, error) {
|
||||
func (s *State) AccountBalance(accountId uint64) *AccountBalance {
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
idBytes, err := BasicCodec.Write(accountId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
accBal := s.accountBalances.Get(accountId)
|
||||
if accBal == nil {
|
||||
return nil
|
||||
}
|
||||
accountBytes := s.accounts.Get(idBytes)
|
||||
if accountBytes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
n, err := int64(0), error(nil)
|
||||
accountBalance := ReadAccountBalance(bytes.NewBuffer(accountBytes), &n, &err)
|
||||
return accountBalance, err
|
||||
return accBal.(*AccountBalance)
|
||||
}
|
||||
|
|
|
@ -36,7 +36,36 @@ func randGenesisState(numAccounts int, numValidators int) *State {
|
|||
|
||||
func TestGenesisSaveLoad(t *testing.T) {
|
||||
|
||||
// Generate a state, save & load it.
|
||||
s0 := randGenesisState(10, 5)
|
||||
t.Log(s0)
|
||||
// Mutate the state to append one block.
|
||||
block := &Block{Data: Data{Txs: []Tx{}}}
|
||||
s0.AppendBlock(block)
|
||||
|
||||
// Save s0, load s1.
|
||||
commitTime := time.Now()
|
||||
s0.Save(commitTime)
|
||||
// s0.db.(*MemDB).Print()
|
||||
s1 := LoadState(s0.db)
|
||||
|
||||
// Compare CommitTime
|
||||
if commitTime.Unix() != s1.CommitTime().Unix() {
|
||||
t.Error("CommitTime was not the same")
|
||||
}
|
||||
// Compare height & blockHash
|
||||
// XXX
|
||||
// Compare Validators
|
||||
s0Vals := s0.Validators()
|
||||
s1Vals := s1.Validators()
|
||||
if s0Vals.Size() != s1Vals.Size() {
|
||||
t.Error("Validators Size changed")
|
||||
}
|
||||
if s0Vals.TotalVotingPower() == 0 {
|
||||
t.Error("s0 Validators TotalVotingPower should not be 0")
|
||||
}
|
||||
if s0Vals.TotalVotingPower() != s1Vals.TotalVotingPower() {
|
||||
t.Error("Validators TotalVotingPower changed")
|
||||
}
|
||||
// TODO Compare accountBalances, height, blockHash
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue