ADR-006: Deployable Functions
Introduction
Implement user defined functions invokable over HTTP within Highway.
Abstract
The goal of user-defined functions is to allow for custom-defined behavior, defined by users which are accessible via HTTP
.
These functions will all be accessible over a single endpoint, predefined within the highway.
When a request is sent to a static endpoint, containing the desired name of the invokable function, the function will be then invoked, with a single parameter queried from ipfs
by the given CID
in the declaration of the url.
User functions
A User Defined Function
is repersented by a single binary
file which is assumed to be executable, and corresponding callback Urls
associated with said executable file. said functions are not permitted to return data to the caller directly, but rather the outer managment of the defined function will provide data to the given urls
as base64 encoded
repersentations as to not permit users to modify the system state of any highway
node directly.
Function definition format
The user's defined function is assumed to be precompiled into binary format. Said Binary is jailed
as to resrtrict privlages on the execution enviorment to the host.
Currently, the executable options are more appealing as it is easier to sandbox a plain binary into a ‘jail’ rather than implementing sandboxing around a reflection execution implementation.
Below is a primitive definition for a user-defined function.
Said binary is stored within the highway node's ipfs
storage with the following file contents as a blob of JSON
UserFunction {
did string // did from defintion
file []bytes // file as a byte encoding
parameters: map[string]string // not the value string is the "type"
}
In the above definition, the total size of the file stored for a user function would be the total bytes of the array and the did string of the owner. This data would be stored on IPFS incurring the cost of file storage and passing that on to the uploader of the function.
Once a function is associated with a name and provided to the highway, a function will then have the association of label → function.
Each function will be a single relation to the user-given function.
Meaning a function can be resolved via its name name
but a function cannot resolve its name, as the function is not explicitly required to have an associative name that matches its function name.
{
did: string
ref: cid
isActive: boolean
}
The above model will be stored within the chain upon
creation
andupdate
. This chain store will incur a cost on the uploader. Later changing the function to inactive will also incur a cost on chain.
The above model is then stored as a file in IPFS
queriable by the returned CID
.
URL Schema
User Defined functions within the Highway will have a single entry point.
/sonr/functions/invoke/{version}/{label}
Where label
is defined when the definition of the function is created.
params to a user defined function over URL
callback? (base64 encoding). cid? (id of the content from a highway node you wish to provide to a function) the above URL has two params
Name | Type | Description |
---|---|---|
queryCid | string | Content ID to be retrieved from file storage (object, blob) |
returnData | string | A URL that will be called and given the returned data from a function |
Function Parameters
Parameters to functions will be nameless and of type string
. the provided data will be deserailized to the described types and given to functions as what they are specified to be in the delceration upon creation. Parameters to functions will be applied in the order as they are provided, content queried by the CID
provided URL when the function is invoked will be the last parameter to the function. The function implementor is responsible for the mapping of the parameters based on the index when implementing.
Returning data from a user defined function
User defined functions cannot modify the state of highways
, meaning data stored within the network. Instead one or many callback URLs
are specifiable, allowing for data to be sent to said urls through url encoding
data return by any function must be encodable
to Base64
standard or data will not be sent.
The callback URLs
can be either an external resource outside of the network of highways, or can be another function defined on the highway.
Invoking a User Defined Function
A function that's invoked should have the following defined within the body
of the HTTP
request
{
did string // owner did
label: string // file as a byte encoding
cid: string // identifier of the function stored within ipfs.
parameters: map[string]string
callbackURLS: string[]
}
The return value will simply be an empty response body with an HTTP
status.
When a function is "invoked" we will use one of the following strategies for calulating cost for a given function's invokation.
Description | Formula | User Pays | Highway Runner Gets | Function Writer Gets | |
---|---|---|---|---|---|
Static Cost Functions | Cost is staticly defined at function creation time. The run time cost is added in addition to the cost paid by the caller | total_cost = static_cost + runtime_fees | total_cost | runtime_fees | static_cost |
Variable Cost Functions | Cost is defined when the function is running. There is a max and min cost that can be paid from the caller's wallet predefined in the function definition. The caller will also need to fund a transaction to refund the remainder of the gas fees to caller. | total_cost = variable_cost + runtime_fees + gas_fees | total_cost | runtime_fees | variable_cost |
"Free" Functions | The function only costs as much as the runtime_fees | total_cost = runtime_fees | total_cost | runtime_fees | N/A |
Static and Varible functions are useful when the function needs to make its own interaction with the chain or fund calls within.
Models and Methods (Highway)
The following methods will be added to Highway
as a module within x
Methods
CreateFunction()
Creates a new function with the provided label
and definition
(function converted to bytes
)
type FunctionDefiniton struct {
label string
did string
definition []byte
parameters: map[string]type
}
Returns
{
"code": int,
"did": "string"
"cid": "string"
}
UpdateFunction()
type FunctionDefiniton struct {
label string
did string
definition []byte
}
Updating a function does not remove the previous function defintion, as there could be reliance on said function. Updating a function creates a new instance of an already defined function by requiring a new version specified in the URL.
Returns
{
"code": int,
"did": "string"
"cid": "string"
}
CLI Commands
The CLI will need a single root level command called function
. function will have the following two sub commands
Name | params | Description |
---|---|---|
add | "name" "path-to-binary" | Adds a single function to a defined name |
remove | "name" | Removes user defined function from the function table |