欢迎所有爱好区块链技术的人加入。

ARCHIVES / 532.HTML

合约数据表字段升级

Surou EOS-新手教程

有些时候,由于前期考虑不周,或者后期设计升级,导致合约table 字段需要增加,或者类型需要更改,所以需要数据迁移,
下面举例我常用的升级方法
假设目前合约内有个table xxxinfo

struct [[eosio::table("xxxinfo"), eosio::contract("eosxxx.game")]] xxxinfo{
        uint64_t id;
		uint64_t test; // 为测试添加的字段
		uint8_t test1; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo"_n, xxxinfo> xxxinfo_tables;

现在升级需要解决的问题是test 当初设计字段类型过大,导致ram 浪费,test1 选型过小,增加 test2字段{uint32_t}.

在合约中增加新的表结构xxxinfo1 及其对象,并修正上面问题

struct [[eosio::table("xxxinfo1"), eosio::contract("eosxxx.game")]] xxxinfo1{
        uint64_t id;
		uint32_t test; // 为测试添加的字段
		uint16_t test1; // 为测试添加的字段
		uint32_t test2; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo1"_n, xxxinfo1> xxxinfo1_tables;

此时合约内同时存在 xxxinfo1 和 xxxinfo1两张表.

增加 迁移执行的action 接口

//.h
ACTION migratexxx();
//.cpp
void migratexxx(){
	xxxinfo1_tables xxxinfo1_table(_self, _self.value);
	
	xxxinfo_tables xxxinfo_table(_self, _self.value);
	auto itr = xxxinfo_table.begin();
	while(itr != xxxinfo_table.end()){
		xxxinfo1_table.emplace( _self, [&]( auto& h ) {
			h.id = xxxinfo1_table.available_primary_key();
			h.test = itr->test;
			h.test1= itr->test1;
		});
		itr ++;
	}
}

停止Dapp,避免迁移期间数据改变,然后执行action
cleos -u https://api.eoslaomao.com push action 合约账户 migratexxx '{}' -p 合约账户

如果数据较多,且数据是累计增长(不修改历史数据),可以分区间执行迁移,迁移过程中,可以不停止dapp,等迁移差不多追上旧表了,再暂停dapp,然后等数据全部迁移完.

修正合约中的新表为

struct [[eosio::table("xxxinfo1"), eosio::contract("eosxxx.game")]] xxxinfo{
        uint64_t id;
		uint32_t test; // 为测试添加的字段
		uint16_t test1; // 为测试添加的字段
		uint32_t test2; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo1"_n, xxxinfo> xxxinfo_tables;

将旧表修改为

struct [[eosio::table("xxxinfo"), eosio::contract("eosxxx.game")]] xxxinfo_bak{
        uint64_t id;
		uint64_t test; // 为测试添加的字段
		uint8_t test1; // 为测试添加的字段

        auto primary_key() const { return id; }
    };

typedef eosio::multi_index<"xxxinfo"_n, xxxinfo_bak> xxxinfo_bak_tables;

修正前后端调用的table名,重新上线,并运行dapp, 建议等 运行一段时间,在删除旧表
增加清理旧表的action

//.h
ACTION clearxxxbak();
//.cpp
void clearxxxbak(){
	xxxinfo_bak_tables xxxinfo_bak_table(_self, _self.value);
	auto itr = xxxinfo_bak_table.begin();
	while(itr != xxxinfo_bak_table.end()){
		itr = xxxinfo_bak_table.erase(itr);
	}
}

然后执行action
cleos -u https://api.eoslaomao.com push action 合约账户 clearxxxbak '{}' -p 合约账户
最后再删除 合约内旧表及对象 就完成了此次合约表升级过程.