Browse Source

...

pull/9/head
Jae Kwon 10 years ago
parent
commit
b73b7a54c7
5 changed files with 101 additions and 53 deletions
  1. +1
    -1
      db/level_db.go
  2. +1
    -1
      db/mem_db.go
  3. +9
    -0
      merkle/iavl_tree.go
  4. +60
    -50
      state/state.go
  5. +30
    -1
      state/state_test.go

+ 1
- 1
db/level_db.go View File

@ -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)
}
}

+ 1
- 1
db/mem_db.go View File

@ -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)
}
}

+ 9
- 0
merkle/iavl_tree.go View File

@ -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 {


+ 60
- 50
state/state.go View File

@ -18,40 +18,55 @@ var (
stateKey = []byte("stateKey")
)
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
}
//-----------------------------------------------------------------------------
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
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, accountBalances []*AccountBalance) *State {
func GenesisState(db DB, genesisTime time.Time, accBals []*AccountBalance) *State {
accounts := merkle.NewIAVLTree(db)
// 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
}
accountBytes := s.accounts.Get(idBytes)
if accountBytes == nil {
return nil, nil
accBal := s.accountBalances.Get(accountId)
if accBal == nil {
return nil
}
n, err := int64(0), error(nil)
accountBalance := ReadAccountBalance(bytes.NewBuffer(accountBytes), &n, &err)
return accountBalance, err
return accBal.(*AccountBalance)
}

+ 30
- 1
state/state_test.go View File

@ -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…
Cancel
Save