Skip to content

Commit

Permalink
Merge pull request #410 from chips-blockchain/verus_test
Browse files Browse the repository at this point in the history
Merging all the changes till deck updation at player ID
  • Loading branch information
sg777 authored May 17, 2024
2 parents 3e7e5f3 + 38aa7f5 commit 166f1e8
Show file tree
Hide file tree
Showing 21 changed files with 344 additions and 187 deletions.
22 changes: 13 additions & 9 deletions docs/protocol/predictable_betting.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The cumulative bet amount collected on various possible predictions of the bet i
| false | 300(200+100) |

Here in the prorata bets, the winning bet amount is calculated as follows:
Lets say the commision taken by host is 5% and validator nodes is 5% for simplicity. In that case 97% of the bet amount is distributed to the winners.
Lets say the commision taken by host is 5% and validator nodes is 5% for simplicity. In that case the remaining 90% of the bet amount is distributed to the winners.
```
winning_bet_amount = bet_amount+ 90%(all_bets_lost_amount) * (bet_amount/all_bets_win_amount)
```
Expand All @@ -55,7 +55,7 @@ all_bets_lost_amount = 300
U1_win_amount = 100 + [90%(300) * (100/800)] = 133.75
```

Like wise if we recompute all for all the users the final bet settelement table looks as follows:
SO the final bet settlement amoutn for all the users based on the outcome A won over B is as follows:

| User | A wins on B | bet_amount | bet_settlement |
| ----------- | ----------- | ---------- | -------------- |
Expand Down Expand Up @@ -102,19 +102,19 @@ Here the host can make a counterbet to the existng bets to change the status fro
The most important thing in the predictable betting is the outcome of the event, and how this outcome of the event is legitimately provided to evaluate the bets. Here we are relying on the validator nodes to feed the outcome of bets and in return the validator nodes gets incentives in answering the bet queries. Its important to note here that the validator nodes are elected by the bet community who are trustworthy in the bet environment and in order to become a validator node one must need to meet certain constraints and guidelines set by the bet community.

To become a validator node one must
a. Go through the election prcess, where the chips holders vote for a specific validator node applicant.
b. The validator node must show the proof that they possess 50k CHIPS.
* Go through the election prcess, where the chips holders vote for a specific validator node applicant.
* The validator node must show the proof that they possess 50k CHIPS.

Whenever the host posts the bets, those bets are visible to all the validator nodes. The job of the validator nodes is based on the outcome of bet the validator nodes answers the queries and store them in the local in the local DB against the specific bet ID.
Whenever the host posts the bets, those bets are visible to all the validator nodes. The job of the validator nodes is based on the outcome of bet the validator nodes answers the queries and store them in the local DB against the specific bet ID.

Once the outcome of the event is revealed in the real world, the host sends requests to the validator nodes to get the outcome of the bet and evaluate the bet accordingly to settle the betting amounts. If the host fail to process the bet with in the time window specified, the users can raise dispute requests with the validator nodes where in which the validator nodes will process the outcome of the bet and settle the funds. The validator nodes gets incentivised for being honest in answering the bet queries and for being available in responding to the host nodes.

The incentives to the validator nodes are based on the queries it answers. The more queries it answers the more incentives it gets. We discuss in detail about how the system is resilient against the dishonest validator and host nodes, and how the dishonest will be moved out of the network and costs incurred for being dishonest in later sections.
The incentives to the validator nodes are based on the queries it answers. The more queries it answers the more incentives it gets. We discuss in detail about how the system is resilient against the dishonest validator and host nodes, and how the dishonest host/validator will be moved out of the network and costs incurred for being dishonest in later sections.

## Lets talk about API's

### Listing the bets by host
Host nodes are the ones who are responsible in creating the prediction markets by posting the bets. In `bets.ini` host lists the bets and publish them to the players when the player node connect to the corresponding host. The sample congiguration data in the `bets.ini` looks as follows:
Host nodes are the ones who are responsible in creating the prediction markets by posting the bets. In `bets.ini` host lists the bets and publish them to the players when the player node connect to the corresponding host. The sample configuration data in the `bets.ini` looks as follows:
```
[bets]
[bets:0]
Expand Down Expand Up @@ -157,7 +157,7 @@ After connecting to backend from GUI, the GUI receives bet method from the backe
"confirmed_bets":[],
}
```
From the GUI the player picks one or multiple bets and send the info to the BE, lets say the player selects the bet "A wins on B" in that case the info the GUI send to BE is in the fowm as shown below:
From the GUI the player picks one or multiple bets and send the info to the BE, lets say the player selects the bet "A wins on B" in that case the info the GUI send to BE is in the form as shown below:
```
{
"method": "bets_selected",
Expand Down Expand Up @@ -199,4 +199,8 @@ Once the player BE receives the bets chosen by the player, it makes the tx to th
"confirmed_bets":[],
}
```
say if any other player matches the bet player by the player, then the bet info is moved from placed_bets to confirmed_bets.
say if any other player matches the bet placed by the player, then the bet info is moved from placed_bets to confirmed_bets.

## Using Verus IDs
The above discussion of the bet uses the data part of the tx to hold the bets and its related info, using verus IDs handling bets will be much efficient. In later steps we develop betting protocols using verus IDs.

2 changes: 1 addition & 1 deletion docs/verus_migration/verus_migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ So with that in mind its important to notedown the following characteristics of

In bet we are representing the data in JSON format and exchanging it over sockets, unlike socket communications with vdxf IDs we need to be cautious about space like how we storing the data on chain and what data we are storing on the chain. To minimize the storage space on blockchain we encode the data as compact strucutres. At the moment we using structures to encode the data for few APIs and eventually once we get clear idea on contents of each update and what exactly an ID can hold then we can map the ID data to a structure and encode in hex and store.

How we going to create the ID's and managing them is an interesting thing to discuss on. The objective of bet is not just for poker but bet as a platform it has capability to host any card games, betting etc..., so with that in mind we create game specific ID's and any data relate to that game will be grouped under it. Lets say we have chips chain launched on verus, for poker game we register ID as `poker.chips@` and for blackjack we register ID as `blackjack.chips10@` and for betting we register ID as `bet.chips@` and so on. Under chips the ID `poker.chips` groups all the information under it, and we again create subID's under `poker.chips` to organize the data for example a subID like `dealer.poker.chips` contains the information about the dealers and likewise `cashier.poker.chips` contains the information about cashiers.
How we going to create the ID's and managing them is an interesting thing to discuss on. The objective of bet is not just for poker but bet as a platform it has capability to host any card games, betting etc..., so with that in mind we create game specific ID's and any data relate to that game will be grouped under it. Lets say we have chips chain launched on verus, for poker game we register ID as `poker.chips@` and for blackjack we register ID as `blackjack.chips@` and for betting we register ID as `bet.chips@` and so on. Under chips the ID `poker.chips` groups all the information under it, and we again create subID's under `poker.chips` to organize the data for example a subID like `dealer.poker.chips` contains the information about the dealers and likewise `cashier.poker.chips` contains the information about cashiers.

In the context of poker, find the following details about ID creation and use of keys to organize the data in IDs as below:
1. [ID creation](./id_creation_process.md)
Expand Down
10 changes: 7 additions & 3 deletions privatebet/bet.c
Original file line number Diff line number Diff line change
Expand Up @@ -544,13 +544,17 @@ static void bet_start(int argc, char **argv)
} else if ((strcmp(argv[1], "print_id") == 0) && (argc > 3)) {
print_id_info(argc, argv);
} else if ((strcmp(argv[1], "add_dealer") == 0) && (argc == 3)) {
add_dealer(argv[2]);
retval = add_dealer(argv[2]);
} else if (strcmp(argv[1], "list_dealers") == 0) {
dlg_info("Dealers ::%s", cJSON_Print(list_dealers()));
cJSON *dealers = list_dealers();
if (dealers) {
dlg_info("Dealers ::%s", cJSON_Print(dealers));
}

} else if (strcmp(argv[1], "list_tables") == 0) {
list_tables();
} else if ((strcmp(argv[1], "reset_id") == 0) && (argc == 3)) {
if (is_id_exists(argv[2], 0))
if (id_cansignfor(argv[2], 0, &retval))
update_cmm(argv[2], NULL);
} else {
bet_command_info();
Expand Down
2 changes: 1 addition & 1 deletion privatebet/bet.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ struct verus_player_config {
int32_t player_id;
char dealer_id[16];
char table_id[16];
char primaryaddress[128];
char wallet_addr[64];
char txid[128];
char verus_pid[128];
};
extern struct verus_player_config player_config;

Expand Down
4 changes: 2 additions & 2 deletions privatebet/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1947,8 +1947,8 @@ void rest_push_cards(struct lws *wsi, cJSON *argjson, int32_t this_playerID)
void rest_display_cards(cJSON *argjson, int32_t this_playerID)
{
char *suit[NSUITS] = { "clubs", "diamonds", "hearts", "spades" };
char *face[NFACES] = { "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "jack", "queen", "king", "ace" };
char *face[NFACES] = { "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "jack", "queen", "king", "ace" };

char action_str[8][100] = { "", "small_blind", "big_blind", "check", "raise", "call", "allin", "fold" };
cJSON *actions = NULL;
Expand Down
1 change: 1 addition & 0 deletions privatebet/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ extern char dcv_hosted_gui_url[128];
int32_t is_table_private;
char table_password[128];
char player_name[128];
char verus_pid[128]; // This is the verus ID owned by the player to which player updates during the game.

int32_t bet_ln_config;
extern int64_t sc_start_block;
Expand Down
18 changes: 14 additions & 4 deletions privatebet/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,23 @@ int32_t bet_parse_verus_player()
strncpy(player_config.table_id, iniparser_getstring(ini, "verus:table_id", NULL),
sizeof(player_config.table_id));
}
if (NULL != iniparser_getstring(ini, "verus:primaryaddress", NULL)) {
strncpy(player_config.primaryaddress, iniparser_getstring(ini, "verus:primaryaddress", NULL),
sizeof(player_config.primaryaddress));
}
if (NULL != iniparser_getstring(ini, "verus:wallet_addr", NULL)) {
strncpy(player_config.wallet_addr, iniparser_getstring(ini, "verus:wallet_addr", NULL),
sizeof(player_config.wallet_addr));
}
if (NULL != iniparser_getstring(ini, "verus:player_id", NULL)) {
strncpy(player_config.verus_pid, iniparser_getstring(ini, "verus:player_id", NULL),
sizeof(player_config.verus_pid));
}
//Check if all IDs are valid
if ((!player_config.dealer_id) || (!player_config.table_id) || (!player_config.verus_pid) ||
!is_id_exists(player_config.dealer_id, 0) || !is_id_exists(player_config.table_id, 0)) {
return ERR_CONFIG_PLAYER_ARGS;
}
//Check if the node has player IDs priv keys
if (!id_cansignfor(player_config.verus_pid, 0, &retval)) {
return retval;
}

return retval;
}
2 changes: 1 addition & 1 deletion privatebet/config/verus_player.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[verus]
dealer_id = "sg777_d" #The player specifically looks if any dealers with this name exists in the available dealer names and prefers that to join, else atm the player picks any one dealer that is available.
table_id = "sg777_t" #If this set, then player looks to join the table with this specific name which is hosted by the dealer it is set in dealer_id and if no dealer_id is set then the player scan through all the dealers and tables available and joins if any table with this name exists, else the player just picks any one table and joins.
primaryaddress = "RUDCNptNJZrzFErgRXgPcfEcWXdY7Rn7x2" #This is the address owned by the player, the cashiers adds this address as the primaryaddress to the corresponding table_id.
wallet_addr = "*" #This is the player registered address from which the player can spend funds from, the default value is *.
player_id = "p1" #This is the verus player ID, to which player updates the game info, so this ID must be signable and spendable from the node in which bet player node is running.
91 changes: 58 additions & 33 deletions privatebet/dealer.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
#include "game.h"
#include "err.h"
#include "misc.h"
#include "commands.h"

struct d_deck_info_struct d_deck_info;
struct game_meta_info_struct game_meta_info;

char all_t_d_p_keys[all_t_d_p_keys_no][128] = { T_D_DECK_KEY, T_D_P1_DECK_KEY, T_D_P2_DECK_KEY, T_D_P3_DECK_KEY,
char all_t_d_p_keys[all_t_d_p_keys_no][128] = { T_D_DECK_KEY, T_D_P1_DECK_KEY, T_D_P2_DECK_KEY, T_D_P3_DECK_KEY,
T_D_P4_DECK_KEY, T_D_P5_DECK_KEY, T_D_P6_DECK_KEY, T_D_P7_DECK_KEY,
T_D_P8_DECK_KEY, T_D_P9_DECK_KEY };

Expand All @@ -22,25 +23,37 @@ char all_game_keys[all_game_keys_no][128] = { T_GAME_INFO_KEY };

char all_game_key_names[all_game_keys_no][128] = { "t_game_info" };

cJSON *add_dealer(char *dealer_id)
int32_t add_dealer(char *dealer_id)
{
int32_t retval = OK;
cJSON *dealers_info = NULL, *dealers = NULL, *out = NULL;

if ((!dealer_id) || (!is_id_exists(dealer_id, 0))) {
dlg_info(
"Either dealer ID is NULL or the ID doesn't exists, make sure ID exists before you add to dealers");
return NULL;
if (!dealer_id) {
return ERR_NULL_ID;
}
if (!is_id_exists(dealer_id, 0)) {
return ERR_ID_NOT_FOUND;
}

if (!id_cansignfor(DEALERS_ID, 0, &retval)) {
return retval;
}

dealers_info = cJSON_CreateObject();
dealers = cJSON_CreateArray();
dealers = list_dealers();
if (!dealers) {
dealers = cJSON_CreateArray();
}
jaddistr(dealers, dealer_id);

cJSON_AddItemToObject(dealers_info, "dealers", dealers);
out = update_cmm_from_id_key_data_cJSON("dealers", DEALERS_KEY, dealers_info, false);
out = update_cmm_from_id_key_data_cJSON(DEALERS_ID, DEALERS_KEY, dealers_info, false);

if (!out) {
return ERR_UPDATEIDENTITY;
}
dlg_info("%s", cJSON_Print(out));
return out;

return retval;
}

int32_t dealer_sb_deck(char *id, bits256 *player_r, int32_t player_id)
Expand Down Expand Up @@ -91,30 +104,38 @@ int32_t dealer_table_init(struct table t)
return ERR_ID_NOT_FOUND;

game_state = get_game_state(t.table_id);
if (game_state == G_ZEROIZED_STATE) {

switch (game_state) {
case G_ZEROIZED_STATE:
game_id = rand256(0);
dlg_info("Updating %s key...", T_GAME_ID_KEY);
out = append_cmm_from_id_key_data_hex(t.table_id, T_GAME_ID_KEY, bits256_str(hexstr, game_id), false);
if (!out)
return ERR_TABLE_LAUNCH;
dlg_info("%s", cJSON_Print(out));

dlg_info("Updating Game state to %s...", game_state_str(G_TABLE_ACTIVE));
out = append_game_state(t.table_id, G_TABLE_ACTIVE, NULL);
if (!out)
return ERR_GAME_STATE_UPDATE;
dlg_info("%s", cJSON_Print(out));

// No break is intentional
case G_TABLE_ACTIVE:
dlg_info("Updating %s key...", T_TABLE_INFO_KEY);
out = append_cmm_from_id_key_data_cJSON(
t.table_id, get_key_data_vdxf_id(T_TABLE_INFO_KEY, bits256_str(hexstr, game_id)),
struct_table_to_cJSON(&t), true);
if (!out)
return ERR_TABLE_LAUNCH;
dlg_info("%s", cJSON_Print(out));

dlg_info("Updating Game state to %s...", game_state_str(G_TABLE_STARTED));
out = append_game_state(t.table_id, G_TABLE_STARTED, NULL);
if (!out)
return ERR_GAME_STATE_UPDATE;
dlg_info("%s", cJSON_Print(out));
} else {
break;
default:
dlg_info("Table is in game, at state ::%s", game_state_str(game_state));
}
return retval;
Expand Down Expand Up @@ -246,7 +267,7 @@ int32_t handle_game_state(char *table_id)
return retval;
}

int32_t update_t_info_at_dealer(struct table t)
int32_t register_table(struct table t)
{
int32_t retval = OK;
cJSON *d_table_info = NULL, *out = NULL;
Expand All @@ -264,33 +285,37 @@ int32_t update_t_info_at_dealer(struct table t)
int32_t dealer_init(struct table t)
{
int32_t retval = OK, game_state;
double balance = 0;

if (!(is_id_exists(t.dealer_id, 0) && is_id_exists(t.table_id, 0))) {
return ERR_ID_NOT_FOUND;
}
if (!(id_cansignfor(t.dealer_id, 0) && id_cansignfor(t.table_id, 0))) {
return ERR_ID_AUTH;
balance = chips_get_balance();
if (balance < RESERVE_AMOUNT) {
dlg_info("Wallet balance ::%f, Minimum funds needed to host a table :: %f", balance, RESERVE_AMOUNT);
return ERR_CHIPS_INSUFFICIENT_FUNDS;
}

//If dealer hasn't added to dealers yet, then add it to dealers.poker.chips10sec@
retval = add_dealer_to_dealers(t.dealer_id);
if (retval != OK) {
dlg_info("%s", bet_err_str(retval));
if ((!id_cansignfor(t.dealer_id, 0, &retval)) || (!id_cansignfor(t.table_id, 0, &retval))) {
return retval;
}

//Updating table_info read from the config to the dealer ID.
retval = update_t_info_at_dealer(t);
if (retval) {
dlg_error("Updating the talbe info to the dealer ID::%s is failed", t.dealer_id);
return retval;
if (!is_dealer_registered(t.dealer_id)) {
// TODO:: An automated mechanism to register the dealer with dealers.poker.chips10sec need to be worked out
return ERR_DEALER_UNREGISTERED;
}

game_state = get_game_state(t.table_id);
if (game_state == G_ZEROIZED_STATE) {
retval = dealer_table_init(t);
if (retval)
if (is_table_registered(t.table_id, t.dealer_id)) {
dlg_info("Table::%s is already registered with the dealer ::%s", t.table_id, t.dealer_id);
} else {
// TODO:: At the moment only one table we are registering with the dealer, if any other table exists it will be replaced with new table info
retval = register_table(t);
if (retval) {
dlg_error("Table::%s, registration at dealer::%s is failed", t.table_id, t.dealer_id);
return retval;
}
}

retval = dealer_table_init(t);
if (retval != OK) {
dlg_info("Table Init is failed");
return retval;
}

while (1) {
Expand Down
4 changes: 2 additions & 2 deletions privatebet/dealer.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "bet.h"

cJSON *add_dealer(char *dealer_id);
int32_t add_dealer(char *dealer_id);
int32_t dealer_table_init(struct table t);
bool is_players_shuffled_deck(char *table_id);
int32_t dealer_shuffle_deck(char *id);
int32_t handle_game_state(char *table_id);
int32_t update_t_info_at_dealer(struct table t);
int32_t register_table(struct table t);
int32_t dealer_init(struct table t);
12 changes: 12 additions & 0 deletions privatebet/err.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,18 @@ const char *bet_err_str(int32_t err_no)
return "Not enough authority to update ID, probably the underlying wallet doesn't have privkeys of the primaryaddresses of ID";
case ERR_ADDR_AUTH:
return "Address/PrimaryAddress is not authorized, the wallet doesn't have private keys to spend or sign";
case ERR_DEALER_UNREGISTERED:
return "Dealer hasn't been registered with dealers.poker.chips10sec";
case ERR_NULL_KEY:
return "Data Key of contentmultimap is NULL, key must be a valid name";
case ERR_NULL_ID:
return "ID name is NULL";
case ERR_TABLE_UNREGISTERED:
return "Table is unregistered with the Dealer";
case ERR_DUPLICATE_PLAYERID:
return "Player ID has already been added to the table";
case ERR_PLAYER_NOT_ADDED:
return "Player ID hasn't added to the table";
default:
return "This error is not handled yet...";
}
Expand Down
6 changes: 6 additions & 0 deletions privatebet/err.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ All the errors that come across in bet are defined here. The error numbers are a
#define ERR_IDS_NOT_CONFIGURED 136
#define ERR_ID_AUTH 137
#define ERR_ADDR_AUTH 138
#define ERR_DEALER_UNREGISTERED 139
#define ERR_NULL_KEY 140
#define ERR_NULL_ID 141
#define ERR_TABLE_UNREGISTERED 142
#define ERR_DUPLICATE_PLAYERID 143
#define ERR_PLAYER_NOT_ADDED 144

// clang-format on
const char *bet_err_str(int32_t err_no);
Expand Down
Loading

0 comments on commit 166f1e8

Please sign in to comment.