OSDN Git Service

edht tx txoutput (#1966)
[bytom/bytom.git] / wallet / utxo.go
index 5f60e90..0952191 100644 (file)
@@ -4,15 +4,15 @@ import (
        "encoding/json"
 
        log "github.com/sirupsen/logrus"
-       "github.com/tendermint/tmlibs/db"
-
-       "github.com/bytom/account"
-       "github.com/bytom/consensus"
-       "github.com/bytom/consensus/segwit"
-       "github.com/bytom/crypto/sha3pool"
-       "github.com/bytom/errors"
-       "github.com/bytom/protocol/bc"
-       "github.com/bytom/protocol/bc/types"
+
+       "github.com/bytom/bytom/account"
+       "github.com/bytom/bytom/consensus"
+       "github.com/bytom/bytom/consensus/segwit"
+       "github.com/bytom/bytom/crypto/sha3pool"
+       dbm "github.com/bytom/bytom/database/leveldb"
+       "github.com/bytom/bytom/errors"
+       "github.com/bytom/bytom/protocol/bc"
+       "github.com/bytom/bytom/protocol/bc/types"
 )
 
 // GetAccountUtxos return all account unspent outputs
@@ -33,7 +33,7 @@ func (w *Wallet) GetAccountUtxos(accountID string, id string, unconfirmed, isSma
        for accountUtxoIter.Next() {
                accountUtxo := &account.UTXO{}
                if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
-                       log.WithField("err", err).Warn("GetAccountUtxos fail on unmarshal utxo")
+                       log.WithFields(log.Fields{"module": logModule, "err": err}).Warn("GetAccountUtxos fail on unmarshal utxo")
                        continue
                }
 
@@ -44,16 +44,10 @@ func (w *Wallet) GetAccountUtxos(accountID string, id string, unconfirmed, isSma
        return accountUtxos
 }
 
-func (w *Wallet) attachUtxos(batch db.Batch, b *types.Block, txStatus *bc.TransactionStatus) {
-       for txIndex, tx := range b.Transactions {
-               statusFail, err := txStatus.GetStatus(txIndex)
-               if err != nil {
-                       log.WithField("err", err).Error("attachUtxos fail on get tx status")
-                       continue
-               }
-
-               //hand update the transaction input utxos
-               inputUtxos := txInToUtxos(tx, statusFail)
+func (w *Wallet) attachUtxos(batch dbm.Batch, b *types.Block) {
+       for _, tx := range b.Transactions {
+               // hand update the transaction input utxos
+               inputUtxos := txInToUtxos(tx)
                for _, inputUtxo := range inputUtxos {
                        if segwit.IsP2WScript(inputUtxo.ControlProgram) {
                                batch.Delete(account.StandardUTXOKey(inputUtxo.OutputID))
@@ -62,24 +56,20 @@ func (w *Wallet) attachUtxos(batch db.Batch, b *types.Block, txStatus *bc.Transa
                        }
                }
 
-               //hand update the transaction output utxos
-               validHeight := uint64(0)
-               if txIndex == 0 {
-                       validHeight = b.Height + consensus.CoinbasePendingBlockNumber
-               }
-               outputUtxos := txOutToUtxos(tx, statusFail, validHeight)
+               // hand update the transaction output utxos
+               outputUtxos := txOutToUtxos(tx, b.Height)
                utxos := w.filterAccountUtxo(outputUtxos)
                if err := batchSaveUtxos(utxos, batch); err != nil {
-                       log.WithField("err", err).Error("attachUtxos fail on batchSaveUtxos")
+                       log.WithFields(log.Fields{"module": logModule, "err": err}).Error("attachUtxos fail on batchSaveUtxos")
                }
        }
 }
 
-func (w *Wallet) detachUtxos(batch db.Batch, b *types.Block, txStatus *bc.TransactionStatus) {
+func (w *Wallet) detachUtxos(batch dbm.Batch, b *types.Block) {
        for txIndex := len(b.Transactions) - 1; txIndex >= 0; txIndex-- {
                tx := b.Transactions[txIndex]
                for j := range tx.Outputs {
-                       resOut, err := tx.Output(*tx.ResultIds[j])
+                       resOut, err := tx.OriginalOutput(*tx.ResultIds[j])
                        if err != nil {
                                continue
                        }
@@ -91,16 +81,10 @@ func (w *Wallet) detachUtxos(batch db.Batch, b *types.Block, txStatus *bc.Transa
                        }
                }
 
-               statusFail, err := txStatus.GetStatus(txIndex)
-               if err != nil {
-                       log.WithField("err", err).Error("detachUtxos fail on get tx status")
-                       continue
-               }
-
-               inputUtxos := txInToUtxos(tx, statusFail)
+               inputUtxos := txInToUtxos(tx)
                utxos := w.filterAccountUtxo(inputUtxos)
                if err := batchSaveUtxos(utxos, batch); err != nil {
-                       log.WithField("err", err).Error("detachUtxos fail on batchSaveUtxos")
+                       log.WithFields(log.Fields{"module": logModule, "err": err}).Error("detachUtxos fail on batchSaveUtxos")
                        return
                }
        }
@@ -116,9 +100,6 @@ func (w *Wallet) filterAccountUtxo(utxos []*account.UTXO) []*account.UTXO {
        result := make([]*account.UTXO, 0, len(utxos))
        for s := range outsByScript {
                if !segwit.IsP2WScript([]byte(s)) {
-                       for _, utxo := range outsByScript[s] {
-                               result = append(result, utxo)
-                       }
                        continue
                }
 
@@ -131,7 +112,7 @@ func (w *Wallet) filterAccountUtxo(utxos []*account.UTXO) []*account.UTXO {
 
                cp := &account.CtrlProgram{}
                if err := json.Unmarshal(data, cp); err != nil {
-                       log.WithField("err", err).Error("filterAccountUtxo fail on unmarshal control program")
+                       log.WithFields(log.Fields{"module": logModule, "err": err}).Error("filterAccountUtxo fail on unmarshal control program")
                        continue
                }
 
@@ -146,7 +127,7 @@ func (w *Wallet) filterAccountUtxo(utxos []*account.UTXO) []*account.UTXO {
        return result
 }
 
-func batchSaveUtxos(utxos []*account.UTXO, batch db.Batch) error {
+func batchSaveUtxos(utxos []*account.UTXO, batch dbm.Batch) error {
        for _, utxo := range utxos {
                data, err := json.Marshal(utxo)
                if err != nil {
@@ -162,57 +143,110 @@ func batchSaveUtxos(utxos []*account.UTXO, batch db.Batch) error {
        return nil
 }
 
-func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO {
+func txInToUtxos(tx *types.Tx) []*account.UTXO {
        utxos := []*account.UTXO{}
        for _, inpID := range tx.Tx.InputIDs {
-               sp, err := tx.Spend(inpID)
-               if err != nil {
+               var utxo *account.UTXO
+               e, ok := tx.Entries[inpID]
+               if !ok {
                        continue
                }
 
-               resOut, err := tx.Output(*sp.SpentOutputId)
-               if err != nil {
-                       log.WithField("err", err).Error("txInToUtxos fail on get resOut")
-                       continue
-               }
+               switch inp := e.(type) {
+               case *bc.Spend:
+                       resOut, err := tx.OriginalOutput(*inp.SpentOutputId)
+                       if err != nil {
+                               log.WithFields(log.Fields{"module": logModule, "err": err}).Error("txInToUtxos fail on get resOut")
+                               continue
+                       }
 
-               if statusFail && *resOut.Source.Value.AssetId != *consensus.BTMAssetID {
+                       utxo = &account.UTXO{
+                               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.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 *resOut.Source.Value.AssetId != *consensus.BTMAssetID {
+                               continue
+                       }
+                       utxo = &account.UTXO{
+                               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,
+                               Vote:           resOut.Vote,
+                       }
+               default:
                        continue
                }
-
-               utxos = append(utxos, &account.UTXO{
-                       OutputID:       *sp.SpentOutputId,
-                       AssetID:        *resOut.Source.Value.AssetId,
-                       Amount:         resOut.Source.Value.Amount,
-                       ControlProgram: resOut.ControlProgram.Code,
-                       SourceID:       *resOut.Source.Ref,
-                       SourcePos:      resOut.Source.Position,
-               })
+               utxos = append(utxos, utxo)
        }
        return utxos
 }
 
-func txOutToUtxos(tx *types.Tx, statusFail bool, vaildHeight uint64) []*account.UTXO {
+func txOutToUtxos(tx *types.Tx, blockHeight uint64) []*account.UTXO {
        utxos := []*account.UTXO{}
        for i, out := range tx.Outputs {
-               bcOut, err := tx.Output(*tx.ResultIds[i])
-               if err != nil {
+               validHeight := uint64(0)
+               entryOutput, ok := tx.Entries[*tx.ResultIds[i]]
+               if !ok {
+                       log.WithFields(log.Fields{"module": logModule}).Error("txOutToUtxos fail on get entryOutput")
                        continue
                }
 
-               if statusFail && *out.AssetAmount.AssetId != *consensus.BTMAssetID {
+               var utxo *account.UTXO
+               switch bcOut := entryOutput.(type) {
+               case *bc.OriginalOutput:
+                       if out.AssetAmount.Amount == uint64(0) {
+                               continue
+                       }
+
+                       if tx.Inputs[0].InputType() == types.CoinbaseInputType {
+                               validHeight = blockHeight + consensus.CoinbasePendingBlockNumber
+                       }
+
+                       utxo = &account.UTXO{
+                               OutputID:       *tx.OutputID(i),
+                               AssetID:        *out.AssetAmount.AssetId,
+                               Amount:         out.AssetAmount.Amount,
+                               ControlProgram: out.ControlProgram,
+                               SourceID:       *bcOut.Source.Ref,
+                               SourcePos:      bcOut.Source.Position,
+                               ValidHeight:    validHeight,
+                       }
+
+               case *bc.VoteOutput:
+                       voteValidHeight := blockHeight + consensus.VotePendingBlockNumber
+                       if validHeight < voteValidHeight {
+                               validHeight = voteValidHeight
+                       }
+
+                       utxo = &account.UTXO{
+                               OutputID:       *tx.OutputID(i),
+                               AssetID:        *out.AssetAmount.AssetId,
+                               Amount:         out.AssetAmount.Amount,
+                               ControlProgram: out.ControlProgram,
+                               SourceID:       *bcOut.Source.Ref,
+                               SourcePos:      bcOut.Source.Position,
+                               ValidHeight:    validHeight,
+                               Vote:           bcOut.Vote,
+                       }
+
+               default:
+                       log.WithFields(log.Fields{"module": logModule}).Warn("txOutToUtxos fail on get bcOut")
                        continue
                }
-
-               utxos = append(utxos, &account.UTXO{
-                       OutputID:       *tx.OutputID(i),
-                       AssetID:        *out.AssetAmount.AssetId,
-                       Amount:         out.Amount,
-                       ControlProgram: out.ControlProgram,
-                       SourceID:       *bcOut.Source.Ref,
-                       SourcePos:      bcOut.Source.Position,
-                       ValidHeight:    vaildHeight,
-               })
+               utxos = append(utxos, utxo)
        }
        return utxos
 }