在Solidity中初始化一个大的固定长度数组

时间:2018-04-17 07:57:30

标签: ethereum solidity smartcontracts

我正在构建一个关于以太坊的游戏作为我的第一个项目,我正面临存储和气体限制。我希望在部署之后在区块链上存储一个存储智能合约以进行查询。我真的需要初始化一个固定长度的数组,其中包含我手动插入的常量值。我的情况如下:

    contract A {

...some states variables/modifiers and events......

uint[] public vector = new uint[](162);

vector = [.......1, 2, 3,......];

function A () {

....some code....

ContractB contract = new ContractB(vector);

}

....functions....

}

此代码未部署。显然我超过混音的气体限制。我尝试了以下方法:

  • 我将矢量分成10个不同的矢量,然后将其中一个传递给构造函数。有了这个,部署就可以了。

我真的需要只有一个向量,因为它代表了一个图的边集,其中ContractB是构建图的数据结构。向量元素的排序如下:

vector = [edge1From, edge1To, edge2From, edge2To,.......]

我得到了81条边(向量中有162个条目)。

我认为我可以创建一个setData函数,在部署之后逐个调用此函数来推送向量中的值,但这不是我的情况,因为我需要在调用之前填充向量

ContractB contract = new ContractB(vector);

现在我可以看到我有两个疑问:

1)我是否错误地尝试在A构造函数内的函数调用中传递vector作为参数?

2)我可以看到我可以为边创建双重映射。像

这样的东西
mapping (bool => mapping(uint => uint)) 

然后我需要多键值映射(从同一点开始的更多边缘)我会有问题像我对向量一样初始化所有映射?

2 个答案:

答案 0 :(得分:0)

如果阵列的值范围足够小,则可以使用更适合uints的尺寸来节省耗气量。以太坊将值存储到32字节的插槽中,并为每个使用的插槽支付20,000气体。如果您能够使用较小尺寸uint(请记住,uintuint256相同),您就可以节省燃气使用量。

例如,请考虑以下合同:

pragma solidity ^0.4.19;

contract Test {
    uint256[100] big;
    uint128[100] small;

    function addBig(uint8 index, uint256 num) public {
        big[index] = num;
    }

    function addSmall(uint8 index, uint128 num1, uint128 num2) public {
        small[index] = num1;
        small[index + 1] = num2;
    }
}

每次使用先前未使用的索引调用addBig()将导致执行成本略高于20,000气体,并导致将一个值添加到阵列中。每次调用addSmall()将花费大约26,000,但是您要向阵列添加2个元素。两者都只使用1个存储槽。如果您可以小于uint128,则可以获得更好的结果。

另一个选项(取决于您是否需要操纵数组数据)是存储您的vector离线链。您可以使用oracle检索数据或将数据存储在IPFS中。

如果这些选项都不适用于您的用例,那么您必须更改数据结构和/或使用多个事务来初始化阵列。

答案 1 :(得分:0)

为什么合同需要在施工时初始化?

这应该有效

pragma solidity ^0.4.2;

contract Graph {
    address owner;

    struct GraphEdge {
        uint128 from;
        uint128 to;
    }

    GraphEdge[] public graph;
    bool public initialized = false;

    constructor() public {
        owner = msg.sender;
    }

    function addEdge(uint128 edgeFrom, uint128 edgeTo) public {
        require(!initialized);
        graph.push(GraphEdge({
            from: edgeFrom,
            to: edgeTo
        }));
    }

    function finalize() public {
        require(msg.sender == owner);
        initialized = true;
    }
}

contract ContractB {
    Graph graph;

    constructor(address graphAddress) public {
        Graph _graph = Graph(graphAddress);
        require(_graph.initialized());
        graph = _graph;
    }
}