0

Newbie here struggling up the learning curve. I have a simple contract which updates a counter value in a singleton table every time its action is executed.

#include <eosio/eosio.hpp>
#include <eosio/singleton.hpp>
using namespace eosio;
using std::string;

class [[eosio::contract]] microBadge : public contract {
   public:
      using contract::contract;
      microBadge(name receiver, name code, datastream<const char *> ds) :
         contract(receiver, code, ds),
         calls("inits"_n, _self.value) {
            calls.set(CallsStruct{1}, _self);
         }

      [[eosio::action]]
      void init( name issuer, string badge, name badgee, string memo );

      using init_action = eosio::action_wrapper<"init"_n, &microBadge::init>;
   private:
      struct [[eosio::table]] CallsStruct { uint32_t count; };
      typedef singleton<"inits"_n, CallsStruct> calls_table;
    // This next typedef is only here because of this bug: https://github.com/EOSIO/eosio.cdt/issues/280
    // Once that's fixed this can be removed.
      typedef eosio::multi_index<"inits"_n, CallsStruct> dump_for_inits;
      calls_table calls;
};
#include <microBadge.hpp>

[[eosio::action]]
void microBadge::init( name issuer, string badge, name badgee, string memo ) {
    require_auth( issuer );
    calls.set(CallsStruct{calls.get().count+1}, _self);
}

First question: after I upload the contract to the chain, I want the table to automatically be initialized to the value 1. Is this possible? Using block explorer, I see no data in the table.

Second question: If I try to execute the 'init' action, I get

Error 3050003: eosio_assert_message assertion failure
Error Details:
assertion failure with message: cannot create objects in table of another contract

I am using account "c1111seattle" on testnet, here is the call:

cleos -u https://testnet.telos.caleos.io push transaction '{
>   "delay_sec": 0,
>   "max_cpu_usage_ms": 0,
>   "actions": [
>     {
>       "account": "c1111seattle",
>       "name": "init",
>       "data": {
>         "issuer": "c1111seattle",
>         "badge": "goofy",
>         "badgee": "c1111seattle",
>         "memo": "test"
>       },
>       "authorization": [
>         {
>           "actor": "c1111seattle",
>           "permission": "active"
>         }
>       ]
>     }

>   ]
> }'

eosio.cdt v1.8.1, Ubuntu 18.04

1

I found my problem, which is in the constructor

      microBadge(name receiver, name code, datastream<const char *> ds) :
         contract(receiver, code, ds),
         calls("inits"_n, _self.value) {
            calls.set(CallsStruct{1}, _self);
         }
  1. The member initialization for table calls needs to specify the table owner (not "inits"_n).

  2. As mentioned in https://eosio.stackexchange.com/a/1667/5784 the class constructor gets called whenever an action is pushed to the blockchain, so we need to programmatically determine what is the first invocation.

Resulting code (which works as intended):

      microBadge(name receiver, name code, datastream<const char *> ds) :
         contract(receiver, code, ds),
         calls(_self, _self.value) {
            if (!calls.exists()) {
               calls.set(CallsStruct{1}, _self);
            }
         }
0

this should help you get through with how to define a singleton:

https://developers.eos.io/manuals/eosio.cdt/v1.8/how-to-guides/multi-index/how-to-define-a-singleton/

if this help page is not enough please provide feedback how you think it could be improved.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.