mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-19 13:10:46 +00:00
Compare commits
13 Commits
ripple/sma
...
smart-escr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b00e517b66 | ||
|
|
0b37247e98 | ||
|
|
d5c5fedea2 | ||
|
|
8403958e3d | ||
|
|
f16fc10903 | ||
|
|
45f674de47 | ||
|
|
dca957e795 | ||
|
|
a8d20049df | ||
|
|
92ff416de8 | ||
|
|
1556bb7795 | ||
|
|
6082e0d9cd | ||
|
|
72b9918168 | ||
|
|
730061f69a |
@@ -168,7 +168,19 @@ def main():
|
||||
if not os.environ.get("TIDY"):
|
||||
return 0
|
||||
|
||||
repo_root = Path(__file__).parent.parent
|
||||
# Derive the repo root from git so this keeps working regardless of where
|
||||
# under the tree this script lives. Fall back to the script location
|
||||
# (bin/pre-commit/ is two levels below the repo root) if git is unavailable.
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=Path(__file__).parent,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
repo_root = Path(result.stdout.strip())
|
||||
else:
|
||||
repo_root = Path(__file__).parent.parent.parent
|
||||
files = staged_files(repo_root)
|
||||
if not files:
|
||||
return 0
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -277,7 +278,7 @@ InstanceWrapper::setGas(std::int64_t gas) const
|
||||
ModulePtr
|
||||
ModuleWrapper::init(StorePtr& s, Bytes const& wasmBin, beast::Journal j)
|
||||
{
|
||||
wasm_byte_vec_t const code{wasmBin.size(), (char*)(wasmBin.data())};
|
||||
wasm_byte_vec_t const code{.size = wasmBin.size(), .data = (char*)(wasmBin.data())};
|
||||
ModulePtr m = ModulePtr(wasm_module_new(s.get(), &code), &wasm_module_delete);
|
||||
if (!m)
|
||||
throw std::runtime_error("can't create module");
|
||||
@@ -711,8 +712,8 @@ WasmiResult
|
||||
WasmiEngine::call(FuncInfo const& f, std::vector<wasm_val_t>& in)
|
||||
{
|
||||
WasmiResult ret(NR);
|
||||
wasm_val_vec_t const inv =
|
||||
in.empty() ? wasm_val_vec_t WASM_EMPTY_VEC : wasm_val_vec_t{in.size(), in.data()};
|
||||
wasm_val_vec_t const inv = in.empty() ? wasm_val_vec_t WASM_EMPTY_VEC
|
||||
: wasm_val_vec_t{.size = in.size(), .data = in.data()};
|
||||
|
||||
#ifdef SHOW_CALL_TIME
|
||||
auto const start = usecs();
|
||||
@@ -799,6 +800,131 @@ WasmiEngine::run(
|
||||
return Unexpected<TER>(tecFAILED_PROCESSING);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct CustomSection
|
||||
{
|
||||
std::string_view name;
|
||||
std::span<char 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 (offset < wasmCode.size())
|
||||
{
|
||||
auto byte = wasmCode[offset++];
|
||||
result |= static_cast<uint32_t>(byte & (shift < 28 ? 0x7Fu : 0x0Fu)) << shift;
|
||||
if ((byte & 0x80) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
shift += 7;
|
||||
if (shift >= 32)
|
||||
{
|
||||
// Drain the rest of the bytes for this leb.
|
||||
while (offset < wasmCode.size())
|
||||
{
|
||||
if ((wasmCode[offset++] & 0x80) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Filter>
|
||||
void
|
||||
filterCustomSections(Bytes const& wasmCode, Filter&& filter)
|
||||
{
|
||||
auto offset = size_t{8}; // Skip Magic number and Version
|
||||
|
||||
if (wasmCode.size() <= offset)
|
||||
{
|
||||
// There is nothing to parse.
|
||||
return;
|
||||
}
|
||||
|
||||
while (offset < wasmCode.size())
|
||||
{
|
||||
auto sectionId = wasmCode[offset++];
|
||||
auto sectionSize = readLEB128(wasmCode, offset);
|
||||
auto nextSection = offset + sectionSize;
|
||||
|
||||
if (nextSection > wasmCode.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (sectionId == 0)
|
||||
{
|
||||
// Wasm custom section marker.
|
||||
auto customSection = CustomSection{};
|
||||
auto size = readLEB128(wasmCode, offset);
|
||||
|
||||
if (offset + size > wasmCode.size() || offset + size > nextSection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
customSection.name =
|
||||
std::string_view{reinterpret_cast<char const*>(wasmCode.data()) + offset, size};
|
||||
offset += size;
|
||||
|
||||
if (offset >= nextSection)
|
||||
{
|
||||
offset = nextSection;
|
||||
continue;
|
||||
}
|
||||
|
||||
size = nextSection - offset;
|
||||
customSection.payload = std::span<char const>{
|
||||
reinterpret_cast<char 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{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,
|
||||
@@ -818,6 +944,11 @@ WasmiEngine::runHlp(
|
||||
if (!hfs.checkSelf())
|
||||
throw std::runtime_error("hfs isn't clean");
|
||||
|
||||
for (auto const& version : extractVersionInfo(wasmCode))
|
||||
{
|
||||
j_.debug() << "Module version: " << version.name << " " << version.version << "\n";
|
||||
}
|
||||
|
||||
// Create and instantiate the module.
|
||||
[[maybe_unused]] int const m = addModule(wasmCode, true, imports, gas);
|
||||
|
||||
@@ -960,7 +1091,7 @@ wasm_trap_t*
|
||||
WasmiEngine::newTrap(std::string const& txt)
|
||||
{
|
||||
static char empty[1] = {0};
|
||||
wasm_message_t msg = {1, empty};
|
||||
wasm_message_t msg = {.size = 1, .data = empty};
|
||||
|
||||
if (!txt.empty())
|
||||
wasm_name_new(&msg, txt.size() + 1, txt.c_str()); // include 0
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include <test/app/wasm_fixtures/fixtures.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/unit_test/SuiteJournal.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/tx/wasm/HostFunc.h>
|
||||
@@ -227,6 +229,34 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
checkResult(re, 6'912, 59);
|
||||
}
|
||||
|
||||
void
|
||||
testVersion()
|
||||
{
|
||||
testcase("wasm module test");
|
||||
// wat2wasm --enable-annotations mymodule.wat -o mymodule.wasm
|
||||
// xxd -p mymodule.wasm | tr -d '\n'
|
||||
static auto const kWasmModule = hexToBytes(
|
||||
"0061736d010000000105016000017f03020100040401700000070a010666696e69736800000a0601040041"
|
||||
"010b0018127872706c2d657363726f772d7374646c6962342e352e360018127872706c2d636f6d6d6f6e2d"
|
||||
"7374646c6962312e322e33");
|
||||
|
||||
StreamSink sink{beast::Severity::Debug};
|
||||
beast::Journal const journal{sink};
|
||||
|
||||
auto& vm = WasmEngine::instance();
|
||||
|
||||
auto hfs = HostFunctions{};
|
||||
auto imports = ImportVec{};
|
||||
WasmImpFunc<Add_proto>(imports, "func-add", reinterpret_cast<void*>(&add), &hfs);
|
||||
|
||||
[[maybe_unused]] auto result =
|
||||
vm.run(kWasmModule, hfs, 10'000'000, "finish", wasmParams(), imports, journal);
|
||||
|
||||
auto const logged = sink.messages().str();
|
||||
BEAST_EXPECT(logged.find("Module version: xrpl-escrow-stdlib 4.5.6") != std::string::npos);
|
||||
BEAST_EXPECT(logged.find("Module version: xrpl-common-stdlib 1.2.3") != std::string::npos);
|
||||
}
|
||||
|
||||
void
|
||||
testBadWasm()
|
||||
{
|
||||
@@ -1549,6 +1579,8 @@ struct Wasm_test : public beast::unit_test::Suite
|
||||
{
|
||||
using namespace test::jtx;
|
||||
|
||||
testVersion();
|
||||
|
||||
testGetDataHelperFunctions();
|
||||
testWasmLib();
|
||||
testBadWasm();
|
||||
|
||||
13
src/test/app/wasm_fixtures/wat/custom_version.wat
Normal file
13
src/test/app/wasm_fixtures/wat/custom_version.wat
Normal file
@@ -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")
|
||||
)
|
||||
Reference in New Issue
Block a user