Skip to main content

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 and update. 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

NameTypeDescription
queryCidstringContent ID to be retrieved from file storage (object, blob)
returnDatastringA 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.

DescriptionFormulaUser PaysHighway Runner GetsFunction Writer Gets
Static Cost FunctionsCost is staticly defined at function creation time. The run time cost is added in addition to the cost paid by the callertotal_cost = static_cost + runtime_feestotal_costruntime_feesstatic_cost
Variable Cost FunctionsCost 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_feestotal_costruntime_feesvariable_cost
"Free" FunctionsThe function only costs as much as the runtime_feestotal_cost = runtime_feestotal_costruntime_feesN/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

NameparamsDescription
add"name" "path-to-binary"Adds a single function to a defined name
remove"name"Removes user defined function from the function table

Diagrams​

Writing encrypted data