OSDN Git Service

feat: add build crosschain input (#91)
[bytom/vapor.git] / protocol / state / utxo_view.go
index d105178..c807144 100644 (file)
@@ -20,6 +20,24 @@ func NewUtxoViewpoint() *UtxoViewpoint {
 }
 
 func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFail bool) error {
+       for _, prevout := range tx.MainchainOutputIDs {
+               entry, ok := view.Entries[prevout]
+               if !ok {
+                       return errors.New("fail to find mainchain output entry")
+               }
+
+               if entry.Type != storage.CrosschainUTXOType {
+                       return errors.New("look up mainchainOutputID but find utxo not from mainchain")
+               }
+
+               if entry.Spent {
+                       return errors.New("mainchain output has been spent")
+               }
+
+               entry.BlockHeight = block.Height
+               entry.SpendOutput()
+       }
+
        for _, prevout := range tx.SpentOutputIDs {
                assetID := bc.AssetID{}
                entryOutput, err := tx.Entry(prevout)
@@ -44,10 +62,13 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa
                if !ok {
                        return errors.New("fail to find utxo entry")
                }
+               if entry.Type == storage.CrosschainUTXOType {
+                       return errors.New("look up spentOutputID but find utxo from mainchain")
+               }
                if entry.Spent {
                        return errors.New("utxo has been spent")
                }
-               if entry.IsCoinBase && entry.BlockHeight+consensus.CoinbasePendingBlockNumber > block.Height {
+               if (entry.Type == storage.CoinbaseUTXOType) && ((entry.BlockHeight + consensus.CoinbasePendingBlockNumber) > block.Height) {
                        return errors.New("coinbase utxo is not ready for use")
                }
                entry.SpendOutput()
@@ -74,11 +95,11 @@ func (view *UtxoViewpoint) ApplyTransaction(block *bc.Block, tx *bc.Tx, statusFa
                        continue
                }
 
-               isCoinbase := false
+               utxoType := storage.NormalUTXOType
                if block != nil && len(block.Transactions) > 0 && block.Transactions[0].ID == tx.ID {
-                       isCoinbase = true
+                       utxoType = storage.CoinbaseUTXOType
                }
-               view.Entries[*id] = storage.NewUtxoEntry(isCoinbase, block.Height, false)
+               view.Entries[*id] = storage.NewUtxoEntry(utxoType, block.Height, false)
        }
        return nil
 }
@@ -102,6 +123,24 @@ func (view *UtxoViewpoint) CanSpend(hash *bc.Hash) bool {
 }
 
 func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error {
+       for _, prevout := range tx.MainchainOutputIDs {
+               // don't simply delete(view.Entries, prevout), because we need to delete from db in saveUtxoView()
+               entry, ok := view.Entries[prevout]
+               if ok && (entry.Type != storage.CrosschainUTXOType) {
+                       return errors.New("look up mainchainOutputID but find utxo not from mainchain")
+               }
+
+               if ok && !entry.Spent {
+                       return errors.New("try to revert an unspent utxo")
+               }
+
+               if !ok {
+                       view.Entries[prevout] = storage.NewUtxoEntry(storage.CrosschainUTXOType, 0, false)
+                       continue
+               }
+               entry.UnspendOutput()
+       }
+
        for _, prevout := range tx.SpentOutputIDs {
                assetID := bc.AssetID{}
                entryOutput, err := tx.Entry(prevout)
@@ -123,11 +162,16 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error {
                }
 
                entry, ok := view.Entries[prevout]
+               if ok && (entry.Type == storage.CrosschainUTXOType) {
+                       return errors.New("look up SpentOutputIDs but find mainchain utxo")
+               }
+
                if ok && !entry.Spent {
                        return errors.New("try to revert an unspent utxo")
                }
+
                if !ok {
-                       view.Entries[prevout] = storage.NewUtxoEntry(false, 0, false)
+                       view.Entries[prevout] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, false)
                        continue
                }
                entry.UnspendOutput()
@@ -154,7 +198,7 @@ func (view *UtxoViewpoint) DetachTransaction(tx *bc.Tx, statusFail bool) error {
                        continue
                }
 
-               view.Entries[*id] = storage.NewUtxoEntry(false, 0, true)
+               view.Entries[*id] = storage.NewUtxoEntry(storage.NormalUTXOType, 0, true)
        }
        return nil
 }