eosio.cdt icon indicating copy to clipboard operation
eosio.cdt copied to clipboard

Unable to compile server wasm

Open NatPDeveloper opened this issue 2 years ago • 4 comments

I'm trying to follow this documentation on how to deployer server WASM which may be called by initialize and run_querry.

When compiling a contract and adding the following:

// initialize this WASM
extern "C" __attribute__((eosio_wasm_entry)) void initialize() {}

// wasm-ql calls this for each incoming query
extern "C" void run_query() {
    // auto request = eosio::unpack<my_query_request>(eosio::get_input_data());

    // std::visit([](auto& x) { process(x, eosio::get_database_status()); }, request.value);
}

I get ⚠️ clang-9: error: unable to execute command: Segmentation fault (core dumped).

The CDT also doesn't seem to recognize the following includes:

// #include <eosio/block_select.hpp>
// #include <eosio/database.hpp>
// #include <eosio/input_output.hpp>

Is there something I need to do to enable these? Using CDT 1.8.0, 1.8.1, also tried 1.6.3. Compiling with -fquery-serve.

I've included the CmakeLists.txt and chess.cpp to reproduce. In order to compile, you'll need to install zeus.

npm i -g @liquidapps/zeus-cmd
mkdir chess; cd chess; zeus box create
zeus unbox chess
// update ./contracts/eos/chess/chess.cpp with code below
zeus compile chess

CmakeLists.txt

cmake_minimum_required(VERSION 3.5)
set(EOSIO_WASM_OLD_BEHAVIOR "Off")
project(chess VERSION 1.0.0)
find_package(eosio.cdt)
set(VCPUWASM "chess-VCPU.wasm")
include_directories(../)
add_executable(${VCPUWASM} ../chess.cpp)
set_target_properties( ${VCPUWASM} PROPERTIES LINK_FLAGS "-fquery-server" SUFFIX "" )
target_compile_options( ${VCPUWASM} PUBLIC -fquery-server )

chess.cpp

#define VACCOUNTS_DELAYED_CLEANUP 120

#include "../dappservices/multi_index.hpp"
#include "movegen.cpp"

#include "attacks.cpp"
#include "bitboard.cpp"
#include "board.cpp"
#include "move.cpp"
#include "exception.cpp"
#include "../dappservices/log.hpp"
#include "../dappservices/oracle.hpp"
#include "../dappservices/cron.hpp"
#include "../dappservices/vaccounts.hpp"
#include "../dappservices/readfn.hpp"
#include "../dappservices/vcpu.hpp"

#define DAPPSERVICES_ACTIONS() \
  XSIGNAL_DAPPSERVICE_ACTION \
  IPFS_DAPPSERVICE_ACTIONS \
  VACCOUNTS_DAPPSERVICE_ACTIONS \
  LOG_DAPPSERVICE_ACTIONS \
  CRON_DAPPSERVICE_ACTIONS \
  ORACLE_DAPPSERVICE_ACTIONS \
  READFN_DAPPSERVICE_ACTIONS \
  VCPU_DAPPSERVICE_ACTIONS
#define DAPPSERVICE_ACTIONS_COMMANDS() \
  IPFS_SVC_COMMANDS()ORACLE_SVC_COMMANDS()CRON_SVC_COMMANDS()VACCOUNTS_SVC_COMMANDS()LOG_SVC_COMMANDS()READFN_SVC_COMMANDS()VCPU_SVC_COMMANDS()
#define CONTRACT_NAME() chess
using std::string;


struct input_t {
  std::string game;
  std::string move;
  bool white;
};

struct result_t {
  input_t input;
  bool isCheck;
  int status;
  int activePlayer;
  bool isValid;
  std::string fen;
};

CONTRACT_START()
      bool timer_callback(name timer, std::vector<char> payload, uint32_t seconds){
        return false;
      }
     [[eosio::action]] void gamecleanup() {
        std::vector<char> payload;
        schedule_timer(_self, payload, 2);
      }


      struct chess_action_payload {
          name vaccount;
          name gamehost;
          name opponent;
          std::string move;
          EOSLIB_SERIALIZE( chess_action_payload, (vaccount)(gamehost)(opponent)(move) )
      };
      struct chess_lobby_action_payload {
          name vaccount;
          name opponent;
          EOSLIB_SERIALIZE( chess_lobby_action_payload, (vaccount)(opponent) )
      };

      [[eosio::action]] void joingame(chess_lobby_action_payload payload) {
        require_vaccount(payload.vaccount);
        game_t games(_self, _self.value, 1024, 64, true, false, VACCOUNTS_DELAYED_CLEANUP);
        bool isHost = false;
        eosio::check(payload.vaccount != name("ai"),"can't play as AI");

        auto existing = games.find(payload.vaccount.value);
        if(existing == games.end()){
            existing = games.find(payload.opponent.value);
            eosio::check(existing == games.end() || existing->opponent == payload.vaccount,"not your game");
        }
        else
          isHost = true;
        if(existing == games.end())
        {
            isHost = true;
            // todo: notify opponent
            games.emplace(_self, [&]( auto& a ) {
                  a.host = payload.vaccount;
                  a.opponent = payload.opponent;
                  a.opponent_joined = (a.opponent == name("ai"));
            });
        }
        else {
            // todo: notify host
            if(!isHost && !existing->opponent_joined){
              games.modify(existing,_self, [&]( auto& a ) {
                a.opponent_joined = true;
              });
            }
        }

      }
      [[eosio::action]] void quitgame(chess_lobby_action_payload payload) {
        require_vaccount(payload.vaccount);
        game_t games(_self, _self.value, 1024, 64, true, false, VACCOUNTS_DELAYED_CLEANUP);
        auto existing = games.find(payload.vaccount.value);
        if(existing == games.end()){
            existing = games.find(payload.opponent.value);
            eosio::check(existing == games.end() || existing->opponent == payload.vaccount,"not your game");
        }
        if(existing != games.end())
          games.erase(existing);
      }
      string getBestMove(string fen){
            string uriStr = "stockfish://" + fen;
            std::vector<char> uri = std::vector<char>(uriStr.begin(), uriStr.end());
            std::vector<char> move = getURI(uri, [&]( auto& results ) {
              return results[0].result;
            });
            string result(move.begin(), move.end());
            return result;
      }
      [[eosio::action]] void movepiece(chess_action_payload payload) {
        require_vaccount(payload.vaccount);
        input_t input;
        game_t games(_self, _self.value, 1024, 64, true, false, VACCOUNTS_DELAYED_CLEANUP);
        auto existing = games.find(payload.gamehost.value);
        input.white = true;
        eosio::check(existing != games.end(), "game doesn't exist");

        input.game = existing->fen;
        if(payload.gamehost != payload.vaccount){
          // opponent
          eosio::check(payload.vaccount == existing->opponent, "not your game");
          input.white = false;
        }
        else{
          // host
          eosio::check(payload.opponent == existing->opponent, "wrong opponent");
        }
        eosio::check(existing->opponent_joined, "opponent didn't join");
        eosio::check(input.white == existing->whiteTurn, "not your turn");


        input.move = payload.move;
        result_t res = call_vcpu_fn<result_t>(name("vmovepiece"), pack(input),[&]( auto& results ) {
          eosio::check(results.size() > 1, "not enough results");
          eosio::check(results[0].result.size() > 0, "not enough results1");
          eosio::check(results[1].result.size() > 0, "not enough results2");
          // todo: compare results
          return results[0].result;
        });
        eosio::check(res.isValid, "invalid move");
        auto ai = (payload.opponent == name("ai")) && input.white;
        if(ai && res.status == 0){
           auto newMove = getBestMove(res.fen);
           input_t newInput;
           newInput.game = res.fen;
           newInput.move = newMove;
           newInput.white = false;
           res = call_vcpu_fn<result_t>(name("vmovepiece"), pack(newInput),[&]( auto& results ) {
            eosio::check(results.size() > 1, "not enough results");
            eosio::check(results[0].result.size() > 0, "not enough results1");
            eosio::check(results[1].result.size() > 0, "not enough results2");
            // todo: compare results
            return results[0].result;
          });
          eosio::check(res.isValid, "invalid AI move");
          input.white = false;
        }
        if(res.status != 0){
          if(res.status == 1){
            // mate
            if(input.white)
              updateScores(1,  payload.vaccount, payload.opponent);
            else
              updateScores(0,  payload.vaccount, payload.opponent);
          }
          else{
            updateScores(0.5,  payload.vaccount, payload.opponent);
          }

        }
        games.modify(existing,_self, [&]( auto& a ) {
            a.fen = res.fen;
            a.whiteTurn = !input.white;
            a.isCheck = res.isCheck;
            a.status = res.status;
        });
    }

      int32_t get_rating_delta(uint32_t my_rating, uint32_t opponent_rating, double my_game_result) {
        auto my_chance_to_win = 1 / ( 1 + pow(10, (opponent_rating - my_rating) / 400));

        return round(32 * (my_game_result - my_chance_to_win));
      }

      uint32_t get_new_rating(uint32_t my_rating, uint32_t opponent_rating, double my_game_result) {
        return my_rating + get_rating_delta(my_rating, opponent_rating, my_game_result);
      }

      uint32_t getScore(name account){
        score_t scores(_self, _self.value, 1024, 64);
        auto existing = scores.find(account.value);
        if(existing == scores.end())
          return 800;
        else return existing->score;
      }
      void setScore(name account, uint32_t score){
        score_t scores(_self, _self.value, 1024, 64);
        auto existing = scores.find(account.value);
        if(existing == scores.end()){
            scores.emplace(_self, [&]( auto& a ) {
                  a.account = account;
                  a.score = score;
            });

        }
        else
        {
            scores.modify(existing,_self, [&]( auto& a ) {
                  a.score = score;
            });
        }
      }
      void updateScores(double game_result, name account_a, name account_b){

        // get score a
        // get score b
        // get_new_rating(a,b,game_result);
        // get_new_rating(b,a,1-game_result);
        // store a
        // store b
      }

      TABLE game {
         string fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
         name host;
         name opponent;
         bool whiteTurn = true;
         bool opponent_joined = false;
         bool isCheck;
         int status;
         uint64_t primary_key()const { return host.value; }
      };

      typedef dapp::multi_index<"games"_n, game> game_t;
      typedef eosio::multi_index<".games"_n, game> game_t_v_abi;
      TABLE shardbucket {
          std::vector<char> shard_uri;
          uint64_t shard;
          uint64_t primary_key() const { return shard; }
      };
      typedef eosio::multi_index<"games"_n, shardbucket> game_t_table_abi;


      TABLE score {
         name account;
         uint32_t score;
         uint64_t primary_key()const { return account.value; }
      };
      typedef dapp::multi_index<"scores"_n, score> score_t;
      typedef eosio::multi_index<".scores"_n, score> score_t_v_abi;

      typedef eosio::multi_index<"scores"_n, shardbucket> score_t_table_abi;

   private:
    VACCOUNTS_APPLY(((chess_action_payload)(movepiece))((chess_lobby_action_payload)(quitgame))((chess_lobby_action_payload)(joingame)))

};
EOSIO_DISPATCH_SVC(CONTRACT_NAME(), (movepiece)(joingame)(quitgame)(regaccount)(xdcommit)(xvinit)(gamecleanup))
// -------------------------------------------------------------------------------------------------
result_t vmovepiece(input_t input)
{
  using cppgen::Board;
  using cppgen::GameOverReason;

  Board board;
  board.loadFen(input.game);
  result_t result;
  result.input = input;
  result.isValid = board.makeMove(input.move);
  if(!result.isValid)
    return result;
  auto isCheck = board.isInCheck();
  auto status = board.getGameOverReason();
  auto activePlayer = board.getActivePlayer();
  result.isCheck = board.isInCheck();
  result.status = (int)board.getGameOverReason();
  result.activePlayer = board.getActivePlayer();
  result.fen = board.getFen();
  return result;
}

char * the_buffer;
uint32_t the_buffer_size;
char * the_result;
bool inited = false;
extern "C" __attribute__((eosio_wasm_entry)) void initialize() {}
extern "C" void run_query() {}
// extern "C"{
//   char * initialize(uint32_t sze){
//     if(!inited){
//       inited = true;
//       the_buffer = (char*)malloc(sze);
//       the_buffer_size = sze;
//       return the_buffer;
//     }
//     else{
//       return the_result;
//     }
//   }
//   uint32_t run_query() {
//     std::vector<char> payload(the_buffer, the_buffer+the_buffer_size);
//     std::vector<char> res;
//     auto method = "vmovepiece";
//     if(method == "vmovepiece"){
//         res =  pack(vmovepiece(unpack<input_t>(payload)));
//     }
//     the_result = res.data();
//     return res.size();
//   }
// }

NatPDeveloper avatar Oct 18 '21 15:10 NatPDeveloper

How are you using this wasm-ql query? What eosio products are you building to run the wasm-ql queries?

sanaraufx avatar Oct 27 '21 17:10 sanaraufx

Hello @sanaraufx ! Thank you for the reply.

I'm using it to fetch a chess move from an AI. At LiquidApps we produce many EOSIO related products, in this case this is a service provided by our nodes known as vCPU which allows contracts to fetch by oracle the requested query, in this case a chess move.

You can see the contracts other files here https://github.com/liquidapps-io/zeus-sdk/tree/master/boxes/groups/sample/chess.

NatPDeveloper avatar Oct 29 '21 19:10 NatPDeveloper

@sanaraufx any update on this?

NatPDeveloper avatar Jan 03 '22 16:01 NatPDeveloper

EOSIO is really dead, what a shame. Abandoning projects even with the amount of $$$ they have

lucca65 avatar Feb 09 '22 17:02 lucca65