Code:
// The 'magic_square' program.
program magic_square.aleo {
// State
// Public
mapping puzzles: u64 => u8;
mapping scores: address => u64;
// Data Structure
struct Board {
r1c1: u8,
r1c2: u8,
r1c3: u8,
r2c1: u8,
r2c3: u8,
r3c1: u8,
r3c2: u8,
r3c3: u8
}
record Token {
owner: address,
amount: u64
}
record Solution {
owner: address,
solution: Board
}
transition add_puzzle(public goal: u8) {
assert_eq(self.caller, aleo1fu0k2qfytzs5fhesgfgjuax6wsh9xx4ftpdapnhzrtruy0tx3urqx3p0ut);
// assert(goal >= 12u8 && goal <= 15u8);
return then finalize(goal);
}
finalize add_puzzle(goal: u8) {
assert(goal >= 12u8 && goal <= 15u8);
// Calculate mapping key from the goal
let key: u64 = BHP256::hash_to_u64(goal);
// Set the key, goal in the puzzles mapping
Mapping::set(puzzles, key, goal);
}
transition get_puzzle_id(goal: u8) -> u64 {
let key: u64 = BHP256::hash_to_u64(goal);
return key;
}
function check_unique(solution: Board) {
assert_neq(solution.r1c1, solution.r1c2);
assert_neq(solution.r1c1, solution.r1c3);
assert_neq(solution.r1c1, solution.r2c1);
assert_neq(solution.r1c1, solution.r2c3);
assert_neq(solution.r1c1, solution.r3c1);
assert_neq(solution.r1c1, solution.r3c2);
assert_neq(solution.r1c1, solution.r3c3);
assert_neq(solution.r1c2, solution.r1c3);
assert_neq(solution.r1c2, solution.r2c1);
assert_neq(solution.r1c2, solution.r2c3);
assert_neq(solution.r1c2, solution.r3c1);
assert_neq(solution.r1c2, solution.r3c2);
assert_neq(solution.r1c2, solution.r3c3);
assert_neq(solution.r1c3, solution.r2c1);
assert_neq(solution.r1c3, solution.r2c3);
assert_neq(solution.r1c3, solution.r3c1);
assert_neq(solution.r1c3, solution.r3c2);
assert_neq(solution.r1c3, solution.r3c3);
assert_neq(solution.r2c1, solution.r2c3);
assert_neq(solution.r2c1, solution.r3c1);
assert_neq(solution.r2c1, solution.r3c2);
assert_neq(solution.r2c1, solution.r3c3);
assert_neq(solution.r2c3, solution.r3c1);
assert_neq(solution.r2c3, solution.r3c2);
assert_neq(solution.r2c3, solution.r3c3);
assert_neq(solution.r3c1, solution.r3c2);
assert_neq(solution.r3c1, solution.r3c3);
assert_neq(solution.r3c2, solution.r3c3);
}
function check_range(solution: Board) {
assert(solution.r1c1 < 9u8);
assert(solution.r1c1 > 0u8);
assert(solution.r1c2 < 9u8);
assert(solution.r1c2 > 0u8);
assert(solution.r1c3 < 9u8);
assert(solution.r1c3 > 0u8);
assert(solution.r2c1 < 9u8);
assert(solution.r2c1 > 0u8);
assert(solution.r2c3 < 9u8);
assert(solution.r2c3 > 0u8);
assert(solution.r3c1 < 9u8);
assert(solution.r3c1 > 0u8);
assert(solution.r3c2 < 9u8);
assert(solution.r3c2 > 0u8);
assert(solution.r3c3 < 9u8);
assert(solution.r3c3 > 0u8);
}
function check_correctness(solution: Board, goal: u8) {
assert_eq(solution.r1c1 + solution.r1c2 + solution.r1c3, goal);
assert_eq(solution.r3c1 + solution.r3c2 + solution.r3c3, goal);
assert_eq(solution.r1c1 + solution.r2c1 + solution.r3c1, goal);
assert_eq(solution.r1c3 + solution.r2c3 + solution.r3c3, goal);
}
transition add_solution(puzzle_id: u64, goal: u8, solution: Board) -> (Token, Solution) {
// Checks if the solution is correct
check_correctness(solution, goal);
// Check if solution is unique
check_unique(solution);
// Check range
check_range(solution);
let token: Token = Token {
owner: self.caller,
amount: 100u64
};
let solution_record: Solution = Solution {
owner: self.caller,
solution: solution
};
return (token, solution_record) then finalize(puzzle_id, goal, self.caller);
}
finalize add_solution(puzzle_id: u64, goal: u8, caller: address) {
// Use get_or_use first
// Get the goal from the mapping
let exists: bool = Mapping::contains(puzzles, puzzle_id);
assert(exists);
let goal_from_mapping: u8 = Mapping::get(puzzles, puzzle_id);
assert_eq(goal, goal_from_mapping);
// Increase score of player
let initial_score: u64 = Mapping::get_or_use(scores, caller, 0u64);
Mapping::set(scores, caller, initial_score + 1u64);
}
}
Accounts Used:
Development Node Account
Private Key APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH
View Key AViewKey1mSnpFFC8Mj4fXbK5YiWgZ3mjiV8CxA79bYNa8ymUpTrw
Address aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px
Developer Account
Private Key APrivateKey1zkpHVhTAJiZPrDeVo6nDyvq2LDRhP2ZgECvr8zqtcefpgsc
View Key AViewKey1mzaT1mopkL7TnVxUr6yhmF7AyXPm8DCNk1tkHEEk7Zso
Address aleo1fu0k2qfytzs5fhesgfgjuax6wsh9xx4ftpdapnhzrtruy0tx3urqx3p0ut
- Clone the snarkos repo
git clone [email protected]:AleoHQ/snarkOS.git
- Checkout the correct version
git checkout 7970ea752ea73ae234f749dd395006e3e231f256
- Install
cargo install --path .
-
Downgrade leo binary zip from here
-
Rename the leo binary to distinguish it from the newer (or) existing version of leo you already have
-
Place it in a directory included in global path. Replace the destination URL accordingly, an example of how the command would look like is given below
mv leo_old /Users/shubham/.cargo/bin/
- Start a local development node
snarkos start --nodisplay --dev 0 --beacon
- Scan for blocks produced by beacon node (You can skip this step as the records always stay the same)
snarkos developer scan -v AViewKey1mSnpFFC8Mj4fXbK5YiWgZ3mjiV8CxA79bYNa8ymUpTrw --start 0 --endpoint "http://localhost:3030"
- Transfer credits to our developer account
snarkos developer execute credits.aleo transfer_private "{ owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private, microcredits: 93750000000000u64.private, _nonce: 4198387698914179364419054715404502698072077412312631840798412024722684186646group.public}" "aleo1fu0k2qfytzs5fhesgfgjuax6wsh9xx4ftpdapnhzrtruy0tx3urqx3p0ut" 83750000000000u64 --private-key "APrivateKey1zkp8CZNn3yeCseEtxuVPbDCwSyhGW6yZKUYKfgXmcpoGPWH" --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --fee 10000000000 --record "{ owner: aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px.private, microcredits: 93750000000000u64.private, _nonce: 6526741553655730916585406598622172875143600009335802058713184455273822212848group.public}"
- Once transferred, scan the last 100 blocks for unspent records. Copy the unspent record. You will have to run this program each time after making a transaction to get an unspent record
snarkos developer scan --view-key AViewKey1mzaT1mopkL7TnVxUr6yhmF7AyXPm8DCNk1tkHEEk7Zso --private-key APrivateKey1zkpHVhTAJiZPrDeVo6nDyvq2LDRhP2ZgECvr8zqtcefpgsc --last 100 --endpoint "http://localhost:3030"
- Deploy the program
snarkos developer deploy magic_square.aleo --private-key APrivateKey1zkpHVhTAJiZPrDeVo6nDyvq2LDRhP2ZgECvr8zqtcefpgsc --query "http://localhost:3030" --path "./build/" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --fee 600000 --record "UNSPENT_RECORD"
- View the program API
import requests
host = "0.0.0.0"
program_name = "magic_square.aleo"
endpoint = f"http://{host}:3030/testnet3/program/{program_name}"
response = requests.get(endpoint)
content = response.content.decode('utf-8').strip('"').split("\\n")
print(endpoint)
for line in content:
print(line)
- Add a puzzle
snarkos developer execute magic_square.aleo add_puzzle "12u8" --private-key APrivateKey1zkpHVhTAJiZPrDeVo6nDyvq2LDRhP2ZgECvr8zqtcefpgsc --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --fee 600000 --record "UNSPENT_RECORD"
- Check the mapping
import requests
host = "0.0.0.0"
program_id = "magic_square_1byx.aleo"
mapping_name = "puzzles"
mapping_key = "67691673676804187u64"
endpoint = f"http://{host}:3030/testnet3/program/{program_id}/mapping/{mapping_name}/{mapping_key}"
result = requests.get(endpoint)
print(endpoint)
print(result.content)
- Add Solution
snarkos developer execute magic_square.aleo add_solution "67691673676804187u64" "12u8" "{r1c1: 1u8, r1c2: 8u8, r1c3: 3u8, r2c1: 5u8, r2c3: 7u8, r3c1: 6u8, r3c2: 4u8, r3c3: 2u8}" --private-key APrivateKey1zkpHVhTAJiZPrDeVo6nDyvq2LDRhP2ZgECvr8zqtcefpgsc --query "http://localhost:3030" --broadcast "http://localhost:3030/testnet3/transaction/broadcast" --fee 600000 --record "UNSPENT_RECORD"
- Transaction View API
import requests
host = "0.0.0.0"
transaction_id = "at1xmqcyuwd6xv5x9z6tn3j7ee572yhzrvhnhg9kscgl96mu8l47ygqrcps6m"
endpoint = f"http://{host}:3030/testnet3/transaction/{transaction_id}"
result = requests.get(endpoint)
print(endpoint)
print(result.content)