X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=application%2Fmov%2Fmov_core.go;fp=application%2Fmov%2Fmov_core.go;h=955a493b849ec4dce69ea1d513bfcafd1e362c08;hb=07ca35e3d7b730db9168e839b63a3e8c44bc9139;hp=6a8855a0cfccb5b95c7adedc78827c6b8680a1db;hpb=cb75951f9f5a341b13db6678f8af0715ad29e615;p=bytom%2Fvapor.git diff --git a/application/mov/mov_core.go b/application/mov/mov_core.go index 6a8855a0..955a493b 100644 --- a/application/mov/mov_core.go +++ b/application/mov/mov_core.go @@ -18,16 +18,18 @@ import ( const maxFeeRate = 0.05 var ( - errInvalidTradePairs = errors.New("The trade pairs in the tx input is invalid") - errStatusFailMustFalse = errors.New("status fail of transaction does not allow to be true") - errInputProgramMustP2WMCScript = errors.New("input program of trade tx must p2wmc script") - errExistCancelOrderInMatchedTx = errors.New("can't exist cancel order in the matched transaction") - errExistTradeInCancelOrderTx = errors.New("can't exist trade in the cancel order transaction") - errAssetIDMustUniqueInMatchedTx = errors.New("asset id must unique in matched transaction") - errRatioOfTradeLessThanZero = errors.New("ratio arguments must greater than zero") - errSpendOutputIDIsIncorrect = errors.New("spend output id of matched tx is not equals to actual matched tx") - errRequestAmountMath = errors.New("request amount of order less than one or big than max of int64") - errNotMatchedOrder = errors.New("order in matched tx is not matched") + errInvalidTradePairs = errors.New("The trade pairs in the tx input is invalid") + errStatusFailMustFalse = errors.New("status fail of transaction does not allow to be true") + errInputProgramMustP2WMCScript = errors.New("input program of trade tx must p2wmc script") + errExistCancelOrderInMatchedTx = errors.New("can't exist cancel order in the matched transaction") + errExistTradeInCancelOrderTx = errors.New("can't exist trade in the cancel order transaction") + errAssetIDMustUniqueInMatchedTx = errors.New("asset id must unique in matched transaction") + errRatioOfTradeLessThanZero = errors.New("ratio arguments must greater than zero") + errSpendOutputIDIsIncorrect = errors.New("spend output id of matched tx is not equals to actual matched tx") + errRequestAmountMath = errors.New("request amount of order less than one or big than max of int64") + errNotMatchedOrder = errors.New("order in matched tx is not matched") + errNotConfiguredRewardProgram = errors.New("reward program is not configured properly") + errRewardProgramIsWrong = errors.New("the reward program is not correct") ) // MovCore represent the core logic of the match module, which include generate match transactions before packing the block, @@ -83,9 +85,10 @@ func (m *MovCore) BeforeProposalBlock(txs []*types.Tx, blockHeight uint64, gasLe return nil, err } - rewardProgram, err := hex.DecodeString(consensus.ActiveNetParams.MovRewardProgram) + program, _ := getRewardProgram(blockHeight) + rewardProgram, err := hex.DecodeString(program) if err != nil { - return nil, err + return nil, errNotConfiguredRewardProgram } matchEngine := match.NewEngine(orderBook, match.NewDefaultFeeStrategy(maxFeeRate), rewardProgram) @@ -142,13 +145,8 @@ func (m *MovCore) StartHeight() uint64 { // ValidateBlock no need to verify the block header, because the first module has been verified. // just need to verify the transactions in the block. func (m *MovCore) ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error { - return m.ValidateTxs(block.Transactions, verifyResults) -} - -// ValidateTxs validate the trade transaction. -func (m *MovCore) ValidateTxs(txs []*types.Tx, verifyResults []*bc.TxVerifyResult) error { - for i, tx := range txs { - if err := m.ValidateTx(tx, verifyResults[i]); err != nil { + for i, tx := range block.Transactions { + if err := m.ValidateTx(tx, verifyResults[i], block.Height); err != nil { return err } } @@ -156,9 +154,9 @@ func (m *MovCore) ValidateTxs(txs []*types.Tx, verifyResults []*bc.TxVerifyResul } // ValidateTx validate one transaction. -func (m *MovCore) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error { +func (m *MovCore) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error { if common.IsMatchedTx(tx) { - if err := validateMatchedTx(tx, verifyResult); err != nil { + if err := validateMatchedTx(tx, verifyResult, blockHeight); err != nil { return err } } else if common.IsCancelOrderTx(tx) { @@ -182,13 +180,19 @@ func (m *MovCore) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) erro return nil } +// matchedTxFee is object to record the mov tx's fee information +type matchedTxFee struct { + rewardProgram []byte + amount int64 +} + // calcFeeAmount return the amount of fee in the matching transaction -func calcFeeAmount(matchedTx *types.Tx) (map[bc.AssetID]int64, error) { - assetFeeMap := make(map[bc.AssetID]int64) +func calcFeeAmount(matchedTx *types.Tx) (map[bc.AssetID]*matchedTxFee, error) { + assetFeeMap := make(map[bc.AssetID]*matchedTxFee) dealProgMaps := make(map[string]bool) for _, input := range matchedTx.Inputs { - assetFeeMap[input.AssetID()] = int64(input.AssetAmount().Amount) + assetFeeMap[input.AssetID()] = &matchedTxFee{amount: int64(input.AssetAmount().Amount)} contractArgs, err := segwit.DecodeP2WMCProgram(input.ControlProgram()) if err != nil { return nil, err @@ -200,10 +204,12 @@ func calcFeeAmount(matchedTx *types.Tx) (map[bc.AssetID]int64, error) { for _, output := range matchedTx.Outputs { assetAmount := output.AssetAmount() if _, ok := dealProgMaps[hex.EncodeToString(output.ControlProgram())]; ok || segwit.IsP2WMCScript(output.ControlProgram()) { - assetFeeMap[*assetAmount.AssetId] -= int64(assetAmount.Amount) - if assetFeeMap[*assetAmount.AssetId] <= 0 { + assetFeeMap[*assetAmount.AssetId].amount -= int64(assetAmount.Amount) + if assetFeeMap[*assetAmount.AssetId].amount <= 0 { delete(assetFeeMap, *assetAmount.AssetId) } + } else { + assetFeeMap[*assetAmount.AssetId].rewardProgram = output.ControlProgram() } } return assetFeeMap, nil @@ -246,7 +252,7 @@ func validateMagneticContractArgs(fromAssetAmount bc.AssetAmount, program []byte return nil } -func validateMatchedTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error { +func validateMatchedTx(tx *types.Tx, verifyResult *bc.TxVerifyResult, blockHeight uint64) error { if verifyResult.StatusFail { return errStatusFailMustFalse } @@ -275,21 +281,32 @@ func validateMatchedTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error { return errAssetIDMustUniqueInMatchedTx } - return validateMatchedTxFeeAmount(tx) + return validateMatchedTxFee(tx, blockHeight) } -func validateMatchedTxFeeAmount(tx *types.Tx) error { - orders, err := getDeleteOrdersFromTx(tx) +func validateMatchedTxFee(tx *types.Tx, blockHeight uint64) error { + matchedTxFees, err := calcFeeAmount(tx) if err != nil { return err } - receivedAmount, priceDiff := match.CalcReceivedAmount(orders) - feeAmounts, err := calcFeeAmount(tx) + for _, fee := range matchedTxFees { + if err := validateRewardProgram(blockHeight, hex.EncodeToString(fee.rewardProgram)); err != nil { + return err + } + } + + orders, err := getDeleteOrdersFromTx(tx) if err != nil { return err } + feeAmounts := make(map[bc.AssetID]int64) + for assetID, fee := range matchedTxFees { + feeAmounts[assetID] = fee.amount + } + + receivedAmount, priceDiff := match.CalcReceivedAmount(orders) feeStrategy := match.NewDefaultFeeStrategy(maxFeeRate) return feeStrategy.Validate(receivedAmount, priceDiff, feeAmounts) } @@ -472,3 +489,31 @@ func mergeOrders(addOrderMap, deleteOrderMap map[string]*common.Order) ([]*commo } return addOrders, deleteOrders } + +// getRewardProgram return the reward program by specified block height +// if no reward program configured, then will return empty string +// if reward program of 0-100 height is configured, but the specified height is 200, then will return 0-100's reward program +// the second return value represent whether to find exactly +func getRewardProgram(height uint64) (string, bool) { + rewardPrograms := consensus.ActiveNetParams.MovRewardPrograms + if len(rewardPrograms) == 0 { + return "", false + } + + var program string + for _, rewardProgram := range rewardPrograms { + program = rewardProgram.Program + if height >= rewardProgram.BeginBlock && height <= rewardProgram.EndBlock { + return program, true + } + } + return program, false +} + +func validateRewardProgram(height uint64, program string) error { + rewardProgram, exact := getRewardProgram(height) + if exact && rewardProgram != program { + return errRewardProgramIsWrong + } + return nil +}