8 "github.com/vapor/asset"
9 "github.com/vapor/blockchain/query"
10 "github.com/vapor/common"
11 dbm "github.com/vapor/database/leveldb"
12 "github.com/vapor/errors"
13 "github.com/vapor/protocol/bc"
16 var errAccntTxIDNotFound = errors.New("account TXID not found")
19 UTXOPrefix = "ACU:" //UTXOPrefix is StandardUTXOKey prefix
20 SUTXOPrefix = "SCU:" //SUTXOPrefix is ContractUTXOKey prefix
21 contractPrefix = "Contract:"
22 accountPrefix = "Account:"
23 TxPrefix = "TXS:" //TxPrefix is wallet database transactions prefix
24 TxIndexPrefix = "TID:" //TxIndexPrefix is wallet database tx index prefix
25 UnconfirmedTxPrefix = "UTXS:" //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
26 GlobalTxIndexPrefix = "GTID:" //GlobalTxIndexPrefix is wallet database global tx index prefix
27 walletKey = "walletInfo"
30 // WalletStorer interface contains wallet storage functions.
31 type WalletStorer interface {
34 GetAssetDefinition(*bc.AssetID) []byte
35 SetAssetDefinition(*bc.AssetID, []byte)
36 GetRawProgram(common.Hash) []byte
37 GetAccountByAccountID(string) []byte
38 DeleteTransactions(uint64)
39 SetTransaction(uint64, uint32, string, []byte)
40 DeleteUnconfirmedTransaction(string)
41 SetGlobalTransactionIndex(string, *bc.Hash, uint64)
42 GetStandardUTXO(bc.Hash) []byte
43 GetTransaction(string) ([]byte, error)
44 GetGlobalTransaction(string) []byte
45 GetTransactions() ([]*query.AnnotatedTx, error)
46 GetUnconfirmedTransactions() ([]*query.AnnotatedTx, error)
47 GetUnconfirmedTransaction(string) []byte
48 SetUnconfirmedTransaction(string, []byte)
49 DeleteStardardUTXO(bc.Hash)
50 DeleteContractUTXO(bc.Hash)
51 SetStandardUTXO(bc.Hash, []byte)
52 SetContractUTXO(bc.Hash, []byte)
53 GetWalletInfo() []byte
55 DeleteWalletTransactions()
57 GetAccountUTXOs(key string) [][]byte
58 SetRecoveryStatus([]byte, []byte)
59 DeleteRecoveryStatus([]byte)
60 GetRecoveryStatus([]byte) []byte
63 // WalletStore store wallet using leveldb
64 type WalletStore struct {
69 // NewWalletStore create new WalletStore struct
70 func NewWalletStore(db dbm.DB) *WalletStore {
76 // InitBatch initial batch
77 func (store *WalletStore) InitBatch() {
78 store.batch = store.DB.NewBatch()
81 // CommitBatch commit batch
82 func (store *WalletStore) CommitBatch() {
83 if store.batch != nil {
88 // ContractKey account control promgram store prefix
89 func ContractKey(hash common.Hash) []byte {
90 return append([]byte(contractPrefix), hash[:]...)
93 // Key account store prefix
94 func Key(name string) []byte {
95 return append([]byte(accountPrefix), []byte(name)...)
98 // StandardUTXOKey makes an account unspent outputs key to store
99 func StandardUTXOKey(id bc.Hash) []byte {
101 return []byte(UTXOPrefix + name)
104 // ContractUTXOKey makes a smart contract unspent outputs key to store
105 func ContractUTXOKey(id bc.Hash) []byte {
107 return []byte(SUTXOPrefix + name)
110 func calcDeleteKey(blockHeight uint64) []byte {
111 return []byte(fmt.Sprintf("%s%016x", TxPrefix, blockHeight))
114 func calcTxIndexKey(txID string) []byte {
115 return []byte(TxIndexPrefix + txID)
118 func calcAnnotatedKey(formatKey string) []byte {
119 return []byte(TxPrefix + formatKey)
122 func calcUnconfirmedTxKey(formatKey string) []byte {
123 return []byte(UnconfirmedTxPrefix + formatKey)
126 func calcGlobalTxIndexKey(txID string) []byte {
127 return []byte(GlobalTxIndexPrefix + txID)
130 func CalcGlobalTxIndex(blockHash *bc.Hash, position uint64) []byte {
131 txIdx := make([]byte, 40)
132 copy(txIdx[:32], blockHash.Bytes())
133 binary.BigEndian.PutUint64(txIdx[32:], position)
137 func formatKey(blockHeight uint64, position uint32) string {
138 return fmt.Sprintf("%016x%08x", blockHeight, position)
141 // GetAssetDefinition get asset definition by assetiD
142 func (store *WalletStore) GetAssetDefinition(assetID *bc.AssetID) []byte {
143 return store.DB.Get(asset.ExtAssetKey(assetID))
146 // SetAssetDefinition set assetID and definition
147 func (store *WalletStore) SetAssetDefinition(assetID *bc.AssetID, definition []byte) {
148 if store.batch == nil {
149 store.DB.Set(asset.ExtAssetKey(assetID), definition)
151 store.batch.Set(asset.ExtAssetKey(assetID), definition)
155 // GetRawProgram get raw program by hash
156 func (store *WalletStore) GetRawProgram(hash common.Hash) []byte {
157 return store.DB.Get(ContractKey(hash))
160 // GetAccountByAccountID get account value by account ID
161 func (store *WalletStore) GetAccountByAccountID(accountID string) []byte {
162 return store.DB.Get(Key(accountID))
165 // DeleteTransactions delete transactions when orphan block rollback
166 func (store *WalletStore) DeleteTransactions(height uint64) {
167 tmpTx := query.AnnotatedTx{}
168 txIter := store.DB.IteratorPrefix(calcDeleteKey(height))
169 defer txIter.Release()
172 if err := json.Unmarshal(txIter.Value(), &tmpTx); err == nil {
173 store.batch.Delete(calcTxIndexKey(tmpTx.ID.String()))
175 store.batch.Delete(txIter.Key())
179 // SetTransaction set raw transaction by block height and tx position
180 func (store *WalletStore) SetTransaction(height uint64, position uint32, txID string, rawTx []byte) {
181 if store.batch == nil {
182 store.DB.Set(calcAnnotatedKey(formatKey(height, position)), rawTx)
183 store.DB.Set(calcTxIndexKey(txID), []byte(formatKey(height, position)))
185 store.batch.Set(calcAnnotatedKey(formatKey(height, position)), rawTx)
186 store.batch.Set(calcTxIndexKey(txID), []byte(formatKey(height, position)))
190 // DeleteUnconfirmedTransaction delete unconfirmed tx by txID
191 func (store *WalletStore) DeleteUnconfirmedTransaction(txID string) {
192 if store.batch == nil {
193 store.DB.Delete(calcUnconfirmedTxKey(txID))
195 store.batch.Delete(calcUnconfirmedTxKey(txID))
199 // SetGlobalTransactionIndex set global tx index by blockhash and position
200 func (store *WalletStore) SetGlobalTransactionIndex(globalTxID string, blockHash *bc.Hash, position uint64) {
201 if store.batch == nil {
202 store.DB.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
204 store.batch.Set(calcGlobalTxIndexKey(globalTxID), CalcGlobalTxIndex(blockHash, position))
208 // GetStandardUTXO get standard utxo by id
209 func (store *WalletStore) GetStandardUTXO(outid bc.Hash) []byte {
210 return store.DB.Get(StandardUTXOKey(outid))
213 // GetTransaction get tx by tx index
214 func (store *WalletStore) GetTransaction(txID string) ([]byte, error) {
215 formatKey := store.DB.Get(calcTxIndexKey(txID))
216 if formatKey == nil {
217 return nil, errAccntTxIDNotFound
219 txInfo := store.DB.Get(calcAnnotatedKey(string(formatKey)))
223 // GetGlobalTransaction get global tx by txID
224 func (store *WalletStore) GetGlobalTransaction(txID string) []byte {
225 return store.DB.Get(calcGlobalTxIndexKey(txID))
228 // GetTransactions get all walletDB transactions
229 func (store *WalletStore) GetTransactions() ([]*query.AnnotatedTx, error) {
230 annotatedTxs := []*query.AnnotatedTx{}
232 txIter := store.DB.IteratorPrefix([]byte(TxPrefix))
233 defer txIter.Release()
235 annotatedTx := &query.AnnotatedTx{}
236 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
239 annotatedTxs = append(annotatedTxs, annotatedTx)
242 return annotatedTxs, nil
245 // GetUnconfirmedTransactions get all unconfirmed txs
246 func (store *WalletStore) GetUnconfirmedTransactions() ([]*query.AnnotatedTx, error) {
247 annotatedTxs := []*query.AnnotatedTx{}
248 txIter := store.DB.IteratorPrefix([]byte(UnconfirmedTxPrefix))
249 defer txIter.Release()
252 annotatedTx := &query.AnnotatedTx{}
253 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
256 annotatedTxs = append(annotatedTxs, annotatedTx)
258 return annotatedTxs, nil
261 // GetUnconfirmedTransaction get unconfirmed tx by txID
262 func (store *WalletStore) GetUnconfirmedTransaction(txID string) []byte {
263 return store.DB.Get(calcUnconfirmedTxKey(txID))
266 // SetUnconfirmedTransaction set unconfirmed tx by txID
267 func (store *WalletStore) SetUnconfirmedTransaction(txID string, rawTx []byte) {
268 if store.batch == nil {
269 store.DB.Set(calcUnconfirmedTxKey(txID), rawTx)
271 store.batch.Set(calcUnconfirmedTxKey(txID), rawTx)
275 // DeleteStardardUTXO delete stardard utxo by outputID
276 func (store *WalletStore) DeleteStardardUTXO(outputID bc.Hash) {
277 if store.batch == nil {
278 store.DB.Delete(StandardUTXOKey(outputID))
280 store.batch.Delete(StandardUTXOKey(outputID))
284 // DeleteContractUTXO delete contract utxo by outputID
285 func (store *WalletStore) DeleteContractUTXO(outputID bc.Hash) {
286 if store.batch == nil {
287 store.DB.Delete(ContractUTXOKey(outputID))
289 store.batch.Delete(ContractUTXOKey(outputID))
293 // SetStandardUTXO set standard utxo
294 func (store *WalletStore) SetStandardUTXO(outputID bc.Hash, data []byte) {
295 if store.batch == nil {
296 store.DB.Set(StandardUTXOKey(outputID), data)
298 store.batch.Set(StandardUTXOKey(outputID), data)
302 // SetContractUTXO set standard utxo
303 func (store *WalletStore) SetContractUTXO(outputID bc.Hash, data []byte) {
304 if store.batch == nil {
305 store.DB.Set(ContractUTXOKey(outputID), data)
307 store.batch.Set(ContractUTXOKey(outputID), data)
311 // GetWalletInfo get wallet information
312 func (store *WalletStore) GetWalletInfo() []byte {
313 return store.DB.Get([]byte(walletKey))
316 // SetWalletInfo get wallet information
317 func (store *WalletStore) SetWalletInfo(rawWallet []byte) {
318 if store.batch == nil {
319 store.DB.Set([]byte(walletKey), rawWallet)
321 store.batch.Set([]byte(walletKey), rawWallet)
325 // DeleteWalletTransactions delete all txs in wallet
326 func (store *WalletStore) DeleteWalletTransactions() {
327 batch := store.DB.NewBatch()
328 txIter := store.DB.IteratorPrefix([]byte(TxPrefix))
329 defer txIter.Release()
332 batch.Delete(txIter.Key())
335 txIndexIter := store.DB.IteratorPrefix([]byte(TxIndexPrefix))
336 defer txIndexIter.Release()
338 for txIndexIter.Next() {
339 batch.Delete(txIndexIter.Key())
344 // DeleteWalletUTXOs delete all txs in wallet
345 func (store *WalletStore) DeleteWalletUTXOs() {
346 batch := store.DB.NewBatch()
347 ruIter := store.DB.IteratorPrefix([]byte(UTXOPrefix))
348 defer ruIter.Release()
350 batch.Delete(ruIter.Key())
353 suIter := store.DB.IteratorPrefix([]byte(SUTXOPrefix))
354 defer suIter.Release()
356 batch.Delete(suIter.Key())
361 // GetAccountUTXOs get all account unspent outputs
362 func (store *WalletStore) GetAccountUTXOs(key string) [][]byte {
363 accountUtxoIter := store.DB.IteratorPrefix([]byte(key))
364 defer accountUtxoIter.Release()
366 rawUTXOs := make([][]byte, 0)
367 for accountUtxoIter.Next() {
368 utxo := accountUtxoIter.Value()
369 rawUTXOs = append(rawUTXOs, utxo)
374 // SetRecoveryStatus set recovery status
375 func (store *WalletStore) SetRecoveryStatus(recoveryKey, rawStatus []byte) {
376 if store.batch == nil {
377 store.DB.Set(recoveryKey, rawStatus)
379 store.batch.Set(recoveryKey, rawStatus)
383 // DeleteRecoveryStatus delete recovery status
384 func (store *WalletStore) DeleteRecoveryStatus(recoveryKey []byte) {
385 if store.batch == nil {
386 store.DB.Delete(recoveryKey)
388 store.batch.Delete(recoveryKey)
392 // GetRecoveryStatus delete recovery status
393 func (store *WalletStore) GetRecoveryStatus(recoveryKey []byte) []byte {
394 return store.DB.Get(recoveryKey)