请求组实体动态_实体中的动态值数组

请求组实体动态

背景 (Background)

During the development and testing of Datona Labs’ Solidity smart data access contract (S-DAC) templates, we often need to handle data with a small but unknown number of items, such as user IDs. Ideally, these are stored in small dynamic arrays of small values.

在开发和Datona Labs的测试密实度的智能数据获取合同(S-DAC)的模板,我们往往需要用小但数量不明的物品,如用户ID来处理数据。 理想情况下,将它们存储在较小值的小型动态数组中。

In the examples for this article, we investigate whether using dynamic value arrays helps us to do that more efficiently than using reference arrays or similar solutions in Solidity.

在本文的示例中,我们研究了使用动态值数组是否比使用Solidity中的引用数组或类似解决方案更有效地做到这一点。

讨论区 (Discussion)

Where we have data comprising a known small number of small numbers, we can employ a value array in Solidity, as per the article “Value Arrays in Solidity” by the author, in which we provide and measure Solidity value arrays. We concluded, amongst other things, that we can reduce my storage space and gas consumption using value arrays in many circumstances.

其中我们具有包括已知的少数小数字的数据,我们可以使用在密实度的值阵列,按文章“ 值阵列在密实度 ”由作者,在此我们提供并测量稠度值阵列。 我们得出的结论是,在许多情况下,我们可以使用值阵列来减少我的存储空间和气体消耗。

This conclusion was reached because Solidity runs on the Ethereum Virtual Machine (EVM) which has a very large machine word of 256bits (32bytes). This feature, combined with high gas consumption for reference array handling, encourages us to consider using value arrays.

之所以得出这个结论,是因为Solidity在以太坊虚拟机(EVM)上运行,该机器具有256位(32字节)非常大的机器字 。 此功能,加上用于参考数组处理的高耗气量,鼓励我们考虑使用值数组。

However, if we are providing our own libraries for fixed value array manipulation, let us determine whether it is feasible to provide dynamic value arrays as well.

但是,如果我们要提供自己的用于固定值数组操作的库,则让我们确定提供动态值数组是否也可行。

Let us compare dynamic value arrays with fixed value arrays and Solidity’s own fixed and dynamic arrays.

让我们将动态值数组与固定值数组以及Solidity自己的固定和动态数组进行比较。

We shall also compare a struct containing a length and a fixed array, as well as a struct containing a value array.

我们还将比较包含长度和固定数组的结构,以及包含值数组的结构。

可能的动态值数组 (Possible Dynamic Value Arrays)

In Solidity, it is only possible to have dynamic storage arrays. Memory arrays have a fixed size and are not permitted to use push() in order to append additional elements.

在Solidity中,只能具有动态存储阵列。 内存数组的大小是固定的,并且不允许使用push()来附加其他元素。

Since we are providing our own code for dynamic value arrays in Solidity libraries, we can also provide push() (and pop()) to be used on both storage and memory arrays.

由于我们在Solidity库中为动态值数组提供了自己的代码,因此我们也可以提供push() (和pop() )同时用于存储和内存阵列。

Dynamic value arrays will need to record and manipulate the current length of the array. In the following code, we have chosen to store the length in the top bits of the 256bit-, 32byte-machine word value.

动态值数组将需要记录和操纵数组的当前长度。 在下面的代码中,我们选择将长度存储在256位,32字节机器字值的高位中。

动态值数组 (Dynamic value arrays)

These are dynamic value arrays that match some of the Solidity available types:

这些是与某些Solidity可用类型匹配的动态值数组:

Dynamic Value ArraysType           Type Name   Descriptionuint128[](1)   uint128d1   one 128bit element value
uint64[](3) uint64d3 three 64bit element values
uint32[](7) uint32d7 seven 32bit element values
uint16[](15) uint16d15 fifteen 16bit element values
uint8[](31) uint8d31 thirty-one 8bit element values

We propose the Type Name as shown above, which is used throughout this article, but you may find a preferable naming convention.

我们建议使用上面显示的类型名称,本文将使用它,但是您可能会发现更好的命名约定。

We will be looking at uint8d31 in more detail, below.

我们将在下面更详细地查看uint8d31。

更多动态值数组 (More dynamic value arrays)

Obviously, there more possible value arrays. Assuming that we are reserving the top bits of the 256bit value to hold the maximum dynamic array length, the number of bits in the X value multiplied by the number of Y elements must be less than or equal to 256 minus enough bits to hold the array length, L:

显然,还有更多可能的值数组。 假设我们保留256bit值的高位以保持最大动态数组长度,则X值中的位数应乘以Y元素的数量必须小于或等于256减去足够的位数以容纳数组长度,L:

More Dynamic Value ArraysType           Type Name  Len  DescriptionuintX[](Y)     uintXdY     L   X * Y <= 256 - Luint255[](1)   uint255d1   1   one 248bit element value
uint126[](2) uint126a2 2 two 124bit element values
uint84[](3) uint84d3 2 three 82bit element values
uint63[](4) uint63d4 3 four 62bit element values
uint50[](5) uint50d5 3 five 51bit element values
uint42[](6) uint42d6 3 six 42bit element values
uint36[](7) uint36d7 3 seven 36bit element values
uint31[](8) uint31d8 4 eight 31bit element values
uint28[](9) uint28d9 4 nine 28bit element values
uint25[](10) uint25d10 4 ten 25bit element values
uint22[](11) uint22d11 4 eleven 22bit element values
uint21[](12) uint21d12 4 twelve 21bit element values
uint19[](13) uint19d13 4 thirteen 19bit element values
uint18[](14) uint18d14 4 fourteen 18bit element values
uint16[](15) uint16d15 4 as above
uint15[](16) uint15d16 5 sixteen 15bit element values
uint14[](17) uint14d17 5 seventeen 14bit element values
uint13[](19) uint13d19 5 nineteen 13bit element values
uint12[](20) uint12d20 5 twenty 12bit element values
uint11[](22) uint11d22 5 twenty-two 11bit element values
uint10[](25) uint10d25 5 twenty-five 10bit element values
uint9[](27) uint9d27 5 twenty-seven 9bit element values
uint8[](31) uint8d31 5 as above
uint7[](35) uint7d35 6 thirty-five 7bit element values
uint6[](41) uint6d41 6 forty-one 6bit element values
uint5[](50) uint5d50 6 fifty 5bit element values
uint4[](62) uint4d62 6 sixty-two 4bit element values
uint3[](83) uint3d83 7 eighty-three 3bit element values
uint2[](124) uint2d124 7 one-hundred & twenty-four 2bit EVs
uint1[](248) uint1d248 8 two-hundred & forty-eight 1bit EVs

The array type needed is project-specific. Additionally, multiple array types may be needed, for instance, uint8d31 for user IDs and uint5d50 for roles.

所需的数组类型是特定于项目的。 此外,可能需要多种数组类型,例如,用于用户ID的uint8d31和用于角色的uint5d50。

Note the uint1d248 value array. That allows us to efficiently encode up to 248 one-bit element values, which represent booleans, into one EVM word. Compare that with Solidity’s bool[248] which consumes 248 times as much space in memory and even eight times as much space in storage.

注意uint1d248值数组。 这样一来,我们就可以将最多248个表示布尔值的1位元素值有效地编码为一个EVM字。 相比之下,Solidity的bool [248]消耗的内存空间是其248倍,甚至是存储空间的8倍。

动态值数组实现 (Dynamic value array implementation)

Here is a useful import file providing get and set functions for the dynamic value array type uint8d31:

这是一个有用的导入文件,为动态值数组类型uint8d31提供get和set函数:

// uint8d31.sollibrary uint8d31 { // provides the equivalent of uint8[](31)
uint constant wordBits = 256;
uint constant bits = 8;
uint constant elements = 31;
uint constant lenBits = 5;
// ensure that (bits * elements) <= (wordBits - lenBits)

uint constant range = 1 << bits;
uint constant max = range - 1;
uint constant lenPos = wordBits - lenBits;

function length(uint va) internal pure returns (uint) {
return va >> lenPos;
} function setLength(uint va, uint len) internal pure returns
(uint) {
require(len <= elements);
return (va & (uint(~0x0) >> lenBits)) | (len << lenPos);
} function get(uint va, uint index) internal pure returns (uint) {
require(index < (va >> lenPos));
return (va >> (bits * index)) & max;
} function set(uint va, uint index, uint value) internal pure
returns (uint) {
require((index < (va >> lenPos)) && (value < range));
index *= bits;
return (va & ~(max << index)) | (value << index);
} function push(uint va, uint value) internal pure returns (uint){
uint len = va >> lenPos;
require((len < elements) && (value < range));
uint posBits = len * bits;
va = (va & ~(max << posBits)) | (value << posBits);
return (va & (uint(~0) >> lenBits)) | ((len + 1) << lenPos);
}
}

The length() function returns the current size of the dynamic value array. You can alter the number of elements in the array using setLength() or push().

length() 函数返回动态值数组的当前大小。 您可以使用setLength()push()更改数组中元素的数量

The get() and set() functions get and set a specific element, as per fixed value arrays, except that only elements that are within the current size of the array may be accessed.

根据固定值数组, get()set()函数获取并设置一个特定元素,只是只能访问该数组当前大小内的元素。

The push() function appends values up to the maximum size of the dynamic value array. Simply define pop() as well to provide an efficient small value stack.

push()函数将值附加到动态值数组的最大大小。 只需定义pop() 以及提供有效的小价值堆栈。

Let’s see a few simple, sunny day tests for the uint8d31 example library code:

让我们来看一下uint8d31示例库代码的一些简单的晴天测试:

import "uint8d31.sol";contract TestUint8d31 {
using uint8d31 for uint;

function test1() public pure {
uint va;
require(va.length() == 0, "length not 0"); va = va.setLength(10);
require(va.length() == 10, "length not 10");
}

function test2() public {
uint va;
va = va.push(0x12);
require(va.get(0) == 0x12, "va[0] not 0x12");
require(va.length() == 1, "length not 1");

va = va.push(0x34);
require(va.get(1) == 0x34, "va[1] not 0x34");
require(va.length() == 2, "length not 2");

va = va.setLength(31);
require(va.length() == 31, "length not 31"); va = va.set(30, 0x78);
require(va.get(30) == 0x78, "va[30] not 0x78");
require(va.length() == 31, "length not 31");
}
}

结构动态数组 (Struct dynamic arrays)

The advantage of using structs is that they are passed by reference to internal (not external) library functions, negating the requirement to assign the function return value from setLength(), set(), and push().

使用struct的优点是通过引用将它们传递给内部(而非外部)库函数,从而无需从setLength()set()push()分配函数返回值。

Here is a struct containing 31 bytes of data in a fixed array and a length, and the associated library functions:

这是一个结构,其中包含31个字节的固定数组数据和一个长度,以及相关的库函数:

struct Suint8u31 { // struct representing uint8[](31)
uint8[31] data;
uint8 length;
}// ------------library Suint8u31lib {
// constant declarations as per uint8d31

function length(Suint8d31 memory s) internal pure returns (uint)
{
return s.length;
} function setLength(Suint8d31 memory s, uint len) ... // other function definitions similar to uint8d31
}

This code is similar to uint8d31, simply substituting s.length and s.data[index] where required and not returning a value from setLength(), set(), or push().

此代码类似于uint8d31,仅在需要时替换s.lengths.data[index] ,而不从setLength()set()push()返回值。

The Suint8u31 struct defined above appears to consume 256bits of address space. But in Solidity, each array comprises an additional 256bit value for the length of the array, even if it’s a fixed array, so we are expecting that the gas consumption of this solution is going to be higher than anticipated.

上面定义的Suint8u31结构似乎占用了256位的地址空间。 但是在Solidity中,即使是固定阵列,每个阵列都为阵列的长度增加了一个256位值,因此我们预计该解决方案的气体消耗将比预期的高。

结构动态值数组 (Struct dynamic value arrays)

Here is a struct containing a dynamic value array and the associated library functions:

这是一个包含动态值数组和关联库函数的结构:

struct Suint8d31 { // struct representing uint8[](31)
uint va; // uint8d31 value array
}// ------------library Suint8d31lib {
// as per uint8d31

function length(Suint8d31 memory s) internal pure returns (uint)
{
return s.va >> lenPos;
} function setLength(Suint8u31 memory s, uint len) ... // other function definitions similar to uint8d31
}

This code is very similar to uint8d31, simply substituting s.va for each occurrence of va, and not returning a value from setLength(), set(), or push().

此代码与uint8d31非常相似,只是将s.va替换为va每次出现,而不会从中返回值 setLength( ), set()push()

Let’s measure the gas consumption right after this enigmatic comfort break.

让我们测量一下这个令人难以置信的舒适休息后的耗气量。

Image for post
Enigmatic photo by Author
作者的神秘照片

耗气量 (Gas Consumption)

Having written the libraries and contracts, we measured the gas consumption using a technique described in article “Gas Cost of Solidity Functions” by the author.

编写了库和合同后,我们使用作者在“ 固体功能的气体成本 ”一文中描述的技术测量了气体消耗。

Here are the legends for the charts given below:

以下是以下图表的图例:

Legend         Meaninguint8[](32)    Solidity dynamic array of 32 uint8
uint8[32] Solidity fixed array of 32 uint8
uint8a32 Fixed Value Array of 32 uint8 (other article)
uint8d31 Dynamic Value Array of <= 31 uint8 (this article)
suint8d31 Struct containing Dynamic Value Array of <= 31 uint8
suint8u31 Struct containing Solidity fixed array of <= 31 uint8

EVM内存空间中的uint8数组 (uint8 arrays in EVM memory space)

Here, we compare using dynamic uint8 arrays in EVM memory space:

在这里,我们比较了在EVM内存空间中使用动态uint8数组的情况:

Image for post
Gas consumption of get and set on uint8 memory variables
在uint8内存变量上获取和设置的耗油量

This chart shows that gas consumption for a handful of common operations on a dynamic value array (uint8d31) only consumes a little more gas than a fixed value array (uint8a32).

该图表显示,动态值数组(uint8d31)上的一些常用操作的耗气量仅比固定值数组(uint8a32)消耗的气量多一些。

All other options consume significantly more gas, especially the struct containing a Solidity fixed array (last column).

所有其他选项消耗的气体明显更多,尤其是包含Solidity固定数组(最后一列)的结构。

This is how the gas consumptions of individual operations compare:

这是各个操作的耗气量比较的方式:

Image for post
Gas consumption of push, get, and set on uint8 memory variables
在uint8内存变量上进行push,get和set的耗油量

Note that push() is not permitted on Solidity memory arrays, even dynamic ones (the gold column for each type), but we did implement it for the dynamic data structures measured in this article.

请注意,Solidity内存数组,甚至动态数组(每种类型的黄金列push()都不允许push() ,但是我们确实为本文中测量的动态数据结构实现了它。

The takeaway from this is that, yet again, the dynamic value array (uint8d31) only consumes a little more gas than a fixed value array (uint8a32), and all other options consume (sometimes a lot) more gas.

这样做的好处是,与固定值数组(uint8a32)相比,动态值数组(uint8d31)仅消耗更多的汽油,而所有其他选项消耗(有时很多)的汽油。

EVM存储空间中的uint8阵列 (uint8 arrays in EVM storage space)

Here, we compare using dynamic uint8 arrays in EVM storage space:

在这里,我们比较了在EVM存储空间中使用动态uint8阵列的情况:

Image for post
Gas consumption of push/set and get uint8 storage variables
推/设置和获取uint8存储变量的耗油量

Here, apart from the high gas consumption of the first and last columns, the picture is clear and the selection less definitive.

在此,除了第一列和最后一列的高耗气量之外,图片清晰,选择不明确。

This is how the gas consumptions of individual operations compare:

这是各个操作的耗气量比较的方式:

Image for post
Gas consumption of push, get and set on uint8 storage variables
推送,获取和设置uint8存储变量的耗油量

The column to focus on is probably the rust column (right-most for each type), which tends to show typical usage after the storage space has been allocated, whereas the first push() or set() causes storage space to be allocated, which consumes a lot of gas on the EVM.

要关注的列可能是rust列(每种类型的最右边),在分配了存储空间后,它通常会显示典型用法,而第一个push()set()会导致分配存储空间,在EVM上消耗大量气体。

Above, the dynamic value array (uint8d31) consumes a little more gas than a fixed value array (uint8a32), and all other options consume a little more gas.

上面,动态值数组(uint8d31)比固定值数组(uint8a32)消耗更多的气体,而所有其他选项消耗的气体也更多。

分包和库的参数 (Parameters to subcontracts and libraries)

Image for post
Gas consumption of passing a uint8 parameter to a subcontract or library
将uint8参数传递给分包合同或库的耗油量

Not surprisingly, the biggest gas consumption is providing an array parameter to a subcontract or library function, and then getting the value back again.

毫不奇怪,最大的气体消耗是为分包合同或库函数提供数组参数,然后再次取回该值。

Using a value instead clearly consumes far less gas.

取而代之,使用一个值显然会消耗更少的汽油。

其他可能性 (Other Possibilities)

If you find dynamic value arrays useful, you may also like to consider fixed value arrays, fixed multi-value arrays, value queues, value stacks, et cetera. And how would your algorithms (such as Sort) perform if they used value arrays instead of reference arrays?

如果发现动态值数组很有用,则可能还需要考虑固定值数组,固定多值数组,值队列,值堆栈等。 如果您的算法(例如Sort )使用值数组而不是引用数组,它们的性能如何?

结论 (Conclusions)

We have provided and measured code for generic library code for uintX[](Y) small dynamic value arrays.

我们已经为uintX [](Y)小型动态值数组的通用库代码提供了已测量的代码。

We can reduce our storage space and gas consumption using dynamic value arrays compared with Solidity’s dynamic arrays.

与Solidity的动态数组相比,我们可以使用动态值数组来减少存储空间和气体消耗。

Where your Solidity smart contracts use small dynamic arrays of small values (for user IDs, roles, et cetera), then the use of dynamic value arrays is likely to consume less gas.

如果您的Solidity智能合约使用较小值的小型动态数组(用于用户ID,角色等),则使用动态值数组可能会消耗较少的汽油。

Where arrays are copied, e.g., for subcontracts or libraries, dynamic value arrays will always consume vastly less gas.

在复制数组的地方(例如,对于分包合同或库),动态值数组将始终消耗少得多的气体。

In other circumstances, continue to use dynamic reference arrays.

在其他情况下,请继续使用动态引用数组。

Thanks for reading!

谢谢阅读!

翻译自: https://medium.com/better-programming/dynamic-value-arrays-in-solidity-8e9b44015833

请求组实体动态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值