首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在yul中获得mstore后的数据?

如何在yul中获得mstore后的数据?
EN

Ethereum用户
提问于 2022-06-04 05:29:45
回答 1查看 633关注 0票数 2

职能如下:

代码语言:javascript
复制
function encodeAmount(
    uint256 amount,
    bytes memory data
) public pure returns(bytes memory){
    bytes memory amountToEncode = abi.encode(amount);
    assembly {
        mstore(add(add(data, 32), 68), mload(add(amountToEncode, 32)))
    }
    return data;
}

数额: 1000000

数据: 0xe5b07cdb0000000000000000000000003416cf6c708da44db2624d63ea0aaef7113527c60000000000000000000000000000000000000000000000000000000000000001

fn应该更改数据中的最后32字节,但函数返回的数据不变。那么,如何获得实际更改的数据呢?

EN

回答 1

Ethereum用户

回答已采纳

发布于 2022-06-04 09:02:35

fn应该更改数据中的最后32字节,但函数返回的数据不变。那么,如何获得实际更改的数据呢?

您的代码有一个depper问题。所提供的数据似乎包括:

  • 4字节函数选择器: e5b07cdb
  • 32字节地址: 0000000000000000000000003416cf6c708da44db2624d63ea0aaef7113527c6
  • 32字节值: 0000000000000000000000000000000000000000000000000000000000000001

总长度为68个字节。

现在在这条线上:

mstore(add(data,32),68),mload(add(amountToEncode,32)

您可以使用add(data, 32)有效地跳过length字段,但是在不更改length字段或更新空闲内存指针的情况下,在提供的数据之后写入数量。此外,没有必要这样做:

代码语言:javascript
复制
bytes memory amountToEncode = abi.encode(amount);

由于总量已经是一个32字节值(uint256)和abi.encoding,所以它只生成一个具有相同值的32字节数组。您还应该确保数据是按照您预期的方式格式化的,即68字节长。如果您正在寻找一种更通用的方法,能够处理可变长度的字节数组,请告诉我。

由于不清楚要在向现有的数据添加数据或覆盖最后32个字节之间到底要做什么,所以在这两种情况下都需要这样做:

将数据添加到现有字节数组(使用第二个版本)

这个版本有缺陷,不要使用它。我之所以离开它,只是因为我相信它可以提供信息。

代码语言:javascript
复制
function encodeAmount(uint256 amount, bytes memory data) public pure returns(bytes memory) {

        require(data.length == 68, "Expected 68 bytes of data");

        assembly {
            // No need to abi encode amount. It's already a 32 bytes values (uint256).
            // Just write it directly after the existing data
            mstore(add(add(data, 32), 68), amount)

            // Increase the length of the byte array by 32 to account for the added data
            mstore(data, add(mload(data), 32))

            // Set the free memory pointer to data + 32 + data.length to ensure that
            // subsequent allocations do not overwrite what we just added.
            mstore(0x40, add(data, add(mload(data), 32)))
        }
        return data;
    }

产生0xe5b07cdb0000000000000000000000003416cf6c708da44db2624d63ea0aaef7113527c6000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000f4240

  • e5b07cdb (函数选择器)
  • 0000000000000000000000003416cf6c708da44db2624d63ea0aaef7113527c6 (地址)
  • 0000000000000000000000000000000000000000000000000000000000000001 (32字节值)
  • 00000000000000000000000000000000000000000000000000000000000f4240 (添加32个字节值: 1000000)

编辑:如果data不是上一次内存分配的结果,我想这个版本有一个缺陷。mstore(0x40, add(data, add(mload(data), 32)))可以取回空闲内存指针,并使内存处于不一致的状态。

此示例说明了该缺陷:

代码语言:javascript
复制
contract Test {

    struct Wrapper {
        uint256 value;
    }

    function edgeCase(uint256 amount, bytes memory data) public pure returns (bytes memory, Wrapper memory walue) {

        // Assuming data starts at offset 0 :
        // data : [0 : 32 + 68] = 100 bytes
        // Free memory starts at 100

        // wrapper is 32 bytes long allocated at the free memory pointer (100)
        // Free memory now starts at 132
        Wrapper memory wrapper;

        wrapper.value = 0;

        // This will take the free memory pointer back to :
        // data (0) + 32 (length) + data.length (68) + 32 (amount) = 132
        // leaving wrapper in an inconsistent state as it is
        // it overwritten by the byte array returned by encodeAmount.
        // Both wrapper and the encoded byte array use the same memory space.
        // With more than 32 bytes allocated between data and the call
        // the free memory pointer will be decremented.
        return (encodeAmount(amount, data), wrapper);
    }


    function encodeAmount(uint256 amount, bytes memory data) public pure returns(bytes memory) {

        require(data.length == 68, "Expected 68 bytes of data");

        assembly {
            // No need to abi encode amount. It's already a 32 bytes values (uint256).
            // Just write it directly after the existing data
            mstore(add(add(data, 32), 68), amount)

            // Increase the length of the byte array by 32 to account for the added data
            mstore(data, add(mload(data), 32))

            // Set the free memory pointer to data + 32 + data.length to ensure that
            // subsequent allocations do not overwrite what we just added.
            mstore(0x40, add(data, add(mload(data), 32)))
        }
        return data;
    }
}

因此,最好使用下面的版本来创建一个新的字节数组,并确保以前分配的数据的内存一致性。

我强烈建议使用该版本,而不是上一个版本,因为我之前提到了这个缺陷.

代码语言:javascript
复制
function encodeAmount(uint256 amount, bytes memory data) public pure returns(bytes memory encoded) {

    require(data.length == 68, "Expected 68 bytes of data");

        assembly {

            // Take a free memory space for the new array
            encoded := mload(0x40)

            // Set the size of the new array
            mstore(encoded, add(mload(data), 32))

            // Set the content of the new array by blocks of 32 bytes
            for {let i:= 0} lt(i, mload(data)) {i := add(i, 32)} {
                mstore(add(add(encoded, 32), i), mload(add(add(data, 32), i)))
            }

            // No need to abi encode amount. It's already a 32 bytes values (uint256).
            // Just write it directly after the existing data
            mstore(add(add(encoded, 32), 68), amount)

            // Update the free memory pointer
            mstore(0x40, add(encoded, add(mload(encoded), 32)))
        }

    return encoded;
}

覆盖字节数组

的最后32个字节

代码语言:javascript
复制
function overwriteAmount(uint256 amount, bytes memory data) public pure returns(bytes memory) {

        require(data.length == 68, "Expected 68 bytes of data");

        assembly {
            // No need to abi encode amount. It's already a 32 bytes values (uint256).
            // Just write it directly over the last 32 bytes of data
            mstore(add(add(data, 32), 36), amount)
        }
        return data;
    }

在这种情况下,不需要更新长度或空闲内存指针,因为我们没有将任何内容更改为内存布局,只更改已经分配的内存空间的内存内容。

产生0xe5b07cdb0000000000000000000000003416cf6c708da44db2624d63ea0aaef7113527c600000000000000000000000000000000000000000000000000000000000f4240

  • e5b07cdb (函数选择器)
  • 0000000000000000000000003416cf6c708da44db2624d63ea0aaef7113527c6 (地址)
  • 00000000000000000000000000000000000000000000000000000000000f4240 (32个字节值: 1000000)

我希望这能回答你的问题。

票数 2
EN
页面原文内容由Ethereum提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://ethereum.stackexchange.com/questions/129536

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档