X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=account%2Futxo_keeper.go;h=4af1a5db508e0dd0553b14898f1960c14e18de22;hb=31f8f7cf1ffbec5365ab6ebf217537809cf714e5;hp=d00d0f39e28a2ed5aa060313455369371cc010b9;hpb=cc968002ceac2dfd7665c2ac2b4c32ab6017b525;p=bytom%2Fvapor.git diff --git a/account/utxo_keeper.go b/account/utxo_keeper.go index d00d0f39..4af1a5db 100644 --- a/account/utxo_keeper.go +++ b/account/utxo_keeper.go @@ -1,16 +1,14 @@ package account import ( + "bytes" "container/list" - "encoding/json" "sort" "sync" "sync/atomic" "time" log "github.com/sirupsen/logrus" - dbm "github.com/tendermint/tmlibs/db" - "github.com/vapor/errors" "github.com/vapor/protocol/bc" ) @@ -21,6 +19,7 @@ const desireUtxoCount = 5 var ( ErrInsufficient = errors.New("reservation found insufficient funds") ErrImmature = errors.New("reservation found immature funds") + ErrVoteLock = errors.New("Locked by the vote") ErrReserved = errors.New("reservation found outputs already reserved") ErrMatchUTXO = errors.New("can't find utxo with given hash") ErrReservation = errors.New("couldn't find reservation") @@ -34,6 +33,7 @@ type UTXO struct { Amount uint64 SourcePos uint64 ControlProgram []byte + Vote []byte AccountID string Address string ControlProgramIndex uint64 @@ -53,7 +53,7 @@ type utxoKeeper struct { // `sync/atomic` expects the first word in an allocated struct to be 64-bit // aligned on both ARM and x86-32. See https://goo.gl/zW7dgq for more details. nextIndex uint64 - db dbm.DB + store AccountStore mtx sync.RWMutex currentHeight func() uint64 @@ -62,9 +62,9 @@ type utxoKeeper struct { reservations map[uint64]*reservation } -func newUtxoKeeper(f func() uint64, walletdb dbm.DB) *utxoKeeper { +func newUtxoKeeper(f func() uint64, store AccountStore) *utxoKeeper { uk := &utxoKeeper{ - db: walletdb, + store: store, currentHeight: f, unconfirmed: make(map[bc.Hash]*UTXO), reserved: make(map[bc.Hash]uint64), @@ -111,17 +111,20 @@ func (uk *utxoKeeper) RemoveUnconfirmedUtxo(hashes []*bc.Hash) { } } -func (uk *utxoKeeper) Reserve(accountID string, assetID *bc.AssetID, amount uint64, useUnconfirmed bool, exp time.Time) (*reservation, error) { +func (uk *utxoKeeper) Reserve(accountID string, assetID *bc.AssetID, amount uint64, useUnconfirmed bool, vote []byte, exp time.Time) (*reservation, error) { uk.mtx.Lock() defer uk.mtx.Unlock() - utxos, immatureAmount := uk.findUtxos(accountID, assetID, useUnconfirmed) + utxos, immatureAmount := uk.findUtxos(accountID, assetID, useUnconfirmed, vote) optUtxos, optAmount, reservedAmount := uk.optUTXOs(utxos, amount) if optAmount+reservedAmount+immatureAmount < amount { return nil, ErrInsufficient } if optAmount+reservedAmount < amount { + if vote != nil { + return nil, ErrVoteLock + } return nil, ErrImmature } @@ -143,39 +146,6 @@ func (uk *utxoKeeper) Reserve(accountID string, assetID *bc.AssetID, amount uint return result, nil } -func (uk *utxoKeeper) ReserveByAddress(address string, assetID *bc.AssetID, amount uint64, useUnconfirmed bool, isReserved bool) (*reservation, error) { - uk.mtx.Lock() - defer uk.mtx.Unlock() - - utxos, immatureAmount := uk.findUtxosByAddress(address, assetID, useUnconfirmed) - optUtxos, optAmount, reservedAmount := uk.optUTXOs(utxos, amount) - if optAmount+reservedAmount+immatureAmount < amount { - return nil, ErrInsufficient - } - if optAmount+reservedAmount < amount { - return nil, ErrImmature - } - - if optAmount < amount { - return nil, ErrReserved - } - - result := &reservation{ - id: atomic.AddUint64(&uk.nextIndex, 1), - utxos: optUtxos, - change: optAmount - amount, - } - - uk.reservations[result.id] = result - if isReserved { - for _, u := range optUtxos { - uk.reserved[u.OutputID] = result.id - } - } - - return result, nil -} - func (uk *utxoKeeper) ReserveParticular(outHash bc.Hash, useUnconfirmed bool, exp time.Time) (*reservation, error) { uk.mtx.Lock() defer uk.mtx.Unlock() @@ -217,10 +187,13 @@ func (uk *utxoKeeper) cancel(rid uint64) { func (uk *utxoKeeper) expireWorker() { ticker := time.NewTicker(1000 * time.Millisecond) + defer ticker.Stop() + for now := range ticker.C { uk.expireReservation(now) } } + func (uk *utxoKeeper) expireReservation(t time.Time) { uk.mtx.Lock() defer uk.mtx.Unlock() @@ -232,14 +205,15 @@ func (uk *utxoKeeper) expireReservation(t time.Time) { } } -func (uk *utxoKeeper) findUtxos(accountID string, assetID *bc.AssetID, useUnconfirmed bool) ([]*UTXO, uint64) { +func (uk *utxoKeeper) findUtxos(accountID string, assetID *bc.AssetID, useUnconfirmed bool, vote []byte) ([]*UTXO, uint64) { immatureAmount := uint64(0) currentHeight := uk.currentHeight() utxos := []*UTXO{} appendUtxo := func(u *UTXO) { - if u.AccountID != accountID || u.AssetID != *assetID { + if u.AccountID != accountID || u.AssetID != *assetID || !bytes.Equal(u.Vote, vote) { return } + if u.ValidHeight > currentHeight { immatureAmount += u.Amount } else { @@ -247,51 +221,15 @@ func (uk *utxoKeeper) findUtxos(accountID string, assetID *bc.AssetID, useUnconf } } - utxoIter := uk.db.IteratorPrefix([]byte(UTXOPreFix)) - defer utxoIter.Release() - for utxoIter.Next() { - u := &UTXO{} - if err := json.Unmarshal(utxoIter.Value(), u); err != nil { - log.WithField("err", err).Error("utxoKeeper findUtxos fail on unmarshal utxo") - continue - } - appendUtxo(u) - } - if !useUnconfirmed { - return utxos, immatureAmount - } - - for _, u := range uk.unconfirmed { - appendUtxo(u) + UTXOs, err := uk.store.ListUTXOs() + if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("utxoKeeper findUtxos fail on unmarshal utxo") } - return utxos, immatureAmount -} -func (uk *utxoKeeper) findUtxosByAddress(address string, assetID *bc.AssetID, useUnconfirmed bool) ([]*UTXO, uint64) { - immatureAmount := uint64(0) - currentHeight := uk.currentHeight() - utxos := []*UTXO{} - appendUtxo := func(u *UTXO) { - if u.Address != address || u.AssetID != *assetID { - return - } - if u.ValidHeight > currentHeight { - immatureAmount += u.Amount - } else { - utxos = append(utxos, u) - } + for _, UTXO := range UTXOs { + appendUtxo(UTXO) } - utxoIter := uk.db.IteratorPrefix([]byte(UTXOPreFix)) - defer utxoIter.Release() - for utxoIter.Next() { - u := &UTXO{} - if err := json.Unmarshal(utxoIter.Value(), u); err != nil { - log.WithField("err", err).Error("utxoKeeper findUtxos fail on unmarshal utxo") - continue - } - appendUtxo(u) - } if !useUnconfirmed { return utxos, immatureAmount } @@ -306,15 +244,7 @@ func (uk *utxoKeeper) findUtxo(outHash bc.Hash, useUnconfirmed bool) (*UTXO, err if u, ok := uk.unconfirmed[outHash]; useUnconfirmed && ok { return u, nil } - - u := &UTXO{} - if data := uk.db.Get(StandardUTXOKey(outHash)); data != nil { - return u, json.Unmarshal(data, u) - } - if data := uk.db.Get(ContractUTXOKey(outHash)); data != nil { - return u, json.Unmarshal(data, u) - } - return nil, ErrMatchUTXO + return uk.store.GetUTXO(outHash) } func (uk *utxoKeeper) optUTXOs(utxos []*UTXO, amount uint64) ([]*UTXO, uint64, uint64) {