我们在重新部署契约(Contract)时遇到问题。每次在新合约版本部署期间更改某些逻辑时,我们都会丢失所有合约相关数据(存储在数组、映射中)。然后我们需要执行数据加载过程,以便将环境恢复到所需状态,这是一个耗时的操作。我尝试将契约(Contract)拆分为两个契约(Contract)(AbcDataContract、AbcActionsContract),但面临访问映射的问题:错误:索引表达式必须是类型、映射或数组(是函数(bytes32)查看外部返回(uint256) )) 初始契约(Contract):
contract AbcContract {
EntityA[] public entities;
mapping (bytes32 => uint) public mapping1;
mapping (bytes32 => uint[]) public mapping2;
mapping (bytes32 => uint[]) public mapping3;
/* Events */
event Event1(uint id);
event Event2(uint id);
/* Structures */
struct EntityA {
string field1;
string field2;
bool field3;
uint field4;
Status field5;
}
enum Status {PROPOSED, VOTED, CONFIRMED}
function function1(...) returns (...)
function function2(...) returns (...)
function function3(...) returns (...)
function function4(...) returns (...)
function function5(...) returns (...)
}
重构合约:
contract AbcDataContract {
EntityA[] public items;
mapping (bytes32 => uint) public mapping1;
mapping (bytes32 => uint[]) public mapping2;
mapping (bytes32 => uint[]) public mapping3;
/* Events */
event Event1(uint id);
event Event2(uint id);
/* Structures */
struct EntityA {
string field1;
string field2;
bool field3;
uint field4;
Status proposalStatus;
}
enum Status {PROPOSED, VOTED, CONFIRMED}
}
contract AbcActionsContract {
AbcDataContract abcDataContract;
/* constructor */
function AbcActionsContract(address _AbcDataContract) {
abcDataContract = AbcDataContract(_AbcDataContract);
}
/* accessing to the mapping like abcDataContract.mapping1[someId] will raise Solidity compile error */
function function1(...) returns (...)
/* accessing to the mapping like abcDataContract.mapping2[someId] will raise Solidity compile error */
function function2(...) returns (...)
/* accessing to the mapping like abcDataContract.mapping3[someId] will raise Solidity compile error */
function function3(...) returns (...)
function function4(...) returns (...)
function function5(...) returns (...)
}
我们希望实现像数据库开发中那样的方法,存储过程/ View /其他非数据对象中的逻辑更改通常不会影响数据本身。这个问题的最佳设计解决方案是什么?
最佳答案
你问题的第一部分相当简单。要访问另一个合约中的公共(public)映射,只需使用 ():
abcDataContract.mapping1(someId)
当然,您也可以提供自己的对 AbcDataContract
的访问方法,而不是使用公共(public)映射。如果您走这条路,我建议您通过界面来访问您的数据合约
至于你问题的设计部分,看起来你走在正确的轨道上。将数据存储分离到自己的合约中具有巨大的好处。由于您不必担心迁移数据,因此不仅部署起来更加容易,而且部署新合约的成本也便宜得多。
话虽如此,我想在您发布的重构版本中指出一些事情。
- 很难判断您打算用
Struct1
做什么。您的伪代码中没有引用它。您无法从 Solidity 中的函数返回结构,除非它们是内部
调用(或者您显式分解该结构)。 - 同样,您无法在合约之间返回字符串。如果您计划在
AbcActionsContract
中使用Struct1.field1/2
,则需要将它们转换为bytes32
。 - 您可能希望将事件定义移至业务逻辑合约中。
将数据存储与业务逻辑分离是升级合约的关键组成部分。使用接口(interface)和库有助于解决这个问题。有几篇博客文章讨论了这个问题。我个人建议从 this one 开始以及后续here .
关于blockchain - 如何改进智能接触设计,以区分同一域对象的数据及其操作功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48065343/