Compare commits

..

1 Commits

Author SHA1 Message Date
Richard Holland
51f8a9c9ac init 2026-06-21 13:35:55 +10:00
6 changed files with 138 additions and 11 deletions

View File

@@ -34,6 +34,7 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.
XRPL_FEATURE(SecureUI, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (HookMap, Supported::yes, VoteBehavior::DefaultYes)
XRPL_FIX (GuardDepth32, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(NamedHooks, Supported::yes, VoteBehavior::DefaultNo)

View File

@@ -262,6 +262,7 @@ LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
{sfHookStateScale, soeOPTIONAL},
{sfCron, soeOPTIONAL},
{sfAMMID, soeOPTIONAL},
{sfSecureUI, soeOPTIONAL},
}))
/** A ledger object which contains a list of object identifiers.

View File

@@ -293,6 +293,7 @@ TYPED_SFIELD(sfAssetClass, VL, 29)
TYPED_SFIELD(sfProvider, VL, 30)
TYPED_SFIELD(sfMPTokenMetadata, VL, 31)
TYPED_SFIELD(sfCredentialType, VL, 32)
TYPED_SFIELD(sfSecureUI, VL, 96)
TYPED_SFIELD(sfHookName, VL, 97)
TYPED_SFIELD(sfRemarkValue, VL, 98)
TYPED_SFIELD(sfRemarkName, VL, 99)

View File

@@ -74,6 +74,7 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet, ({
{sfTickSize, soeOPTIONAL},
{sfNFTokenMinter, soeOPTIONAL},
{sfHookStateScale, soeOPTIONAL},
{sfSecureUI, soeOPTIONAL},
}))
/** This transaction type cancels an existing escrow. */

View File

@@ -197,6 +197,31 @@ SetAccount::preflight(PreflightContext const& ctx)
return temMALFORMED;
}
if (tx.isFieldPresent(sfSecureUI))
{
if (!ctx.rules.enabled(featureSecureUI))
return temMALFORMED;
Blob ui = tx.getFieldVL(sfSecureUI);
if (ui.size() == 0)
{
// this is an unset operation, pass
}
else if (ui.size() > 4096)
{
JLOG(j.trace()) << "SecureUI: Too long > 4096 bytes";
return temMALFORMED;
}
else if (!URIToken::validateUTF8(ui))
{
JLOG(j.trace()) << "SecureUI: Not UTF-8";
return temMALFORMED;
}
// valid
}
return preflight2(ctx);
}
@@ -699,6 +724,23 @@ SetAccount::doApply()
sle->setFieldU16(sfHookStateScale, newScale);
}
}
if (tx.isFieldPresent(sfSecureUI))
{
Blob ui = tx.getFieldVL(sfSecureUI);
if (ui.size() == 0)
{
// unset operation
if (sle->isFieldPresent(sfSecureUI))
sle->makeFieldAbsent(sfSecureUI);
}
else
{
// set operation
sle->setFieldVL(sfSecureUI, std::move(ui));
}
}
ctx_.view().update(sle);
return tesSUCCESS;

View File

@@ -22,8 +22,12 @@
#include <xrpld/app/main/Application.h>
#include <xrpld/app/misc/AmendmentTable.h>
#include <xrpld/app/misc/NetworkOPs.h>
#include <xrpld/rpc/detail/TransactionSign.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/json_writer.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/RPCErr.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/protocol/digest.h>
#include <xrpl/protocol/jss.h>
@@ -31,6 +35,14 @@
#include <magic_enum.hpp>
#include <sstream>
#define MAGIC_ENUM(x, _min, _max) \
template <> \
struct magic_enum::customize::enum_range<x> \
{ \
static constexpr int min = _min; \
static constexpr int max = _max; \
};
#define MAGIC_ENUM_16(x) \
template <> \
struct magic_enum::customize::enum_range<x> \
@@ -46,6 +58,15 @@
static constexpr bool is_flags = true; \
};
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);
MAGIC_ENUM_FLAG(ripple::OfferCreateFlags);
@@ -171,19 +192,24 @@ private:
ret[jss::TYPES]["Done"] = -1;
std::map<int32_t, std::string> type_map{{-1, "Done"}};
for (auto const& [rawName, typeValue] : sTypeMap)
for (auto const& entry : magic_enum::enum_entries<SerializedTypeID>())
{
std::string typeName =
translate(std::string(rawName).substr(4) /* remove STI_ */);
ret[jss::TYPES][typeName] = typeValue;
type_map[typeValue] = typeName;
const auto name = entry.second;
std::string type_name =
translate(name.data() + 4 /* remove STI_ */);
int32_t type_value = static_cast<int32_t>(entry.first);
ret[jss::TYPES][type_name] = type_value;
type_map[type_value] = type_name;
}
ret[jss::LEDGER_ENTRY_TYPES] = Json::objectValue;
ret[jss::LEDGER_ENTRY_TYPES][jss::Invalid] = -1;
for (auto const& f : LedgerFormats::getInstance())
for (auto const& entry : magic_enum::enum_entries<LedgerEntryType>())
{
ret[jss::LEDGER_ENTRY_TYPES][f.getName()] = f.getType();
const auto name = entry.second;
std::string type_name = translate(name.data() + 2 /* remove lt_ */);
int32_t type_value = static_cast<int32_t>(entry.first);
ret[jss::LEDGER_ENTRY_TYPES][type_name] = type_value;
}
ret[jss::FIELDS] = Json::arrayValue;
@@ -300,16 +326,71 @@ private:
}
ret[jss::TRANSACTION_RESULTS] = Json::objectValue;
for (auto const& [code, terInfo] : transResults())
for (auto const& entry : magic_enum::enum_entries<TELcodes>())
{
ret[jss::TRANSACTION_RESULTS][terInfo.first] = code;
const auto name = entry.second;
ret[jss::TRANSACTION_RESULTS][STR(name)] =
static_cast<int32_t>(entry.first);
}
for (auto const& entry : magic_enum::enum_entries<TEMcodes>())
{
const auto name = entry.second;
ret[jss::TRANSACTION_RESULTS][STR(name)] =
static_cast<int32_t>(entry.first);
}
for (auto const& entry : magic_enum::enum_entries<TEFcodes>())
{
const auto name = entry.second;
ret[jss::TRANSACTION_RESULTS][STR(name)] =
static_cast<int32_t>(entry.first);
}
for (auto const& entry : magic_enum::enum_entries<TERcodes>())
{
const auto name = entry.second;
ret[jss::TRANSACTION_RESULTS][STR(name)] =
static_cast<int32_t>(entry.first);
}
for (auto const& entry : magic_enum::enum_entries<TEScodes>())
{
const auto name = entry.second;
ret[jss::TRANSACTION_RESULTS][STR(name)] =
static_cast<int32_t>(entry.first);
}
for (auto const& entry : magic_enum::enum_entries<TECcodes>())
{
const auto name = entry.second;
ret[jss::TRANSACTION_RESULTS][STR(name)] =
static_cast<int32_t>(entry.first);
}
auto const translate_tt = [](std::string inp) -> std::string {
if (inp == "Amendment")
return "EnableAmendment";
if (inp == "Fee")
return "SetFee";
if (inp == "PaychanClaim")
return "PaymentChannelClaim";
if (inp == "PaychanCreate")
return "PaymentChannelCreate";
if (inp == "PaychanFund")
return "PaymentChannelFund";
if (inp == "RegularKeySet")
return "SetRegularKey";
if (inp == "HookSet")
return "SetHook";
if (inp == "RemarksSet")
return "SetRemarks";
return inp;
};
ret[jss::TRANSACTION_TYPES] = Json::objectValue;
ret[jss::TRANSACTION_TYPES][jss::Invalid] = -1;
for (auto const& f : TxFormats::getInstance())
for (auto const& entry : magic_enum::enum_entries<TxType>())
{
ret[jss::TRANSACTION_TYPES][f.getName()] = f.getType();
const auto name = entry.second;
std::string type_name = translate_tt(translate(name.data() + 2));
int32_t type_value = static_cast<int32_t>(entry.first);
ret[jss::TRANSACTION_TYPES][type_name] = type_value;
}
// Transaction Flags: