Селектор функции кодирования с подписью в Zig

Я работаю над проектом Zig, который включает в себя кодирование аргументов в соответствии с правилами кодирования ABI. Проект включает функцию abiEncodeWithSignature, целью которой является получение сигнатуры функции и набора аргументов, а затем возврат байтов, закодированных в ABI. Функция использует оператор переключения для обработки различных типов аргументов, включая конкретный случай для 256-битного целого числа без знака (@"u256") и фрагментов беззнаковых байтов ([]const u8 и []u8).

Проблема возникает при запуске модульных тестов для этой функции. Первый тест, который кодирует сигнатуру функции без аргументов, проходит без проблем. Однако второй тест терпит неудачу, когда я начинаю добавлять аргументы.

Есть ли у кого-нибудь идеи или предложения о том, как решить эту проблему, чтобы обеспечить правильную поддержку и кодирование всех типов аргументов?

Для справки: https://noxx.substack.com/p/evm-deep-dives-the-path-to-shadowy?s=r

const std = @import("std");
const crypto = std.crypto;
const mem = std.mem;
const testing = std.testing;

const @"u256" = [32]u8;

pub fn abiEncodeWithSignature(signature: []const u8, args: anytype) ![]const u8 {
    // Convert the function signature to a Keccak-256 hash
    var hash: [32]u8 = undefined;
    crypto.hash.sha3.Keccak256.hash(signature, &hash, .{});

    // Take the first 4 bytes of the hash as the function selector
    const selector = hash[0..4];

    // Create a list to store the encoded arguments
    var encoded_args = std.ArrayList(u8).init(std.heap.page_allocator);
    defer encoded_args.deinit();

    // Encode each argument according to the ABI encoding rules
    inline for (args, 0..) |arg, i| {
        const arg_type = @TypeOf(arg);
        std.debug.print("Argument at index {}: type = {s}, value = {any}\n", .{ i, @typeName(arg_type), arg });

        switch (arg_type) {
            []const u8 => {
                std.debug.print("Appending address argument: {any}\n", .{arg});
                // Left-pad the address with 12 zero bytes to make it 32 bytes long
                var padded_address: [32]u8 = undefined;
                for (padded_address[0..12]) |*byte| {
                    byte.* = 0; // Pad with zeros
                }
                std.mem.copy(u8, padded_address[12..], arg[0..20]);
                try encoded_args.appendSlice(padded_address[0..]); // Append the padded address
            },
            *[32]u8 => {
                std.debug.print("Appending u256 argument: {any}\n", .{arg});
                try encoded_args.appendSlice(arg[0..]); // Convert the array to a slice
            },
            else => {
                std.debug.print("Unsupported argument type at index {}: {s}\n", .{ i, @typeName(arg_type) });
                return error.UnsupportedArgumentType;
            },
        }
    }

    // Concatenate the function selector and the encoded arguments
    var result = try std.heap.page_allocator.alloc(u8, selector.len + encoded_args.items.len);
    mem.copy(u8, result[0..selector.len], selector);
    mem.copy(u8, result[selector.len..], encoded_args.items);

    return result;
}

pub fn main() !void {
    std.debug.print("Run `zig test` to run the tests.\n", .{});
}

test "abiEncodeWithSignature.store(uint256)" {
    const signature = "store(uint256)";

    const encoded = try abiEncodeWithSignature(signature, .{});
    defer std.heap.page_allocator.free(encoded);

    // Expected result: 6057361d
    const expected = [_]u8{ 0x60, 0x57, 0x36, 0x1d };

    try testing.expectEqualSlices(u8, &expected, encoded);
}

test "abiEncodeWithSignature.store(uint256, address)" {
    const signature = "store(uint256,address)";

    // Adjust amount_bytes to be a [32]u8 array, representing a uint256.
    var amount_bytes: [32]u8 = undefined;
    amount_bytes[31] = 0x01; // Assuming little-endian, place the value at the end.

    const address_bytes = [_]u8{ 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90 };

    const encoded = try abiEncodeWithSignature(signature, .{ @as([]const u8, &amount_bytes), @as([]const u8, &address_bytes) });
    defer std.heap.page_allocator.free(encoded);

    const expected = [_]u8{
        0xce, 0xaa, 0x31, 0x82, // Function selector
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // amount
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, // address
    };

    try testing.expectEqualSlices(u8, &expected, encoded);
}
Test [2/2] test.abiEncodeWithSignature.store(uint256, address)... Argument at index 0: type=[]const u8, value = { 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 1 }
Appending address argument: { 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 1 }
Argument at index 1: type=[]const u8, value = { 18, 52, 86, 120, 144, 18, 52, 86, 120, 144, 18, 52, 86, 120, 144, 18, 52, 86, 120, 144 }
Appending address argument: { 18, 52, 86, 120, 144, 18, 52, 86, 120, 144, 18, 52, 86, 120, 144, 18, 52, 86, 120, 144 }
slices differ. first difference occurs at index 16 (0x10)

============ expected this output: =============  len: 68 (0x44)

CE AA 31 82 00 00 00 00  00 00 00 00 00 00 00 00  ..1.............
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
00 00 00 01 00 00 00 00  00 00 00 00 00 00 00 00  ................
12 34 56 78 90 12 34 56  78 90 12 34 56 78 90 12  .4Vx..4Vx..4Vx..
34 56 78 90                                       4Vx.

============= instead found this: ==============  len: 68 (0x44)

CE AA 31 82 00 00 00 00  00 00 00 00 00 00 00 00  ..1.............
AA AA AA AA AA AA AA AA  AA AA AA AA AA AA AA AA  ................
AA AA AA AA 00 00 00 00  00 00 00 00 00 00 00 00  ................
12 34 56 78 90 12 34 56  78 90 12 34 56 78 90 12  .4Vx..4Vx..4Vx..
34 56 78 90                                       4Vx.

================================================

Test [2/2] test.abiEncodeWithSignature.store(uint256, address)... FAIL (TestExpectedEqual)
/opt/homebrew/Cellar/zig/0.11.0/lib/zig/std/testing.zig:380:5: 0x100ecf113 in expectEqualSlices__anon_1697 (test)
    return error.TestExpectedEqual;
    ^
/Users/christopher.bradley/boringlabs/zigsol/src/main.zig:89:5: 0x100ed0613 in test.abiEncodeWithSignature.store(uint256, address) (test)
    try testing.expectEqualSlices(u8, &expected, encoded);
    ^
1 passed; 0 skipped; 1 failed.
error: the following test command failed with exit code 1:
/Users/christopher.bradley/boringlabs/zigsol/zig-cache/o/29627c5bf39569b46dda51a33e32e0e7/test
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

amount_bytes и address_bytes не являются срезами , это массивы:

@compileLog(@TypeOf(amount_bytes)); // @as(type, [1]u8)
@compileLog(@TypeOf(address_bytes)); // @as(type, [20]u8)

Обычно приведение к срезу осуществляется так же просто, как &array или array[0..], но в данном случае вы используете anytype, поэтому вам нужно указать явно: @as([]const u8, &array). Так:

const encoded = try abiEncodeWithSignature(signature, .{ @as([]const u8, &amount_bytes), @as([]const u8, &address_bytes) });

Это сработало, но все еще есть проблема с заполнением

xchrisbradley 09.04.2024 02:20
zig ============ expected this output: ============= len: 68 (0x44) CE AA 31 82 00 00 00 00 00 00 00 00 00 00 00 00 ..1............. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 .4Vx..4Vx..4Vx.. 34 56 78 90 4Vx.
xchrisbradley 09.04.2024 02:22
zig ============= instead found this: ============== len: 68 (0x44) CE AA 31 82 00 00 00 00 00 00 00 00 00 00 00 00 ..1............. AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA ................ AA AA AA AA 00 00 00 00 00 00 00 00 00 00 00 00 ................ 12 34 56 78 90 12 34 56 78 90 12 34 56 78 90 12 .4Vx..4Vx..4Vx.. 34 56 78 90 4Vx.
xchrisbradley 09.04.2024 02:22

Я обновил код, чтобы отразить

xchrisbradley 09.04.2024 02:22

1. Вы не должны редактировать такие вопросы. 2. Вы оставили большую часть amount_bytes памяти неинициализированной. Zig устанавливает неинициализированную память в 0xaa в режиме отладки.

sigod 09.04.2024 09:36

Другие вопросы по теме