diff --git a/common/utils/util.go b/common/utils/util.go index 6dada604..25105bc6 100644 --- a/common/utils/util.go +++ b/common/utils/util.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/sirupsen/logrus" "golang.org/x/xerrors" + "gorm.io/gorm" "math/big" "regexp" "runtime" @@ -200,3 +201,18 @@ func GetCurrentGoroutineStack() string { n := runtime.Stack(buf[:], false) return string(buf[:n]) } +func DBTransactional(db *gorm.DB, handle func() error) (err error) { + tx := db.Begin() + defer func() { + if p := recover(); p != nil { + tx.Rollback() + panic(p) + } else if err != nil { + tx.Rollback() + } else { + err = tx.Commit().Error + } + }() + err = handle() + return +} diff --git a/rpc_server/api/v1/sponsor.go b/rpc_server/api/v1/sponsor.go index fe4c09af..35c28ebb 100644 --- a/rpc_server/api/v1/sponsor.go +++ b/rpc_server/api/v1/sponsor.go @@ -66,7 +66,7 @@ func WithdrawSponsor(ctx *gin.Context) { return } -type SponsorDepositTransaction struct { +type sponsorDepositTransaction struct { TxHash string `json:"tx_hash"` Amount string `json:"amount"` UpdateType global_const.UpdateType `json:"update_type"` @@ -90,12 +90,12 @@ func GetSponsorDepositAndWithdrawTransactions(ctx *gin.Context) { models, err := sponsor_manager.GetDepositAndWithDrawLog(userId, isTestNet) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - response.FailCode(ctx, 301, "No Deposit Transactions") + response.FailCode(ctx, 400, "No Deposit Transactions") } } - trans := make([]SponsorDepositTransaction, 0) + trans := make([]sponsorDepositTransaction, 0) for _, depositModel := range models { - tran := SponsorDepositTransaction{ + tran := sponsorDepositTransaction{ TxHash: depositModel.TxHash, Amount: depositModel.Amount.String(), } @@ -105,11 +105,6 @@ func GetSponsorDepositAndWithdrawTransactions(ctx *gin.Context) { return } -type SponsorMetaResponse struct { - AvailableBalance string `json:"available_balance"` - SponsorAddress string `json:"sponsor_address"` -} - // GetSponsorMetaData // @Tags Sponsor // @Description Get Sponsor Balance @@ -126,10 +121,13 @@ func GetSponsorMetaData(ctx *gin.Context) { balance, err := sponsor_manager.FindUserSponsorBalance(userId, isTestNet) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { - response.FailCode(ctx, 301, "No Balance") + response.FailCode(ctx, 400, "No Balance") } } - result := SponsorMetaResponse{ + result := struct { + AvailableBalance string `json:"available_balance"` + SponsorAddress string `json:"sponsor_address"` + }{ AvailableBalance: balance.AvailableBalance.String(), SponsorAddress: balance.SponsorAddress, } diff --git a/sponsor_manager/sponsor_changelog_repository.go b/sponsor_manager/sponsor_changelog_repository.go index 7d0694f4..768ed50d 100644 --- a/sponsor_manager/sponsor_changelog_repository.go +++ b/sponsor_manager/sponsor_changelog_repository.go @@ -32,7 +32,7 @@ func LogBalanceChange(updateType global_const.UpdateType, balanceType global_con return } func GetDepositAndWithDrawLog(userId string, IsTestNet bool) (models []*UserSponsorBalanceUpdateLogDBModel, err error) { - tx := relayDB.Model(&UserSponsorBalanceUpdateLogDBModel{}).Where("pay_user_id = ?", userId).Where("is_test_net = ?", IsTestNet).Where("update_type = ?", global_const.UpdateTypeDeposit).Or("update_type = ?", global_const.UpdateTypeWithdraw).Find(&models) + tx := relayDB.Model(&UserSponsorBalanceUpdateLogDBModel{}).Where("pay_user_id = ?", userId).Where("is_test_net = ?", IsTestNet).Where("update_type in (?)", []global_const.UpdateType{global_const.UpdateTypeDeposit, global_const.UpdateTypeWithdraw}).Find(&models) if tx.Error != nil { return nil, tx.Error } diff --git a/sponsor_manager/sponsor_service.go b/sponsor_manager/sponsor_service.go index 4f6d72f2..009d001c 100644 --- a/sponsor_manager/sponsor_service.go +++ b/sponsor_manager/sponsor_service.go @@ -77,29 +77,25 @@ func LockUserBalance(userId string, userOpHash []byte, isTestNet bool, availableBalance := new(big.Float).Sub(balanceModel.AvailableBalance.Float, lockAmount) balanceModel.LockBalance = BigFloat{lockBalance} balanceModel.AvailableBalance = BigFloat{availableBalance} - tx := relayDB.Begin() - if updateErr := tx.Model(&UserSponsorBalanceDBModel{}). - Where("pay_user_id = ?", balanceModel.PayUserId). - Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { - tx.Rollback() - return nil, updateErr - } + err = utils.DBTransactional(relayDB, func() error { + if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). + Where("pay_user_id = ?", balanceModel.PayUserId). + Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { + return err + } - changeModel := &UserSponsorBalanceUpdateLogDBModel{ - UserOpHash: UserOphashStr, - PayUserId: userId, - Amount: BigFloat{lockAmount}, - IsTestNet: isTestNet, - UpdateType: global_const.UpdateTypeLock, - } - if createErr := tx.Create(changeModel).Error; createErr != nil { - tx.Rollback() - return nil, createErr - } - if commitErr := tx.Commit().Error; commitErr != nil { - tx.Rollback() - return nil, commitErr - } + changeModel := &UserSponsorBalanceUpdateLogDBModel{ + UserOpHash: UserOphashStr, + PayUserId: userId, + Amount: BigFloat{lockAmount}, + IsTestNet: isTestNet, + UpdateType: global_const.UpdateTypeLock, + } + if createErr := relayDB.Create(changeModel).Error; createErr != nil { + return err + } + return nil + }) return nil, nil } @@ -119,31 +115,31 @@ func ReleaseBalanceWithActualCost(userId string, userOpHash []byte, refundBalance := new(big.Float).Sub(lockBalance.Float, actualGasCost) balanceModel.AvailableBalance = BigFloat{new(big.Float).Add(balanceModel.AvailableBalance.Float, refundBalance)} - tx := relayDB.Begin() - if updateErr := tx.Model(&UserSponsorBalanceDBModel{}). - Model(&UserSponsorBalanceDBModel{}). - Where("pay_user_id = ?", balanceModel.PayUserId). - Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { - tx.Rollback() + err = utils.DBTransactional(relayDB, func() error { + if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). + Model(&UserSponsorBalanceDBModel{}). + Where("pay_user_id = ?", balanceModel.PayUserId). + Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { + return err + } + + changeDBModel := &UserSponsorBalanceUpdateLogDBModel{ + UserOpHash: userOpHashHex, + PayUserId: changeModel.PayUserId, + Amount: BigFloat{refundBalance}, + Source: "GasTank", + IsTestNet: isTestNet, + UpdateType: global_const.UpdateTypeRelease, + } + if createErr := relayDB.Create(changeDBModel).Error; createErr != nil { + return createErr + } + return nil + }) + if err != nil { return nil, err } - changeDBModel := &UserSponsorBalanceUpdateLogDBModel{ - UserOpHash: userOpHashHex, - PayUserId: changeModel.PayUserId, - Amount: BigFloat{refundBalance}, - Source: "GasTank", - IsTestNet: isTestNet, - UpdateType: global_const.UpdateTypeRelease, - } - if createErr := tx.Create(changeDBModel).Error; createErr != nil { - tx.Rollback() - return nil, createErr - } - if commitErr := tx.Commit().Error; commitErr != nil { - tx.Rollback() - return nil, commitErr - } return balanceModel, nil } @@ -163,30 +159,29 @@ func ReleaseUserOpHashLockWhenFail(userOpHash []byte, isTestNet bool) (*UserSpon lockBalance := changeModel.Amount balanceModel.LockBalance = BigFloat{new(big.Float).Sub(balanceModel.LockBalance.Float, lockBalance.Float)} balanceModel.AvailableBalance = BigFloat{new(big.Float).Add(balanceModel.AvailableBalance.Float, lockBalance.Float)} - tx := relayDB.Begin() - if updateErr := tx.Model(&UserSponsorBalanceDBModel{}). - Where("pay_user_id = ?", balanceModel.PayUserId). - Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { - tx.Rollback() - return nil, err - } + err = utils.DBTransactional(relayDB, func() error { + if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). + Where("pay_user_id = ?", balanceModel.PayUserId). + Where("is_test_net = ?", isTestNet).Updates(balanceModel).Error; updateErr != nil { + return err + } - changeDBModel := &UserSponsorBalanceUpdateLogDBModel{ - UserOpHash: userOpHashHex, - PayUserId: changeModel.PayUserId, - Amount: lockBalance, - IsTestNet: isTestNet, - UpdateType: global_const.UpdateTypeRelease, - } - if createErr := tx.Create(changeDBModel).Error; createErr != nil { - tx.Rollback() - return nil, createErr - } - if commitErr := tx.Commit().Error; commitErr != nil { - tx.Rollback() - return nil, commitErr + changeDBModel := &UserSponsorBalanceUpdateLogDBModel{ + UserOpHash: userOpHashHex, + PayUserId: changeModel.PayUserId, + Amount: lockBalance, + IsTestNet: isTestNet, + UpdateType: global_const.UpdateTypeRelease, + } + if createErr := relayDB.Create(changeDBModel).Error; createErr != nil { + return createErr + } + return nil + }) + if err != nil { + return nil, err } - return nil, err + return balanceModel, nil } //----------Functions---------- @@ -194,54 +189,57 @@ func ReleaseUserOpHashLockWhenFail(userOpHash []byte, isTestNet bool) (*UserSpon func DepositSponsor(input *model.DepositSponsorRequest) (*UserSponsorBalanceDBModel, error) { balanceModel, err := FindUserSponsorBalance(input.PayUserId, input.IsTestNet) + if err != nil { + return nil, err + } - tx := relayDB.Begin() - if errors.Is(err, gorm.ErrRecordNotFound) { - //init Data - balanceModel = &UserSponsorBalanceDBModel{} - balanceModel.AvailableBalance = BigFloat{big.NewFloat(0)} - balanceModel.PayUserId = input.PayUserId - balanceModel.LockBalance = BigFloat{big.NewFloat(0)} - balanceModel.IsTestNet = input.IsTestNet - err = tx.Create(balanceModel).Error + err = utils.DBTransactional(relayDB, func() error { + if errors.Is(err, gorm.ErrRecordNotFound) { + //init Data + balanceModel = &UserSponsorBalanceDBModel{} + balanceModel.AvailableBalance = BigFloat{big.NewFloat(0)} + balanceModel.PayUserId = input.PayUserId + balanceModel.LockBalance = BigFloat{big.NewFloat(0)} + balanceModel.IsTestNet = input.IsTestNet + err = relayDB.Create(balanceModel).Error + if err != nil { + + return err + } + } if err != nil { - tx.Rollback() - return nil, err + + return err } - } + newAvailableBalance := BigFloat{new(big.Float).Add(balanceModel.AvailableBalance.Float, input.Amount)} + balanceModel.AvailableBalance = newAvailableBalance + + if updateErr := relayDB.Model(balanceModel). + Where("pay_user_id = ?", balanceModel.PayUserId). + Where("is_test_net = ?", input.IsTestNet).Updates(balanceModel).Error; updateErr != nil { + + return updateErr + } + + txInfoJSon, _ := json.Marshal(input.TxInfo) + changeModel := &UserSponsorBalanceUpdateLogDBModel{ + PayUserId: input.PayUserId, + Amount: BigFloat{input.Amount}, + Source: "Deposit", + IsTestNet: input.IsTestNet, + UpdateType: global_const.UpdateTypeDeposit, + TxHash: input.TxHash, + TxInfo: txInfoJSon, + } + if createErr := relayDB.Create(changeModel).Error; createErr != nil { + return createErr + } + return nil + }) if err != nil { - tx.Rollback() return nil, err } - newAvailableBalance := BigFloat{new(big.Float).Add(balanceModel.AvailableBalance.Float, input.Amount)} - balanceModel.AvailableBalance = newAvailableBalance - - if updateErr := tx.Model(balanceModel). - Where("pay_user_id = ?", balanceModel.PayUserId). - Where("is_test_net = ?", input.IsTestNet).Updates(balanceModel).Error; updateErr != nil { - tx.Rollback() - return nil, updateErr - } - - txInfoJSon, _ := json.Marshal(input.TxInfo) - chagneModel := &UserSponsorBalanceUpdateLogDBModel{ - PayUserId: input.PayUserId, - Amount: BigFloat{input.Amount}, - Source: "Deposit", - IsTestNet: input.IsTestNet, - UpdateType: global_const.UpdateTypeDeposit, - TxHash: input.TxHash, - TxInfo: txInfoJSon, - } - if createErr := tx.Create(chagneModel).Error; createErr != nil { - tx.Rollback() - return nil, createErr - } - if commitErr := tx.Commit().Error; commitErr != nil { - tx.Rollback() - return nil, commitErr - } return balanceModel, nil } @@ -255,28 +253,27 @@ func WithDrawSponsor(input *model.WithdrawSponsorRequest) (*UserSponsorBalanceDB } newAvailableBalance := new(big.Float).Sub(balanceModel.AvailableBalance.Float, input.Amount) balanceModel.AvailableBalance = BigFloat{newAvailableBalance} - tx := relayDB.Begin() - if updateErr := tx.Model(&UserSponsorBalanceDBModel{}). - Where("pay_user_id = ?", balanceModel.PayUserId). - Where("is_test_net = ?", input.IsTestNet).Updates(balanceModel).Error; updateErr != nil { - tx.Rollback() - return nil, updateErr - } - changeModel := &UserSponsorBalanceUpdateLogDBModel{ - PayUserId: input.PayUserId, - Amount: BigFloat{input.Amount}, - Source: "Withdraw", - IsTestNet: input.IsTestNet, - UpdateType: global_const.UpdateTypeWithdraw, - TxHash: input.TxHash, - } - if createErr := tx.Create(changeModel).Error; createErr != nil { - tx.Rollback() - return nil, createErr - } - if commitErr := tx.Commit().Error; commitErr != nil { - tx.Rollback() - return nil, commitErr + err = utils.DBTransactional(relayDB, func() error { + if updateErr := relayDB.Model(&UserSponsorBalanceDBModel{}). + Where("pay_user_id = ?", balanceModel.PayUserId). + Where("is_test_net = ?", input.IsTestNet).Updates(balanceModel).Error; updateErr != nil { + return updateErr + } + changeModel := &UserSponsorBalanceUpdateLogDBModel{ + PayUserId: input.PayUserId, + Amount: BigFloat{input.Amount}, + Source: "Withdraw", + IsTestNet: input.IsTestNet, + UpdateType: global_const.UpdateTypeWithdraw, + TxHash: input.TxHash, + } + if createErr := relayDB.Create(changeModel).Error; createErr != nil { + return createErr + } + return nil + }) + if err != nil { + return nil, err } return balanceModel, nil }