X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=blobdiff_plain;f=wallet%2Futxo.go;h=a1b44fa33bde7099095b6476f333757c81a97b78;hp=e1373f529215e7259824d9d629173ad3c916dfd9;hb=b5adb513416f1c03bb6503e208eb21550b5ac4cc;hpb=2cba4a674b67c3a4f781d464b90b3cfcedccd993 diff --git a/wallet/utxo.go b/wallet/utxo.go index e1373f52..a1b44fa3 100644 --- a/wallet/utxo.go +++ b/wallet/utxo.go @@ -1,54 +1,42 @@ package wallet import ( - "encoding/json" - log "github.com/sirupsen/logrus" "github.com/vapor/account" "github.com/vapor/consensus" "github.com/vapor/consensus/segwit" "github.com/vapor/crypto/sha3pool" - dbm "github.com/vapor/database/leveldb" - "github.com/vapor/errors" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" ) // GetAccountUtxos return all account unspent outputs func (w *Wallet) GetAccountUtxos(accountID string, id string, unconfirmed, isSmartContract bool, vote bool) []*account.UTXO { - prefix := account.UTXOPreFix - if isSmartContract { - prefix = account.SUTXOPrefix - } - accountUtxos := []*account.UTXO{} if unconfirmed { accountUtxos = w.AccountMgr.ListUnconfirmedUtxo(accountID, isSmartContract) } - accountUtxoIter := w.DB.IteratorPrefix([]byte(prefix + id)) - defer accountUtxoIter.Release() - - for accountUtxoIter.Next() { - accountUtxo := &account.UTXO{} - if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Warn("GetAccountUtxos fail on unmarshal utxo") - continue - } + confirmedUTXOs, err := w.Store.ListAccountUTXOs(id, isSmartContract) + if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("GetAccountUtxos fail.") + } + accountUtxos = append(accountUtxos, confirmedUTXOs...) + newAccountUtxos := []*account.UTXO{} + for _, accountUtxo := range accountUtxos { if vote && accountUtxo.Vote == nil { continue } - if accountID == accountUtxo.AccountID || accountID == "" { - accountUtxos = append(accountUtxos, accountUtxo) + newAccountUtxos = append(newAccountUtxos, accountUtxo) } } - return accountUtxos + return newAccountUtxos } -func (w *Wallet) attachUtxos(batch dbm.Batch, b *types.Block, txStatus *bc.TransactionStatus) { +func (w *Wallet) attachUtxos(b *types.Block, txStatus *bc.TransactionStatus, store WalletStore) { for txIndex, tx := range b.Transactions { statusFail, err := txStatus.GetStatus(txIndex) if err != nil { @@ -60,32 +48,31 @@ func (w *Wallet) attachUtxos(batch dbm.Batch, b *types.Block, txStatus *bc.Trans inputUtxos := txInToUtxos(tx, statusFail) for _, inputUtxo := range inputUtxos { if segwit.IsP2WScript(inputUtxo.ControlProgram) { - batch.Delete(account.StandardUTXOKey(inputUtxo.OutputID)) + w.AccountMgr.DeleteStandardUTXO(inputUtxo.OutputID) } else { - batch.Delete(account.ContractUTXOKey(inputUtxo.OutputID)) + store.DeleteContractUTXO(inputUtxo.OutputID) } } //hand update the transaction output utxos - validHeight := uint64(0) - if txIndex == 0 { - validHeight = b.Height + consensus.CoinbasePendingBlockNumber - } - outputUtxos := txOutToUtxos(tx, statusFail, validHeight) + outputUtxos := txOutToUtxos(tx, statusFail, b.Height) utxos := w.filterAccountUtxo(outputUtxos) - if err := batchSaveUtxos(utxos, batch); err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("attachUtxos fail on batchSaveUtxos") + if err := w.saveUtxos(utxos, store); err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("attachUtxos fail on saveUtxos") } } } -func (w *Wallet) detachUtxos(batch dbm.Batch, b *types.Block, txStatus *bc.TransactionStatus) { +func (w *Wallet) detachUtxos(b *types.Block, txStatus *bc.TransactionStatus, store WalletStore) { for txIndex := len(b.Transactions) - 1; txIndex >= 0; txIndex-- { tx := b.Transactions[txIndex] for j := range tx.Outputs { code := []byte{} switch resOut := tx.Entries[*tx.ResultIds[j]].(type) { case *bc.IntraChainOutput: + if resOut.Source.Value.Amount == uint64(0) { + continue + } code = resOut.ControlProgram.Code case *bc.VoteOutput: code = resOut.ControlProgram.Code @@ -94,9 +81,9 @@ func (w *Wallet) detachUtxos(batch dbm.Batch, b *types.Block, txStatus *bc.Trans } if segwit.IsP2WScript(code) { - batch.Delete(account.StandardUTXOKey(*tx.ResultIds[j])) + w.AccountMgr.DeleteStandardUTXO(*tx.ResultIds[j]) } else { - batch.Delete(account.ContractUTXOKey(*tx.ResultIds[j])) + store.DeleteContractUTXO(*tx.ResultIds[j]) } } @@ -108,7 +95,7 @@ func (w *Wallet) detachUtxos(batch dbm.Batch, b *types.Block, txStatus *bc.Trans inputUtxos := txInToUtxos(tx, statusFail) utxos := w.filterAccountUtxo(inputUtxos) - if err := batchSaveUtxos(utxos, batch); err != nil { + if err := w.saveUtxos(utxos, store); err != nil { log.WithFields(log.Fields{"module": logModule, "err": err}).Error("detachUtxos fail on batchSaveUtxos") return } @@ -133,14 +120,12 @@ func (w *Wallet) filterAccountUtxo(utxos []*account.UTXO) []*account.UTXO { var hash [32]byte sha3pool.Sum256(hash[:], []byte(s)) - data := w.DB.Get(account.ContractKey(hash)) - if data == nil { + cp, err := w.AccountMgr.GetControlProgram(bc.NewHash(hash)) + if err != nil && err != account.ErrFindCtrlProgram { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("filterAccountUtxo fail.") continue } - - cp := &account.CtrlProgram{} - if err := json.Unmarshal(data, cp); err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("filterAccountUtxo fail on unmarshal control program") + if cp == nil { continue } @@ -155,17 +140,16 @@ func (w *Wallet) filterAccountUtxo(utxos []*account.UTXO) []*account.UTXO { return result } -func batchSaveUtxos(utxos []*account.UTXO, batch dbm.Batch) error { +func (w *Wallet) saveUtxos(utxos []*account.UTXO, store WalletStore) error { for _, utxo := range utxos { - data, err := json.Marshal(utxo) - if err != nil { - return errors.Wrap(err, "failed marshal accountutxo") - } - if segwit.IsP2WScript(utxo.ControlProgram) { - batch.Set(account.StandardUTXOKey(utxo.OutputID), data) + if err := w.AccountMgr.SetStandardUTXO(utxo.OutputID, utxo); err != nil { + return err + } } else { - batch.Set(account.ContractUTXOKey(utxo.OutputID), data) + if err := store.SetContractUTXO(utxo.OutputID, utxo); err != nil { + return err + } } } return nil @@ -174,38 +158,41 @@ func batchSaveUtxos(utxos []*account.UTXO, batch dbm.Batch) error { func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO { utxos := []*account.UTXO{} for _, inpID := range tx.Tx.InputIDs { - sp, err := tx.Spend(inpID) - if err != nil { - continue - } - entryOutput, err := tx.Entry(*sp.SpentOutputId) + e, err := tx.Entry(inpID) if err != nil { - log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get entryOutput") continue } - utxo := &account.UTXO{} - switch resOut := entryOutput.(type) { - case *bc.IntraChainOutput: + switch inp := e.(type) { + case *bc.Spend: + resOut, err := tx.IntraChainOutput(*inp.SpentOutputId) + if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get resOut for spedn") + continue + } if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID { continue } utxo = &account.UTXO{ - OutputID: *sp.SpentOutputId, + OutputID: *inp.SpentOutputId, AssetID: *resOut.Source.Value.AssetId, Amount: resOut.Source.Value.Amount, ControlProgram: resOut.ControlProgram.Code, SourceID: *resOut.Source.Ref, SourcePos: resOut.Source.Position, } - - case *bc.VoteOutput: + case *bc.VetoInput: + resOut, err := tx.VoteOutput(*inp.SpentOutputId) + if err != nil { + log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get resOut for vetoInput") + continue + } if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID { continue } utxo = &account.UTXO{ - OutputID: *sp.SpentOutputId, + OutputID: *inp.SpentOutputId, AssetID: *resOut.Source.Value.AssetId, Amount: resOut.Source.Value.Amount, ControlProgram: resOut.ControlProgram.Code, @@ -213,20 +200,18 @@ func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO { SourcePos: resOut.Source.Position, Vote: resOut.Vote, } - default: - log.WithFields(log.Fields{"module": logModule}).Error("txInToUtxos fail on get resOut") continue } - utxos = append(utxos, utxo) } return utxos } -func txOutToUtxos(tx *types.Tx, statusFail bool, vaildHeight uint64) []*account.UTXO { +func txOutToUtxos(tx *types.Tx, statusFail bool, blockHeight uint64) []*account.UTXO { utxos := []*account.UTXO{} for i, out := range tx.Outputs { + validHeight := uint64(0) entryOutput, err := tx.Entry(*tx.ResultIds[i]) if err != nil { log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txOutToUtxos fail on get entryOutput") @@ -236,9 +221,14 @@ func txOutToUtxos(tx *types.Tx, statusFail bool, vaildHeight uint64) []*account. utxo := &account.UTXO{} switch bcOut := entryOutput.(type) { case *bc.IntraChainOutput: - if statusFail && *out.AssetAmount().AssetId != *consensus.BTMAssetID { + if (statusFail && *out.AssetAmount().AssetId != *consensus.BTMAssetID) || out.AssetAmount().Amount == uint64(0) { continue } + + if tx.Inputs[0].InputType() == types.CoinbaseInputType { + validHeight = blockHeight + consensus.ActiveNetParams.CoinbasePendingBlockNumber + } + utxo = &account.UTXO{ OutputID: *tx.OutputID(i), AssetID: *out.AssetAmount().AssetId, @@ -246,13 +236,19 @@ func txOutToUtxos(tx *types.Tx, statusFail bool, vaildHeight uint64) []*account. ControlProgram: out.ControlProgram(), SourceID: *bcOut.Source.Ref, SourcePos: bcOut.Source.Position, - ValidHeight: vaildHeight, + ValidHeight: validHeight, } case *bc.VoteOutput: if statusFail && *out.AssetAmount().AssetId != *consensus.BTMAssetID { continue } + + voteValidHeight := blockHeight + consensus.ActiveNetParams.VotePendingBlockNumber + if validHeight < voteValidHeight { + validHeight = voteValidHeight + } + utxo = &account.UTXO{ OutputID: *tx.OutputID(i), AssetID: *out.AssetAmount().AssetId, @@ -260,7 +256,7 @@ func txOutToUtxos(tx *types.Tx, statusFail bool, vaildHeight uint64) []*account. ControlProgram: out.ControlProgram(), SourceID: *bcOut.Source.Ref, SourcePos: bcOut.Source.Position, - ValidHeight: vaildHeight, + ValidHeight: validHeight, Vote: bcOut.Vote, }