9 "github.com/vapor/asset"
10 "github.com/vapor/blockchain/query"
11 "github.com/vapor/common"
12 dbm "github.com/vapor/database/leveldb"
13 "github.com/vapor/errors"
14 "github.com/vapor/protocol/bc"
17 var errAccntTxIDNotFound = errors.New("account TXID not found")
20 UTXOPrefix = "ACU:" //UTXOPrefix is StandardUTXOKey prefix
21 SUTXOPrefix = "SCU:" //SUTXOPrefix is ContractUTXOKey prefix
22 contractPrefix = "Contract:"
23 accountPrefix = "Account:"
24 TxPrefix = "TXS:" //TxPrefix is wallet database transactions prefix
25 TxIndexPrefix = "TID:" //TxIndexPrefix is wallet database tx index prefix
26 UnconfirmedTxPrefix = "UTXS:" //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
27 GlobalTxIndexPrefix = "GTID:" //GlobalTxIndexPrefix is wallet database global tx index prefix
28 walletKey = "walletInfo"
31 // WalletStorer interface contains wallet storage functions.
32 type WalletStorer interface {
35 GetAssetDefinition(*bc.AssetID) []byte
36 SetAssetDefinition(*bc.AssetID, []byte)
37 GetRawProgram(common.Hash) []byte
38 GetAccountByAccountID(string) []byte
39 DeleteTransactions(uint64)
40 SetTransaction(uint64, uint32, string, []byte)
41 DeleteUnconfirmedTransaction(string)
42 SetGlobalTransactionIndex(string, *bc.Hash, uint64)
43 GetStandardUTXO(bc.Hash) []byte
44 GetTransaction(string) ([]byte, error)
45 GetGlobalTransaction(string) []byte
46 GetTransactions() ([]*query.AnnotatedTx, error)
47 GetUnconfirmedTransactions() ([]*query.AnnotatedTx, error)
48 GetUnconfirmedTransaction(string) []byte
49 SetUnconfirmedTransaction(string, []byte)
50 DeleteStardardUTXO(bc.Hash)
51 DeleteContractUTXO(bc.Hash)
52 SetStandardUTXO(bc.Hash, []byte)
53 SetContractUTXO(bc.Hash, []byte)
54 GetWalletInfo() []byte
56 DeleteWalletTransactions()
58 GetAccountUTXOs(key string) [][]byte
59 SetRecoveryStatus([]byte, []byte)
60 DeleteRecoveryStatus([]byte)
61 GetRecoveryStatus([]byte) []byte
64 // WalletStore store wallet using leveldb
65 type WalletStore struct {
70 type WalletBatch struct {
74 // NewWalletStore create new WalletStore struct
75 func NewWalletStore(db dbm.DB) *WalletStore {
82 // InitBatch initial batch
83 func (store *WalletStore) InitBatch() {
84 if store.batch == nil {
85 store.batch = store.DB.NewBatch()
86 fmt.Println("InitBatch type of store.batch is:", reflect.TypeOf(store.batch))
87 fmt.Println("InitBatch value of store.batch is: ", reflect.ValueOf(store.batch))
88 fmt.Printf("InitBatch store.batch pointer is: %p\n", store.batch)
92 // CommitBatch commit batch
93 func (store *WalletStore) CommitBatch() {
94 fmt.Println("CommitBatch...")
95 if store.batch != nil {
96 fmt.Println("CommitBatch not nil...")
97 fmt.Println("CommitBatch type of store.batch is:", reflect.TypeOf(store.batch))
98 fmt.Println("CommitBatch value of store.batch is: ", reflect.ValueOf(store.batch))
99 fmt.Printf("CommitBatch store.batch pointer is: %p\n", store.batch)
102 // store.batch = store.DB.NewBatch()
106 // ContractKey account control promgram store prefix
107 func ContractKey(hash common.Hash) []byte {
108 return append([]byte(contractPrefix), hash[:]...)
111 // Key account store prefix
112 func Key(name string) []byte {
113 return append([]byte(accountPrefix), []byte(name)...)
116 // StandardUTXOKey makes an account unspent outputs key to store
117 func StandardUTXOKey(id bc.Hash) []byte {
119 return []byte(UTXOPrefix + name)
122 // ContractUTXOKey makes a smart contract unspent outputs key to store
123 func ContractUTXOKey(id bc.Hash) []byte {
125 return []byte(SUTXOPrefix + name)
128 func calcDeleteKey(blockHeight uint64) []byte {
129 return []byte(fmt.Sprintf("%s%016x", TxPrefix, blockHeight))
132 func calcTxIndexKey(txID string) []byte {
133 return []byte(TxIndexPrefix + txID)
136 func calcAnnotatedKey(formatKey string) []byte {
137 return []byte(TxPrefix + formatKey)
140 func calcUnconfirmedTxKey(formatKey string) []byte {
141 return []byte(UnconfirmedTxPrefix + formatKey)
144 func calcGlobalTxIndexKey(txID string) []byte {
145 return []byte(GlobalTxIndexPrefix + txID)
148 func CalcGlobalTxIndex(blockHash *bc.Hash, position uint64) []byte {
149 txIdx := make([]byte, 40)
150 copy(txIdx[:32], blockHash.Bytes())
151 binary.BigEndian.PutUint64(txIdx[32:], position)
155 func formatKey(blockHeight uint64, position uint32) string {
156 return fmt.Sprintf("%016x%08x", blockHeight, position)
159 // GetAssetDefinition get asset definition by assetiD
160 func (store *WalletStore) GetAssetDefinition(assetID *bc.AssetID) []byte {
161 return store.DB.Get(asset.ExtAssetKey(assetID))
164 // SetAssetDefinition set assetID and definition
165 func (store *WalletStore) SetAssetDefinition(assetID *bc.AssetID, definition []byte) {
166 if store.batch == nil {
167 store.DB.Set(asset.ExtAssetKey(assetID), definition)
169 store.batch.Set(asset.ExtAssetKey(assetID), definition)
173 // GetRawProgram get raw program by hash
174 func (store *WalletStore) GetRawProgram(hash common.Hash) []byte {
175 return store.DB.Get(ContractKey(hash))
178 // GetAccountByAccountID get account value by account ID
179 func (store *WalletStore) GetAccountByAccountID(accountID string) []byte {
180 return store.DB.Get(Key(accountID))
183 // DeleteTransactions delete transactions when orphan block rollback
184 func (store *WalletStore) DeleteTransactions(height uint64) {
185 tmpTx := query.AnnotatedTx{}
186 batch := store.DB.NewBatch()
187 if store.batch != nil {
190 txIter := store.DB.IteratorPrefix(calcDeleteKey(height))
191 defer txIter.Release()
194 if err := json.Unmarshal(txIter.Value(), &tmpTx); err == nil {
195 batch.Delete(calcTxIndexKey(tmpTx.ID.String()))
197 batch.Delete(txIter.Key())
199 if store.batch == nil {
204 // SetTransaction set raw transaction by block height and tx position
205 func (store *WalletStore) SetTransaction(height uint64, position uint32, txID string, rawTx []byte) {
206 fmt.Println("SetTransaction...")
207 if store.batch == nil {
208 fmt.Println("SetTransaction ... nil")
209 batch := store.DB.NewBatch()
210 fmt.Println("type of batch is:", reflect.TypeOf(batch))
211 batch.Set(calcAnnotatedKey(formatKey(height, position)), rawTx)
212 batch.Set(calcTxIndexKey(txID), []byte(formatKey(height, position)))
215 fmt.Println("SetTransaction ... not nil")
217 // store.batch = store.DB.NewBatch()
218 fmt.Println("type of store.batch is:", reflect.TypeOf(store.batch))
219 store.batch.Set(calcAnnotatedKey(formatKey(height, position)), rawTx)
220 store.batch.Set(calcTxIndexKey(txID), []byte(formatKey(height, position)))
221 // store.CommitBatch()
222 // store.batch.Write()
226 // DeleteUnconfirmedTransaction delete unconfirmed tx by txID
227 func (store *WalletStore) DeleteUnconfirmedTransaction(txID string) {
228 if store.batch == nil {
229 store.DB.Delete(calcUnconfirmedTxKey(txID))
231 store.batch.Delete(calcUnconfirmedTxKey(txID))
235 // SetGlobalTransactionIndex set global tx index by blockhash and position
236 func (store *WalletStore) SetGlobalTransactionIndex(globalTxID string, blockHash *bc.Hash, position uint64) {
237 if store.batch == nil {
238 store.DB.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
240 store.batch.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
244 // GetStandardUTXO get standard utxo by id
245 func (store *WalletStore) GetStandardUTXO(outid bc.Hash) []byte {
246 return store.DB.Get(StandardUTXOKey(outid))
249 // GetTransaction get tx by tx index
250 func (store *WalletStore) GetTransaction(txID string) ([]byte, error) {
251 fmt.Println("GetTransaction... txID: ", txID)
252 formatKey := store.DB.Get(calcTxIndexKey(txID))
253 if formatKey == nil {
254 return nil, errAccntTxIDNotFound
256 txInfo := store.DB.Get(calcAnnotatedKey(string(formatKey)))
260 // GetGlobalTransaction get global tx by txID
261 func (store *WalletStore) GetGlobalTransaction(txID string) []byte {
262 return store.DB.Get(calcGlobalTxIndexKey(txID))
265 // GetTransactions get all walletDB transactions
266 func (store *WalletStore) GetTransactions() ([]*query.AnnotatedTx, error) {
267 annotatedTxs := []*query.AnnotatedTx{}
269 txIter := store.DB.IteratorPrefix([]byte(TxPrefix))
270 defer txIter.Release()
272 annotatedTx := &query.AnnotatedTx{}
273 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
276 annotatedTxs = append(annotatedTxs, annotatedTx)
279 return annotatedTxs, nil
282 // GetUnconfirmedTransactions get all unconfirmed txs
283 func (store *WalletStore) GetUnconfirmedTransactions() ([]*query.AnnotatedTx, error) {
284 annotatedTxs := []*query.AnnotatedTx{}
285 txIter := store.DB.IteratorPrefix([]byte(UnconfirmedTxPrefix))
286 defer txIter.Release()
289 annotatedTx := &query.AnnotatedTx{}
290 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
293 annotatedTxs = append(annotatedTxs, annotatedTx)
295 return annotatedTxs, nil
298 // GetUnconfirmedTransaction get unconfirmed tx by txID
299 func (store *WalletStore) GetUnconfirmedTransaction(txID string) []byte {
300 return store.DB.Get(calcUnconfirmedTxKey(txID))
303 // SetUnconfirmedTransaction set unconfirmed tx by txID
304 func (store *WalletStore) SetUnconfirmedTransaction(txID string, rawTx []byte) {
305 if store.batch == nil {
306 store.DB.Set(calcUnconfirmedTxKey(txID), rawTx)
308 store.batch.Set(calcUnconfirmedTxKey(txID), rawTx)
312 // DeleteStardardUTXO delete stardard utxo by outputID
313 func (store *WalletStore) DeleteStardardUTXO(outputID bc.Hash) {
314 if store.batch == nil {
315 store.DB.Delete(StandardUTXOKey(outputID))
317 store.batch.Delete(StandardUTXOKey(outputID))
321 // DeleteContractUTXO delete contract utxo by outputID
322 func (store *WalletStore) DeleteContractUTXO(outputID bc.Hash) {
323 if store.batch == nil {
324 store.DB.Delete(ContractUTXOKey(outputID))
326 store.batch.Delete(ContractUTXOKey(outputID))
330 // SetStandardUTXO set standard utxo
331 func (store *WalletStore) SetStandardUTXO(outputID bc.Hash, data []byte) {
332 if store.batch == nil {
333 store.DB.Set(StandardUTXOKey(outputID), data)
335 store.batch.Set(StandardUTXOKey(outputID), data)
339 // SetContractUTXO set standard utxo
340 func (store *WalletStore) SetContractUTXO(outputID bc.Hash, data []byte) {
341 if store.batch == nil {
342 store.DB.Set(ContractUTXOKey(outputID), data)
344 store.batch.Set(ContractUTXOKey(outputID), data)
348 // GetWalletInfo get wallet information
349 func (store *WalletStore) GetWalletInfo() []byte {
350 return store.DB.Get([]byte(walletKey))
353 // SetWalletInfo get wallet information
354 func (store *WalletStore) SetWalletInfo(rawWallet []byte) {
355 if store.batch == nil {
356 store.DB.Set([]byte(walletKey), rawWallet)
358 store.batch.Set([]byte(walletKey), rawWallet)
362 // DeleteWalletTransactions delete all txs in wallet
363 func (store *WalletStore) DeleteWalletTransactions() {
364 batch := store.DB.NewBatch()
365 txIter := store.DB.IteratorPrefix([]byte(TxPrefix))
366 defer txIter.Release()
369 batch.Delete(txIter.Key())
372 txIndexIter := store.DB.IteratorPrefix([]byte(TxIndexPrefix))
373 defer txIndexIter.Release()
375 for txIndexIter.Next() {
376 batch.Delete(txIndexIter.Key())
381 // DeleteWalletUTXOs delete all txs in wallet
382 func (store *WalletStore) DeleteWalletUTXOs() {
383 batch := store.DB.NewBatch()
384 ruIter := store.DB.IteratorPrefix([]byte(UTXOPrefix))
385 defer ruIter.Release()
387 batch.Delete(ruIter.Key())
390 suIter := store.DB.IteratorPrefix([]byte(SUTXOPrefix))
391 defer suIter.Release()
393 batch.Delete(suIter.Key())
398 // GetAccountUTXOs get all account unspent outputs
399 func (store *WalletStore) GetAccountUTXOs(key string) [][]byte {
400 accountUtxoIter := store.DB.IteratorPrefix([]byte(key))
401 defer accountUtxoIter.Release()
403 rawUTXOs := make([][]byte, 0)
404 for accountUtxoIter.Next() {
405 utxo := accountUtxoIter.Value()
406 rawUTXOs = append(rawUTXOs, utxo)
411 // SetRecoveryStatus set recovery status
412 func (store *WalletStore) SetRecoveryStatus(recoveryKey, rawStatus []byte) {
413 if store.batch == nil {
414 store.DB.Set(recoveryKey, rawStatus)
416 store.batch.Set(recoveryKey, rawStatus)
420 // DeleteRecoveryStatus delete recovery status
421 func (store *WalletStore) DeleteRecoveryStatus(recoveryKey []byte) {
422 if store.batch == nil {
423 store.DB.Delete(recoveryKey)
425 store.batch.Delete(recoveryKey)
429 // GetRecoveryStatus delete recovery status
430 func (store *WalletStore) GetRecoveryStatus(recoveryKey []byte) []byte {
431 return store.DB.Get(recoveryKey)