PaulSonOfLars / gotgbot

Autogenerated Go wrapper for the telegram API. Inspired by the python-telegram-bot library.
MIT License
493 stars 108 forks source link

Panic on invoice payment submission #128

Closed bazuker closed 9 months ago

bazuker commented 9 months ago

Steps:

  1. An invoice is created (see handlePayment)
  2. A user enters credit card info and submits the payment
  3. The library panics. See the stack trace

Setup

...
    telegramBot, err := gotgbot.NewBot(telegramBotToken, nil)
    if err != nil {
        panic("failed to create new bot: " + err.Error())
    }
    // Create updater and dispatcher.
    dispatcher := ext.NewDispatcher(&ext.DispatcherOpts{
        // If an error is returned by a handler, log it and continue going.
        Error: func(b *gotgbot.Bot, ctx *ext.Context, err error) ext.DispatcherAction {
            log.Println("an error occurred while handling update:", err.Error())
            return ext.DispatcherActionNoop
        },
        MaxRoutines: ext.DefaultMaxRoutines,
    })
    updater := ext.NewUpdater(dispatcher, nil)

    dispatcher.AddHandler(handlers.NewConversation(
        []ext.Handler{
            ...
            handlers.NewCommand("payment", handlePayment), // This handler
        },
        map[string][]ext.Handler{
            ...
        },
        &handlers.ConversationOpts{
            ...
        },
    ))
...
func handlePayment(b *gotgbot.Bot, ctx *ext.Context) error {
    _, err := b.SendInvoice(
        ctx.EffectiveChat.Id,
        "Purchase points",
        "Buy 1000 points",
        "payload1000",
        paymentToken,
        "USD",
        []gotgbot.LabeledPrice{
            {
                Label:  "pay1000",
                Amount: 10 * 100,
            },
        },
        nil,
    )
    if err != nil {
        return fmt.Errorf("failed to send invoice: %w", err)
    }
       // Panic after this

    return handlers.EndConversation()
}

Stack trace

2023/12/24 00:50:36 Failed to process update: panic recovered: runtime error: invalid memory address or nil pointer dereference
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/dispatcher.go:344 +0x1c
github.com/PaulSonOfLars/gotgbot/v2/ext.(*Dispatcher).ProcessUpdate.func1()
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/dispatcher.go:282 +0x64
panic({0x1047e9a40?, 0x1049c9290?})
        /usr/local/go/src/runtime/panic.go:914 +0x218
github.com/PaulSonOfLars/gotgbot/v2/ext/handlers/conversation.StateKey(0x140002a3dd0, 0x12?)
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/handlers/conversation/common.go:20 +0x98
github.com/PaulSonOfLars/gotgbot/v2/ext/handlers/conversation.(*InMemoryStorage).Get(0x1400007d2c0, 0x104530bc8?)
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/handlers/conversation/in_memory.go:31 +0x48
github.com/PaulSonOfLars/gotgbot/v2/ext/handlers.Conversation.getNextHandler({{0x14000062200, 0x2, 0x2}, 0x1400007d290, {0x10483c880, 0x1400007d2c0}, {0x14000012540, 0x1, 0x1}, {0x0, ...}, ...}, ...)
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/handlers/conversation.go:173 +0x70
github.com/PaulSonOfLars/gotgbot/v2/ext/handlers.Conversation.CheckUpdate(...)
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/handlers/conversation.go:74
github.com/PaulSonOfLars/gotgbot/v2/ext.(*Dispatcher).iterateOverHandlerGroups(0x14000134200, 0x1047cdac0?, 0x14000134300?)
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/dispatcher.go:297 +0x114
github.com/PaulSonOfLars/gotgbot/v2/ext.BaseProcessor.ProcessUpdate(...)
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/processor.go:20
github.com/PaulSonOfLars/gotgbot/v2/ext.(*Dispatcher).ProcessUpdate(0x14000134200, 0x14000134000, 0x100?, 0x1047cdac0?)
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/dispatcher.go:288 +0x9c
github.com/PaulSonOfLars/gotgbot/v2/ext.(*Dispatcher).processRawUpdate(0x0?, 0x0?, {0x1400008c200, 0xf3, 0x100})
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/dispatcher.go:265 +0xac
github.com/PaulSonOfLars/gotgbot/v2/ext.(*Dispatcher).Start.func1({0x1400008c200?, 0x10458bbe4?, 0x140001f0000?})
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/dispatcher.go:213 +0x6c
created by github.com/PaulSonOfLars/gotgbot/v2/ext.(*Dispatcher).Start in goroutine 23
        /Users/bazuker/go/pkg/mod/github.com/!paul!son!of!lars/gotgbot/v2@v2.0.0-rc.23/ext/dispatcher.go:203 +0x38
PaulSonOfLars commented 9 months ago

Hi @bazuker, thanks for the report!

This looks to be an issue with the conversation logic rather than invoices. Are you able to provide a minimal repro of this issue? I don't seem to be able to reproduce it on my end.

Also - just to double check, are you using the handlePayment method for any other handlers (other than the "payment" command you show here)? It looks like it might be being triggered by another handler which isn't chat-scoped (eg, ShippingQuery and PreCheckoutQuery). If this is the case, you might want to consider setting the KeyStrategy to KeyStrategySender, since it doesn't make sense to use chatids as part of the key strategy if there is no chat!

bazuker commented 9 months ago

Hey @PaulSonOfLars! Thanks for replying and Merry Christmas!

Changing the KeyStrategy to KeyStrategySender -> StateStorage: conversation.NewInMemoryStorage(conversation.KeyStrategySender) has fixed the panic, however the transaction still fails, but now without any error message so I still do no understand what is going on unfortunately.

Also, how do I capture the successfully completed transaction? Maybe I need to define another handler somewhere?

PaulSonOfLars commented 9 months ago

Merry Christmas to you too @bazuker!

Good to know - I'll be sure to add a check to handle chat-less updates. Wasn't something I had considered at time of writing.

From your description, it sounds like the sending of the payment is done OK, so SendInvoice likely isn't failing (hence no error there).

So, my question here is going to be, how do you know the transaction is failing? What about https://core.telegram.org/bots/api#answerprecheckoutquery; are you handling the checkout query as telegram expects? Checkouts don't work if not handled within 10s, which may be the issue

bazuker commented 9 months ago

@PaulSonOfLars I see. How to create an update handler for the callback made by telegram API to use bot.AnswerPreCheckoutQuery(..)?

I've tried adding something like this

dispatcher.AddHandler(handlers.NewCallback(nil, func(b *gotgbot.Bot, ctx *ext.Context) error {
        fmt.Println("some update!")
        return nil
    }))

But it does not seem to catch the pre-checkout update.

PaulSonOfLars commented 9 months ago

Well @bazuker, it isnt a callback update, its a precheckout update, which is why that handler doesn't trigger for it :)

It also looks like youre the first person using the lib for payment-related things, so there havent been any payment handlers added yet - I just opened up #129 to add new payment related handlers.

Would appreciate it if you could give it a try and come with any feedback (eg, other filters to add?) that you might have! You should be able to use the commit SHA to try out my changes before i merge them in with go get github.com/PaulSonOfLars/gotgbot/v2@5cd5cd5e49a45c53c22f69240824ab890cc3e120

bazuker commented 9 months ago

@PaulSonOfLars thank you!

PaulSonOfLars commented 9 months ago

Glad I could help! I'll take this as confirmation that the PR worked as expected :)