0

I have initially the following multi_index table:

struct [[eosio::table]] plastict
{
    uint64_t id;
    uint64_t type;

    uint64_t primary_key() const { return id; }
};
typedef eosio::multi_index<"items"_n, item> items;
items items_table;

I have deployed initial smart contract and now am I trying to add a new field to the the table items. According to the info, I have found in a couple of EOS issues, I have added the new field at the end of the table struct:

struct [[eosio::table]] plastict
{
    uint64_t id;
    uint64_t type;
    uint64_t state;

    uint64_t primary_key() const { return id; }
};
typedef eosio::multi_index<"items"_n, item> items;
items items_table;

Unfortunately, after I have re-compiled and re-deployed the smart contract, when I try to read the table content, I get the following:

Error: {"code":500,"message":"Internal Service Error","error":{"code":3015013,"name":"unpack_exception","what":"Unpack data exception","details":[{"message":"Stream unexpectedly ended; unable to unpack field 'state' of struct 'item'","file":"abi_serializer.cpp","line_number":307,"method":"_binary_to_variant"}]}}

I don't need backward compatibility, thats why I am not wrapping the new field within binary_extension type, but I want to keep all the data already inserted and keep it accessible.

Appreciate any ideas and remarks ?

  • Do you care about the previous data in the table or do you just want to have the table accept the new struct and be done with it? – netuoso - EOS Titan Aug 23 '19 at 16:31
  • Yes, I need the already inserted data in the table and keep it accessible. – vladich Aug 23 '19 at 17:12
  • Ok submitted an answer that addresses both situations. Also made an example to go along with the answer github.com/netuoso/eos-migrate-demo. Hope it helps; this is a common question. – netuoso - EOS Titan Aug 23 '19 at 17:40
1

If you don't care about the data from old_table:

  • Erase all records from old_table
  • Deploy NEWCONTRACT with modified old_table

If you want to persist the data from old_table:

  • Define the new and old structs/tables in NEW_CONTRACT1
  • Write a function that will move data from old_table to new_table; adding new column
  • Deploy NEW_CONTRACT2 version that has old_table modified the way you want
  • Reverse the data migration function to move data from new_table back to old_table

Now your user will be able to query old_table the way they did before and the contract will not throw an exception. You simply cannot modify a table that has any existing data inside of it.

I have an example contract for this process you can view at: https://github.com/netuoso/eos-migrate-demo

Note: If you have a table with many records, it is possible the transaction time limit will be reached. In that situation, you could modify the migrate function to only move a limited number of records each time you call it.

|improve this answer|||||
  • quite complicated but true – Jimmy Guo Aug 24 '19 at 2:43
  • Both suggestions are not the solutions I am trying to find. I need to keep the same contract and the data already written in the contract tables, so I was wondering is there a working solution where I can upgrade the already existing table and redeploy the entire smart contract again and continue working with the new version of the contract/table - without breaking the table and table keys. – vladich Aug 27 '19 at 13:30
  • I gave you possible solutions and explained to you clearly that no, it is literally impossible to change the structure of a table with existing data. I've explained how you can preserve your data in the table within the means of EOSIO. – netuoso - EOS Titan Aug 27 '19 at 13:32

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.