diff --git a/onchain/permissionless-arbitration/offchain/blockchain/client.lua b/onchain/permissionless-arbitration/offchain/blockchain/client.lua index 8b4edba9..3d50b8e6 100644 --- a/onchain/permissionless-arbitration/offchain/blockchain/client.lua +++ b/onchain/permissionless-arbitration/offchain/blockchain/client.lua @@ -1,5 +1,5 @@ local Hash = require "cryptography.hash" -local utils = require "utils" +local eth_ebi = require "utils.eth_ebi" local function parse_topics(json) local _, _, topics = json:find( @@ -7,7 +7,7 @@ local function parse_topics(json) ) local t = {} - for k,_ in string.gmatch(topics, [["(0x%x+)"]]) do + for k, _ in string.gmatch(topics, [["(0x%x+)"]]) do table.insert(t, k) end @@ -19,7 +19,7 @@ local function parse_data(json, sig) [==["data":"(0x%x+)"]==] ) - local decoded_data = utils.decode_event_data(sig, data) + local decoded_data = eth_ebi.decode_event_data(sig, data) return decoded_data end @@ -48,11 +48,11 @@ end local function parse_logs(logs, data_sig) local ret = {} - for k,_ in string.gmatch(logs, [[{[^}]*}]]) do + for k, _ in string.gmatch(logs, [[{[^}]*}]]) do local emited_topics = parse_topics(k) local decoded_data = parse_data(k, data_sig) local meta = parse_meta(k) - table.insert(ret, {emited_topics = emited_topics, decoded_data = decoded_data, meta = meta}) + table.insert(ret, { emited_topics = emited_topics, decoded_data = decoded_data, meta = meta }) end return ret @@ -62,7 +62,7 @@ local function join_tables(...) local function join(ret, t, ...) if not t then return ret end - for k,v in ipairs(t) do + for k, v in ipairs(t) do ret[k] = v end @@ -91,15 +91,15 @@ local function sort_and_dedup(t) end) local ret = {} - for k,v in ipairs(t) do - local v2 = t[k+1] + for k, v in ipairs(t) do + local v2 = t[k + 1] if not v2 then table.insert(ret, v) else local m1, m2 = v.meta, v2.meta if not (m1.block_number == m2.block_number and m1.log_index == m2.log_index) then table.insert(ret, v) - end + end end end @@ -107,8 +107,8 @@ local function sort_and_dedup(t) end local function quote_args(args, not_quote) - local quoted_args = {} - for _,v in ipairs(args) do + local quoted_args = {} + for _, v in ipairs(args) do if type(v) == "table" then if v._tag == "tuple" then local qa = quote_args(v, true) @@ -116,7 +116,7 @@ local function quote_args(args, not_quote) local sb = "'(" .. ca .. ")'" table.insert(quoted_args, sb) else - local qa = quote_args(v, true) + local qa = quote_args(v, true) local ca = table.concat(qa, ",") local sb = "'[" .. ca .. "]'" table.insert(quoted_args, sb) @@ -124,7 +124,7 @@ local function quote_args(args, not_quote) elseif not_quote then table.insert(quoted_args, v) else - table.insert(quoted_args, '"'..v..'"') + table.insert(quoted_args, '"' .. v .. '"') end end @@ -144,7 +144,6 @@ function Client:new(blockchain) setmetatable(client, self) return client - end local cast_logs_template = [==[ @@ -153,16 +152,16 @@ cast rpc -r "%s" eth_getLogs \ ]==] function Client:_read_logs(tournament_address, sig, topics, data_sig) - topics = topics or {false, false, false} - local encoded_sig = utils.encode_sig(sig) + topics = topics or { false, false, false } + local encoded_sig = eth_ebi.encode_sig(sig) table.insert(topics, 1, encoded_sig) assert(#topics == 4, "topics doesn't have four elements") local topics_strs = {} - for _,v in ipairs(topics) do + for _, v in ipairs(topics) do local s if v then - s = '"'..v..'"' + s = '"' .. v .. '"' else s = "null" end @@ -198,8 +197,8 @@ cast call --rpc-url "%s" "%s" "%s" %s 2>&1 function Client:_call(address, sig, args) local quoted_args = {} - for _,v in ipairs(args) do - table.insert(quoted_args, '"'..v..'"') + for _, v in ipairs(args) do + table.insert(quoted_args, '"' .. v .. '"') end local args_str = table.concat(quoted_args, " ") @@ -236,20 +235,20 @@ function Client:read_match_created(tournament_address, commitment_hash) local sig = "matchCreated(bytes32,bytes32,bytes32)" local data_sig = "(bytes32)" - local logs1 = self:_read_logs(tournament_address, sig, {commitment_hash, false, false}, data_sig) - local logs2 = self:_read_logs(tournament_address, sig, {false, commitment_hash, false}, data_sig) + local logs1 = self:_read_logs(tournament_address, sig, { commitment_hash, false, false }, data_sig) + local logs2 = self:_read_logs(tournament_address, sig, { false, commitment_hash, false }, data_sig) local logs = sort_and_dedup(join_tables(logs1, logs2)) local ret = {} - for k,v in ipairs(logs) do + for k, v in ipairs(logs) do local log = {} log.tournament_address = tournament_address log.meta = v.meta - log.commitment_one = Hash:from_digest(v.emited_topics[2]) - log.commitment_two = Hash:from_digest(v.emited_topics[3]) - log.left_hash = Hash:from_digest(v.decoded_data[1]) + log.commitment_one = Hash:from_digest_hex(v.emited_topics[2]) + log.commitment_two = Hash:from_digest_hex(v.emited_topics[3]) + log.left_hash = Hash:from_digest_hex(v.decoded_data[1]) log.match_id_hash = log.commitment_one:join(log.commitment_two) ret[k] = log @@ -261,7 +260,7 @@ end function Client:read_commitment(tournament_address, commitment_hash) local sig = "getCommitment(bytes32)((uint64,uint64),bytes32)" - local call_ret = self:_call(tournament_address, sig, {commitment_hash}) + local call_ret = self:_call(tournament_address, sig, { commitment_hash }) assert(#call_ret == 2) local allowance, last_resume = call_ret[1]:match "%((%d+),(%d+)%)" @@ -274,7 +273,7 @@ function Client:read_commitment(tournament_address, commitment_hash) local ret = { clock = clock, - final_state = Hash:from_digest(call_ret[2]) + final_state = Hash:from_digest_hex(call_ret[2]) } return ret @@ -284,14 +283,14 @@ function Client:read_tournament_created(tournament_address, match_id_hash) local sig = "newInnerTournament(bytes32,address)" local data_sig = "(address)" - local logs = self:_read_logs(tournament_address, sig, {match_id_hash, false, false}, data_sig) + local logs = self:_read_logs(tournament_address, sig, { match_id_hash, false, false }, data_sig) assert(#logs <= 1) if #logs == 0 then return false end local log = logs[1] local ret = { - parent_match = Hash:from_digest(match_id_hash), + parent_match = Hash:from_digest_hex(match_id_hash), new_tournament = log.decoded_data[1], } @@ -300,10 +299,10 @@ end function Client:match(address, match_id_hash) local sig = "getMatch(bytes32)(bytes32,bytes32,bytes32,uint64,uint64,uint64)" - local ret = self:_call(address, sig, {match_id_hash}) - ret[1] = Hash:from_digest(ret[1]) - ret[2] = Hash:from_digest(ret[2]) - ret[3] = Hash:from_digest(ret[3]) + local ret = self:_call(address, sig, { match_id_hash }) + ret[1] = Hash:from_digest_hex(ret[1]) + ret[2] = Hash:from_digest_hex(ret[2]) + ret[3] = Hash:from_digest_hex(ret[3]) return ret end @@ -312,18 +311,17 @@ function Client:tournament_winner(address) local sig = "tournamentWinner()(bytes32)" local ret = self:_call(address, sig, {}) - return Hash:from_digest(ret[1]) + return Hash:from_digest_hex(ret[1]) end function Client:root_tournament_winner(address) local sig = "rootTournamentFinalState()(bool,bytes32)" local ret = self:_call(address, sig, {}) - ret[2] = Hash:from_digest(ret[2]) + ret[2] = Hash:from_digest_hex(ret[2]) return ret end - function Client:maximum_delay(address) local sig = "maximumEnforceableDelay()(uint64)" local ret = self:_call(address, sig, {}) @@ -331,7 +329,6 @@ function Client:maximum_delay(address) return ret end - local cast_send_template = [[ cast send --private-key "%s" --rpc-url "%s" "%s" "%s" %s 2>&1 ]] @@ -363,7 +360,7 @@ end function Client:tx_join_tournament(tournament_address, final_state, proof, left_child, right_child) local sig = [[joinTournament(bytes32,bytes32[],bytes32,bytes32)]] - self:_send_tx(tournament_address, sig, {final_state, proof, left_child, right_child}) + self:_send_tx(tournament_address, sig, { final_state, proof, left_child, right_child }) end function Client:tx_advance_match( @@ -373,30 +370,29 @@ function Client:tx_advance_match( self:_send_tx( tournament_address, sig, - {{commitment_one, commitment_two, _tag = "tuple"}, left, right, new_left, new_right} + { { commitment_one, commitment_two, _tag = "tuple" }, left, right, new_left, new_right } ) end - function Client:tx_seal_inner_match( tournament_address, commitment_one, commitment_two, left, right, initial_hash, proof ) local sig = - [[sealInnerMatchAndCreateInnerTournament((bytes32,bytes32),bytes32,bytes32,bytes32,bytes32[])]] + [[sealInnerMatchAndCreateInnerTournament((bytes32,bytes32),bytes32,bytes32,bytes32,bytes32[])]] self:_send_tx( tournament_address, sig, - {{commitment_one, commitment_two, _tag = "tuple"}, left, right, initial_hash, proof} + { { commitment_one, commitment_two, _tag = "tuple" }, left, right, initial_hash, proof } ) end function Client:tx_win_inner_match(tournament_address, child_tournament_address, left, right) local sig = - [[winInnerMatch(address,bytes32,bytes32)]] + [[winInnerMatch(address,bytes32,bytes32)]] self:_send_tx( tournament_address, sig, - {child_tournament_address, left, right} + { child_tournament_address, left, right } ) end @@ -404,11 +400,11 @@ function Client:tx_seal_leaf_match( tournament_address, commitment_one, commitment_two, left, right, initial_hash, proof ) local sig = - [[sealLeafMatch((bytes32,bytes32),bytes32,bytes32,bytes32,bytes32[])]] + [[sealLeafMatch((bytes32,bytes32),bytes32,bytes32,bytes32,bytes32[])]] self:_send_tx( tournament_address, sig, - {{commitment_one, commitment_two, _tag = "tuple"}, left, right, initial_hash, proof} + { { commitment_one, commitment_two, _tag = "tuple" }, left, right, initial_hash, proof } ) end @@ -416,15 +412,14 @@ function Client:tx_win_leaf_match( tournament_address, commitment_one, commitment_two, left, right ) local sig = - [[winLeafMatch((bytes32,bytes32),bytes32,bytes32)]] + [[winLeafMatch((bytes32,bytes32),bytes32,bytes32)]] self:_send_tx( tournament_address, sig, - {{commitment_one, commitment_two, _tag = "tuple"}, left, right} + { { commitment_one, commitment_two, _tag = "tuple" }, left, right } ) end - return Client diff --git a/onchain/permissionless-arbitration/offchain/blockchain/node.lua b/onchain/permissionless-arbitration/offchain/blockchain/node.lua index dce2ea04..3ca56e13 100644 --- a/onchain/permissionless-arbitration/offchain/blockchain/node.lua +++ b/onchain/permissionless-arbitration/offchain/blockchain/node.lua @@ -18,10 +18,12 @@ local function start_blockchain(account_num) local pid = tonumber(reader:read()) - local handle = {reader = reader, pid = pid} - setmetatable(handle, {__gc = function(t) - stop_blockchain(t.reader, t.pid) - end}) + local handle = { reader = reader, pid = pid } + setmetatable(handle, { + __gc = function(t) + stop_blockchain(t.reader, t.pid) + end + }) print(string.format("Blockchain running with pid %d", pid)) return handle @@ -57,12 +59,11 @@ local function capture_blockchain_data(reader, account_num) _, _, endpoint = str:find("Listening on ([%w%p]+)") until endpoint - return {address = addresses, pk = pks}, endpoint + return { address = addresses, pk = pks }, endpoint end local function deploy_contracts(endpoint, deployer, initial_hash) - -- -- Deploy Single Level Factory print "Deploying Single Level factory..." @@ -183,7 +184,7 @@ function Blockchain:new(account_num) blockchain._handle = handle blockchain._accounts = accounts blockchain._current_account = 1 - blockchain.endpoint = "http://"..endpoint + blockchain.endpoint = "http://" .. endpoint setmetatable(blockchain, self) return blockchain diff --git a/onchain/permissionless-arbitration/offchain/computation/commitment.lua b/onchain/permissionless-arbitration/offchain/computation/commitment.lua index 2f5781c1..e7280d16 100644 --- a/onchain/permissionless-arbitration/offchain/computation/commitment.lua +++ b/onchain/permissionless-arbitration/offchain/computation/commitment.lua @@ -83,7 +83,10 @@ local function build_commitment(base_cycle, log2_stride, log2_stride_count, mach local machine = Machine:new_from_path(machine_path) if log2_stride >= consts.log2_uarch_span then - assert(log2_stride - consts.log2_uarch_span + log2_stride_count <= 63) + assert( + log2_stride + log2_stride_count <= + consts.log2_emulator_span + consts.log2_uarch_span + ) return build_big_machine_commitment(base_cycle, log2_stride, log2_stride_count, machine) else assert(log2_stride == 0) @@ -91,6 +94,34 @@ local function build_commitment(base_cycle, log2_stride, log2_stride_count, mach end end +local CommitmentBuilder = {} +CommitmentBuilder.__index = CommitmentBuilder + +function CommitmentBuilder:new(machine_path) + local c = { + machine_path = machine_path, + commitments = {} + } + setmetatable(c, self) + return c +end + +function CommitmentBuilder:build(base_cycle, level) + assert(level <= consts.levels) + if not self.commitments[level] then + self.commitments[level] = {} + elseif self.commitments[level][base_cycle] then + return self.commitments[level][base_cycle] + end + + local l = consts.levels - level + 1 + local log2_stride, log2_stride_count = consts.log2step[l], consts.heights[l] + print(log2_stride, log2_stride_count) + + local _, commitment = build_commitment(base_cycle, log2_stride, log2_stride_count, self.machine_path) + self.commitments[level][base_cycle] = commitment + return commitment +end -- local path = "program/simple-program" -- -- local initial, tree = build_commitment(0, 0, 64, path) @@ -154,4 +185,4 @@ x (0 0 0 | x) (0 0 0 | x) (0 0 0 | x) (0 0 0 | x) -- end --]] -return build_commitment +return CommitmentBuilder diff --git a/onchain/permissionless-arbitration/offchain/computation/fake_commitment.lua b/onchain/permissionless-arbitration/offchain/computation/fake_commitment.lua new file mode 100644 index 00000000..c9f716db --- /dev/null +++ b/onchain/permissionless-arbitration/offchain/computation/fake_commitment.lua @@ -0,0 +1,18 @@ +local Hash = require "cryptography.hash" +local consts = require "constants" + +local CommitmentBuilder = {} +CommitmentBuilder.__index = CommitmentBuilder + +function CommitmentBuilder:new() + local c = {} + setmetatable(c, self) + return c +end + +function CommitmentBuilder:build(_, level) + local commitment = Hash.zero:iterated_merkle(consts.heights[level]) + return commitment +end + +return CommitmentBuilder diff --git a/onchain/permissionless-arbitration/offchain/computation/machine.lua b/onchain/permissionless-arbitration/offchain/computation/machine.lua index 1d9be341..a52f7be5 100644 --- a/onchain/permissionless-arbitration/offchain/computation/machine.lua +++ b/onchain/permissionless-arbitration/offchain/computation/machine.lua @@ -55,6 +55,7 @@ function Machine:new_from_path(path) cycle = 0, ucycle = 0, start_cycle = start_cycle, + initial_hash = Hash:from_digest(machine:get_root_hash()) } setmetatable(b, self) @@ -96,8 +97,6 @@ function Machine:increment_uarch() self.ucycle = self.ucycle + 1 end - - function Machine:ureset() assert(self.ucycle == arithmetic.max_uint64) self.machine:reset_uarch_state() diff --git a/onchain/permissionless-arbitration/offchain/constants.lua b/onchain/permissionless-arbitration/offchain/constants.lua index 6cff43a6..a4d631b5 100644 --- a/onchain/permissionless-arbitration/offchain/constants.lua +++ b/onchain/permissionless-arbitration/offchain/constants.lua @@ -1,12 +1,12 @@ local arithmetic = require "utils.arithmetic" -local log2_uarch_span = 64 -local log2_emulator_span = 63 +local log2_uarch_span = 16 +local log2_emulator_span = 47 local constants = { levels = 4, - log2step = {24, 14, 7, 0}, - heights = {39, 10, 7, 7}, + log2step = { 24, 14, 7, 0 }, + heights = { 39, 10, 7, 7 }, log2_uarch_span = log2_uarch_span, uarch_span = arithmetic.max_uint(log2_uarch_span), diff --git a/onchain/permissionless-arbitration/offchain/entrypoint.lua b/onchain/permissionless-arbitration/offchain/entrypoint.lua index 4ad7e2ec..62753407 100755 --- a/onchain/permissionless-arbitration/offchain/entrypoint.lua +++ b/onchain/permissionless-arbitration/offchain/entrypoint.lua @@ -5,6 +5,59 @@ package.cpath = package.cpath .. ";/opt/cartesi/lib/lua/5.4/?.so" print "Hello, world!" os.execute "cd offchain/program && ./gen_machine_simple.sh" +local machine_path = "offchain/program/simple-program" + +local Player = require "player" +local Client = require "blockchain.client" + +local Machine = require "computation.machine" +local initial_hash = Machine:new_from_path(machine_path):state().root_hash + +local Blockchain = require "blockchain.node" +local blockchain = Blockchain:new() +local contract = blockchain:deploy_contract(initial_hash) + + +local p1 +do + local CommitmentBuilder = require "computation.commitment" + local builder = CommitmentBuilder:new(machine_path) + local client = Client:new(blockchain) + p1 = Player:new(contract, client, builder) +end + +local p2 +do + local FakeCommitmentBuilder = require "computation.fake_commitment" + local builder = FakeCommitmentBuilder:new() + local client = Client:new(blockchain) + p2 = Player:new(contract, client, builder) +end + +local i = 0 +while true do + print(string.format("\n\n### ROUND %d ###\n", i)) + + print "Player 1 react" + if p1:react() then break end + + print "" + + print "Player 2 react" + if p2:react() then break end + + i = i + 1 +end + + + + + + + + + + -- os.execute "jsonrpc-remote-cartesi-machine --server-address=localhost:8080 &" -- os.execute "sleep 2" @@ -13,11 +66,11 @@ os.execute "cd offchain/program && ./gen_machine_simple.sh" -- require "computation.commitment" -- require "computation.machine_test" -local Blockchain = require "blockchain.node" +-- local Blockchain = require "blockchain.node" -local bc = Blockchain:new(100) -local initial_hash = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" -bc:deploy_contract(initial_hash) +-- local bc = Blockchain:new(100) +-- local initial_hash = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" +-- bc:deploy_contract(initial_hash) -- local utils = require "utils" diff --git a/onchain/permissionless-arbitration/offchain/player.lua b/onchain/permissionless-arbitration/offchain/player.lua index 12abd061..740fbad4 100644 --- a/onchain/permissionless-arbitration/offchain/player.lua +++ b/onchain/permissionless-arbitration/offchain/player.lua @@ -3,15 +3,16 @@ local constants = require "constants" local Player = {} Player.__index = Player -function Player:new(root_tournament_address, client, machine) +function Player:new(root_tournament_address, client, commitment_builder) local player = { root_tournament = { + base_big_cycle = 0, address = root_tournament_address, level = constants.levels, parent = false, }, client = client, - machine = machine, + commitment_builder = commitment_builder, commitments = {}, called_win = {} } @@ -28,11 +29,9 @@ end function Player:_react_tournament(tournament) local commitment = self.commitments[tournament.address] if not commitment then - commitment = self.machine:commitment( - constants.log2step[tournament.level], - constants.heights[constants.levels - tournament.level + 1], - false, -- TODO - false -- TODO + commitment = self.commitment_builder:build( + tournament.base_big_cycle, + tournament.level ) self.commitments[tournament.address] = commitment end @@ -114,7 +113,6 @@ function Player:_react_match(match, commitment) left, right ) - else local address = self.client:read_tournament_created( match.tournament.address, @@ -128,7 +126,6 @@ function Player:_react_match(match, commitment) return self:_react_tournament(new_tournament) end - elseif match.current_height == 1 then -- match to be sealed local found, left, right = commitment:children(match.current_other_parent) @@ -183,6 +180,7 @@ function Player:_react_match(match, commitment) new_tournament.address = address new_tournament.level = match.tournament.level - 1 new_tournament.parent = match.tournament + new_tournament.base_big_cycle = match.leaf_cycle return self:_react_tournament(new_tournament) end @@ -221,7 +219,6 @@ function Player:_react_match(match, commitment) end end - function Player:_latest_match(tournament, commitment) local matches = self.client:read_match_created(tournament.address, commitment.root) local last_match = matches[#matches] @@ -237,6 +234,10 @@ function Player:_latest_match(tournament, commitment) last_match.current_height = tonumber(m[6]) last_match.tournament = tournament + local level = tournament.level + last_match.leaf_cycle = tournament.base_big_cycle + + (last_match.running_leaf << (constants.log2step[level] + constants.log2_uarch_span)) + return last_match end diff --git a/onchain/permissionless-arbitration/offchain/utils/arithmetic.lua b/onchain/permissionless-arbitration/offchain/utils/arithmetic.lua index 6192a0b2..18ce44c6 100644 --- a/onchain/permissionless-arbitration/offchain/utils/arithmetic.lua +++ b/onchain/permissionless-arbitration/offchain/utils/arithmetic.lua @@ -10,7 +10,7 @@ local function ulte(x, y) end local function is_pow2(x) - return (x & (x-1)) == 0 + return (x & (x - 1)) == 0 end -- Returns number of leading zeroes of x. Shamelessly stolen from the book @@ -18,12 +18,22 @@ end local function clz(x) if x == 0 then return 64 end local n = 0 - if (x & 0xFFFFFFFF00000000) == 0 then n = n + 32; x = x << 32 end - if (x & 0xFFFF000000000000) == 0 then n = n + 16; x = x << 16 end - if (x & 0xFF00000000000000) == 0 then n = n + 8; x = x << 8 end - if (x & 0xF000000000000000) == 0 then n = n + 4; x = x << 4 end - if (x & 0xC000000000000000) == 0 then n = n + 2; x = x << 2 end - if (x & 0x8000000000000000) == 0 then n = n + 1 end + if (x & 0xFFFFFFFF00000000) == 0 then + n = n + 32; x = x << 32 + end + if (x & 0xFFFF000000000000) == 0 then + n = n + 16; x = x << 16 + end + if (x & 0xFF00000000000000) == 0 then + n = n + 8; x = x << 8 + end + if (x & 0xF000000000000000) == 0 then + n = n + 4; x = x << 4 + end + if (x & 0xC000000000000000) == 0 then + n = n + 2; x = x << 2 + end + if (x & 0x8000000000000000) == 0 then n = n + 1 end return n end diff --git a/onchain/permissionless-arbitration/offchain/utils/eth_ebi.lua b/onchain/permissionless-arbitration/offchain/utils/eth_ebi.lua new file mode 100644 index 00000000..467bf804 --- /dev/null +++ b/onchain/permissionless-arbitration/offchain/utils/eth_ebi.lua @@ -0,0 +1,31 @@ +local function encode_sig(sig) + local cmd = string.format([[cast sig-event "%s"]], sig) + + local handle = io.popen(cmd) + assert(handle) + + local encoded_sig = handle:read() + handle:close() + return encoded_sig +end + +local function decode_event_data(sig, data) + local cmd = string.format([[cast --abi-decode "bananas()%s" %s]], sig, data) + + local handle = io.popen(cmd) + assert(handle) + + local decoded_data + local ret = {} + repeat + decoded_data = handle:read() + table.insert(ret, decoded_data) + until not decoded_data + handle:close() + return ret +end + +return { + encode_sig = encode_sig, + decode_event_data = decode_event_data, +}