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
1 change: 1 addition & 0 deletions __tests__/controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,7 @@ describe("Reserves tests", () => {

beforeAll(async () => {
const envWithReserves = {
...env,
Process: {
...env.Process,
Tags: [
Expand Down
1 change: 1 addition & 0 deletions __tests__/liquidations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@ describe("Position liquidation", () => {

beforeEach(async () => {
const envWithFriend = {
...env,
Process: {
...env.Process,
Tags: env.Process.Tags.map((t) => {
Expand Down
1 change: 1 addition & 0 deletions __tests__/supply.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,7 @@ describe("AO delegation", () => {

beforeEach(async () => {
const envWithWAO = {
...env,
Process: {
...env.Process,
Tags: [
Expand Down
1 change: 1 addition & 0 deletions __tests__/token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,7 @@ describe("Token standard functionalities", () => {
};
const friendTicker = "TST";
const envWithFriend = {
...env,
Process: {
...env.Process,
Tags: env.Process.Tags.map((t) => {
Expand Down
13 changes: 9 additions & 4 deletions __tests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ export async function setupProcess(defaultEnvironment: Environment, keepMemory =
// current state of the process
let currentMemory: ArrayBuffer | null = null;

const module = generateArweaveAddress()

// handler function that automatically saves the state
return async (msg, env) => {
// call handle
const res = await defaultHandle(currentMemory, msg, env || defaultEnvironment);
const envWithRandomMod = env || defaultEnvironment;
// @ts-expect-error
envWithRandomMod.Module = { Id: module };
const res = await defaultHandle(currentMemory, msg, envWithRandomMod);

// save memory
if (keepMemory)
Expand Down Expand Up @@ -177,7 +182,7 @@ expect.extend({
},
toBeFloatStringEncoded(actual: unknown) {
const pass = typeof actual === "string" && actual.match(/^-?\d+(\.\d+)?$/) !== null;

return {
pass,
message: () => `expected ${this.utils.printReceived(actual)} to be a ${this.utils.printExpected("string encoded float")}`
Expand All @@ -193,7 +198,7 @@ expect.extend({
},
toBeJsonEncoded(actual: string, matcher: jest.AsymmetricMatcher) {
let parsed: unknown;

try {
parsed = JSON.parse(actual);
} catch (error: any) {
Expand Down Expand Up @@ -226,7 +231,7 @@ expect.extend({
})
])
};

if (this.isNot) {
expect(actual).not.toEqual(expect.objectContaining(objTest));
} else {
Expand Down
25 changes: 23 additions & 2 deletions src/process.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ local redeem = require ".supply.redeem"
local delegation = require ".supply.delegation"

local precision = require ".utils.precision"
local chance = require ".utils.chance"

HandlersAdded = HandlersAdded or false

-- add handlers for inputs
local function setup_handlers()
local function setup_handlers(msg)
-- only add handlers once
if HandlersAdded then return end

Expand Down Expand Up @@ -361,11 +362,31 @@ function process.handle(msg, env)
return ao.result()
end

if not RandomSeeded then
chance.seed(tonumber(msg["Block-Height"] .. chance.stringToSeed(ao.env.Process.Owner .. ao.env.Module.Id .. ao.id)))
math.random = function(...)
local args = {...}
local n = #args
if n == 0 then
return chance.random()
end
if n == 1 then
return chance.integer(1, args[1])
end
if n == 2 then
return chance.integer(args[1], args[2])
end
return chance.random()
end

RandomSeeded = true
end

-- the controller is the process spawner
Controller = Controller or ao.env.Process.Owner

-- add handlers
setup_handlers()
setup_handlers(msg)

-- eval handlers
local co = coroutine.create(function() return pcall(Handlers.evaluate, msg, ao.env) end)
Expand Down
117 changes: 117 additions & 0 deletions src/utils/chance.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
-- Copyright (c) 2025 Forward Research
-- Code from the aos codebase: https://github.com/permaweb/aos

--- The Chance module provides utilities for generating random numbers and values. Returns the chance table.
-- @module chance

local N = 624
local M = 397
local MATRIX_A = 0x9908b0df
local UPPER_MASK = 0x80000000
local LOWER_MASK = 0x7fffffff

--- Initializes mt[N] with a seed
-- @lfunction init_genrand
-- @tparam {table} o The table to initialize
-- @tparam {number} s The seed
local function init_genrand(o, s)
o.mt[0] = s & 0xffffffff
for i = 1, N - 1 do
o.mt[i] = (1812433253 * (o.mt[i - 1] ~ (o.mt[i - 1] >> 30))) + i
-- See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
-- In the previous versions, MSBs of the seed affect
-- only MSBs of the array mt[].
-- 2002/01/09 modified by Makoto Matsumoto
o.mt[i] = o.mt[i] & 0xffffffff
-- for >32 bit machines
end
o.mti = N
end

--- Generates a random number on [0,0xffffffff]-interval
-- @lfunction genrand_int32
-- @tparam {table} o The table to generate the random number from
-- @treturn {number} The random number
local function genrand_int32(o)
local y
local mag01 = {} -- mag01[x] = x * MATRIX_A for x=0,1
mag01[0] = 0x0
mag01[1] = MATRIX_A
if o.mti >= N then -- generate N words at one time
if o.mti == N + 1 then -- if init_genrand() has not been called,
init_genrand(o, 5489) -- a default initial seed is used
end
for kk = 0, N - M - 1 do
y = (o.mt[kk] & UPPER_MASK) | (o.mt[kk + 1] & LOWER_MASK)
o.mt[kk] = o.mt[kk + M] ~ (y >> 1) ~ mag01[y & 0x1]
end
for kk = N - M, N - 2 do
y = (o.mt[kk] & UPPER_MASK) | (o.mt[kk + 1] & LOWER_MASK)
o.mt[kk] = o.mt[kk + (M - N)] ~ (y >> 1) ~ mag01[y & 0x1]
end
y = (o.mt[N - 1] & UPPER_MASK) | (o.mt[0] & LOWER_MASK)
o.mt[N - 1] = o.mt[M - 1] ~ (y >> 1) ~ mag01[y & 0x1]

o.mti = 0
end

y = o.mt[o.mti]
o.mti = o.mti + 1

-- Tempering
y = y ~ (y >> 11)
y = y ~ ((y << 7) & 0x9d2c5680)
y = y ~ ((y << 15) & 0xefc60000)
y = y ~ (y >> 18)

return y
end

local MersenneTwister = {}
MersenneTwister.mt = {}
MersenneTwister.mti = N + 1


--- The Random table
-- @table Random
-- @field seed The seed function
-- @field random The random function
-- @field integer The integer function
local Random = {}

--- Sets a new random table given a seed.
-- @function seed
-- @tparam {number} seed The seed
function Random.seed(seed)
init_genrand(MersenneTwister, seed)
end

--- Generates a random number on [0,1)-real-interval.
-- @function random
-- @treturn {number} The random number
function Random.random()
return genrand_int32(MersenneTwister) * (1.0 / 4294967296.0)
end

--- Returns a random integer. The min and max are INCLUDED in the range.
-- The max integer in lua is math.maxinteger
-- The min is math.mininteger
-- @function Random.integer
-- @tparam {number} min The minimum value
-- @tparam {number} max The maximum value
-- @treturn {number} The random integer
function Random.integer(min, max)
assert(max >= min, "max must bigger than min")
return math.floor(Random.random() * (max - min + 1) + min)
end

function Random.stringToSeed(s)
local seed = 0
for i = 1, #s do
local char = string.byte(s, i)
seed = seed + char
end
return seed
end

return Random
6 changes: 3 additions & 3 deletions src/utils/handlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ function handlers.receive(pattern, timeout)
end

handlers.advanced({
name = "_once_" .. tostring(handlers.onceNonce),
name = "_once_" .. tostring(Timestamp) .. tostring(math.random(1e9)),
position = "prepend",
pattern = pattern,
maxRuns = 1,
Expand Down Expand Up @@ -162,7 +162,7 @@ function handlers.once(...)
pattern = select(2, ...)
handle = select(3, ...)
else
name = "_once_" .. tostring(handlers.onceNonce)
name = "_once_" .. tostring(Timestamp) .. tostring(math.random(1e9))
handlers.onceNonce = handlers.onceNonce + 1
pattern = select(1, ...)
handle = select(2, ...)
Expand Down Expand Up @@ -405,7 +405,7 @@ function handlers.advanced(config)

if idx ~= nil and idx > 0 then
-- found a handler to update
handlers[idx] = config
handlers.list[idx] = config
else
-- a handler with this name doesn't exist yet, so we add it
--
Expand Down
2 changes: 1 addition & 1 deletion src/utils/scheduler.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function mod.schedule(...)

-- wait for response
Handlers.advanced({
name = "_once_" .. tostring(Handlers.onceNonce),
name = "_once_" .. tostring(Timestamp) .. tostring(math.random(1e9)),
position = "prepend",
pattern = {
From = msg.Target,
Expand Down