Skip to content

Commit 6f2e63e

Browse files
Merge pull request #38 from useLiquidOps/fix/unqueue-on-timeout-error
Fix queue errors and infinite errors
2 parents cd38396 + feee1d4 commit 6f2e63e

3 files changed

Lines changed: 85 additions & 45 deletions

File tree

src/controller/queue.lua

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
local utils = require ".utils.utils"
2-
31
local mod = {}
42

53
-- Add or remove a user from the queue in the controller
@@ -46,20 +44,33 @@ function mod.setQueued(address, queued)
4644
}
4745
end
4846

49-
-- Make a handle function use the global queue of the controller
50-
---@param handle HandlerFunction Handle function to wrap
51-
---@param errorHandler fun(msg: Message, env: Message, err: unknown)? Optional error handler
52-
---@return HandlerFunction
53-
function mod.useQueue(handle, errorHandler)
54-
return function (msg, env)
55-
-- default sender of the interaction is the message sender
56-
local sender = msg.From
57-
local isCreditNotice = msg.Tags.Action == "Credit-Notice"
58-
59-
-- if the message is a credit notice, update the sender
60-
if isCreditNotice then
61-
sender = msg.Tags.Sender
62-
end
47+
-- Get the user to be queued, depending on the type of the message
48+
---@param msg Message Message to process
49+
---@return string
50+
function mod.getUserToQueue(msg)
51+
-- return sender if it is a credit notice
52+
if msg.Tags.Action == "Credit-Notice" then
53+
return msg.Tags.Sender
54+
end
55+
56+
-- the msg sender should be queued if it is not a credit-notice
57+
return msg.From
58+
end
59+
60+
-- Make a handler use the global queue of the controller. This is
61+
-- usually needed for handlers that impelement complex behavior by
62+
-- waiting for several message responses before completion to prevent
63+
-- double spending
64+
---@param config table Configuration for the handler
65+
---@return table
66+
function mod.useQueue(config)
67+
-- original handle function and error handler
68+
local handle = config.handle
69+
local errorHandler = config.errorHandler
70+
71+
-- override handle function to queue and unqueue
72+
config.handle = function (msg, env)
73+
local sender = mod.getUserToQueue(msg)
6374

6475
-- update and set queue
6576
local res = mod.setQueued(sender, true).receive()
@@ -76,7 +87,10 @@ function mod.useQueue(handle, errorHandler)
7687
errorHandler(msg, env, err)
7788
else
7889
-- no error handler, throw the error
79-
error(err)
90+
-- do not error() here - that would trigger
91+
-- the handler's error handler, which would
92+
-- try to unqueue the user
93+
Handlers.defaultErrorHandler(msg, env, err)
8094
end
8195

8296
return
@@ -99,6 +113,26 @@ function mod.useQueue(handle, errorHandler)
99113
end
100114
end
101115
end
116+
117+
-- override error handler to unqueue the user
118+
config.errorHandler = function (msg, env, err)
119+
-- call wrapped error handler if provided
120+
if errorHandler ~= nil then
121+
errorHandler(msg, env, err or "Unknown error")
122+
else
123+
Handlers.defaultErrorHandler(msg, env, err)
124+
end
125+
126+
-- get user to unqueue
127+
local sender = mod.getUserToQueue(msg)
128+
129+
-- unqueue and notify if it failed
130+
mod
131+
.setQueued(sender, false)
132+
.notifyOnFailedQueue()
133+
end
134+
135+
return config
102136
end
103137

104138
return mod

src/process.lua

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -239,22 +239,21 @@ local function setup_handlers()
239239
msg.reply({ ["Borrow-Balance"] = tostring(borrowBalance) })
240240
end
241241
)
242-
Handlers.add(
243-
"borrow-loan-borrow",
244-
Handlers.utils.hasMatchingTag("Action", "Borrow"),
245-
-- needs unqueueing because of coroutines
246-
queue.useQueue(oracle.withOracle(borrow))
247-
)
248-
Handlers.advanced({
242+
Handlers.advanced(queue.useQueue({
243+
name = "borrow-loan-borrow",
244+
pattern = { Action = "Borrow" },
245+
handle = oracle.withOracle(borrow)
246+
}))
247+
Handlers.advanced(queue.useQueue({
249248
name = "borrow-repay",
250249
pattern = {
251250
From = CollateralID,
252251
Action = "Credit-Notice",
253252
["X-Action"] = "Repay"
254253
},
255-
handle = queue.useQueue(repay.handler),
254+
handle = repay.handler,
256255
errorHandler = repay.error
257-
})
256+
}))
258257
Handlers.add(
259258
"borrow-position-collateralization",
260259
Handlers.utils.hasMatchingTag("Action", "Position"),
@@ -271,16 +270,16 @@ local function setup_handlers()
271270
position.handlers.allPositions
272271
)
273272

274-
Handlers.advanced({
273+
Handlers.advanced(queue.useQueue({
275274
name = "supply-mint",
276275
pattern = {
277276
From = CollateralID,
278277
Action = "Credit-Notice",
279278
["X-Action"] = "Mint"
280279
},
281-
handle = queue.useQueue(mint.handler),
280+
handle = mint.handler,
282281
errorHandler = mint.error
283-
})
282+
}))
284283
Handlers.add(
285284
"supply-price",
286285
Handlers.utils.hasMatchingTag("Action", "Exchange-Rate-Current"),
@@ -302,12 +301,11 @@ local function setup_handlers()
302301
})
303302
end
304303
)
305-
-- needs unqueueing because of coroutines
306-
Handlers.add(
307-
"supply-redeem",
308-
Handlers.utils.hasMatchingTag("Action", "Redeem"),
309-
queue.useQueue(oracle.withOracle(redeem))
310-
)
304+
Handlers.advanced(queue.useQueue({
305+
name = "supply-redeem",
306+
pattern = { Action = "Redeem" },
307+
handle = oracle.withOracle(redeem)
308+
}))
311309

312310
Handlers.add(
313311
"token-info",
@@ -329,12 +327,11 @@ local function setup_handlers()
329327
Handlers.utils.hasMatchingTag("Action", "Balances"),
330328
balance.balances
331329
)
332-
-- needs unqueueing because of coroutines
333-
Handlers.add(
334-
"token-transfer",
335-
Handlers.utils.hasMatchingTag("Action", "Transfer"),
336-
queue.useQueue(oracle.withOracle(transfer))
337-
)
330+
Handlers.advanced(queue.useQueue({
331+
name = "token-transfer",
332+
pattern = { Action = "Transfer" },
333+
handle = oracle.withOracle(transfer)
334+
}))
338335

339336
HandlersAdded = true
340337
end

src/utils/handlers.lua

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,7 @@ end
464464
-- @treturn The response from the handler(s). Returns a default message if no handler matches.
465465
function handlers.evaluate(msg, env)
466466
local handled = false
467+
local toRemove = {} -- handlers to remove after evaluation
467468
assert(type(msg) == 'table', 'msg is not valid')
468469
assert(type(env) == 'table', 'env is not valid')
469470

@@ -482,8 +483,8 @@ function handlers.evaluate(msg, env)
482483
o.onRemove("timeout")
483484
o.onRemove = nil
484485
end
485-
handlers.remove(o.name)
486-
match = 0
486+
o.handle = function () end
487+
table.insert(toRemove, o.name)
487488
end
488489
end
489490

@@ -550,7 +551,7 @@ function handlers.evaluate(msg, env)
550551
o.onRemove("expired")
551552
o.onRemove = nil
552553
end
553-
handlers.remove(o.name)
554+
table.insert(toRemove, o.name)
554555
end
555556
end
556557
end
@@ -563,8 +564,16 @@ function handlers.evaluate(msg, env)
563564
-- reset current error handler
564565
handlers.currentErrorHandler = handlers.defaultErrorHandler
565566

567+
-- remove marked handlers
568+
for _, name in ipairs(toRemove) do
569+
handlers.remove(name)
570+
end
571+
566572
-- make sure the request was handled
567-
assert(handled or msg.Id == ao.id, "The request could not be handled")
573+
assert(
574+
handled or msg.Id == ao.id or string.match(msg.Action or "", "Error$"),
575+
"The request could not be handled"
576+
)
568577
end
569578

570579
return handlers

0 commit comments

Comments
 (0)