github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/mainchain/storages/account_store.go (about)

     1  package storages
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"bytes"
     7  
     8  	"encoding/binary"
     9  
    10  	"github.com/syndtr/goleveldb/leveldb/util"
    11  	"github.com/sixexorg/magnetic-ring/common"
    12  	"github.com/sixexorg/magnetic-ring/store/db"
    13  	mcom "github.com/sixexorg/magnetic-ring/store/mainchain/common"
    14  	"github.com/sixexorg/magnetic-ring/store/mainchain/states"
    15  )
    16  
    17  var (
    18  	zero = big.NewInt(0)
    19  )
    20  
    21  //prototype pattern
    22  type AccountStore struct {
    23  	enableCache bool
    24  	dbDir       string
    25  	store       *db.LevelDBStore
    26  	//cache *AccountCache
    27  }
    28  
    29  func NewAccoutStore(dbDir string, enableCache bool) (*AccountStore, error) {
    30  	var err error
    31  	store, err := db.NewLevelDBStore(dbDir)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	accountStore := &AccountStore{
    36  		dbDir:       dbDir,
    37  		store:       store,
    38  		enableCache: enableCache,
    39  	}
    40  	/*	if enableCache {
    41  		cache, err := NewAccountCache()
    42  		if err != nil {
    43  			return nil, err
    44  		}
    45  		accountStore.cache = cache
    46  	}*/
    47  	return accountStore, nil
    48  }
    49  
    50  //NewBatch start a commit batch
    51  func (this *AccountStore) NewBatch() {
    52  	this.store.NewBatch()
    53  }
    54  func (this *AccountStore) CommitTo() error {
    55  	return this.store.BatchCommit()
    56  }
    57  
    58  func (this *AccountStore) GetByHeight(height uint64, account common.Address) (*states.AccountState, error) {
    59  	key := this.getKey(account, height)
    60  	v, err := this.store.Get(key)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	bf := bytes.NewBuffer(key)
    65  	bf.Write(v)
    66  	as := &states.AccountState{}
    67  	err = as.Deserialize(bf)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	return as, nil
    72  }
    73  func (this *AccountStore) GetAccountRange(start, end uint64, account common.Address) (states.AccountStates, error) {
    74  	s := this.getKey(account, start)
    75  	l := this.getKey(account, end)
    76  	iter := this.store.NewSeniorIterator(&util.Range{Start: s, Limit: l})
    77  	ass := states.AccountStates{}
    78  	bf := bytes.NewBuffer(nil)
    79  	var err error
    80  	for iter.Next() {
    81  		bf.Write(iter.Key())
    82  		bf.Write(iter.Value())
    83  		as := &states.AccountState{}
    84  		err = as.Deserialize(bf)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  		ass = append(ass, as)
    89  		bf.Reset()
    90  	}
    91  	iter.Release()
    92  	return ass, nil
    93  }
    94  func (this *AccountStore) GetPrev(height uint64, account common.Address) (*states.AccountState, error) {
    95  	key := this.getKey(account, height)
    96  	iter := this.store.NewIterator(nil)
    97  	buff := bytes.NewBuffer(nil)
    98  	flag := true
    99  	if iter.Seek(key) {
   100  		if bytes.Compare(iter.Key(), key) == 0 {
   101  			buff.Write(iter.Key())
   102  			buff.Write(iter.Value())
   103  			flag = false
   104  		}
   105  	}
   106  	if flag && iter.Prev() {
   107  		buff.Write(iter.Key())
   108  		buff.Write(iter.Value())
   109  	}
   110  	iter.Release()
   111  	err := iter.Error()
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	if buff.Len() == 0 {
   116  		return &states.AccountState{
   117  			Address: account,
   118  			Data: &states.Account{
   119  				Balance:     big.NewInt(0),
   120  				EnergyBalance: big.NewInt(0),
   121  			},
   122  		}, nil
   123  	}
   124  	as := &states.AccountState{}
   125  	err = as.Deserialize(buff)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	if as.Address.Equals(account) {
   131  		return as, nil
   132  	}
   133  	return &states.AccountState{
   134  		Address: account,
   135  		Data: &states.Account{
   136  			Balance:     big.NewInt(0),
   137  			EnergyBalance: big.NewInt(0),
   138  		},
   139  	}, nil
   140  }
   141  
   142  //SaveBlock persist block to store
   143  func (this *AccountStore) Save(account *states.AccountState) error {
   144  	key := account.GetKey()
   145  	buff := new(bytes.Buffer)
   146  	err := account.Serialize(buff)
   147  	if err != nil {
   148  		return err
   149  	}
   150  	err = this.store.Put(key, buff.Bytes())
   151  	if err != nil {
   152  		return err
   153  
   154  	}
   155  	return nil
   156  }
   157  func (this *AccountStore) BatchSave(states states.AccountStates) error {
   158  	for _, v := range states {
   159  		key := v.GetKey()
   160  		buff := new(bytes.Buffer)
   161  		err := v.Serialize(buff)
   162  		if err != nil {
   163  			return err
   164  		}
   165  		this.store.BatchPut(key, buff.Bytes())
   166  
   167  	}
   168  	return nil
   169  }
   170  
   171  func (this *AccountStore) getKey(account common.Address, height uint64) []byte {
   172  	buff := make([]byte, 1+common.AddrLength+8)
   173  	buff[0] = byte(mcom.ST_ACCOUNT)
   174  	copy(buff[1:common.AddrLength+1], account[:])
   175  	binary.LittleEndian.PutUint64(buff[common.AddrLength+1:], height)
   176  	return buff
   177  }