OSDN Git Service

fk
[bytom/vapor.git] / federation / synchron / mainchain_keeper.go
index 65dec7a..c97754a 100644 (file)
@@ -1,9 +1,12 @@
 package synchron
 
 import (
+       "bytes"
        "encoding/hex"
+       "fmt"
        "time"
 
+       btmBc "github.com/bytom/protocol/bc"
        btmTypes "github.com/bytom/protocol/bc/types"
        "github.com/jinzhu/gorm"
        log "github.com/sirupsen/logrus"
@@ -16,8 +19,6 @@ import (
        "github.com/vapor/protocol/bc"
 )
 
-var ErrInconsistentDB = errors.New("inconsistent db status")
-
 type mainchainKeeper struct {
        cfg        *config.Chain
        db         *gorm.DB
@@ -97,7 +98,7 @@ func (m *mainchainKeeper) tryAttachBlock(chain *orm.Chain, block *btmTypes.Block
        blockHash := block.Hash()
        log.WithFields(log.Fields{"block_height": block.Height, "block_hash": blockHash.String()}).Info("start to attachBlock")
        m.db.Begin()
-       if err := m.processBlock(chain, block); err != nil {
+       if err := m.processBlock(chain, block, txStatus); err != nil {
                m.db.Rollback()
                return err
        }
@@ -105,23 +106,134 @@ func (m *mainchainKeeper) tryAttachBlock(chain *orm.Chain, block *btmTypes.Block
        return m.db.Commit().Error
 }
 
-func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *btmTypes.Block) error {
+func (m *mainchainKeeper) processBlock(chain *orm.Chain, block *btmTypes.Block, txStatus *bc.TransactionStatus) error {
        if err := m.processIssuing(block.Transactions); err != nil {
                return err
        }
 
-       // for i, tx := range txs {
-       //      if isDepositFromMainchain(tx) {
-       //              bp.processDepositFromMainchain(uint64(i), tx)
-       //      }
-       //      if isWithdrawalToMainchain(tx) {
-       //              bp.processWithdrawalToMainchain(uint64(i), tx)
-       //      }
-       // }
+       for i, tx := range block.Transactions {
+               if m.isDepositTx(tx) {
+                       if err := m.processDepositTx(chain, block, txStatus, uint64(i), tx); err != nil {
+                               return err
+                       }
+               }
+
+               if m.isWithdrawalTx(tx) {
+                       if err := m.processWithdrawalTx(uint64(i), tx); err != nil {
+                               return err
+                       }
+               }
+       }
 
        return m.processChainInfo(chain, block)
 }
 
+func (m *mainchainKeeper) isDepositTx(tx *btmTypes.Tx) bool {
+       for _, output := range tx.Outputs {
+               if bytes.Equal(output.OutputCommitment.ControlProgram, fedProg) {
+                       return true
+               }
+       }
+       return false
+}
+
+func (m *mainchainKeeper) isWithdrawalTx(tx *btmTypes.Tx) bool {
+       for _, input := range tx.Inputs {
+               if bytes.Equal(input.ControlProgram(), fedProg) {
+                       return true
+               }
+       }
+       return false
+}
+
+func (m *mainchainKeeper) processDepositTx(chain *orm.Chain, block *btmTypes.Block, txStatus *bc.TransactionStatus, txIndex uint64, tx *btmTypes.Tx) error {
+       blockHash := block.Hash()
+
+       var muxID btmBc.Hash
+       isMuxIDFound := false
+       for _, resOutID := range tx.ResultIds {
+               resOut, ok := tx.Entries[*resOutID].(*btmBc.Output)
+               if ok {
+                       muxID = *resOut.Source.Ref
+                       isMuxIDFound = true
+                       break
+               }
+       }
+       if !isMuxIDFound {
+               return errors.New("fail to get mux id")
+       }
+
+       rawTx, err := tx.MarshalText()
+       if err != nil {
+               return err
+       }
+
+       ormTx := &orm.CrossTransaction{
+               ChainID:        chain.ID,
+               BlockHeight:    block.Height,
+               BlockHash:      blockHash.String(),
+               TxIndex:        txIndex,
+               MuxID:          muxID.String(),
+               TxHash:         tx.ID.String(),
+               RawTransaction: string(rawTx),
+               // Status         uint8
+       }
+       if err := m.db.Create(ormTx).Error; err != nil {
+               return errors.Wrap(err, fmt.Sprintf("create mainchain DepositTx %s", tx.ID.String()))
+       }
+
+       statusFail := txStatus.VerifyStatus[txIndex].StatusFail
+       crossChainInputs, err := m.getCrossChainInputs(ormTx.ID, tx, statusFail)
+       if err != nil {
+               return err
+       }
+
+       for _, input := range crossChainInputs {
+               if err := m.db.Create(input).Error; err != nil {
+                       return errors.Wrap(err, fmt.Sprintf("create DepositFromMainchain input: txid(%s), pos(%d)", tx.ID.String(), input.SourcePos))
+               }
+       }
+
+       return nil
+}
+
+func (m *mainchainKeeper) getCrossChainInputs(mainchainTxID uint64, tx *btmTypes.Tx, statusFail bool) ([]*orm.CrossTransactionInput, error) {
+       // assume inputs are from an identical owner
+       script := hex.EncodeToString(tx.Inputs[0].ControlProgram())
+       inputs := []*orm.CrossTransactionInput{}
+       for i, rawOutput := range tx.Outputs {
+               // check valid deposit
+               if !bytes.Equal(rawOutput.OutputCommitment.ControlProgram, fedProg) {
+                       continue
+               }
+
+               if statusFail && *rawOutput.OutputCommitment.AssetAmount.AssetId != *btmConsensus.BTMAssetID {
+                       continue
+               }
+
+               asset, err := m.getAsset(rawOutput.OutputCommitment.AssetAmount.AssetId.String())
+               if err != nil {
+                       return nil, err
+               }
+
+               // default null SidechainTxID, which will be set after submitting deposit tx on sidechain
+               input := &orm.CrossTransactionInput{
+                       MainchainTxID: mainchainTxID,
+                       SourcePos:     uint64(i),
+                       AssetID:       asset.ID,
+                       AssetAmount:   rawOutput.OutputCommitment.AssetAmount.Amount,
+                       Script:        script,
+               }
+               inputs = append(inputs, input)
+       }
+       return inputs, nil
+}
+
+func (m *mainchainKeeper) processWithdrawalTx(txIndex uint64, tx *btmTypes.Tx) error {
+       return nil
+}
+
+// TODO: maybe common
 func (m *mainchainKeeper) processChainInfo(chain *orm.Chain, block *btmTypes.Block) error {
        blockHash := block.Hash()
        chain.BlockHash = blockHash.String()
@@ -166,6 +278,7 @@ func (m *mainchainKeeper) processIssuing(txs []*btmTypes.Tx) error {
        return nil
 }
 
+// TODO: maybe common
 func (m *mainchainKeeper) getAsset(assetID string) (*orm.Asset, error) {
        if asset := m.assetCache.Get(assetID); asset != nil {
                return asset, nil