Skip to content
This repository has been archived by the owner on Mar 12, 2024. It is now read-only.

Commit

Permalink
feat(arbitration): improve lua prototype
Browse files Browse the repository at this point in the history
* Rename `utils.log` to `utils.helper`
* Fastforward blockchain when all players idle
  • Loading branch information
stephenctw committed Sep 4, 2023
1 parent b560f3c commit c86a81e
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 78 deletions.
21 changes: 21 additions & 0 deletions onchain/permissionless-arbitration/offchain/blockchain/client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,27 @@ function Client:tx_win_leaf_match(
)
end

local cast_advance_template = [==[
cast rpc -r "%s" evm_increaseTime %d
]==]

function Client:advance_time(seconds)
local cmd = string.format(
cast_advance_template,
self.endpoint,
seconds
)

local handle = io.popen(cmd)
assert(handle)
local ret = handle:read "*a"
handle:close()

if ret:find "Error" then
error(string.format("Advance time `%d`s failed:\n%s", seconds, ret))
end
end

return Client


Expand Down
55 changes: 29 additions & 26 deletions onchain/permissionless-arbitration/offchain/entrypoint.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,11 @@ package.path = package.path .. ";./offchain/?.lua"
package.cpath = package.cpath .. ";/opt/cartesi/lib/lua/5.4/?.so"

local machine_path = "offchain/program/simple-program"
local ps_template = [[ps %s | grep defunct | wc -l]]

local log = require 'utils.log'
local helper = require 'utils.helper'
local Blockchain = require "blockchain.node"
local Machine = require "computation.machine"

local function is_zombie(pid)
local reader = io.popen(string.format(ps_template, pid))
ret = reader:read()
reader:close()
return tonumber(ret) == 1
end

local function stop_players(pid_reader)
for pid, reader in pairs(pid_reader) do
print(string.format("Stopping player with pid %s...", pid))
os.execute(string.format("kill -15 %s", pid))
reader:close()
print "Player stopped"
end

end
local Client = require "blockchain.client"

print "Hello, world!"
os.execute "cd offchain/program && ./gen_machine_simple.sh"
Expand Down Expand Up @@ -53,23 +36,45 @@ end
-- gracefully end children processes
setmetatable(pid_reader, {
__gc = function(t)
stop_players(t)
helper.stop_players(t)
end
})

local no_active_players = 0
local all_idle = 0
local client = Client:new(1)
local last_ts = [[01/01/2000 00:00:00]]
while true do
local last_ts = [[01/01/2000 00:00:00]]
local players = 0

for pid, reader in pairs(pid_reader) do
local msg_out = 0
players = players + 1
if is_zombie(pid) then
log.log(pid_player[pid], string.format("player process %s is dead", pid))
last_ts, msg_out = helper.log_to_ts(reader, last_ts)

-- close the reader and delete the reader entry when there's no more msg in the buffer
-- and the process has already ended
if msg_out == 0 and helper.is_zombie(pid) then
helper.log(pid_player[pid], string.format("player process %s is dead", pid))
reader:close()
pid_reader[pid] = nil
pid_player[pid] = nil
end
end

if players > 0 then
if helper.all_players_idle(pid_player) then
all_idle = all_idle + 1
helper.rm_all_players_idle(pid_player)
else
last_ts = log.log_to_ts(reader, last_ts)
all_idle = 0
end

-- if all players are idle for 10 consecutive iterations, advance blockchain
if all_idle == 10 then
print("all players idle, fastforward blockchain for 30 seconds...")
client:advance_time(30)
all_idle = 0
end
end

Expand All @@ -81,8 +86,6 @@ while true do

-- if no active player processes for 10 consecutive iterations, break loop
if no_active_players == 10 then break end

-- TODO: if all players are idle, advance anvil
end

print "Good-bye, world!"
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local constants = require "constants"
local bint = require 'utils.bint' (256) -- use 256 bits integers
local log = require 'utils.log'
local helper = require 'utils.helper'

local Machine = require "computation.machine"
local Client = require "blockchain.client"
Expand Down Expand Up @@ -48,29 +48,29 @@ function Player:_react_tournament(tournament)
if not tournament.parent then
local winner_final_state = self.client:root_tournament_winner(tournament.address)
if winner_final_state[1] == "true" then
log.log(self.player_index, "TOURNAMENT FINISHED, HURRAYYY")
log.log(self.player_index, "Winner commitment: " .. winner_final_state[2]:hex_string())
log.log(self.player_index, "Final state: " .. winner_final_state[3]:hex_string())
helper.log(self.player_index, "TOURNAMENT FINISHED, HURRAYYY")
helper.log(self.player_index, "Winner commitment: " .. winner_final_state[2]:hex_string())
helper.log(self.player_index, "Final state: " .. winner_final_state[3]:hex_string())
return true
end
else
local tournament_winner = self.client:inner_tournament_winner(tournament.address)
if tournament_winner[1] == "true" then
local old_commitment = self.commitments[tournament.parent.address]
if tournament_winner[2] ~= old_commitment.root_hash then
log.log(self.player_index, "player lost tournament")
helper.log(self.player_index, "player lost tournament")
self.has_lost = true
return
end

if self.called_win[tournament.address] then
log.log(self.player_index, "player already called winInnerMatch")
helper.log(self.player_index, "player already called winInnerMatch")
return
else
self.called_win[tournament.address] = true
end

log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"win tournament %s of level %d for commitment %s",
tournament.address,
tournament.level,
Expand All @@ -94,7 +94,7 @@ end
function Player:_react_match(match, commitment)
-- TODO call timeout if needed

log.log(self.player_index, "HEIGHT: " .. match.current_height)
helper.log(self.player_index, "HEIGHT: " .. match.current_height)
if match.current_height == 0 then
-- match sealed
if match.tournament.level == 1 then
Expand All @@ -106,11 +106,11 @@ function Player:_react_match(match, commitment)

if finished then
local delay = tonumber(self.client:maximum_delay(match.tournament.address)[1])
log.log(self.player_index, "DELAY", delay - os.time())
helper.log(self.player_index, "DELAY", delay - os.time())
return
end

log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"Calculating access logs for step %s",
match.running_leaf
))
Expand All @@ -119,7 +119,7 @@ function Player:_react_match(match, commitment)
local ucycle = (match.running_leaf & constants.uarch_span):touinteger()
local logs = Machine:get_logs(self.machine_path, cycle, ucycle)

log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"win leaf match in tournament %s of level %d for commitment %s",
match.tournament.address,
match.tournament.level,
Expand All @@ -135,7 +135,7 @@ function Player:_react_match(match, commitment)
logs
)
if not ok then
log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"win leaf match reverted: %s",
e
))
Expand All @@ -157,7 +157,10 @@ function Player:_react_match(match, commitment)
elseif match.current_height == 1 then
-- match to be sealed
local found, left, right = match.current_other_parent:children()
if not found then return end
if not found then
helper.touch_player_idle(self.player_index)
return
end

local initial_hash, proof
if match.running_leaf:iszero() then
Expand All @@ -167,7 +170,7 @@ function Player:_react_match(match, commitment)
end

if match.tournament.level == 1 then
log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"seal leaf match in tournament %s of level %d for commitment %s",
match.tournament.address,
match.tournament.level,
Expand All @@ -183,7 +186,7 @@ function Player:_react_match(match, commitment)
proof
)
else
log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"seal inner match in tournament %s of level %d for commitment %s",
match.tournament.address,
match.tournament.level,
Expand Down Expand Up @@ -216,6 +219,7 @@ function Player:_react_match(match, commitment)
-- match running
local found, left, right = match.current_other_parent:children()
if not found then
helper.touch_player_idle(self.player_index)
return
end

Expand All @@ -230,7 +234,7 @@ function Player:_react_match(match, commitment)
assert(f)
end

log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"advance match with current height %d in tournament %s of level %d for commitment %s",
match.current_height,
match.tournament.address,
Expand Down Expand Up @@ -284,13 +288,15 @@ function Player:_join_tournament_if_needed(tournament, commitment)
assert(f)
local last, proof = commitment:last()

log.log(self.player_index, string.format(
helper.log(self.player_index, string.format(
"join tournament %s of level %d with commitment %s",
tournament.address,
tournament.level,
commitment.root_hash
))
self.client:tx_join_tournament(tournament.address, last, proof, left, right)
else
helper.touch_player_idle(self.player_index)
end
end

Expand Down
93 changes: 93 additions & 0 deletions onchain/permissionless-arbitration/offchain/utils/helper.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
local color = require "utils.color"

local names = {'green', 'yellow', 'blue', 'pink', 'cyan', 'white'}
local idle_template = [[ls player%d_idle 2> /dev/null | grep player%d_idle | wc -l]]
local ps_template = [[ps %s | grep defunct | wc -l]]

local function log(player_index, msg)
local color_index = (player_index - 1) % #names + 1
local timestamp = os.date("%m/%d/%Y %X")
print(color.reset .. color.fg[names[color_index]] .. string.format("[#%d][%s] %s", player_index, timestamp, msg) .. color.reset)
end

local function log_to_ts(reader, last_ts)
-- print everything hold in the buffer which has smaller timestamp
-- this is to synchronise when there're gaps in between the logs
local msg_output = 0
while true do
local msg = reader:read()
if msg then
msg_output = msg_output + 1
print(msg)

local i, j = msg:find("%d%d/%d%d/%d%d%d%d %d%d:%d%d:%d%d")
if i and j then
local timestamp = msg:sub(i, j)
if timestamp > last_ts then
last_ts = timestamp
break
end
end
else
break
end
end
return last_ts, msg_output
end

local function is_zombie(pid)
local reader = io.popen(string.format(ps_template, pid))
ret = reader:read()
reader:close()
return tonumber(ret) == 1
end

local function stop_players(pid_reader)
for pid, reader in pairs(pid_reader) do
print(string.format("Stopping player with pid %s...", pid))
os.execute(string.format("kill -15 %s", pid))
reader:close()
print "Player stopped"
end
end

local function touch_player_idle(player_index)
os.execute(string.format("touch player%d_idle", player_index))
end

local function is_player_idle(player_index)
local reader = io.popen(string.format(idle_template, player_index, player_index))
ret = reader:read()
reader:close()
return tonumber(ret) == 1
end

local function rm_player_idle(player_index)
os.execute(string.format("rm player%d_idle", player_index))
end

local function all_players_idle(pid_player)
for pid, player in pairs(pid_player) do
if not is_player_idle(player) then
return false
end
end
return true
end

local function rm_all_players_idle(pid_player)
for pid, player in pairs(pid_player) do
rm_player_idle(player)
end
return true
end

return {
log = log,
log_to_ts = log_to_ts,
is_zombie = is_zombie,
stop_players = stop_players,
touch_player_idle = touch_player_idle,
all_players_idle = all_players_idle,
rm_all_players_idle = rm_all_players_idle
}
35 changes: 0 additions & 35 deletions onchain/permissionless-arbitration/offchain/utils/log.lua

This file was deleted.

0 comments on commit c86a81e

Please sign in to comment.