Add BPF support & C-based BPF tic-tac-toe (#1422)
Add initial support for BPF and a C port of tictactoe
This commit is contained in:
9
programs/bpf/move_funds_c/build.sh
Executable file
9
programs/bpf/move_funds_c/build.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
OUTDIR="${1:-../../../target/release/}"
|
||||
THISDIR=$(dirname "$0")
|
||||
mkdir -p "$OUTDIR"
|
||||
/usr/local/opt/llvm/bin/clang -Werror -target bpf -O2 -emit-llvm -fno-builtin -o "$OUTDIR"/move_funds_c.bc -c "$THISDIR"/src/move_funds.c
|
||||
/usr/local/opt/llvm/bin/llc -march=bpf -filetype=obj -function-sections -o "$OUTDIR"/move_funds_c.o "$OUTDIR"/move_funds_c.bc
|
||||
|
||||
#/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble "$OUTDIR"/move_funds_c.o
|
3
programs/bpf/move_funds_c/dump.sh
Executable file
3
programs/bpf/move_funds_c/dump.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble ../../../target/release/move_funds_c.o
|
130
programs/bpf/move_funds_c/src/move_funds.c
Normal file
130
programs/bpf/move_funds_c/src/move_funds.c
Normal file
@ -0,0 +1,130 @@
|
||||
|
||||
//#include <stdint.h>
|
||||
//#include <stddef.h>
|
||||
|
||||
#if 1
|
||||
// one way to define a helper function is with index as a fixed value
|
||||
#define BPF_TRACE_PRINTK_IDX 6
|
||||
static int (*sol_print)(int, int, int, int, int) = (void *)BPF_TRACE_PRINTK_IDX;
|
||||
#else
|
||||
// relocation is another option
|
||||
extern int sol_print(int, int, int, int, int);
|
||||
#endif
|
||||
|
||||
typedef long long unsigned int uint64_t;
|
||||
typedef long long int int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
typedef enum { false = 0, true } bool;
|
||||
|
||||
#define SIZE_PUBKEY 32
|
||||
typedef struct {
|
||||
uint8_t x[SIZE_PUBKEY];
|
||||
} SolPubkey;
|
||||
|
||||
typedef struct {
|
||||
SolPubkey *key;
|
||||
int64_t tokens;
|
||||
uint64_t userdata_len;
|
||||
uint8_t *userdata;
|
||||
SolPubkey *program_id;
|
||||
} SolKeyedAccounts;
|
||||
|
||||
// TODO support BPF function calls rather then forcing everything to be inlined
|
||||
#define SOL_FN_PREFIX __attribute__((always_inline)) static
|
||||
|
||||
// TODO move this to a registered helper
|
||||
SOL_FN_PREFIX void sol_memcpy(void *dst, void *src, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
*((uint8_t *)dst + i) = *((uint8_t *)src + i);
|
||||
}
|
||||
}
|
||||
|
||||
#define sol_panic() _sol_panic(__LINE__)
|
||||
SOL_FN_PREFIX void _sol_panic(uint64_t line) {
|
||||
sol_print(0, 0, 0xFF, 0xFF, line);
|
||||
char *pv = (char *)1;
|
||||
*pv = 1;
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX int sol_deserialize(uint8_t *src, uint64_t num_ka, SolKeyedAccounts *ka,
|
||||
uint8_t **userdata, uint64_t *userdata_len) {
|
||||
if (num_ka != *(uint64_t *)src) {
|
||||
return -1;
|
||||
}
|
||||
src += sizeof(uint64_t);
|
||||
|
||||
// TODO fixed iteration loops ok? unrolled?
|
||||
for (int i = 0; i < num_ka; i++) { // TODO this should end up unrolled, confirm
|
||||
// key
|
||||
ka[i].key = (SolPubkey *)src;
|
||||
src += SIZE_PUBKEY;
|
||||
|
||||
// tokens
|
||||
ka[i].tokens = *(uint64_t *)src;
|
||||
src += sizeof(uint64_t);
|
||||
|
||||
// account userdata
|
||||
ka[i].userdata_len = *(uint64_t *)src;
|
||||
src += sizeof(uint64_t);
|
||||
ka[i].userdata = src;
|
||||
src += ka[i].userdata_len;
|
||||
|
||||
// program_id
|
||||
ka[i].program_id = (SolPubkey *)src;
|
||||
src += SIZE_PUBKEY;
|
||||
}
|
||||
// tx userdata
|
||||
*userdata_len = *(uint64_t *)src;
|
||||
src += sizeof(uint64_t);
|
||||
*userdata = src;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// -- Debug --
|
||||
|
||||
SOL_FN_PREFIX void print_key(SolPubkey *key) {
|
||||
for (int j = 0; j < SIZE_PUBKEY; j++) {
|
||||
sol_print(0, 0, 0, j, key->x[j]);
|
||||
}
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX void print_userdata(uint8_t *data, int len) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
sol_print(0, 0, 0, j, data[j]);
|
||||
}
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX void print_params(uint64_t num_ka, SolKeyedAccounts *ka,
|
||||
uint8_t *userdata, uint64_t userdata_len) {
|
||||
sol_print(0, 0, 0, 0, num_ka);
|
||||
for (int i = 0; i < num_ka; i++) {
|
||||
// key
|
||||
print_key(ka[i].key);
|
||||
|
||||
// tokens
|
||||
sol_print(0, 0, 0, 0, ka[i].tokens);
|
||||
|
||||
// account userdata
|
||||
print_userdata(ka[i].userdata, ka[i].userdata_len);
|
||||
|
||||
// program_id
|
||||
print_key(ka[i].program_id);
|
||||
}
|
||||
// tx userdata
|
||||
print_userdata(userdata, userdata_len);
|
||||
}
|
||||
|
||||
void entrypoint(char *buf) {
|
||||
SolKeyedAccounts ka[3];
|
||||
uint64_t userdata_len;
|
||||
uint8_t *userdata;
|
||||
|
||||
if (0 != sol_deserialize((uint8_t *)buf, 3, ka, &userdata, &userdata_len)) {
|
||||
return;
|
||||
}
|
||||
|
||||
print_params(3, ka, userdata, userdata_len);
|
||||
}
|
8
programs/bpf/noop_rust/Cargo.toml
Normal file
8
programs/bpf/noop_rust/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "noop_rust"
|
||||
version = "0.1.0"
|
||||
authors = ["Jack May <jack@solana.com>"]
|
||||
|
||||
[dependencies]
|
||||
rbpf = { git = "https://github.com/solana-labs/rbpf" }
|
||||
solana = { path = "../../.." }
|
10
programs/bpf/noop_rust/build.sh
Executable file
10
programs/bpf/noop_rust/build.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
# TODO building release flavor with rust produces a bunch of output .bc files
|
||||
INTERDIR=../../../target/release
|
||||
OUTDIR="${1:-../../../target/debug/}"
|
||||
mkdir -p "$OUTDIR"
|
||||
# cargo +nightly rustc --release -- -C panic=abort --emit=llvm-ir
|
||||
cargo +nightly rustc --release -- -C panic=abort --emit=llvm-bc
|
||||
cp "$INTERDIR"/deps/noop_rust-*.bc "$OUTDIR"/noop_rust.bc
|
||||
/usr/local/opt/llvm/bin/llc -march=bpf -filetype=obj -o "$OUTDIR"/noop_rust.o "$OUTDIR"/noop_rust.bc
|
3
programs/bpf/noop_rust/dump.sh
Executable file
3
programs/bpf/noop_rust/dump.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble target/release/noop_rust.o
|
15
programs/bpf/noop_rust/src/lib.rs
Normal file
15
programs/bpf/noop_rust/src/lib.rs
Normal file
@ -0,0 +1,15 @@
|
||||
extern crate rbpf;
|
||||
|
||||
use std::mem::transmute;
|
||||
|
||||
#[no_mangle]
|
||||
#[link_section = ".text,entrypoint"] // TODO platform independent needed
|
||||
pub extern "C" fn entrypoint(_raw: *mut u8) {
|
||||
let bpf_func_trace_printk = unsafe {
|
||||
transmute::<u64, extern "C" fn(u64, u64, u64, u64, u64)>(
|
||||
rbpf::helpers::BPF_TRACE_PRINTK_IDX as u64,
|
||||
)
|
||||
};
|
||||
|
||||
bpf_func_trace_printk(0, 0, 1, 2, 3);
|
||||
}
|
9
programs/bpf/tictactoe_c/build.sh
Executable file
9
programs/bpf/tictactoe_c/build.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
OUTDIR="${1:-../../../target/release/}"
|
||||
THISDIR=$(dirname "$0")
|
||||
mkdir -p "$OUTDIR"
|
||||
/usr/local/opt/llvm/bin/clang -Werror -target bpf -O2 -emit-llvm -fno-builtin -o "$OUTDIR"/tictactoe_c.bc -c "$THISDIR"/src/tictactoe.c
|
||||
/usr/local/opt/llvm/bin/llc -march=bpf -filetype=obj -function-sections -o "$OUTDIR"/tictactoe_c.o "$OUTDIR"/tictactoe_c.bc
|
||||
|
||||
# /usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble "$OUTDIR"/tictactoe_c.o
|
3
programs/bpf/tictactoe_c/dump.sh
Executable file
3
programs/bpf/tictactoe_c/dump.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/local/opt/llvm/bin/llvm-objdump -color -source -disassemble ../../../target/release/tictactoe_c.o
|
57
programs/bpf/tictactoe_c/makefile
Executable file
57
programs/bpf/tictactoe_c/makefile
Executable file
@ -0,0 +1,57 @@
|
||||
# Notes:
|
||||
|
||||
# TODO needs more investigation into what r10 is used for
|
||||
# -O2 adds changes the generated code from:
|
||||
# main:
|
||||
# 0: b7 01 00 00 00 00 00 00 r1 = 0
|
||||
# 1: 63 1a fc ff 00 00 00 00 *(u32 *)(r10 - 4) = r1
|
||||
# 2: bf 10 00 00 00 00 00 00 r0 = r1
|
||||
# 3: 95 00 00 00 00 00 00 00 exit
|
||||
# To:
|
||||
# main:
|
||||
# 0: b7 00 00 00 00 00 00 00 r0 = 0
|
||||
# 1: 95 00 00 00 00 00 00 00 exit
|
||||
|
||||
# - building bpf module that includes stdint.h with clang only (no w/ llc) results in an error
|
||||
# $(TOOLS_DIR)/clang -nostdlib -O2 -fpie -target bpf -o bpf.o -c bpf.c
|
||||
# => n file included from /usr/include/sys/_types/_intptr_t.h:30:
|
||||
# => /usr/include/machine/types.h:37:2: error: architecture not supported
|
||||
# => error architecture not supported
|
||||
|
||||
TOOLS_DIR = /usr/local/opt/llvm/bin
|
||||
|
||||
test_x86.o: test.c
|
||||
$(TOOLS_DIR)/clang -O2 -fpie -target x86_64 -o $@ -c $<
|
||||
|
||||
test_x86.so: test_x86.o
|
||||
$(TOOLS_DIR)/ld.lld --shared -o $@ $<
|
||||
|
||||
test_x86_dylib.o: test.c
|
||||
$(TOOLS_DIR)/clang -O2 -fpie -target x86_64-apple-darwin13.0.0 -o $@ -c $<
|
||||
|
||||
test_x86.dylib: test_x86_dylib.o
|
||||
/usr/local/opt/llvm/bin/ld64.lld -dylib -lc -arch x86_64 -o $@ $<
|
||||
|
||||
# TODO does not work if pulling in stdlib, claims unsupported architecture
|
||||
bpf_clang.o: bpf.c
|
||||
$(TOOLS_DIR)/clang -nostdlib -O2 -fpie -target bpf -o bpf.o -c bpf.c
|
||||
|
||||
bpf.o: bpf.c
|
||||
$(TOOLS_DIR)/clang -O2 -emit-llvm -c $< -o - | $(TOOLS_DIR)/llc -march=bpf -filetype=obj -o $@
|
||||
|
||||
bpf_rust.o: bpf_rust.rs
|
||||
rustc +nightly -C opt-level=2 -C panic=abort --emit llvm-bc $<
|
||||
$(TOOLS_DIR)/llc -march=bpf -filetype=obj -function-sections -o $@ bpf_rust.bc
|
||||
|
||||
dumpall:
|
||||
$(TOOLS_DIR)/llvm-objdump -color -source -disassemble *.o
|
||||
|
||||
cleanall:
|
||||
rm -f *.o
|
||||
rm -f *.so
|
||||
rm -f *.dylib
|
||||
rm -f *.ll
|
||||
rm -rf *.bc
|
||||
|
||||
all: bpf_clang.o bpf.o
|
||||
|
370
programs/bpf/tictactoe_c/src/tictactoe.c
Normal file
370
programs/bpf/tictactoe_c/src/tictactoe.c
Normal file
@ -0,0 +1,370 @@
|
||||
|
||||
//#include <stdint.h>
|
||||
//#include <stddef.h>
|
||||
|
||||
#if 1
|
||||
#define BPF_TRACE_PRINTK_IDX 6
|
||||
static int (*sol_print)(int, int, int, int, int) = (void *)BPF_TRACE_PRINTK_IDX;
|
||||
#else
|
||||
// relocation is another option
|
||||
extern int sol_print(int, int, int, int, int);
|
||||
#endif
|
||||
|
||||
typedef long long unsigned int uint64_t;
|
||||
typedef long long int int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
typedef enum { false = 0, true } bool;
|
||||
|
||||
#define SIZE_PUBKEY 32
|
||||
typedef struct {
|
||||
uint8_t x[SIZE_PUBKEY];
|
||||
} SolPubkey;
|
||||
|
||||
typedef struct {
|
||||
SolPubkey *key;
|
||||
int64_t tokens;
|
||||
uint64_t userdata_len;
|
||||
uint8_t *userdata;
|
||||
SolPubkey *program_id;
|
||||
} SolKeyedAccounts;
|
||||
|
||||
// TODO support BPF function calls rather then forcing everything to be inlined
|
||||
#define SOL_FN_PREFIX __attribute__((always_inline)) static
|
||||
|
||||
// TODO move this to a registered helper
|
||||
SOL_FN_PREFIX void sol_memcpy(void *dst, void *src, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
*((uint8_t *)dst + i) = *((uint8_t *)src + i);
|
||||
}
|
||||
}
|
||||
|
||||
#define sol_panic() _sol_panic(__LINE__)
|
||||
SOL_FN_PREFIX void _sol_panic(uint64_t line) {
|
||||
sol_print(0, 0, 0xFF, 0xFF, line);
|
||||
char *pv = (char *)1;
|
||||
*pv = 1;
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX int sol_deserialize(uint8_t *src, uint64_t num_ka, SolKeyedAccounts *ka,
|
||||
uint8_t **userdata, uint64_t *userdata_len) {
|
||||
if (num_ka != *(uint64_t *)src) {
|
||||
return -1;
|
||||
}
|
||||
src += sizeof(uint64_t);
|
||||
|
||||
// TODO fixed iteration loops ok? unrolled?
|
||||
for (int i = 0; i < num_ka; i++) { // TODO this should end up unrolled, confirm
|
||||
// key
|
||||
ka[i].key = (SolPubkey *)src;
|
||||
src += SIZE_PUBKEY;
|
||||
|
||||
// tokens
|
||||
ka[i].tokens = *(uint64_t *)src;
|
||||
src += sizeof(uint64_t);
|
||||
|
||||
// account userdata
|
||||
ka[i].userdata_len = *(uint64_t *)src;
|
||||
src += sizeof(uint64_t);
|
||||
ka[i].userdata = src;
|
||||
src += ka[i].userdata_len;
|
||||
|
||||
// program_id
|
||||
ka[i].program_id = (SolPubkey *)src;
|
||||
src += SIZE_PUBKEY;
|
||||
}
|
||||
// tx userdata
|
||||
*userdata_len = *(uint64_t *)src;
|
||||
src += sizeof(uint64_t);
|
||||
*userdata = src;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -- TicTacToe --
|
||||
|
||||
// Board Coodinates
|
||||
// | 0,0 | 1,0 | 2,0 |
|
||||
// | 0,1 | 1,1 | 2,1 |
|
||||
// | 0,2 | 1,2 | 2,2 |
|
||||
|
||||
typedef enum {
|
||||
Result_Ok,
|
||||
Result_Panic,
|
||||
Result_GameInProgress,
|
||||
Result_InvalidArguments,
|
||||
Result_InvalidMove,
|
||||
Result_InvalidUserdata,
|
||||
Result_InvalidTimestamp,
|
||||
Result_NoGame,
|
||||
Result_NotYourTurn,
|
||||
Result_PlayerNotFound,
|
||||
Result_UserdataTooSmall,
|
||||
} Result;
|
||||
|
||||
typedef enum { BoardItem_F, BoardItem_X, BoardItem_O } BoardItem;
|
||||
|
||||
typedef enum {
|
||||
State_Waiting,
|
||||
State_XMove,
|
||||
State_OMove,
|
||||
State_XWon,
|
||||
State_OWon,
|
||||
State_Draw,
|
||||
} State;
|
||||
|
||||
typedef struct {
|
||||
SolPubkey player_x;
|
||||
SolPubkey player_o;
|
||||
State state;
|
||||
BoardItem board[9];
|
||||
int64_t keep_alive[2];
|
||||
} Game;
|
||||
|
||||
typedef enum {
|
||||
Command_Init = 0,
|
||||
Command_Join,
|
||||
Command_KeepAlive,
|
||||
Command_Move,
|
||||
} Command;
|
||||
|
||||
SOL_FN_PREFIX void game_dump_board(Game *self) {
|
||||
sol_print(0, 0, 0x9, 0x9, 0x9);
|
||||
sol_print(0, 0, self->board[0], self->board[1], self->board[2]);
|
||||
sol_print(0, 0, self->board[3], self->board[4], self->board[5]);
|
||||
sol_print(0, 0, self->board[6], self->board[7], self->board[8]);
|
||||
sol_print(0, 0, 0x9, 0x9, 0x9);
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX void game_create(Game *self, SolPubkey *player_x) {
|
||||
sol_memcpy(self->player_x.x, player_x, SIZE_PUBKEY);
|
||||
// TODO self->player_o = 0;
|
||||
self->state = State_Waiting;
|
||||
self->keep_alive[0] = 0;
|
||||
self->keep_alive[1] = 0;
|
||||
|
||||
// TODO fixed iteration loops ok? unrolled?
|
||||
for (int i = 0; i < 9; i++) {
|
||||
self->board[i] = BoardItem_F;
|
||||
}
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX Result game_join(Game *self, SolPubkey *player_o,
|
||||
int64_t timestamp) {
|
||||
if (self->state == State_Waiting) {
|
||||
sol_memcpy(self->player_o.x, player_o, SIZE_PUBKEY);
|
||||
self->state = State_XMove;
|
||||
|
||||
if (timestamp <= self->keep_alive[1]) {
|
||||
return Result_InvalidTimestamp;
|
||||
} else {
|
||||
self->keep_alive[1] = timestamp;
|
||||
return Result_Ok;
|
||||
}
|
||||
}
|
||||
return Result_GameInProgress;
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX bool game_same(BoardItem x_or_o, BoardItem one, BoardItem two,
|
||||
BoardItem three) {
|
||||
if (x_or_o == one && x_or_o == two && x_or_o == three) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX bool game_same_player(SolPubkey *one, SolPubkey *two) {
|
||||
// TODO fixed iteration loops ok? unrolled?
|
||||
for (int i = 0; i < SIZE_PUBKEY; i++) {
|
||||
if (one->x[i] != two->x[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX Result game_next_move(Game *self, SolPubkey *player, int x, int y) {
|
||||
int board_index = y * 3 + x;
|
||||
if (board_index >= 9 || self->board[board_index] != BoardItem_F) {
|
||||
return Result_InvalidMove;
|
||||
}
|
||||
|
||||
BoardItem x_or_o;
|
||||
State won_state;
|
||||
|
||||
switch (self->state) {
|
||||
case State_XMove:
|
||||
if (!game_same_player(player, &self->player_x)) {
|
||||
return Result_PlayerNotFound;
|
||||
}
|
||||
self->state = State_OMove;
|
||||
x_or_o = BoardItem_X;
|
||||
won_state = State_XWon;
|
||||
break;
|
||||
|
||||
case State_OMove:
|
||||
if (!game_same_player(player, &self->player_o)) {
|
||||
return Result_PlayerNotFound;
|
||||
}
|
||||
self->state = State_XMove;
|
||||
x_or_o = BoardItem_O;
|
||||
won_state = State_OWon;
|
||||
break;
|
||||
|
||||
default:
|
||||
return Result_NotYourTurn;
|
||||
}
|
||||
|
||||
self->board[board_index] = x_or_o;
|
||||
|
||||
// game_dump_board(self);
|
||||
|
||||
bool winner =
|
||||
// Check rows
|
||||
game_same(x_or_o, self->board[0], self->board[1], self->board[2]) ||
|
||||
game_same(x_or_o, self->board[3], self->board[4], self->board[5]) ||
|
||||
game_same(x_or_o, self->board[6], self->board[7], self->board[8]) ||
|
||||
// Check columns
|
||||
game_same(x_or_o, self->board[0], self->board[3], self->board[6]) ||
|
||||
game_same(x_or_o, self->board[1], self->board[4], self->board[7]) ||
|
||||
game_same(x_or_o, self->board[2], self->board[5], self->board[8]) ||
|
||||
// Check both diagonals
|
||||
game_same(x_or_o, self->board[0], self->board[4], self->board[8]) ||
|
||||
game_same(x_or_o, self->board[2], self->board[4], self->board[6]);
|
||||
|
||||
if (winner) {
|
||||
self->state = won_state;
|
||||
}
|
||||
|
||||
{
|
||||
int draw = true;
|
||||
// TODO fixed iteration loops ok? unrolled?
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (BoardItem_F == self->board[i]) {
|
||||
draw = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (draw) {
|
||||
self->state = State_Draw;
|
||||
}
|
||||
}
|
||||
return Result_Ok;
|
||||
}
|
||||
|
||||
SOL_FN_PREFIX Result game_keep_alive(Game *self, SolPubkey *player,
|
||||
int64_t timestamp) {
|
||||
switch (self->state) {
|
||||
case State_Waiting:
|
||||
case State_XMove:
|
||||
case State_OMove:
|
||||
if (game_same_player(player, &self->player_x)) {
|
||||
if (timestamp <= self->keep_alive[0]) {
|
||||
return Result_InvalidTimestamp;
|
||||
}
|
||||
self->keep_alive[0] = timestamp;
|
||||
} else if (game_same_player(player, &self->player_o)) {
|
||||
if (timestamp <= self->keep_alive[1]) {
|
||||
return Result_InvalidTimestamp;
|
||||
}
|
||||
self->keep_alive[1] = timestamp;
|
||||
} else {
|
||||
return Result_PlayerNotFound;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Result_Ok;
|
||||
}
|
||||
|
||||
void entrypoint(uint8_t *buf) {
|
||||
SolKeyedAccounts ka[3];
|
||||
uint64_t userdata_len;
|
||||
uint8_t *userdata;
|
||||
int err = 0;
|
||||
|
||||
if (0 != sol_deserialize(buf, 3, ka, &userdata, &userdata_len)) {
|
||||
sol_panic();
|
||||
}
|
||||
|
||||
if (sizeof(Game) > ka[1].userdata_len) {
|
||||
sol_print(0, 0, 0xFF, sizeof(Game), ka[1].userdata_len);
|
||||
sol_panic();
|
||||
}
|
||||
Game game;
|
||||
sol_memcpy(&game, ka[1].userdata, ka[1].userdata_len);
|
||||
|
||||
Command command = *userdata;
|
||||
sol_print(0, 0, 0, 0, command);
|
||||
switch (command) {
|
||||
case Command_Init:
|
||||
game_create(&game, ka[2].key);
|
||||
break;
|
||||
|
||||
case Command_Join:
|
||||
err = game_join(&game, ka[0].key, userdata[8]);
|
||||
break;
|
||||
|
||||
case Command_KeepAlive:
|
||||
err = game_keep_alive(&game, ka[0].key, /*TODO*/ 0);
|
||||
break;
|
||||
|
||||
case Command_Move:
|
||||
err = game_next_move(&game, ka[0].key, userdata[8], userdata[9]);
|
||||
break;
|
||||
|
||||
default:
|
||||
sol_panic();
|
||||
}
|
||||
|
||||
sol_memcpy(ka[1].userdata, &game, ka[1].userdata_len);
|
||||
sol_print(0, 0, 0, err, game.state);
|
||||
}
|
||||
|
||||
// // -- Debug --
|
||||
|
||||
// SOL_FN_PREFIX void print_key(SolPubkey *key) {
|
||||
// for (int j = 0; j < SIZE_PUBKEY; j++) {
|
||||
// sol_print(0, 0, 0, j, key->x[j]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// SOL_FN_PREFIX void print_userdata(uint8_t *data, int len) {
|
||||
// for (int j = 0; j < len; j++) {
|
||||
// sol_print(0, 0, 0, j, data[j]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// SOL_FN_PREFIX void print_params(uint64_t num_ka, SolKeyedAccounts *ka,
|
||||
// uint8_t *userdata, uint64_t userdata_len) {
|
||||
// sol_print(0, 0, 0, 0, num_ka);
|
||||
// for (int i = 0; i < num_ka; i++) {
|
||||
// // key
|
||||
// print_key(ka[i].key);
|
||||
|
||||
// // tokens
|
||||
// sol_print(0, 0, 0, 0, ka[i].tokens);
|
||||
|
||||
// // account userdata
|
||||
// print_userdata(ka[i].userdata, ka[i].userdata_len);
|
||||
|
||||
// // program_id
|
||||
// print_key(ka[i].program_id);
|
||||
// }
|
||||
// // tx userdata
|
||||
// print_userdata(userdata, userdata_len);
|
||||
// }
|
||||
|
||||
// void entrypoint(char *buf) {
|
||||
// SolKeyedAccounts ka[3];
|
||||
// uint64_t userdata_len;
|
||||
// uint8_t *userdata;
|
||||
|
||||
// if (0 != sol_deserialize((uint8_t *)buf, 3, ka, &userdata_len, &userdata)) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// print_params(3, ka, userdata, userdata_len);
|
||||
// }
|
@ -15,7 +15,7 @@ authors = [
|
||||
[dependencies]
|
||||
bincode = "1.0.0"
|
||||
generic-array = { version = "0.12.0", default-features = false, features = ["serde"] }
|
||||
solana_program_interface = { path = "../../common" }
|
||||
solana_program_interface = { path = "../../../common" }
|
||||
|
||||
[lib]
|
||||
name = "move_funds"
|
@ -13,7 +13,7 @@ authors = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
solana_program_interface = { path = "../../common" }
|
||||
solana_program_interface = { path = "../../../common" }
|
||||
|
||||
[lib]
|
||||
name = "noop"
|
@ -3,4 +3,7 @@ extern crate solana_program_interface;
|
||||
use solana_program_interface::account::KeyedAccount;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn process(_infos: &mut Vec<KeyedAccount>, _data: &[u8]) {}
|
||||
pub extern "C" fn process(_infos: &mut Vec<KeyedAccount>, _data: &[u8]) {
|
||||
//println!("AccountInfos: {:#?}", _infos);
|
||||
//println!("data: {:#?}", data);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "print"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
"Anatoly Yakovenko <anatoly@solana.com>",
|
||||
"Greg Fitzgerald <greg@solana.com>",
|
||||
"Stephen Akridge <stephen@solana.com>",
|
||||
"Michael Vines <mvines@solana.com>",
|
||||
"Rob Walker <rob@solana.com>",
|
||||
"Pankaj Garg <pankaj@solana.com>",
|
||||
"Tyera Eulberg <tyera@solana.com>",
|
||||
"Jack May <jack@solana.com>",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
solana_program_interface = { path = "../../common" }
|
||||
|
||||
[lib]
|
||||
name = "print"
|
||||
crate-type = ["dylib"]
|
||||
|
@ -1,9 +0,0 @@
|
||||
extern crate solana_program_interface;
|
||||
|
||||
use solana_program_interface::account::KeyedAccount;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn process(infos: &mut Vec<KeyedAccount>, _data: &[u8]) {
|
||||
println!("AccountInfos: {:#?}", infos);
|
||||
//println!("data: {:#?}", data);
|
||||
}
|
Reference in New Issue
Block a user