Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 51 additions & 17 deletions src/controller/queue.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
local utils = require ".utils.utils"

local mod = {}

-- Add or remove a user from the queue in the controller
Expand Down Expand Up @@ -46,20 +44,33 @@ function mod.setQueued(address, queued)
}
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
-- 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 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
local res = mod.setQueued(sender, true).receive()
Expand All @@ -76,7 +87,10 @@ function mod.useQueue(handle, errorHandler)
errorHandler(msg, env, err)
else
-- no error handler, throw the error
error(err)
-- 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

return
Expand All @@ -99,6 +113,26 @@ function mod.useQueue(handle, errorHandler)
end
end
end

-- 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")
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

return config
end

return mod
45 changes: 21 additions & 24 deletions src/process.lua
Original file line number Diff line number Diff line change
Expand Up @@ -239,22 +239,21 @@ 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({
Handlers.advanced(queue.useQueue({
name = "borrow-loan-borrow",
pattern = { Action = "Borrow" },
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),
handle = repay.handler,
errorHandler = repay.error
})
}))
Handlers.add(
"borrow-position-collateralization",
Handlers.utils.hasMatchingTag("Action", "Position"),
Expand All @@ -271,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),
handle = mint.handler,
errorHandler = mint.error
})
}))
Handlers.add(
"supply-price",
Handlers.utils.hasMatchingTag("Action", "Exchange-Rate-Current"),
Expand All @@ -302,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",
Expand All @@ -329,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
Expand Down
17 changes: 13 additions & 4 deletions src/utils/handlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand All @@ -482,8 +483,8 @@ function handlers.evaluate(msg, env)
o.onRemove("timeout")
o.onRemove = nil
end
handlers.remove(o.name)
match = 0
o.handle = function () end
table.insert(toRemove, o.name)
end
end

Expand Down Expand Up @@ -550,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
Expand All @@ -563,8 +564,16 @@ 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")
assert(
handled or msg.Id == ao.id or string.match(msg.Action or "", "Error$"),
"The request could not be handled"
)
end

return handlers