Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add procedure to find the next active player #5

Merged
merged 4 commits into from
May 13, 2024
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
790 changes: 445 additions & 345 deletions lib/contracts/core/game.masm

Large diffs are not rendered by default.

123 changes: 123 additions & 0 deletions lib/contracts/notes/game/check.masm
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use.miden::account
use.miden::note
use.miden::contracts::wallets::basic->wallet

const.NO_OF_PLAYERS_INDEX=57
const.CURRENT_TURN_PLAYER_PUB_KEY_INDEX=60
const.PLAYER_STATS_SLOTS=13
const.CARDS_SLOTS=52
const.PLAYER_CHECK_COUNTER=63

proc.play_check
# => [...]
push.PLAYER_CHECK_COUNTER exec.account::get_item
# => [0, 0, 0, player_check_counter]
drop drop drop
# => [player_check_counter]

# check whether previous players have checked or not
dup push.1 add
push.CURRENT_TURN_PLAYER_PUB_KEY_INDEX exec.account::get_item
# => [0, 0, 0, current_turn_player_pub_key_index, player_check_counter + 1, player_check_counter]
drop drop drop
# => [current_turn_player_pub_key_index, player_check_counter + 1, player_check_counter]
push.CARDS_SLOTS sub
push.PLAYER_STATS_SLOTS div
# => [player no., player_check_counter + 1, player_check_counter]
eq
# => [0/1, player_check_counter]

if.true
push.1 add
# => [player_check_counter + 1]
else
drop
# => [...]
end

padw drop push.PLAYER_CHECK_COUNTER
exec.account::set_item
dropw dropw
# => [...]

# need to update the turn of the player
push.CURRENT_TURN_PLAYER_PUB_KEY_INDEX exec.account::get_item
# => [0, 0, 0, current_turn_player_pub_key_index]
drop drop drop
# => [current_turn_player_pub_key_index]

push.PLAYER_STATS_SLOTS add
# => [current_turn_player_pub_key_index + 13]
# => [next_turn_index]

push.NO_OF_PLAYERS_INDEX exec.account::get_item
drop drop drop
# => [no_of_players, next_turn_index]

# Calculate last_player_index = 52 + 13 * no_of_players + 0
push.PLAYER_STATS_SLOTS mul
push.CARDS_SLOTS add
# => [last_player_index, next_turn_index]

mem_store.0
# => [next_turn_index]

push.1
# => [1, next_turn_index]

while.true

dup push.9 add
# => [next_turn_index + 9, next_turn_index]
exec.account::get_item
drop drop drop
# => [is_fold, next_turn_index]

if.true
# if player has folded
dup mem_load.0 lt
# => [0/1, next_turn_index]

if.true
push.PLAYER_STATS_SLOTS add
push.1
# => [1, next_turn_index + 13]
else
push.0
end
else
# checking is fold
# => [next_turn_index]

padw drop
# => [0, 0, 0, next_turn_index]

push.CURRENT_TURN_PLAYER_PUB_KEY_INDEX # slot of current turn
# => [CURRENT_TURN_PLAYER_PUB_KEY_INDEX, 0, 0, 0, next_turn_index]

exec.account::set_item
dropw dropw
# => [...]
push.0
end
end
dropw
# => [...]
end

begin
dropw

call.play_check
# => [...]

dropw
exec.note::get_assets drop mem_loadw
# => [ASSET, ...]

# load the asset and add it to the account
call.wallet::receive_asset
# => [...]

dropw
end
89 changes: 89 additions & 0 deletions lib/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::notes::{
create_play_raise_note,
create_play_call_note,
create_play_fold_note,
create_play_check_note
};
use crate::constants::CLIENT_CONFIG_FILE_NAME;
use miden_client::client::rpc::NodeRpcClient;
Expand Down Expand Up @@ -76,6 +77,13 @@ pub struct PlayFoldTransactionData {
target_account_id: AccountId,
}

#[derive(Clone)]
pub struct PlayCheckTransactionData {
asset: Asset,
sender_account_id: AccountId,
target_account_id: AccountId,
}

impl SendCardTransactionData {
pub fn account_id(&self) -> AccountId {
self.sender_account_id
Expand Down Expand Up @@ -140,6 +148,19 @@ impl PlayFoldTransactionData {
}
}

impl PlayCheckTransactionData {
pub fn account_id(&self) -> AccountId {
self.sender_account_id
}
pub fn new(asset: Asset, sender_account_id: AccountId, target_account_id: AccountId) -> Self {
Self {
asset,
sender_account_id,
target_account_id,
}
}
}

pub trait AzeGameMethods {
// fn get_tx_executor(&self) -> TransactionExecutor<ClientDataStore<D>>;
fn store(&self) -> SqliteStore;
Expand Down Expand Up @@ -171,6 +192,11 @@ pub trait AzeGameMethods {
// auth_info: AuthInfo,
transaction_template: AzeTransactionTemplate
) -> Result<TransactionRequest, ClientError>;
fn build_aze_play_check_tx_request(
&mut self,
// auth_info: AuthInfo,
transaction_template: AzeTransactionTemplate
) -> Result<TransactionRequest, ClientError>;
fn new_game_account(
&mut self,
template: AzeAccountTemplate,
Expand Down Expand Up @@ -564,6 +590,67 @@ impl<N: NodeRpcClient, R: FeltRng, S: Store> AzeGameMethods for Client<N, R, S>
)
}

fn build_aze_play_check_tx_request(
&mut self,
// auth_info: AuthInfo,
transaction_template: AzeTransactionTemplate
) -> Result<TransactionRequest, ClientError> {
let account_id = transaction_template.account_id();
let account_auth = self.store().get_account_auth(account_id)?;

let (sender_account_id, target_account_id, asset) = match transaction_template {
AzeTransactionTemplate::PlayCheck(
PlayCheckTransactionData { asset, sender_account_id, target_account_id },
) => (sender_account_id, target_account_id, asset),
_ => panic!("Invalid transaction template"),
};

let random_coin = self.get_random_coin();

let created_note = create_play_check_note(
self,
sender_account_id,
target_account_id,
[asset].to_vec(),
NoteType::Public,
random_coin
)?;

let recipient = created_note
.recipient_digest()
.iter()
.map(|x| x.as_int().to_string())
.collect::<Vec<_>>()
.join(".");

let note_tag = created_note.metadata().tag().inner();
let note_type = NoteType::Public;

let tx_script = ProgramAst::parse(
&transaction_request::AUTH_SEND_ASSET_SCRIPT
.replace("{recipient}", &recipient)
.replace("{note_type}", &Felt::new(note_type as u64).to_string())
.replace("{tag}", &Felt::new(note_tag.into()).to_string())
.replace("{asset}", &prepare_word(&asset.into()).to_string())
).expect("shipped MASM is well-formed");

let tx_script = {
let script_inputs = vec![account_auth.into_advice_inputs()];
self.compile_tx_script(tx_script, script_inputs, vec![])?
};

println!("Created txn script");

Ok(
TransactionRequest::new(
sender_account_id,
BTreeMap::new(),
vec![created_note],
Some(tx_script)
)
)
}

fn new_send_card_transaction(
&mut self,
asset: Asset,
Expand All @@ -590,6 +677,7 @@ pub enum AzeTransactionTemplate {
PlayRaise(PlayRaiseTransactionData),
PlayCall(PlayCallTransactionData),
PlayFold(PlayFoldTransactionData),
PlayCheck(PlayCheckTransactionData),
}

impl AzeTransactionTemplate {
Expand All @@ -600,6 +688,7 @@ impl AzeTransactionTemplate {
AzeTransactionTemplate::PlayRaise(p) => p.account_id(),
AzeTransactionTemplate::PlayCall(p) => p.account_id(),
AzeTransactionTemplate::PlayFold(p) => p.account_id(),
AzeTransactionTemplate::PlayCheck(p) => p.account_id(),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion lib/src/constants/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ pub const PLAYER_INITIAL_BALANCE: u8 = 10;
pub const HIGHEST_BET: u8 = SMALL_BLIND_AMOUNT;
pub const PLAYER_BALANCE_SLOT: u8 = 68;
pub const CURRENT_TURN_INDEX_SLOT: u8 = 60;
pub const PLAYER_STATS_SLOTS: u8 = 13;
pub const PLAYER_STATS_SLOTS: u8 = 13;
pub const CHECK_COUNTER_SLOT: u8 = 63;
24 changes: 24 additions & 0 deletions lib/src/notes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,30 @@ pub fn create_play_fold_note<R: FeltRng, N: NodeRpcClient, S: Store>(
Ok(Note::new(vault, metadata, recipient))
}

pub fn create_play_check_note<R: FeltRng, N: NodeRpcClient, S: Store>(
client: &mut Client<N, R, S>,
sender_account_id: AccountId,
target_account_id: AccountId,
assets: Vec<Asset>,
note_type: NoteType,
mut rng: RpoRandomCoin
) -> Result<Note, NoteError> {
let note_script = include_str!("../../contracts/notes/game/check.masm");
let script_ast = ProgramAst::parse(note_script).unwrap();
let note_script = client.compile_note_script(script_ast, vec![]).unwrap();

let note_inputs = NoteInputs::new(vec![]).unwrap();
let tag = NoteTag::from_account_id(target_account_id, NoteExecutionMode::Local)?;
let serial_num = rng.draw_word();
let aux = ZERO;

let metadata = NoteMetadata::new(sender_account_id, NoteType::Public, tag, aux)?;
let vault = NoteAssets::new(assets)?;
let recipient = NoteRecipient::new(serial_num, note_script, note_inputs);

Ok(Note::new(vault, metadata, recipient))
}

// TODO: remove this function after testing
pub async fn mint_note(
client: &mut AzeClient,
Expand Down
83 changes: 83 additions & 0 deletions node/src/api/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use aze_lib::client::{
PlayRaiseTransactionData,
PlayCallTransactionData,
PlayFoldTransactionData,
PlayCheckTransactionData,
AzeTransactionTemplate,
AzeGameMethods,
};
Expand Down Expand Up @@ -278,5 +279,87 @@ pub async fn aze_poker_game_fold() -> Result<Json<GameActionResponse>, GameActio
println!("Executed and synced with node");
log_slots(&client, target_account_id).await;

Ok(Json(GameActionResponse { is_taken: true }))
}

#[post("/v1/game/check")]
pub async fn aze_poker_game_check() -> Result<Json<GameActionResponse>, GameActionError> {
let mut client: AzeClient = create_aze_client();

let small_blind_amt = 5u8;
let buy_in_amt = 100u8;
let no_of_players = 4u8;
let current_turn_index = 65u8;
let player_balance = 10u8;

let slot_data = GameStorageSlotData::new(
small_blind_amt,
buy_in_amt,
no_of_players,
current_turn_index,
small_blind_amt,
player_balance
);

let (game_account, _) = client
.new_game_account(
AzeAccountTemplate::GameAccount {
mutable_code: false,
storage_mode: AccountStorageMode::Local, // for now
},
Some(slot_data)
)
.unwrap();
let game_account_id = game_account.id();
log_slots(&client, game_account_id).await;

let (player_account, _) = client
.new_game_account(
AzeAccountTemplate::PlayerAccount {
mutable_code: false,
storage_mode: AccountStorageMode::Local, // for now
},
None
)
.unwrap();
let player_account_id = player_account.id();

let (faucet_account, _) = client
.new_account(AccountTemplate::FungibleFaucet {
token_symbol: TokenSymbol::new("MATIC").unwrap(),
decimals: 8,
max_supply: 1_000_000_000,
storage_mode: AccountStorageMode::Local,
})
.unwrap();
let faucet_account_id = faucet_account.id();

let note = mint_note(&mut client, player_account_id, faucet_account_id, NoteType::Public).await;
println!("Minted note");
consume_notes(&mut client, player_account_id, &[note]).await;

let fungible_asset = FungibleAsset::new(faucet_account_id, BUY_IN_AMOUNT).unwrap();
let sender_account_id = player_account_id;
let target_account_id = game_account_id;

let playcheck_txn_data = PlayCheckTransactionData::new(
Asset::Fungible(fungible_asset),
sender_account_id,
game_account_id
);
let transaction_template = AzeTransactionTemplate::PlayCheck(playcheck_txn_data);
let txn_request = client.build_aze_play_check_tx_request(transaction_template).unwrap();
execute_tx_and_sync(&mut client, txn_request.clone()).await;

let note_id = txn_request.expected_output_notes()[0].id();
let note = client.get_input_note(note_id).unwrap();

let tx_template = TransactionTemplate::ConsumeNotes(target_account_id, vec![note.id()]);
let tx_request = client.build_transaction_request(tx_template).unwrap();
execute_tx_and_sync(&mut client, tx_request).await;

println!("Executed and synced with node");
log_slots(&client, target_account_id).await;

Ok(Json(GameActionResponse { is_taken: true }))
}
Loading
Loading