github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/store/mainchain/extstorages/league_account_store.go (about) 1 package extstorages 2 3 import ( 4 "bytes" 5 6 "math/big" 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/common/sink" 13 "github.com/sixexorg/magnetic-ring/errors" 14 "github.com/sixexorg/magnetic-ring/store/db" 15 mcom "github.com/sixexorg/magnetic-ring/store/mainchain/common" 16 "github.com/sixexorg/magnetic-ring/store/mainchain/extstates" 17 "github.com/sixexorg/magnetic-ring/store/storelaw" 18 ) 19 20 //Redundancy of the leagues data 21 type ExternalLeague struct { 22 enableCache bool 23 dbDir string 24 store *db.LevelDBStore 25 } 26 27 func NewExternalLeague(dbDir string, enableCache bool) (*ExternalLeague, error) { 28 store, err := db.NewLevelDBStore(dbDir) 29 if err != nil { 30 return nil, err 31 } 32 el := new(ExternalLeague) 33 34 el.enableCache = enableCache 35 el.dbDir = dbDir 36 el.store = store 37 return el, nil 38 } 39 40 //NewBatch start a commit batch 41 func (this *ExternalLeague) NewBatch() { 42 this.store.NewBatch() 43 } 44 func (this *ExternalLeague) CommitTo() error { 45 return this.store.BatchCommit() 46 } 47 48 func (this *ExternalLeague) GetAccountByHeight(account, leagueId common.Address, height uint64) (*extstates.Account, error) { 49 key := this.getKey(leagueId, account, height) 50 //fmt.Println("🛢 🛢 🛢 🛢 🛢 🛢 get ", hex.EncodeToString(key)) 51 val, err := this.store.Get(key) 52 if err != nil { 53 return nil, err 54 } 55 acc, err := this.deserializeAccount(val) 56 if err != nil { 57 return nil, err 58 } 59 return acc, nil 60 } 61 func (this *ExternalLeague) GetPrev(height uint64, account, leagueId common.Address) (storelaw.AccountStater, error) { 62 key := this.getKey(leagueId, account, height) 63 iter := this.store.NewIterator(nil) 64 buff := bytes.NewBuffer(nil) 65 flag := true 66 if iter.Seek(key) { 67 if bytes.Compare(iter.Key(), key) == 0 { 68 buff.Write(iter.Key()) 69 buff.Write(iter.Value()) 70 flag = false 71 } 72 } 73 if flag && iter.Prev() { 74 buff.Write(iter.Key()) 75 buff.Write(iter.Value()) 76 } 77 iter.Release() 78 err := iter.Error() 79 if err != nil { 80 return nil, err 81 } 82 if buff.Len() == 0 { 83 return &extstates.LeagueAccountState{ 84 Address: account, 85 LeagueId: leagueId, 86 Height: height, 87 Data: &extstates.Account{ 88 Balance: big.NewInt(0), 89 EnergyBalance: big.NewInt(0), 90 }, 91 }, nil 92 } 93 as := &extstates.LeagueAccountState{} 94 err = as.Deserialize(buff) 95 if err != nil { 96 return nil, err 97 } 98 if as.Address.Equals(account) && as.LeagueId.Equals(leagueId) { 99 return as, nil 100 } 101 return &extstates.LeagueAccountState{ 102 Address: account, 103 LeagueId: leagueId, 104 Height: height, 105 Data: &extstates.Account{ 106 Balance: big.NewInt(0), 107 EnergyBalance: big.NewInt(0), 108 }, 109 }, nil 110 } 111 func (this *ExternalLeague) GetAccountRange(start, end uint64, account, leagueId common.Address) (storelaw.AccountStaters, error) { 112 s := this.getKey(leagueId, account, start) 113 l := this.getKey(leagueId, account, end) 114 iter := this.store.NewSeniorIterator(&util.Range{Start: s, Limit: l}) 115 ass := storelaw.AccountStaters{} 116 bf := bytes.NewBuffer(nil) 117 var err error 118 for iter.Next() { 119 bf.Write(iter.Key()) 120 bf.Write(iter.Value()) 121 as := &extstates.LeagueAccountState{} 122 err = as.Deserialize(bf) 123 if err != nil { 124 return nil, err 125 } 126 ass = append(ass, as) 127 bf.Reset() 128 } 129 iter.Release() 130 return ass, nil 131 } 132 133 //SaveBlock persist block to store 134 func (this *ExternalLeague) Save(state storelaw.AccountStater) error { 135 key := state.GetKey() 136 buff := new(bytes.Buffer) 137 err := state.Serialize(buff) 138 if err != nil { 139 return err 140 } 141 err = this.store.Put(key, buff.Bytes()) 142 if err != nil { 143 return err 144 } 145 return nil 146 } 147 func (this *ExternalLeague) BatchSave(states storelaw.AccountStaters) error { 148 for _, v := range states { 149 key := v.GetKey() 150 //fmt.Println("🛢 🛢 🛢 🛢 🛢 🛢 save ", hex.EncodeToString(key)) 151 buff := new(bytes.Buffer) 152 err := v.Serialize(buff) 153 if err != nil { 154 return err 155 } 156 this.store.BatchPut(key, buff.Bytes()) 157 } 158 return nil 159 } 160 161 func (this *ExternalLeague) getKey(leagueId, account common.Address, height uint64) []byte { 162 buff := make([]byte, 1+2*common.AddrLength+8) 163 buff[0] = byte(mcom.EXT_LEAGUE_ACCOUNT) 164 copy(buff[1:common.AddrLength+1], leagueId[:]) 165 copy(buff[common.AddrLength+1:common.AddrLength*2+1], account[:]) 166 binary.LittleEndian.PutUint64(buff[common.AddrLength*2+1:], height) 167 return buff 168 } 169 170 func (this *ExternalLeague) deserializeAccount(val []byte) (*extstates.Account, error) { 171 source := sink.NewZeroCopySource(val) 172 account := &extstates.Account{} 173 eof := false 174 var err error 175 account.Nonce, eof = source.NextUint64() 176 bal, eof := source.NextComplex() 177 account.Balance, err = bal.ComplexToBigInt() 178 if err != nil { 179 return nil, err 180 } 181 bbl, eof := source.NextComplex() 182 account.EnergyBalance, err = bbl.ComplexToBigInt() 183 if err != nil { 184 return nil, err 185 } 186 account.BonusHeight, eof = source.NextUint64() 187 if eof { 188 return nil, errors.ERR_TXRAW_EOF 189 } 190 return account, nil 191 }