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



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

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 构造函数内的函数调用中将向量作为参数传递是错误的吗?

2)我可以看到我可以为边缘创建双重映射。类似的东西

mapping (bool => mapping(uint => uint)) 

但是接下来我将需要多键值映射(从同一点开始的更多边),并且我将遇到像使用向量一样一次初始化所有映射的问题?

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

这应该有效

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;
}
}

如果数组的值范围足够小,则可以通过使用更合适的uints大小来节省气体消耗。以太坊将值存储到 32 字节插槽中,您需要为使用的每个插槽支付 20,000 gas。如果您能够使用较小尺寸的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 gas 的执行成本,并导致一个值被添加到数组中。每次调用addSmall()将花费大约 26,000 个,但您将向数组添加 2 个元素。两者都只使用 1 个插槽的存储空间。如果你能比uint128小,你可以得到更好的结果。

另一种选择(取决于您是否需要操作数组数据)是将vector存储在链下。您可以使用预言机检索数据或将数据存储在IPFS中。

如果这两个选项都不适用于您的用例,那么您将不得不更改数据结构和/或使用多个事务来初始化数组。

最新更新