mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-10 13:45:49 +00:00
Compare commits
10 Commits
acctx-test
...
func-hooks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6a27e895e | ||
|
|
b56dc38c22 | ||
|
|
e654219ba5 | ||
|
|
89cacb1258 | ||
|
|
8ccff44e8c | ||
|
|
420240a2ab | ||
|
|
230873f196 | ||
|
|
1fb1a99ea2 | ||
|
|
e0b63ac70e | ||
|
|
da8df63be3 |
2
.github/workflows/build-in-docker.yml
vendored
2
.github/workflows/build-in-docker.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
checkout:
|
||||
runs-on: [self-hosted, vanity]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
clean: false
|
||||
checkpatterns:
|
||||
|
||||
@@ -764,6 +764,7 @@ if (tests)
|
||||
src/test/app/ValidatorSite_test.cpp
|
||||
src/test/app/SetHook_test.cpp
|
||||
src/test/app/SetHookTSH_test.cpp
|
||||
src/test/app/SetHookV3_test.cpp
|
||||
src/test/app/Wildcard_test.cpp
|
||||
src/test/app/XahauGenesis_test.cpp
|
||||
src/test/app/tx/apply_test.cpp
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
#!/bin/bash
|
||||
#!/bin/bash -u
|
||||
# We use set -e and bash with -u to bail on first non zero exit code of any
|
||||
# processes launched or upon any unbound variable.
|
||||
# We use set -x to print commands before running them to help with
|
||||
# debugging.
|
||||
set -ex
|
||||
|
||||
set -e
|
||||
|
||||
echo "START INSIDE CONTAINER - CORE"
|
||||
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
#!/bin/bash
|
||||
#!/bin/bash -u
|
||||
# We use set -e and bash with -u to bail on first non zero exit code of any
|
||||
# processes launched or upon any unbound variable.
|
||||
# We use set -x to print commands before running them to help with
|
||||
# debugging.
|
||||
set -ex
|
||||
|
||||
set -e
|
||||
|
||||
echo "START INSIDE CONTAINER - FULL"
|
||||
|
||||
@@ -19,7 +26,7 @@ yum-config-manager --disable centos-sclo-sclo
|
||||
####
|
||||
|
||||
cd /io;
|
||||
mkdir src/certs;
|
||||
mkdir -p src/certs;
|
||||
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h;
|
||||
if [ "`grep certbundle.h src/ripple/net/impl/RegisterSSLCerts.cpp | wc -l`" -eq "0" ]
|
||||
then
|
||||
@@ -66,8 +73,8 @@ then
|
||||
#endif/g" src/ripple/net/impl/RegisterSSLCerts.cpp &&
|
||||
sed -i "s/#include <ripple\/net\/RegisterSSLCerts.h>/\0\n#include <certs\/certbundle.h>/g" src/ripple/net/impl/RegisterSSLCerts.cpp
|
||||
fi
|
||||
mkdir .nih_c;
|
||||
mkdir .nih_toolchain;
|
||||
mkdir -p .nih_c;
|
||||
mkdir -p .nih_toolchain;
|
||||
cd .nih_toolchain &&
|
||||
yum install -y wget lz4 lz4-devel git llvm13-static.x86_64 llvm13-devel.x86_64 devtoolset-10-binutils zlib-static ncurses-static -y \
|
||||
devtoolset-7-gcc-c++ \
|
||||
@@ -115,7 +122,7 @@ tar -xf libunwind-13.0.1.src.tar.xz &&
|
||||
cp -r libunwind-13.0.1.src/include libunwind-13.0.1.src/src lld-13.0.1.src/ &&
|
||||
cd lld-13.0.1.src &&
|
||||
rm -rf build CMakeCache.txt &&
|
||||
mkdir build &&
|
||||
mkdir -p build &&
|
||||
cd build &&
|
||||
cmake .. -DLLVM_LIBRARY_DIR=/usr/lib64/llvm13/lib/ -DCMAKE_INSTALL_PREFIX=/usr/lib64/llvm13/ -DCMAKE_BUILD_TYPE=Release &&
|
||||
make -j$3 install &&
|
||||
@@ -125,7 +132,7 @@ cd ../../ &&
|
||||
echo "-- Build WasmEdge --" &&
|
||||
( wget -nc -q https://github.com/WasmEdge/WasmEdge/archive/refs/tags/0.11.2.zip; unzip -o 0.11.2.zip; ) &&
|
||||
cd WasmEdge-0.11.2 &&
|
||||
( mkdir build; echo "" ) &&
|
||||
( mkdir -p build; echo "" ) &&
|
||||
cd build &&
|
||||
export BOOST_ROOT="/usr/local/src/boost_1_86_0" &&
|
||||
export Boost_LIBRARY_DIRS="/usr/local/lib" &&
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
#!/bin/bash
|
||||
#!/bin/bash -u
|
||||
# We use set -e and bash with -u to bail on first non zero exit code of any
|
||||
# processes launched or upon any unbound variable.
|
||||
# We use set -x to print commands before running them to help with
|
||||
# debugging.
|
||||
set -ex
|
||||
|
||||
set -e
|
||||
|
||||
echo "START BUILDING (HOST)"
|
||||
|
||||
@@ -36,7 +43,8 @@ fi
|
||||
|
||||
STATIC_CONTAINER=$(docker ps -a | grep $CONTAINER_NAME |wc -l)
|
||||
|
||||
if [[ "$STATIC_CONTAINER" -gt "0" && "$GITHUB_REPOSITORY" != "" ]]; then
|
||||
#if [[ "$STATIC_CONTAINER" -gt "0" && "$GITHUB_REPOSITORY" != "" ]]; then
|
||||
if false; then
|
||||
echo "Static container, execute in static container to have max. cache"
|
||||
docker start $CONTAINER_NAME
|
||||
docker exec -i $CONTAINER_NAME /hbb_exe/activate-exec bash -x /io/build-core.sh "$GITHUB_REPOSITORY" "$GITHUB_SHA" "$BUILD_CORES" "$GITHUB_RUN_NUMBER"
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
using GuardLog =
|
||||
std::optional<std::reference_wrapper<std::basic_ostream<char>>>;
|
||||
|
||||
#define DEBUG_GUARD 0
|
||||
#define DEBUG_GUARD_VERBOSE 0
|
||||
#define DEBUG_GUARD_VERY_VERBOSE 0
|
||||
#define DEBUG_GUARD 1
|
||||
#define DEBUG_GUARD_VERBOSE 1
|
||||
#define DEBUG_GUARD_VERY_VERBOSE 1
|
||||
|
||||
#define GUARDLOG(logCode) \
|
||||
if (!guardLog) \
|
||||
@@ -901,23 +901,23 @@ validateGuards(
|
||||
// followed by an leb128 length
|
||||
int section_type = wasm[i++];
|
||||
|
||||
if (section_type == 0)
|
||||
{
|
||||
GUARDLOG(hook::log::CUSTOM_SECTION_DISALLOWED)
|
||||
<< "Malformed transaction. "
|
||||
<< "Hook contained a custom section, which is not allowed. Use "
|
||||
"cleaner.\n";
|
||||
return {};
|
||||
}
|
||||
// if (section_type == 0)
|
||||
// {
|
||||
// GUARDLOG(hook::log::CUSTOM_SECTION_DISALLOWED)
|
||||
// << "Malformed transaction. "
|
||||
// << "Hook contained a custom section, which is not allowed. Use "
|
||||
// "cleaner.\n";
|
||||
// return {};
|
||||
// }
|
||||
|
||||
if (section_type <= last_section_type)
|
||||
{
|
||||
GUARDLOG(hook::log::SECTIONS_OUT_OF_SEQUENCE)
|
||||
<< "Malformed transcation. "
|
||||
<< "Hook contained wasm sections that were either repeated or "
|
||||
"were out of sequence.\n";
|
||||
return {};
|
||||
}
|
||||
// if (section_type <= last_section_type)
|
||||
// {
|
||||
// GUARDLOG(hook::log::SECTIONS_OUT_OF_SEQUENCE)
|
||||
// << "Malformed transcation. "
|
||||
// << "Hook contained wasm sections that were either repeated or "
|
||||
// "were out of sequence.\n";
|
||||
// return {};
|
||||
// }
|
||||
|
||||
last_section_type = section_type;
|
||||
|
||||
@@ -1139,21 +1139,32 @@ validateGuards(
|
||||
}
|
||||
}
|
||||
|
||||
if (wasm[i] == 'm' && wasm[i + 1] == 'e' && wasm[i + 2] == 't' && wasm[i + 3] == 'h' && wasm[i + 4] == 'o' && wasm[i + 5] == 'd')
|
||||
{
|
||||
i += name_len;
|
||||
CHECK_SHORT_HOOK();
|
||||
i++;
|
||||
CHECK_SHORT_HOOK();
|
||||
hook_func_idx = parseLeb128(wasm, i, &i);
|
||||
CHECK_SHORT_HOOK();
|
||||
continue;
|
||||
}
|
||||
|
||||
i += name_len + 1;
|
||||
parseLeb128(wasm, i, &i);
|
||||
CHECK_SHORT_HOOK();
|
||||
}
|
||||
|
||||
// execution to here means export section was parsed
|
||||
if (!hook_func_idx)
|
||||
{
|
||||
GUARDLOG(hook::log::EXPORT_MISSING)
|
||||
<< "Malformed transaction. "
|
||||
<< "Hook did not export: "
|
||||
<< (!hook_func_idx ? "int64_t hook(uint32_t); " : "")
|
||||
<< "\n";
|
||||
return {};
|
||||
}
|
||||
// if (!hook_func_idx)
|
||||
// {
|
||||
// GUARDLOG(hook::log::EXPORT_MISSING)
|
||||
// << "Malformed transaction. "
|
||||
// << "Hook did not export: "
|
||||
// << (!hook_func_idx ? "int64_t hook(uint32_t); " : "")
|
||||
// << "\n";
|
||||
// return {};
|
||||
// }
|
||||
}
|
||||
else if (section_type == 3) // function section
|
||||
{
|
||||
@@ -1295,13 +1306,13 @@ validateGuards(
|
||||
else
|
||||
{
|
||||
// fail
|
||||
GUARDLOG(hook::log::FUNC_TYPE_INVALID)
|
||||
<< "Invalid function type. Not used by any import or "
|
||||
"hook/cbak func. "
|
||||
<< "Codesec: " << section_type << " "
|
||||
<< "Local: " << j << " "
|
||||
<< "Offset: " << i << "\n";
|
||||
return {};
|
||||
// GUARDLOG(hook::log::FUNC_TYPE_INVALID)
|
||||
// << "Invalid function type. Not used by any import or "
|
||||
// "hook/cbak func. "
|
||||
// << "Codesec: " << section_type << " "
|
||||
// << "Local: " << j << " "
|
||||
// << "Offset: " << i << "\n";
|
||||
// return {};
|
||||
}
|
||||
|
||||
int param_count = parseLeb128(wasm, i, &i);
|
||||
@@ -1320,11 +1331,11 @@ validateGuards(
|
||||
}
|
||||
else if (param_count != (*first_signature).get().size() - 1)
|
||||
{
|
||||
GUARDLOG(hook::log::FUNC_TYPE_INVALID)
|
||||
<< "Malformed transaction. "
|
||||
<< "Hook API: " << *first_name
|
||||
<< " has the wrong number of parameters.\n";
|
||||
return {};
|
||||
// GUARDLOG(hook::log::FUNC_TYPE_INVALID)
|
||||
// << "Malformed transaction. "
|
||||
// << "Hook API: " << *first_name
|
||||
// << " has the wrong number of parameters.\n";
|
||||
// return {};
|
||||
}
|
||||
|
||||
for (int k = 0; k < param_count; ++k)
|
||||
@@ -1388,12 +1399,12 @@ validateGuards(
|
||||
// most compilers out
|
||||
if (result_count != 1)
|
||||
{
|
||||
GUARDLOG(hook::log::FUNC_RETURN_COUNT)
|
||||
<< "Malformed transaction. "
|
||||
<< "Hook declares a function type that returns fewer "
|
||||
"or more than one value. "
|
||||
<< "\n";
|
||||
return {};
|
||||
// GUARDLOG(hook::log::FUNC_RETURN_COUNT)
|
||||
// << "Malformed transaction. "
|
||||
// << "Hook declares a function type that returns fewer "
|
||||
// "or more than one value. "
|
||||
// << "\n";
|
||||
// return {};
|
||||
}
|
||||
|
||||
// this can only ever be 1 in production, but in testing it may
|
||||
|
||||
@@ -723,6 +723,9 @@ public:
|
||||
uint32_t wasmParam,
|
||||
beast::Journal const& j)
|
||||
{
|
||||
|
||||
static WasmEdge_String _hookFunctionName = WasmEdge_StringCreateByCString("methodCreate");
|
||||
|
||||
// HookExecutor can only execute once
|
||||
assert(!spent);
|
||||
|
||||
@@ -761,7 +764,7 @@ public:
|
||||
vm.ctx,
|
||||
reinterpret_cast<const uint8_t*>(wasm),
|
||||
len,
|
||||
callback ? cbakFunctionName : hookFunctionName,
|
||||
_hookFunctionName,
|
||||
params,
|
||||
1,
|
||||
returns,
|
||||
|
||||
@@ -69,7 +69,6 @@ public:
|
||||
std::uint32_t offset;
|
||||
std::uint32_t limit;
|
||||
bool bUnlimited;
|
||||
bool strict;
|
||||
};
|
||||
|
||||
struct AccountTxPageOptions
|
||||
@@ -80,7 +79,6 @@ public:
|
||||
std::optional<AccountTxMarker> marker;
|
||||
std::uint32_t limit;
|
||||
bool bAdmin;
|
||||
bool strict;
|
||||
};
|
||||
|
||||
using AccountTx =
|
||||
@@ -103,7 +101,6 @@ public:
|
||||
bool forward = false;
|
||||
uint32_t limit = 0;
|
||||
std::optional<AccountTxMarker> marker;
|
||||
bool strict;
|
||||
};
|
||||
|
||||
struct AccountTxResult
|
||||
|
||||
@@ -43,62 +43,6 @@ private:
|
||||
std::map<uint256, AccountTx> transactionMap_;
|
||||
std::map<AccountID, AccountTxData> accountTxMap_;
|
||||
|
||||
// helper function to scan for an account ID inside the tx and meta blobs
|
||||
// used for strict filtering of account_tx
|
||||
bool
|
||||
isAccountInvolvedInTx(AccountID const& account, AccountTx const& accountTx)
|
||||
{
|
||||
auto const& txn = accountTx.first;
|
||||
auto const& meta = accountTx.second;
|
||||
|
||||
// Search metadata, excluding RegularKey false positives
|
||||
Blob const metaBlob = meta->getAsObject().getSerializer().peekData();
|
||||
if (metaBlob.size() >= account.size())
|
||||
{
|
||||
auto it = metaBlob.begin();
|
||||
while (true)
|
||||
{
|
||||
// Find next occurrence of account
|
||||
it = std::search(
|
||||
it,
|
||||
metaBlob.end(),
|
||||
account.data(),
|
||||
account.data() + account.size());
|
||||
|
||||
if (it == metaBlob.end())
|
||||
break;
|
||||
|
||||
// Check if this is a RegularKey field (0x8814 prefix)
|
||||
if (it >= metaBlob.begin() + 2)
|
||||
{
|
||||
auto prefix = *(it - 2);
|
||||
auto prefix2 = *(it - 1);
|
||||
if (prefix != 0x88 || prefix2 != 0x14)
|
||||
{
|
||||
// Found account not preceded by RegularKey prefix
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too close to start to be RegularKey
|
||||
return true;
|
||||
}
|
||||
|
||||
++it; // Move past this occurrence
|
||||
}
|
||||
}
|
||||
|
||||
// Search transaction blob
|
||||
Blob const txnBlob = txn->getSTransaction()->getSerializer().peekData();
|
||||
return txnBlob.size() >= account.size() &&
|
||||
std::search(
|
||||
txnBlob.begin(),
|
||||
txnBlob.end(),
|
||||
account.data(),
|
||||
account.data() + account.size()) != txnBlob.end();
|
||||
}
|
||||
|
||||
public:
|
||||
RWDBDatabase(Application& app, Config const& config, JobQueue& jobQueue)
|
||||
: app_(app), useTxTables_(config.useTxTables())
|
||||
@@ -249,17 +193,7 @@ public:
|
||||
std::size_t count = 0;
|
||||
for (const auto& [_, accountData] : accountTxMap_)
|
||||
{
|
||||
for (const auto& tx : accountData.transactions)
|
||||
{
|
||||
// RH NOTE: options isn't provided to this function
|
||||
// but this function is probably only used internally
|
||||
// so make it reflect the true number (unfiltered)
|
||||
|
||||
// if (options.strict &&
|
||||
// !isAccountInvolvedInTx(options.account, tx))
|
||||
// continue;
|
||||
count++;
|
||||
}
|
||||
count += accountData.transactions.size();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -673,17 +607,12 @@ public:
|
||||
{
|
||||
for (const auto& [txSeq, txIndex] : txIt->second)
|
||||
{
|
||||
AccountTx const accountTx = accountData.transactions[txIndex];
|
||||
if (options.strict &&
|
||||
!isAccountInvolvedInTx(options.account, accountTx))
|
||||
continue;
|
||||
|
||||
if (skipped < options.offset)
|
||||
{
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
|
||||
AccountTx const accountTx = accountData.transactions[txIndex];
|
||||
std::uint32_t const inLedger = rangeCheckedCast<std::uint32_t>(
|
||||
accountTx.second->getLgrSeq());
|
||||
accountTx.first->setStatus(COMMITTED);
|
||||
@@ -723,18 +652,13 @@ public:
|
||||
innerRIt != rIt->second.rend();
|
||||
++innerRIt)
|
||||
{
|
||||
AccountTx const accountTx =
|
||||
accountData.transactions[innerRIt->second];
|
||||
|
||||
if (options.strict &&
|
||||
!isAccountInvolvedInTx(options.account, accountTx))
|
||||
continue;
|
||||
|
||||
if (skipped < options.offset)
|
||||
{
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
AccountTx const accountTx =
|
||||
accountData.transactions[innerRIt->second];
|
||||
std::uint32_t const inLedger = rangeCheckedCast<std::uint32_t>(
|
||||
accountTx.second->getLgrSeq());
|
||||
accountTx.first->setLedger(inLedger);
|
||||
@@ -770,19 +694,12 @@ public:
|
||||
{
|
||||
for (const auto& [txSeq, txIndex] : txIt->second)
|
||||
{
|
||||
AccountTx const accountTx = accountData.transactions[txIndex];
|
||||
|
||||
if (options.strict &&
|
||||
!isAccountInvolvedInTx(options.account, accountTx))
|
||||
continue;
|
||||
|
||||
const auto& [txn, txMeta] = accountTx;
|
||||
|
||||
if (skipped < options.offset)
|
||||
{
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
const auto& [txn, txMeta] = accountData.transactions[txIndex];
|
||||
result.emplace_back(
|
||||
txn->getSTransaction()->getSerializer().peekData(),
|
||||
txMeta->getAsObject().getSerializer().peekData(),
|
||||
@@ -821,20 +738,13 @@ public:
|
||||
innerRIt != rIt->second.rend();
|
||||
++innerRIt)
|
||||
{
|
||||
AccountTx const accountTx =
|
||||
accountData.transactions[innerRIt->second];
|
||||
|
||||
if (options.strict &&
|
||||
!isAccountInvolvedInTx(options.account, accountTx))
|
||||
continue;
|
||||
|
||||
const auto& [txn, txMeta] = accountTx;
|
||||
|
||||
if (skipped < options.offset)
|
||||
{
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
const auto& [txn, txMeta] =
|
||||
accountData.transactions[innerRIt->second];
|
||||
result.emplace_back(
|
||||
txn->getSTransaction()->getSerializer().peekData(),
|
||||
txMeta->getAsObject().getSerializer().peekData(),
|
||||
@@ -928,23 +838,18 @@ public:
|
||||
return {newmarker, total};
|
||||
}
|
||||
|
||||
AccountTx const& accountTx =
|
||||
accountData.transactions[index];
|
||||
|
||||
Blob rawTxn = accountTx.first->getSTransaction()
|
||||
Blob rawTxn = accountData.transactions[index]
|
||||
.first->getSTransaction()
|
||||
->getSerializer()
|
||||
.peekData();
|
||||
Blob rawMeta = accountTx.second->getAsObject()
|
||||
Blob rawMeta = accountData.transactions[index]
|
||||
.second->getAsObject()
|
||||
.getSerializer()
|
||||
.peekData();
|
||||
|
||||
if (rawMeta.size() == 0)
|
||||
onUnsavedLedger(ledgerSeq);
|
||||
|
||||
if (options.strict &&
|
||||
!isAccountInvolvedInTx(options.account, accountTx))
|
||||
continue;
|
||||
|
||||
onTransaction(
|
||||
rangeCheckedCast<std::uint32_t>(ledgerSeq),
|
||||
"COMMITTED",
|
||||
@@ -988,23 +893,18 @@ public:
|
||||
return {newmarker, total};
|
||||
}
|
||||
|
||||
AccountTx const& accountTx =
|
||||
accountData.transactions[index];
|
||||
|
||||
Blob rawTxn = accountTx.first->getSTransaction()
|
||||
Blob rawTxn = accountData.transactions[index]
|
||||
.first->getSTransaction()
|
||||
->getSerializer()
|
||||
.peekData();
|
||||
Blob rawMeta = accountTx.second->getAsObject()
|
||||
Blob rawMeta = accountData.transactions[index]
|
||||
.second->getAsObject()
|
||||
.getSerializer()
|
||||
.peekData();
|
||||
|
||||
if (rawMeta.size() == 0)
|
||||
onUnsavedLedger(ledgerSeq);
|
||||
|
||||
if (options.strict &&
|
||||
!isAccountInvolvedInTx(options.account, accountTx))
|
||||
continue;
|
||||
|
||||
onTransaction(
|
||||
rangeCheckedCast<std::uint32_t>(ledgerSeq),
|
||||
"COMMITTED",
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include <ripple/app/rdb/backend/detail/Node.h>
|
||||
#include <ripple/basics/BasicConfig.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/basics/strHex.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/core/SociDB.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
@@ -759,34 +758,14 @@ transactionsSQL(
|
||||
options.minLedger);
|
||||
}
|
||||
|
||||
// Convert account ID to hex string for binary search
|
||||
std::string accountHex =
|
||||
strHex(options.account.data(), options.account.size());
|
||||
|
||||
std::string sql;
|
||||
|
||||
// For metadata search:
|
||||
// 1. Look for account ID not preceded by 8814 (RegularKey field)
|
||||
// 2. OR look for account in raw transaction
|
||||
std::string filterClause = options.strict ? "AND (("
|
||||
"hex(TxnMeta) LIKE '%" +
|
||||
accountHex +
|
||||
"%' AND "
|
||||
"hex(TxnMeta) NOT LIKE '%8814" +
|
||||
accountHex +
|
||||
"%'"
|
||||
") OR hex(RawTxn) LIKE '%" +
|
||||
accountHex + "%')"
|
||||
: "";
|
||||
|
||||
if (count)
|
||||
sql = boost::str(
|
||||
boost::format("SELECT %s FROM AccountTransactions "
|
||||
"INNER JOIN Transactions ON Transactions.TransID = "
|
||||
"AccountTransactions.TransID "
|
||||
"WHERE Account = '%s' %s %s %s LIMIT %u, %u;") %
|
||||
selection % toBase58(options.account) % filterClause % maxClause %
|
||||
minClause % beast::lexicalCastThrow<std::string>(options.offset) %
|
||||
"WHERE Account = '%s' %s %s LIMIT %u, %u;") %
|
||||
selection % toBase58(options.account) % maxClause % minClause %
|
||||
beast::lexicalCastThrow<std::string>(options.offset) %
|
||||
beast::lexicalCastThrow<std::string>(numberOfResults));
|
||||
else
|
||||
sql = boost::str(
|
||||
@@ -794,16 +773,15 @@ transactionsSQL(
|
||||
"SELECT %s FROM "
|
||||
"AccountTransactions INNER JOIN Transactions "
|
||||
"ON Transactions.TransID = AccountTransactions.TransID "
|
||||
"WHERE Account = '%s' %s %s %s "
|
||||
"WHERE Account = '%s' %s %s "
|
||||
"ORDER BY AccountTransactions.LedgerSeq %s, "
|
||||
"AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
|
||||
"LIMIT %u, %u;") %
|
||||
selection % toBase58(options.account) % filterClause % maxClause %
|
||||
minClause % (descending ? "DESC" : "ASC") %
|
||||
selection % toBase58(options.account) % maxClause % minClause %
|
||||
(descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
|
||||
(descending ? "DESC" : "ASC") %
|
||||
beast::lexicalCastThrow<std::string>(options.offset) %
|
||||
beast::lexicalCastThrow<std::string>(numberOfResults));
|
||||
|
||||
JLOG(j.trace()) << "txSQL query: " << sql;
|
||||
return sql;
|
||||
}
|
||||
@@ -1136,21 +1114,6 @@ accountTxPage(
|
||||
if (limit_used > 0)
|
||||
newmarker = options.marker;
|
||||
|
||||
// Convert account ID to hex string for binary search
|
||||
std::string accountHex =
|
||||
strHex(options.account.data(), options.account.size());
|
||||
|
||||
// Add metadata search filter similar to transactionsSQL
|
||||
std::string filterClause = options.strict
|
||||
? " AND ((hex(TxnMeta) LIKE '%" + accountHex +
|
||||
"%' "
|
||||
"AND hex(TxnMeta) NOT LIKE '%8814" +
|
||||
accountHex +
|
||||
"%') "
|
||||
"OR hex(RawTxn) LIKE '%" +
|
||||
accountHex + "%')"
|
||||
: "";
|
||||
|
||||
static std::string const prefix(
|
||||
R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
||||
Status,RawTxn,TxnMeta
|
||||
@@ -1169,12 +1132,12 @@ accountTxPage(
|
||||
{
|
||||
sql = boost::str(
|
||||
boost::format(
|
||||
prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u %s
|
||||
prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
|
||||
ORDER BY AccountTransactions.LedgerSeq %s,
|
||||
AccountTransactions.TxnSeq %s
|
||||
LIMIT %u;)")) %
|
||||
toBase58(options.account) % options.minLedger % options.maxLedger %
|
||||
filterClause % order % order % queryLimit);
|
||||
order % order % queryLimit);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1187,25 +1150,25 @@ accountTxPage(
|
||||
auto b58acct = toBase58(options.account);
|
||||
sql = boost::str(
|
||||
boost::format((
|
||||
R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
|
||||
R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
||||
Status,RawTxn,TxnMeta
|
||||
FROM AccountTransactions, Transactions WHERE
|
||||
(AccountTransactions.TransID = Transactions.TransID AND
|
||||
AccountTransactions.Account = '%s' AND
|
||||
AccountTransactions.LedgerSeq BETWEEN %u AND %u) %s
|
||||
AccountTransactions.LedgerSeq BETWEEN %u AND %u)
|
||||
UNION
|
||||
SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
|
||||
FROM AccountTransactions, Transactions WHERE
|
||||
(AccountTransactions.TransID = Transactions.TransID AND
|
||||
AccountTransactions.Account = '%s' AND
|
||||
AccountTransactions.LedgerSeq = %u AND
|
||||
AccountTransactions.TxnSeq %s %u) %s
|
||||
AccountTransactions.TxnSeq %s %u)
|
||||
ORDER BY AccountTransactions.LedgerSeq %s,
|
||||
AccountTransactions.TxnSeq %s
|
||||
LIMIT %u;
|
||||
)")) %
|
||||
b58acct % minLedger % maxLedger % filterClause % b58acct %
|
||||
findLedger % compare % findSeq % filterClause % order % order %
|
||||
queryLimit);
|
||||
b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
|
||||
findSeq % order % order % queryLimit);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1776,7 +1776,7 @@ Transactor::operator()()
|
||||
|
||||
// write state if all chains executed successfully
|
||||
if (isTesSuccess(result))
|
||||
hook::finalizeHookState(stateMap, ctx_, ctx_.tx.getTransactionID());
|
||||
result = hook::finalizeHookState(stateMap, ctx_, ctx_.tx.getTransactionID());
|
||||
|
||||
// write hook results
|
||||
// this happens irrespective of whether final result was a tesSUCCESS
|
||||
@@ -2031,8 +2031,9 @@ Transactor::operator()()
|
||||
for (auto const& [accID, hookHashes] : aawMap)
|
||||
doAgainAsWeak(accID, hookHashes, stateMap, weakResults, proMeta);
|
||||
|
||||
result = hook::finalizeHookState(stateMap, ctx_, ctx_.tx.getTransactionID());
|
||||
|
||||
// write hook results
|
||||
hook::finalizeHookState(stateMap, ctx_, ctx_.tx.getTransactionID());
|
||||
for (auto& weakResult : weakResults)
|
||||
hook::finalizeHookResult(weakResult, ctx_, isTesSuccess(result));
|
||||
|
||||
|
||||
@@ -40,17 +40,6 @@ strHex(FwdIt begin, FwdIt end)
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class FwdIt>
|
||||
std::string
|
||||
strHex(FwdIt begin, std::size_t length)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(2 * length);
|
||||
boost::algorithm::hex(
|
||||
begin, std::next(begin, length), std::back_inserter(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class = decltype(std::declval<T>().begin())>
|
||||
std::string
|
||||
strHex(T const& from)
|
||||
|
||||
@@ -223,8 +223,7 @@ doAccountTxHelp(RPC::Context& context, AccountTxArgs const& args)
|
||||
result.ledgerRange.max,
|
||||
result.marker,
|
||||
args.limit,
|
||||
isUnlimited(context.role),
|
||||
args.strict};
|
||||
isUnlimited(context.role)};
|
||||
|
||||
auto const db =
|
||||
dynamic_cast<SQLiteDatabase*>(&context.app.getRelationalDatabase());
|
||||
@@ -370,9 +369,6 @@ doAccountTxJson(RPC::JsonContext& context)
|
||||
args.forward =
|
||||
params.isMember(jss::forward) && params[jss::forward].asBool();
|
||||
|
||||
args.strict =
|
||||
params.isMember(jss::strict) ? params[jss::strict].asBool() : true;
|
||||
|
||||
if (!params.isMember(jss::account))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
#include <magic/magic_enum.h>
|
||||
#include <sstream>
|
||||
|
||||
#define MAGIC_ENUM(x) \
|
||||
#define MAGIC_ENUM(x, _min, _max) \
|
||||
template <> \
|
||||
struct magic_enum::customize::enum_range<x> \
|
||||
{ \
|
||||
static constexpr int min = -20000; \
|
||||
static constexpr int max = 20000; \
|
||||
static constexpr int min = _min; \
|
||||
static constexpr int max = _max; \
|
||||
};
|
||||
|
||||
#define MAGIC_ENUM_16(x) \
|
||||
@@ -59,14 +59,14 @@
|
||||
static constexpr bool is_flags = true; \
|
||||
};
|
||||
|
||||
MAGIC_ENUM(ripple::SerializedTypeID);
|
||||
MAGIC_ENUM(ripple::LedgerEntryType);
|
||||
MAGIC_ENUM(ripple::TELcodes);
|
||||
MAGIC_ENUM(ripple::TEMcodes);
|
||||
MAGIC_ENUM(ripple::TEFcodes);
|
||||
MAGIC_ENUM(ripple::TERcodes);
|
||||
MAGIC_ENUM(ripple::TEScodes);
|
||||
MAGIC_ENUM(ripple::TECcodes);
|
||||
MAGIC_ENUM(ripple::SerializedTypeID, -2, 10004);
|
||||
MAGIC_ENUM(ripple::LedgerEntryType, 0, 255);
|
||||
MAGIC_ENUM(ripple::TELcodes, -399, 300);
|
||||
MAGIC_ENUM(ripple::TEMcodes, -299, -200);
|
||||
MAGIC_ENUM(ripple::TEFcodes, -199, -100);
|
||||
MAGIC_ENUM(ripple::TERcodes, -99, -1);
|
||||
MAGIC_ENUM(ripple::TEScodes, 0, 1);
|
||||
MAGIC_ENUM(ripple::TECcodes, 100, 255);
|
||||
MAGIC_ENUM_16(ripple::TxType);
|
||||
MAGIC_ENUM_FLAG(ripple::UniversalFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::AccountSetFlags);
|
||||
|
||||
1
src/test/app/.env
Normal file
1
src/test/app/.env
Normal file
@@ -0,0 +1 @@
|
||||
HOOKS_COMPILE_HOST=http://localhost:9000
|
||||
140
src/test/app/SetHookV3_test.cpp
Normal file
140
src/test/app/SetHookV3_test.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2016 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
#include <ripple/app/hook/Enum.h>
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/tx/impl/SetHook.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/app/SetHook_wasm.h>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/hook.h>
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
#include <ripple/json/json_reader.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace test {
|
||||
|
||||
class SetHookV3_test : public beast::unit_test::suite
|
||||
{
|
||||
private:
|
||||
// helper
|
||||
void static overrideFlag(Json::Value& jv)
|
||||
{
|
||||
jv[jss::Flags] = hsfOVERRIDE;
|
||||
}
|
||||
|
||||
public:
|
||||
// This is a large fee, large enough that we can set most small test hooks
|
||||
// without running into fee issues we only want to test fee code specifically in
|
||||
// fee unit tests, the rest of the time we want to ignore it.
|
||||
#define HSFEE fee(100'000'000)
|
||||
#define M(m) memo(m, "", "")
|
||||
std::string
|
||||
loadHook()
|
||||
{
|
||||
std::string name = "/Users/darkmatter/projects/ledger-works/xahaud/src/test/app/wasm/custom.wasm";
|
||||
if (!std::filesystem::exists(name)) {
|
||||
std::cout << "File does not exist: " << name << "\n";
|
||||
return "";
|
||||
}
|
||||
|
||||
std::ifstream hookFile(name, std::ios::binary);
|
||||
|
||||
if (!hookFile)
|
||||
{
|
||||
std::cout << "Failed to open file: " << name << "\n";
|
||||
return "";
|
||||
}
|
||||
|
||||
// Read the file into a vector
|
||||
std::vector<char> buffer((std::istreambuf_iterator<char>(hookFile)), std::istreambuf_iterator<char>());
|
||||
|
||||
// Check if the buffer is empty
|
||||
if (buffer.empty()) {
|
||||
std::cout << "File is empty or could not be read properly.\n";
|
||||
return "";
|
||||
}
|
||||
|
||||
return strHex(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
testSimple(FeatureBitset features)
|
||||
{
|
||||
testcase("Test simple");
|
||||
|
||||
using namespace jtx;
|
||||
|
||||
// Env env{*this, features};
|
||||
Env env{*this, envconfig(), features, nullptr,
|
||||
beast::severities::kTrace
|
||||
};
|
||||
|
||||
auto const alice = Account{"alice"};
|
||||
auto const gw = Account{"gateway"};
|
||||
auto const USD = gw["USD"];
|
||||
env.fund(XRP(10000), alice, gw);
|
||||
env.close();
|
||||
env.trust(USD(100000), alice);
|
||||
env.close();
|
||||
env(pay(gw, alice, USD(10000)));
|
||||
env.close();
|
||||
|
||||
std::string hook = loadHook();
|
||||
std::cout << "Hook: " << hook << "\n";
|
||||
|
||||
// install the hook on alice
|
||||
env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0),
|
||||
M("set simple"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
// // invoke the hook
|
||||
// Json::Value jv = invoke::invoke(alice);
|
||||
// Json::Value params{Json::arrayValue};
|
||||
// Json::Value pv;
|
||||
// Json::Value piv;
|
||||
// piv[jss::HookParameterName] = "736F6D6566756E63";
|
||||
// piv[jss::HookParameterValue] = "736F6D6566756E63";
|
||||
// pv[jss::HookParameter] = piv;
|
||||
// params[0u] = pv;
|
||||
// jv[jss::HookParameters] = params;
|
||||
env(invoke::invoke(alice), M("test simple"), fee(XRP(1)));
|
||||
}
|
||||
|
||||
void
|
||||
testWithFeatures(FeatureBitset features)
|
||||
{
|
||||
testSimple(features);
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
using namespace test::jtx;
|
||||
auto const sa = supported_amendments();
|
||||
testWithFeatures(sa);
|
||||
}
|
||||
};
|
||||
BEAST_DEFINE_TESTSUITE(SetHookV3, app, ripple);
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
#undef M
|
||||
10
src/test/app/contracts/base.c
Normal file
10
src/test/app/contracts/base.c
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#include "hookapi.h"
|
||||
|
||||
int64_t hook(uint32_t reserved) {
|
||||
TRACESTR("Base.c: Called.");
|
||||
_g(1,1);
|
||||
return accept(SBUF("base: Finished."), __LINE__);;
|
||||
}
|
||||
20
src/test/app/contracts/custom.c
Normal file
20
src/test/app/contracts/custom.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#include "hookapi.h"
|
||||
// #define DEBUG 1
|
||||
// #define SBUF(str) (uint32_t)(str), sizeof(str)
|
||||
// #define TRACESTR(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), sizeof(v), 0);
|
||||
// // hook developers should use this guard macro, simply GUARD(<maximum iterations>)
|
||||
// #define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
// #define GUARDM(maxiter, n) _g(( (1ULL << 31U) + (__LINE__ << 16) + n), (maxiter)+1)
|
||||
|
||||
// hooks-cli compile-c contracts/custom.c build
|
||||
|
||||
int64_t methodCreate(uint32_t reserved) {
|
||||
TRACESTR("somefunc.c: Called.");
|
||||
for (int i = 0; GUARD(10), i < 10; i++) {
|
||||
TRACESTR("somefunc.c: Iterating.");
|
||||
}
|
||||
return accept(SBUF("somefunc.c: Finished."), __LINE__);
|
||||
}
|
||||
@@ -245,68 +245,6 @@ class AccountTx_test : public beast::unit_test::suite
|
||||
p[jss::ledger_hash] = to_string(env.closed()->info().parentHash);
|
||||
BEAST_EXPECT(noTxs(env.rpc("json", "account_tx", to_string(p))));
|
||||
}
|
||||
|
||||
// Strict
|
||||
{
|
||||
Account S1{"S1"};
|
||||
Account S2{"S2"};
|
||||
Account S3{"S3"};
|
||||
env.fund(XRP(10000), S1);
|
||||
env.fund(XRP(10000), S2);
|
||||
env.fund(XRP(10000), S3);
|
||||
env.close();
|
||||
|
||||
// Regular key set
|
||||
env(regkey(S1, S2));
|
||||
env.close();
|
||||
|
||||
// we'll make a payment between S1 and S3
|
||||
env(pay(S1, S3, XRP(100)));
|
||||
env.close();
|
||||
|
||||
auto hasTxs = [](Json::Value const& j, bool strict) {
|
||||
if (!j.isMember(jss::result) ||
|
||||
j[jss::result][jss::status] != "success")
|
||||
return false;
|
||||
|
||||
if (strict)
|
||||
{
|
||||
return (j[jss::result][jss::transactions].size() == 3) &&
|
||||
(j[jss::result][jss::transactions][0u][jss::tx]
|
||||
[jss::TransactionType] == jss::SetRegularKey) &&
|
||||
(j[jss::result][jss::transactions][1u][jss::tx]
|
||||
[jss::TransactionType] == jss::AccountSet) &&
|
||||
(j[jss::result][jss::transactions][2u][jss::tx]
|
||||
[jss::TransactionType] == jss::Payment);
|
||||
}
|
||||
|
||||
return (j[jss::result][jss::transactions].size() == 4) &&
|
||||
(j[jss::result][jss::transactions][0u][jss::tx]
|
||||
[jss::TransactionType] == jss::Payment) &&
|
||||
(j[jss::result][jss::transactions][1u][jss::tx]
|
||||
[jss::TransactionType] == jss::SetRegularKey) &&
|
||||
(j[jss::result][jss::transactions][2u][jss::tx]
|
||||
[jss::TransactionType] == jss::AccountSet) &&
|
||||
(j[jss::result][jss::transactions][3u][jss::tx]
|
||||
[jss::TransactionType] == jss::Payment);
|
||||
};
|
||||
|
||||
Json::Value p{jParms};
|
||||
p[jss::account] = S2.human();
|
||||
|
||||
BEAST_EXPECT(
|
||||
hasTxs(env.rpc("json", "account_tx", to_string(p)), true));
|
||||
|
||||
p[jss::strict] = true;
|
||||
|
||||
BEAST_EXPECT(
|
||||
hasTxs(env.rpc("json", "account_tx", to_string(p)), true));
|
||||
|
||||
p[jss::strict] = false;
|
||||
|
||||
BEAST_EXPECT(
|
||||
hasTxs(env.rpc("json", "account_tx", to_string(p)), false));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user