Skip to content
Open
99 changes: 99 additions & 0 deletions src/libxrpl/tx/wasm/WasmiVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,98 @@ WasmiEngine::run(
return Unexpected<TER>(tecFAILED_PROCESSING);
}

namespace {

struct CustomSection
{
std::string_view name;
std::span<uint8_t const> payload;
};

struct Version
{
std::string_view name;
std::string_view version;
};

uint32_t
readLEB128(Bytes const& wasmCode, size_t& offset)
{
auto result = uint32_t{};
auto shift = uint32_t{};
while (true)
{
auto byte = wasmCode[offset++];
Comment thread
depthfirst-app[bot] marked this conversation as resolved.
result |= (byte & 0x7F) << shift;
Comment thread
depthfirst-app[bot] marked this conversation as resolved.
Outdated
Comment thread
TimothyBanks marked this conversation as resolved.
Outdated
if ((byte & 0x80) == 0)
{
break;
}
shift += 7;
}
return result;
}

template <typename Filter>
void
filterCustomSections(Bytes const& wasmCode, Filter&& filter)
{
auto offset = size_t{8}; // Skip Magic number and Version

while (offset < wasmCode.size())
{
auto sectionId = wasmCode[offset++];
auto sectionSize = readLEB128(wasmCode, offset);
auto nextSection = offset + sectionSize;
Comment thread
depthfirst-app[bot] marked this conversation as resolved.

if (sectionId == 0)
{
auto customSection = CustomSection{};

auto size = readLEB128(wasmCode, offset);
customSection.name =
std::string_view{reinterpret_cast<char const*>(wasmCode.data()) + offset, size};
Comment thread
depthfirst-app[bot] marked this conversation as resolved.
offset += size;

size = nextSection - offset;
customSection.payload = std::span<uint8_t const>{
reinterpret_cast<uint8_t const*>(wasmCode.data()) + offset, size};

if (filter(customSection))
{
return;
}
}
offset = nextSection;
}
}

std::vector<Version>
extractVersionInfo(Bytes const& wasmCode)
{
static constexpr auto kCommonLib = "xrpl-common-stdlib";
static constexpr auto kEscrowLib = "xrpl-escrow-stdlib";

auto versions = std::vector<Version>{};
filterCustomSections(wasmCode, [&](auto const& section) {
if (section.name == kCommonLib || section.name == kEscrowLib)
{
versions.emplace_back(
Version{
.name = section.name,
.version = std::string_view{
reinterpret_cast<char const*>(section.payload.data()),
section.payload.size()}});
}

// Just read until we have found all the information we are looking for.
return versions.size() == 2;
});
return versions;
}

} // namespace

Expected<WasmResult<int32_t>, TER>
WasmiEngine::runHlp(
Bytes const& wasmCode,
Expand All @@ -818,6 +910,13 @@ WasmiEngine::runHlp(
if (!hfs.checkSelf())
throw std::runtime_error("hfs isn't clean");

auto versionInfo = extractVersionInfo(wasmCode);

for (auto const& version : versionInfo)
{
std::cout << version.name << " " << version.version << "\n";
}

// Create and instantiate the module.
[[maybe_unused]] int const m = addModule(wasmCode, true, imports, gas);

Expand Down
22 changes: 22 additions & 0 deletions src/test/app/Wasm_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,26 @@ struct Wasm_test : public beast::unit_test::Suite
checkResult(re, 6'912, 59);
}

void
testVersion()
{
testcase("wasm lib test");
static auto const kWasmModule = hexToBytes(
"0061736d010000000105016000017f03020100040401700000070a010666696e69736800000a0601040041"
"010b0018127872706c2d657363726f772d7374646c6962342e352e360018127872706c2d636f6d6d6f6e2d"
"7374646c6962312e322e33");

auto& vm = WasmEngine::instance();

HostFunctions hfs;
ImportVec imports;
WasmImpFunc<Add_proto>(imports, "func-add", reinterpret_cast<void*>(&add), &hfs);
Comment thread
TimothyBanks marked this conversation as resolved.

auto re = vm.run(kWasmModule, hfs, 10'000'000, "finish", wasmParams(1234), imports);

checkResult(re, 1, 59);
}

void
testBadWasm()
{
Expand Down Expand Up @@ -1549,6 +1569,8 @@ struct Wasm_test : public beast::unit_test::Suite
{
using namespace test::jtx;

testVersion();

testGetDataHelperFunctions();
testWasmLib();
testBadWasm();
Expand Down
13 changes: 13 additions & 0 deletions src/test/app/wasm_fixtures/wat/custom_version.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(module
;; Define a table with exactly 0 entries
(table 0 funcref)

;; Standard finish function
(func $finish (result i32)
i32.const 1
)
(export "finish" (func $finish))

(@custom "xrpl-escrow-stdlib" "4.5.6")
(@custom "xrpl-common-stdlib" "1.2.3")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not proposing these as the version information, just showing how it would be done.

)
Loading