Unverified Commit 0fbf2354 authored by Simon Esposito's avatar Simon Esposito Committed by GitHub
Browse files

Improve error on invalid wallet update (#546)

Return WalletNegativeError when updating a wallet with an amount higher than the available funds. Resolves #468
Do not log such an error when it occurs. Resolves #540
parent e62b2ca6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ require (
	github.com/gorilla/mux v1.7.4
	github.com/gorilla/websocket v1.4.2
	github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1
	github.com/heroiclabs/nakama-common v1.11.1-0.20210203184030-64cd8d070d43
	github.com/heroiclabs/nakama-common v1.11.1-0.20210204123435-b06844f83f0c
	github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
	github.com/jackc/pgx v3.5.0+incompatible
	github.com/jmhodges/levigo v1.0.0 // indirect
+2 −4
+10 −11
Original line number Diff line number Diff line
@@ -104,7 +104,9 @@ func UpdateWallets(ctx context.Context, logger *zap.Logger, db *sql.DB, updates
		}
		return nil
	}); err != nil {
		if _, ok := err.(*runtime.WalletNegativeError); !ok {
			logger.Error("Error updating wallets.", zap.Error(err))
		}
		// Ensure there are no partially updated wallets returned as results, they would not be reflected in database anyway.
		for _, result := range results {
			result.Updated = nil
@@ -171,7 +173,6 @@ func updateWallets(ctx context.Context, logger *zap.Logger, tx *sql.Tx, updates
	}

	// Go through the changesets and attempt to calculate the new state for each wallet.
	var changesetErr error
	for _, update := range updates {
		userID := update.UserID.String()
		walletMap, ok := wallets[userID]
@@ -191,14 +192,15 @@ func updateWallets(ctx context.Context, logger *zap.Logger, tx *sql.Tx, updates
			// Existing value may be 0 or missing.
			newValue := walletMap[k] + v
			if newValue < 0 {
				// Programmer error, no need to log.
				changesetErr = fmt.Errorf("wallet update rejected negative value at path '%v'", k)
				continue
				// Insufficient funds
				return nil, &runtime.WalletNegativeError{
					UserID:  userID,
					Path:    k,
					Current: walletMap[k],
					Amount:  v,
				}
			walletMap[k] = newValue
			}
		if changesetErr != nil {
			continue
			walletMap[k] = newValue
		}

		result.Updated = walletMap
@@ -224,9 +226,6 @@ func updateWallets(ctx context.Context, logger *zap.Logger, tx *sql.Tx, updates
			statements = append(statements, fmt.Sprintf("($%v::UUID, $%v, $%v, $%v)", strconv.Itoa(len(params)-3), strconv.Itoa(len(params)-2), strconv.Itoa(len(params)-1), strconv.Itoa(len(params))))
		}
	}
	if changesetErr != nil {
		return nil, changesetErr
	}

	if len(updatedWallets) > 0 {
		// Ensure updates are done in natural order of user ID.
+12 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ package runtime
import (
	"context"
	"database/sql"
	"fmt"
	"os"

	"github.com/heroiclabs/nakama-common/api"
@@ -773,6 +774,17 @@ type WalletUpdateResult struct {
	Previous map[string]int64
}

type WalletNegativeError struct {
	UserID  string
	Path    string
	Current int64
	Amount  int64
}

func (e *WalletNegativeError) Error() string {
	return fmt.Sprintf("wallet update rejected negative value at path '%v'", e.Path)
}

type WalletLedgerItem interface {
	GetID() string
	GetUserID() string
+1 −1
Original line number Diff line number Diff line
@@ -135,7 +135,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopena
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options
github.com/grpc-ecosystem/grpc-gateway/v2/runtime
github.com/grpc-ecosystem/grpc-gateway/v2/utilities
# github.com/heroiclabs/nakama-common v1.11.1-0.20210203184030-64cd8d070d43
# github.com/heroiclabs/nakama-common v1.11.1-0.20210204123435-b06844f83f0c
github.com/heroiclabs/nakama-common/api
github.com/heroiclabs/nakama-common/rtapi
github.com/heroiclabs/nakama-common/runtime