Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ao): update ao module to allow for ario src code #421

Closed
wants to merge 2 commits into from
Closed
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
7,524 changes: 7,524 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions process/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
stack_size: 33554432 # 32Mib
initial_memory: 50331648 # 48Mib
maximum_memory: 8589934592 # 8Gib
target: 64
21 changes: 14 additions & 7 deletions process/process.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
-- @module process

-- @dependencies
local pretty = require('.pretty')
local base64 = require('.base64')
local json = require('json')
-- local pretty = require('.pretty')
-- local base64 = require('.base64')
-- local json = require('json')
local chance = require('.chance')
local crypto = require('.crypto.init')
-- local crypto = require('.crypto.init')
local coroutine = require('coroutine')
-- set alias ao for .ao library
if not _G.package.loaded['ao'] then _G.package.loaded['ao'] = require('.ao') end
Expand Down Expand Up @@ -250,7 +250,7 @@ end
-- @tparam {table} env The environment to initialize the state with
local function initializeState(msg, env)
if not Seeded then
chance.seed(tonumber(msg['Block-Height'] .. stringToSeed(msg.Owner .. msg.Module .. msg.Id)))
chance.seed(tonumber(msg['Block-Height'] .. stringToSeed(msg.Owner .. "hello-there" .. msg.Id)))
math.random = function (...)
local args = {...}
local n = #args
Expand Down Expand Up @@ -316,7 +316,7 @@ function process.handle(msg, _)
ao.id = ao.env.Process.Id
initializeState(msg, ao.env)
HANDLER_PRINT_LOGS = {}

-- set os.time to return msg.Timestamp
os.time = function () return msg.Timestamp end

Expand Down Expand Up @@ -359,6 +359,9 @@ function process.handle(msg, _)
require('.eval')(ao)
)

-- AR.IO PROCESS CODE
require(".src.init").init()

-- Added for aop6 boot loader
-- See: https://github.com/permaweb/aos/issues/342
-- Only run bootloader when Process Message is First Message
Expand All @@ -367,7 +370,11 @@ function process.handle(msg, _)
function (msg)
return msg.Tags.Type == "Process" and Owner == msg.From
end,
require('.boot')(ao)
function ()
require('.boot')(ao)
-- load all the initial state once
require(".state.init").init()
end
)
end

Expand Down
36 changes: 36 additions & 0 deletions process/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash
set -e

# Step 1: Build the project
echo "Running: ao build"
ao build

# Step 2: Run tests
echo "Running: npm run test test/into.test.js"
npm run test test/into.test.js

# Step 3: Publish and capture output
echo "Running: ao publish ... (capturing module ID)"
publish_output=$(ao publish -w ./wallet.json ./process.wasm \
-t Compute-Limit -v 9000000000000 \
-t Memory-Limit -v 8589934592 \
-t Name -v aos-test-2.0.4 \
-t Module-Format -v wasm64-unknown-emscripten-draft_2024_02_15 \
--bundler https://up.arweave.net)

# Optionally display the full publish output
echo "$publish_output"

# Step 4: Extract the 43-character alphanumeric module ID
# This pattern will match exactly 43 characters (letters, digits, underscore or hyphen if needed)
MODULE_ID=$(echo "$publish_output" | grep -oE "[A-Za-z0-9_-]{43}")
if [ -z "$MODULE_ID" ]; then
echo "Error: Could not find a module ID in the publish output."
exit 1
fi

echo "Extracted Module ID: $MODULE_ID"

# Step 5: Use the module ID in the final command
echo "Running: aos -w ./wallet.json --module=$MODULE_ID"
aos -w ./wallet.json --module=$MODULE_ID
129 changes: 129 additions & 0 deletions process/src/ao_event.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
local utils = require(".src.utils")
local json = require(".src.json")

--- @class AOEvent
--- @field data table<string, any> The data table holding the event fields.
--- @field sampleRate number|nil Optional sample rate.
--- @field addField fun(self: AOEvent, key: string, value: any): AOEvent Adds a single field to the event.
--- @field addFields fun(self: AOEvent, fields: table<string, any>): AOEvent Adds multiple fields to the event.
--- @field addFieldsIfExist fun(self: AOEvent, table: table<string, any>|nil, fields: table<string>): AOEvent Adds specific fields if they exist in the given table.
--- @field addFieldsWithPrefixIfExist fun(self: AOEvent, srcTable: table<string, any>, prefix: string, fields: table<string>): AOEvent
--- Adds fields with a prefix if they exist in the source table.
--- @field printEvent fun(self: AOEvent): nil Prints the event in JSON format.
--- @field toJSON fun(self: AOEvent): string Converts the event to a JSON string.

--- Factory function for creating an "AOEvent"
--- @param initialData table<string, any> Optional initial data to populate the event with.
--- @returns AOEvent
local function AOEvent(initialData)
local event = {
sampleRate = nil, -- Optional sample rate
}

if type(initialData) ~= "table" then
print("ERROR: AOEvent data must be a table.")
event.data = {}
else
event.data = initialData
end

local function isValidTableValueType(value)
local valueType = type(value)
return valueType == "string" or valueType == "number" or valueType == "boolean" or value == nil
end

local function isValidType(value)
local valueType = type(value)
if isValidTableValueType(value) then
return true
elseif valueType == "table" then
-- Prevent nested tables
for _, v in pairs(value) do
if not isValidTableValueType(v) then
return false
end
end
return true
end
return false
end

--- Add a field to the event
--- @param key string The key to add to the event.
--- @param value any The value to add to the event.
--- @param trainCase boolean|nil Whether to convert the key to Train Case. Defaults to true.
function event:addField(key, value, trainCase)
trainCase = trainCase ~= false -- default to true unless explicitly set to false
if type(key) ~= "string" then
print("ERROR: Field key must be a string.")
return self
end
if not isValidType(value) then
print(
"ERROR: Invalid field value type: "
.. type(value)
.. ". Supported types are string, number, boolean, or nil."
)
if type(value) == "table" then
print("Invalid field value: " .. require(".json").encode(value))
end
return self
end
self.data[trainCase and utils.toTrainCase(key) or key] = value
return self
end

function event:addFields(fields)
if type(fields) ~= "table" then
print("ERROR: Fields must be provided as a table.")
return self
end
for key, value in pairs(fields) do
self:addField(key, value)
end
return self
end

function event:addFieldsIfExist(table, fields)
table = table == nil and {} or table -- allow for nil OR a table, but not other falsey value types
if type(table) ~= "table" then
print("ERROR: Table and fields must be provided as tables.")
return self
end
for _, key in pairs(fields) do
if table[key] then
self:addField(key, table[key])
end
end
return self
end

function event:addFieldsWithPrefixIfExist(srcTable, prefix, fields)
srcTable = srcTable == nil and {} or srcTable -- allow for nil OR a table, but not other falsey value types
if type(srcTable) ~= "table" or type(fields) ~= "table" then
print("ERROR: table and fields must be provided as a table.")
return self
end
for _, key in pairs(fields) do
if srcTable[key] ~= nil then
self:addField(prefix .. key, srcTable[key])
end
end
return self
end

function event:printEvent()
print(self:toJSON())
end

function event:toJSON()
-- The _e: 1 flag signifies that this is an event. Ensure it is set.
self.data["_e"] = 1
return json.encode(self.data)
end

return event
end

-- Return the AOEvent function to make it accessible from other files
return AOEvent
26 changes: 26 additions & 0 deletions process/src/ario_event.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
local AOEvent = require(".src.ao_event")
local utils = require(".src.utils")

--- @alias ARIOEvent AOEvent

--- Convenience factory function for pre populating analytic and msg fields into AOEvents
--- @param msg table
--- @param initialData table<string, any> | nil Optional initial data to populate the event with.
--- @returns ARIOEvent
local function ARIOEvent(msg, initialData)
local event = AOEvent({
Cron = msg.Cron or false,
Cast = msg.Cast or false,
})
event:addFields(msg.Tags or {})
event:addFieldsIfExist(msg, { "From", "Timestamp", "Action" })
event:addField("Message-Id", msg.Id)
event:addField("From-Formatted", utils.formatAddress(msg.From))
event:addField("Memory-KiB-Used", collectgarbage("count"), false)
if initialData ~= nil then
event:addFields(initialData)
end
return event
end

return ARIOEvent
Loading