From e441f77858a9ca84ca475725432d07a2a84bbba1 Mon Sep 17 00:00:00 2001 From: Marton Lederer Date: Fri, 18 Jul 2025 20:09:14 +0200 Subject: [PATCH 1/7] feat: unqueue error handler wip --- src/controller/queue.lua | 44 ++++++++++++++++++++++++++++++++-------- src/process.lua | 17 +++++++++++----- src/utils/handlers.lua | 5 +++-- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/controller/queue.lua b/src/controller/queue.lua index 34744c1..97af087 100644 --- a/src/controller/queue.lua +++ b/src/controller/queue.lua @@ -46,20 +46,26 @@ function mod.setQueued(address, queued) } end +-- Get the user to be queued, depending on the type of the message +---@param msg Message Message to process +---@return string +function mod.getUserToQueue(msg) + -- return sender if it is a credit notice + if msg.Tags.Action == "Credit-Notice" then + return msg.Tags.Sender + end + + -- the msg sender should be queued if it is not a credit-notice + return msg.From +end + -- Make a handle function use the global queue of the controller ---@param handle HandlerFunction Handle function to wrap ---@param errorHandler fun(msg: Message, env: Message, err: unknown)? Optional error handler ---@return HandlerFunction function mod.useQueue(handle, errorHandler) return function (msg, env) - -- default sender of the interaction is the message sender - local sender = msg.From - local isCreditNotice = msg.Tags.Action == "Credit-Notice" - - -- if the message is a credit notice, update the sender - if isCreditNotice then - sender = msg.Tags.Sender - end + local sender = mod.getUserToQueue(msg) -- update and set queue local res = mod.setQueued(sender, true).receive() @@ -101,4 +107,26 @@ function mod.useQueue(handle, errorHandler) end end +-- Make the error handler unqueue the user +---@param errorHandler fun(msg: Message, env: Message, err: unknown)? Optional error handler +---return fun(msg: Message, env: Message, err: unknown) +function mod.useErrorHandler(errorHandler) + return function (msg, env, err) + -- call wrapped error handler if provided + if errorHandler ~= nil then + errorHandler(msg, env, err or "Unknown error") + else + Handlers.defaultErrorHandler(msg, env, err) + end + + -- get user to unqueue + local sender = mod.getUserToQueue(msg) + + -- unqueue and notify if it failed + mod + .setQueued(sender, false) + .notifyOnFailedQueue() + end +end + return mod diff --git a/src/process.lua b/src/process.lua index 5b6b540..1cb3ed6 100644 --- a/src/process.lua +++ b/src/process.lua @@ -239,12 +239,19 @@ local function setup_handlers() msg.reply({ ["Borrow-Balance"] = tostring(borrowBalance) }) end ) - Handlers.add( - "borrow-loan-borrow", - Handlers.utils.hasMatchingTag("Action", "Borrow"), + -- Handlers.add( + -- "borrow-loan-borrow", + -- Handlers.utils.hasMatchingTag("Action", "Borrow"), + -- -- needs unqueueing because of coroutines + -- queue.useQueue(oracle.withOracle(borrow)) + -- ) + Handlers.advanced({ + name = "borrow-loan-borrow", + pattern = { Action = "Borrow" }, -- needs unqueueing because of coroutines - queue.useQueue(oracle.withOracle(borrow)) - ) + handle = queue.useQueue(oracle.withOracle(borrow)), + errorHandler = queue.useErrorHandler() + }) Handlers.advanced({ name = "borrow-repay", pattern = { diff --git a/src/utils/handlers.lua b/src/utils/handlers.lua index af15377..82dbb1d 100644 --- a/src/utils/handlers.lua +++ b/src/utils/handlers.lua @@ -482,8 +482,9 @@ function handlers.evaluate(msg, env) o.onRemove("timeout") o.onRemove = nil end - handlers.remove(o.name) - match = 0 + --handlers.remove(o.name) + o.handle = function () end + --match = 0 end end From d900bda8defa159b28b927ca852d7815e85d0b8f Mon Sep 17 00:00:00 2001 From: Marton Lederer Date: Tue, 22 Jul 2025 12:37:54 +0200 Subject: [PATCH 2/7] feat: timeout fix wip --- src/controller/queue.lua | 2 +- src/process.lua | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/controller/queue.lua b/src/controller/queue.lua index 97af087..83096ed 100644 --- a/src/controller/queue.lua +++ b/src/controller/queue.lua @@ -82,7 +82,7 @@ function mod.useQueue(handle, errorHandler) errorHandler(msg, env, err) else -- no error handler, throw the error - error(err) + Handlers.defaultErrorHandler(msg, env, err) end return diff --git a/src/process.lua b/src/process.lua index 1cb3ed6..b497c81 100644 --- a/src/process.lua +++ b/src/process.lua @@ -239,12 +239,6 @@ local function setup_handlers() msg.reply({ ["Borrow-Balance"] = tostring(borrowBalance) }) end ) - -- Handlers.add( - -- "borrow-loan-borrow", - -- Handlers.utils.hasMatchingTag("Action", "Borrow"), - -- -- needs unqueueing because of coroutines - -- queue.useQueue(oracle.withOracle(borrow)) - -- ) Handlers.advanced({ name = "borrow-loan-borrow", pattern = { Action = "Borrow" }, From 385f03793fd303aa2845ad0b4301230cc2117c97 Mon Sep 17 00:00:00 2001 From: Marton Lederer Date: Tue, 22 Jul 2025 13:19:45 +0200 Subject: [PATCH 3/7] feat: use queue error handler wrapper for repay --- src/process.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/process.lua b/src/process.lua index b497c81..8e63993 100644 --- a/src/process.lua +++ b/src/process.lua @@ -253,8 +253,8 @@ local function setup_handlers() Action = "Credit-Notice", ["X-Action"] = "Repay" }, - handle = queue.useQueue(repay.handler), - errorHandler = repay.error + handle = queue.useQueue(repay.handler, repay.error), + errorHandler = queue.useErrorHandler(repay.error) }) Handlers.add( "borrow-position-collateralization", From edd7a9f22c15055e307098b27e2632334a7417ea Mon Sep 17 00:00:00 2001 From: Marton Lederer Date: Tue, 22 Jul 2025 14:08:35 +0200 Subject: [PATCH 4/7] feat: use queue error handler for minting --- src/controller/queue.lua | 3 +++ src/process.lua | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/controller/queue.lua b/src/controller/queue.lua index 83096ed..4dfbf94 100644 --- a/src/controller/queue.lua +++ b/src/controller/queue.lua @@ -82,6 +82,9 @@ function mod.useQueue(handle, errorHandler) errorHandler(msg, env, err) else -- no error handler, throw the error + -- do not error() here - that would trigger + -- the handler's error handler, which would + -- try to unqueue the user Handlers.defaultErrorHandler(msg, env, err) end diff --git a/src/process.lua b/src/process.lua index 8e63993..b69f1c4 100644 --- a/src/process.lua +++ b/src/process.lua @@ -279,8 +279,8 @@ local function setup_handlers() Action = "Credit-Notice", ["X-Action"] = "Mint" }, - handle = queue.useQueue(mint.handler), - errorHandler = mint.error + handle = queue.useQueue(mint.handler, mint.error), + errorHandler = queue.useErrorHandler(mint.error) }) Handlers.add( "supply-price", From 301be14ab02d35d18c85350d481bb1dd825066b5 Mon Sep 17 00:00:00 2001 From: Marton Lederer Date: Tue, 22 Jul 2025 14:32:12 +0200 Subject: [PATCH 5/7] refactor: useQueue --- src/controller/queue.lua | 31 +++++++++++++++------------ src/process.lua | 46 ++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/src/controller/queue.lua b/src/controller/queue.lua index 4dfbf94..2ab9fe5 100644 --- a/src/controller/queue.lua +++ b/src/controller/queue.lua @@ -1,5 +1,3 @@ -local utils = require ".utils.utils" - local mod = {} -- Add or remove a user from the queue in the controller @@ -59,12 +57,19 @@ function mod.getUserToQueue(msg) return msg.From end --- Make a handle function use the global queue of the controller ----@param handle HandlerFunction Handle function to wrap ----@param errorHandler fun(msg: Message, env: Message, err: unknown)? Optional error handler ----@return HandlerFunction -function mod.useQueue(handle, errorHandler) - return function (msg, env) +-- Make a handler use the global queue of the controller. This is +-- usually needed for handlers that impelement complex behavior by +-- waiting for several message responses before completion to prevent +-- double spending +---@param config table Configuration for the handler +---@return table +function mod.useQueue(config) + -- original handle function and error handler + local handle = config.handle + local errorHandler = config.errorHandler + + -- override handle function to queue and unqueue + config.handle = function (msg, env) local sender = mod.getUserToQueue(msg) -- update and set queue @@ -108,13 +113,9 @@ function mod.useQueue(handle, errorHandler) end end end -end --- Make the error handler unqueue the user ----@param errorHandler fun(msg: Message, env: Message, err: unknown)? Optional error handler ----return fun(msg: Message, env: Message, err: unknown) -function mod.useErrorHandler(errorHandler) - return function (msg, env, err) + -- override error handler to unqueue the user + config.errorHandler = function (msg, env, err) -- call wrapped error handler if provided if errorHandler ~= nil then errorHandler(msg, env, err or "Unknown error") @@ -130,6 +131,8 @@ function mod.useErrorHandler(errorHandler) .setQueued(sender, false) .notifyOnFailedQueue() end + + return config end return mod diff --git a/src/process.lua b/src/process.lua index b69f1c4..b147767 100644 --- a/src/process.lua +++ b/src/process.lua @@ -239,23 +239,21 @@ local function setup_handlers() msg.reply({ ["Borrow-Balance"] = tostring(borrowBalance) }) end ) - Handlers.advanced({ + Handlers.advanced(queue.useQueue({ name = "borrow-loan-borrow", pattern = { Action = "Borrow" }, - -- needs unqueueing because of coroutines - handle = queue.useQueue(oracle.withOracle(borrow)), - errorHandler = queue.useErrorHandler() - }) - Handlers.advanced({ + handle = oracle.withOracle(borrow) + })) + Handlers.advanced(queue.useQueue({ name = "borrow-repay", pattern = { From = CollateralID, Action = "Credit-Notice", ["X-Action"] = "Repay" }, - handle = queue.useQueue(repay.handler, repay.error), - errorHandler = queue.useErrorHandler(repay.error) - }) + handle = repay.handler, + errorHandler = repay.error + })) Handlers.add( "borrow-position-collateralization", Handlers.utils.hasMatchingTag("Action", "Position"), @@ -272,16 +270,16 @@ local function setup_handlers() position.handlers.allPositions ) - Handlers.advanced({ + Handlers.advanced(queue.useQueue({ name = "supply-mint", pattern = { From = CollateralID, Action = "Credit-Notice", ["X-Action"] = "Mint" }, - handle = queue.useQueue(mint.handler, mint.error), - errorHandler = queue.useErrorHandler(mint.error) - }) + handle = mint.handler, + errorHandler = mint.error + })) Handlers.add( "supply-price", Handlers.utils.hasMatchingTag("Action", "Exchange-Rate-Current"), @@ -303,12 +301,11 @@ local function setup_handlers() }) end ) - -- needs unqueueing because of coroutines - Handlers.add( - "supply-redeem", - Handlers.utils.hasMatchingTag("Action", "Redeem"), - queue.useQueue(oracle.withOracle(redeem)) - ) + Handlers.advanced(queue.useQueue({ + name = "supply-redeem", + pattern = { Action = "Redeem" }, + handle = oracle.withOracle(redeem) + })) Handlers.add( "token-info", @@ -330,12 +327,11 @@ local function setup_handlers() Handlers.utils.hasMatchingTag("Action", "Balances"), balance.balances ) - -- needs unqueueing because of coroutines - Handlers.add( - "token-transfer", - Handlers.utils.hasMatchingTag("Action", "Transfer"), - queue.useQueue(oracle.withOracle(transfer)) - ) + Handlers.advanced(queue.useQueue({ + name = "token-transfer", + pattern = { Action = "Transfer" }, + handle = oracle.withOracle(transfer) + })) HandlersAdded = true end From 8872fba22c53720aaebb7f6c0221d083373e14f1 Mon Sep 17 00:00:00 2001 From: Marton Lederer Date: Tue, 22 Jul 2025 15:42:33 +0200 Subject: [PATCH 6/7] fix: post-remove handlers --- src/utils/handlers.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/utils/handlers.lua b/src/utils/handlers.lua index 82dbb1d..8ba651c 100644 --- a/src/utils/handlers.lua +++ b/src/utils/handlers.lua @@ -464,6 +464,7 @@ end -- @treturn The response from the handler(s). Returns a default message if no handler matches. function handlers.evaluate(msg, env) local handled = false + local toRemove = {} -- handlers to remove after evaluation assert(type(msg) == 'table', 'msg is not valid') assert(type(env) == 'table', 'env is not valid') @@ -482,9 +483,8 @@ function handlers.evaluate(msg, env) o.onRemove("timeout") o.onRemove = nil end - --handlers.remove(o.name) o.handle = function () end - --match = 0 + table.insert(toRemove, o.name) end end @@ -551,7 +551,7 @@ function handlers.evaluate(msg, env) o.onRemove("expired") o.onRemove = nil end - handlers.remove(o.name) + table.insert(toRemove, o.name) end end end @@ -564,6 +564,11 @@ function handlers.evaluate(msg, env) -- reset current error handler handlers.currentErrorHandler = handlers.defaultErrorHandler + -- remove marked handlers + for _, name in ipairs(toRemove) do + handlers.remove(name) + end + -- make sure the request was handled assert(handled or msg.Id == ao.id, "The request could not be handled") end From feee1d4c30391a6d46c2d2c4f964cdc7e7efab3b Mon Sep 17 00:00:00 2001 From: Marton Lederer Date: Mon, 14 Jul 2025 18:49:41 +0200 Subject: [PATCH 7/7] feat: prevent recursive errors --- src/utils/handlers.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils/handlers.lua b/src/utils/handlers.lua index 8ba651c..d75c73a 100644 --- a/src/utils/handlers.lua +++ b/src/utils/handlers.lua @@ -570,7 +570,10 @@ function handlers.evaluate(msg, env) end -- make sure the request was handled - assert(handled or msg.Id == ao.id, "The request could not be handled") + assert( + handled or msg.Id == ao.id or string.match(msg.Action or "", "Error$"), + "The request could not be handled" + ) end return handlers