Created
October 3, 2022 10:38
-
-
Save TheCyberWatchers/5ec9a626188e1eb70cbd4772e4bbc8be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//index.mjs | |
import { loadStdlib } from "@reach-sh/stdlib"; | |
import * as backend from './build/index.main.mjs'; | |
const stdlib = loadStdlib(); | |
const startingBalance = stdlib.parseCurrency(100); | |
const accAlice = await stdlib.newTestAccount(startingBalance); | |
const accBob = await stdlib.newTestAccount(startingBalance); | |
const fmt = (x) => stdlib.formatCurrency(x, 4); | |
const getBalance = async (who) => fmt(await stdlib.balanceOf(who)); | |
const beforeAlice = await getBalance(accAlice); | |
const beforeBob = await getBalance(accBob); | |
const ctcAlice = accAlice.contract(backend); | |
const ctcBob = accBob.contract(backend, ctcAlice.getInfo()); | |
const HAND = ['Rock', 'Paper', 'Scissors']; | |
const OUTCOME = ['Bob Wins!', 'Draw', 'Alice Wins!']; | |
const Player = (Who) => ({ | |
...stdlib.hasRandom, | |
getHand: async() => { | |
const hand = Math.floor(Math.random() * 3); | |
console.log(`${Who} played ${HAND[hand]}`) | |
if (Math.random() <= 0.01) { | |
for (let i = 0; i < 10; i++){ | |
console.log(`${Who} takes their sweet time sending it back`); | |
await stdlib.wait(1); | |
} | |
} | |
return hand; | |
}, | |
seeOutcome: (outcome) => { | |
console.log(`${Who} saw outcome ${OUTCOME[outcome]}`); | |
}, | |
informTimeout: () => { | |
console.log(`${Who} observed a timeout`); | |
} | |
}) | |
await Promise.all([ | |
ctcAlice.p.Alice({ | |
// Alice interact object here | |
...Player('Alice'), | |
wager: stdlib.parseCurrency(5), | |
deadline: 10, | |
}), | |
ctcBob.p.Bob({ | |
// Bob interact object here | |
...Player('Bob'), | |
acceptWager: (amt) => { | |
console.log(`Bob accepts the wager of ${fmt(amt)}.`); | |
}, | |
}), | |
]); | |
const afterAlice = await getBalance(accAlice); | |
const afterBob = await getBalance(accBob); | |
console.log(`Alice went from ${beforeAlice} to ${afterAlice}`); | |
console.log(`Bob went from ${beforeBob} to ${afterBob}`); | |
//index.rsh | |
'reach 0.1' | |
const [ isHand, ROCK, PAPER, SCISSORS ] = makeEnum(3); | |
const [ isOutcome, B_WINS, DRAW, A_WINS ] = makeEnum(3); | |
const winner = (handAlice, handBob) => | |
((handAlice + (4 - handBob)) % 3); | |
assert(winner(ROCK, PAPER) == B_WINS); | |
assert(winner(PAPER, ROCK) == A_WINS); | |
assert(winner(ROCK, ROCK) == DRAW); | |
/* | |
forall(UInt, a => | |
forall(UInt, b => | |
forall(UInt, c => | |
forall(UInt, d => | |
assert(isOutcome(winner(a, b, c, d))))))); | |
*/ | |
forall(UInt, handAlice => | |
forall(UInt, handBob => | |
assert(isOutcome(winner(handAlice, handBob))))); | |
forall(UInt, (hand) => | |
assert(winner(hand, hand) == DRAW)); | |
const Player = { | |
...hasRandom, | |
getHand: Fun([], UInt), | |
seeOutcome: Fun([UInt], Null), | |
informTimeout: Fun([], Null), | |
} | |
export const main = Reach.App(() => { | |
const Alice = Participant('Alice', { | |
// specify Alice's interact interface here | |
...Player, | |
wager: UInt, | |
deadline: UInt, | |
}) | |
const Bob = Participant('Bob', { | |
...Player, | |
acceptWager: Fun([UInt], Null), | |
}) | |
init() | |
const informTimeout = () => { | |
each([Alice, Bob], () => { | |
interact.informTimeout(); | |
}); | |
}; | |
// write program here | |
Alice.only(() => { | |
const amount = declassify(interact.wager); | |
const deadline = declassify(interact.deadline); | |
}) | |
Alice.publish(amount, deadline) | |
.pay(amount) | |
commit() | |
Bob.only(() => { | |
interact.acceptWager(amount); | |
}); | |
Bob.pay(amount) | |
.timeout(relativeTime(deadline), () => closeTo(Alice, informTimeout)); | |
//must be in consensus | |
var [outcome, v2] = [DRAW, 0]; | |
invariant(balance() == (2 * amount)) | |
while(outcome == DRAW){ | |
//body of loop | |
commit(); | |
Alice.only(() => { | |
const _handAlice = interact.getHand(); | |
const [_commitAlice, _saltAlice] = makeCommitment(interact, _handAlice); | |
const commitAlice = declassify(_commitAlice); | |
}); | |
Alice.publish(commitAlice) | |
.timeout(relativeTime(deadline), () => closeTo(Bob, informTimeout)); | |
commit(); | |
unknowable(Bob, Alice(_handAlice, _saltAlice)); | |
Bob.only(() => { | |
const handBob = declassify(interact.getHand()); | |
}) | |
Bob.publish(handBob) | |
.timeout(relativeTime(deadline), () => closeTo(Alice, informTimeout)); | |
commit(); | |
Alice.only(() => { | |
const saltAlice = declassify(_saltAlice); | |
const handAlice = declassify(_handAlice); | |
}); | |
Alice.publish(saltAlice, handAlice) | |
.timeout(relativeTime(deadline), () => closeTo(Bob, informTimeout)); | |
checkCommitment(commitAlice, saltAlice, handAlice); | |
outcome = winner(handAlice, handBob); | |
continue; | |
} | |
//assert(outcome == A_WINS || outcome == B_WINS); | |
transfer(2 * amount).to(outcome == A_WINS ? Alice : Bob); | |
commit() | |
each([Alice, Bob], () => { | |
interact.seeOutcome(outcome) | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment