Merge branch 'ripple/se/fees' of https://github.com/XRPLF/rippled into ripple/smart-escrow

This commit is contained in:
Mayukha Vadari
2026-04-03 10:50:09 -04:00
87 changed files with 401 additions and 321 deletions

View File

@@ -76,11 +76,11 @@ fi
if ! grep -q 'Dev Null' src/test/rpc/ValidatorInfo_test.cpp; then
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ValidatorInfo_test.cpp)" > src/test/rpc/ValidatorInfo_test.cpp
fi
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/DoManifest.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/DoManifest.cpp)" > src/xrpld/rpc/handlers/DoManifest.cpp
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/server_info/Manifest.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/server_info/Manifest.cpp)" > src/xrpld/rpc/handlers/server_info/Manifest.cpp
fi
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/ValidatorInfo.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/ValidatorInfo.cpp
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp; then
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp
fi
if ! grep -q 'Bougalis' include/xrpl/basics/SlabAllocator.h; then
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/SlabAllocator.h)" > include/xrpl/basics/SlabAllocator.h # cspell: ignore Nikolaos Bougalis nikb

View File

@@ -143,7 +143,7 @@ public:
Serializer msg;
msg.add64(v);
auto const data = msg.getData();
auto data = msg.getData();
#ifdef DEBUG_OUTPUT
std::cout << "m: " << std::setw(20) << mantissa() << ", e: " << std::setw(12) << exponent()

View File

@@ -14,7 +14,7 @@ getIntBytes(STBase const* obj)
{
static_assert(std::is_integral<T>::value, "Only integral types");
auto const& num(static_cast<STInteger<T> const*>(obj));
auto const& num(static_cast<STInteger<T> const*>(obj)); // NOLINT
T const data = adjustWasmEndianess(num->value());
auto const* b = reinterpret_cast<uint8_t const*>(&data);
auto const* e = reinterpret_cast<uint8_t const*>(&data + 1);
@@ -42,13 +42,13 @@ getAnyFieldData(STBase const* obj)
return Unexpected(HostFunctionError::NOT_LEAF_FIELD);
case STI_ACCOUNT: {
auto const* account(dynamic_cast<STAccount const*>(obj));
auto const* account(static_cast<STAccount const*>(obj)); // NOLINT
auto const& data = account->value();
return Bytes{data.begin(), data.end()};
}
case STI_ISSUE: {
auto const* issue(dynamic_cast<STIssue const*>(obj));
auto const* issue(static_cast<STIssue const*>(obj)); // NOLINT
Asset const& asset(issue->value());
// XRP and IOU will be processed by serializer
if (asset.holds<MPTIssue>())
@@ -61,7 +61,7 @@ getAnyFieldData(STBase const* obj)
}
case STI_VL: {
auto const* vl(dynamic_cast<STBlob const*>(obj));
auto const* vl(static_cast<STBlob const*>(obj)); // NOLINT
auto const& data = vl->value();
return Bytes{data.begin(), data.end()};
}
@@ -84,7 +84,7 @@ getAnyFieldData(STBase const* obj)
// LCOV_EXCL_STOP
case STI_UINT256: {
auto const* uint256Obj(dynamic_cast<STUInt256 const*>(obj));
auto const* uint256Obj(static_cast<STUInt256 const*>(obj)); // NOLINT
auto const& data = uint256Obj->value();
return Bytes{data.begin(), data.end()};
}
@@ -165,14 +165,14 @@ locateField(STObject const& obj, Slice const& locator)
if (STI_ARRAY == field->getSType())
{
auto const* arr = dynamic_cast<STArray const*>(field);
auto const* arr = static_cast<STArray const*>(field); // NOLINT
if (sfieldCode < 0 || std::cmp_greater_equal(sfieldCode, arr->size()))
return Unexpected(HostFunctionError::INDEX_OUT_OF_BOUNDS);
field = &(arr->operator[](sfieldCode));
}
else if (STI_OBJECT == field->getSType())
{
auto const* o = dynamic_cast<STObject const*>(field);
auto const* o = static_cast<STObject const*>(field); // NOLINT
auto const it = knownSFields.find(sfieldCode);
if (it == knownSFields.end())
@@ -183,7 +183,7 @@ locateField(STObject const& obj, Slice const& locator)
}
else if (STI_VECTOR256 == field->getSType())
{
auto const* v = dynamic_cast<STVector256 const*>(field);
auto const* v = static_cast<STVector256 const*>(field); // NOLINT
if (sfieldCode < 0 || std::cmp_greater_equal(sfieldCode, v->size()))
return Unexpected(HostFunctionError::INDEX_OUT_OF_BOUNDS);
return FieldValue(&(v->operator[](sfieldCode)));
@@ -206,9 +206,9 @@ getArrayLen(FieldValue const& variantField)
if (STBase const* const* field = std::get_if<STBase const*>(&variantField))
{
if ((*field)->getSType() == STI_VECTOR256)
return dynamic_cast<STVector256 const*>(*field)->size();
return static_cast<STVector256 const*>(*field)->size(); // NOLINT
if ((*field)->getSType() == STI_ARRAY)
return dynamic_cast<STArray const*>(*field)->size();
return static_cast<STArray const*>(*field)->size(); // NOLINT
}
// uint256 is not an array so that variant should still return NO_ARRAY

View File

@@ -328,7 +328,7 @@ static inline HostFunctions*
getHF(void* env)
{
auto const* udata = reinterpret_cast<WasmUserData*>(env);
HostFunctions const* hf = reinterpret_cast<HostFunctions*>(udata->first);
HostFunctions* hf = reinterpret_cast<HostFunctions*>(udata->first); // NOLINT
return hf;
}
@@ -341,7 +341,7 @@ checkGas(void* env)
auto const* runtime = reinterpret_cast<InstanceWrapper const*>(hf->getRT());
if (runtime == nullptr)
{
wasm_trap_t const* trap = reinterpret_cast<wasm_trap_t*>(
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
WasmEngine::instance().newTrap("hf no runtime")); // LCOV_EXCL_LINE
return Unexpected(trap); // LCOV_EXCL_LINE
}
@@ -352,14 +352,14 @@ checkGas(void* env)
if (runtime->setGas(x) < 0)
{
wasm_trap_t const* trap = reinterpret_cast<wasm_trap_t*>(
wasm_trap_t* trap = reinterpret_cast<wasm_trap_t*>( // NOLINT
WasmEngine::instance().newTrap("can't set gas")); // LCOV_EXCL_LINE
return Unexpected(trap); // LCOV_EXCL_LINE
}
if (gas < impFunc.gas)
{
wasm_trap_t const* trap =
wasm_trap_t* const trap = // NOLINT
reinterpret_cast<wasm_trap_t*>(WasmEngine::instance().newTrap("hf out of gas"));
return Unexpected(trap);
}

View File

@@ -918,7 +918,7 @@ WasmiEngine::newTrap(std::string const& txt)
if (!txt.empty())
wasm_name_new(&msg, txt.size() + 1, txt.c_str()); // include 0
wasm_trap_t const* trap = wasm_trap_new(store_.get(), &msg);
wasm_trap_t* trap = wasm_trap_new(store_.get(), &msg); // NOLINT
if (!txt.empty())
wasm_byte_vec_delete(&msg);

View File

@@ -176,7 +176,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
Env env(
*this,
envconfig([](std::unique_ptr<Config> cfg) {
cfg->START_UP = StartUpType::FRESH;
cfg->START_UP = StartUpType::Fresh;
return cfg;
}),
features);
@@ -375,7 +375,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
// transaction processing This is necessary because the config
// cannot be updated in the middle of a test, and we cannot easily
// create a Smart Escrow while the compute limit is set to 0
env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto sle = std::make_shared<SLE>(keylet);
sle->setAccountID(sfAccount, alice.id());

View File

@@ -1,7 +1,7 @@
#include <test/jtx/TestSuite.h>
#include <xrpld/rpc/detail/RPCHelpers.h>
#include <xrpld/rpc/handlers/WalletPropose.h>
#include <xrpld/rpc/handlers/admin/keygen/WalletPropose.h>
#include <xrpl/json/json_value.h>
#include <xrpl/json/json_writer.h>

View File

@@ -7,7 +7,7 @@
#include <xrpld/overlay/detail/Tuning.h>
#include <xrpld/overlay/predicates.h>
#include <xrpld/peerfinder/make_Manager.h>
#include <xrpld/rpc/handlers/GetCounts.h>
#include <xrpld/rpc/handlers/admin/status/GetCounts.h>
#include <xrpld/rpc/json_body.h>
#include <xrpl/basics/base64.h>

View File

@@ -1,6 +1,6 @@
#include <xrpld/rpc/detail/Handler.h>
#include <xrpld/rpc/handlers/Handlers.h>
#include <xrpld/rpc/handlers/Version.h>
#include <xrpld/rpc/handlers/server_info/Version.h>
#include <xrpl/basics/contract.h>
#include <xrpl/protocol/ApiVersion.h>
@@ -75,7 +75,7 @@ Handler const handlerArray[]{
{"account_nfts", byRef(&doAccountNFTs), Role::USER, NO_CONDITION},
{"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
{"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
{"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
{"account_tx", byRef(&doAccountTx), Role::USER, NO_CONDITION},
{"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
{"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
{"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},

View File

@@ -0,0 +1,71 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/detail/RPCHelpers.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/PayChan.h>
#include <xrpl/protocol/RPCErr.h>
#include <xrpl/protocol/jss.h>
#include <optional>
namespace xrpl {
// {
// public_key: <public_key>
// channel_id: 256-bit channel id
// drops: 64-bit uint (as string)
// signature: signature to verify
// }
Json::Value
doChannelVerify(RPC::JsonContext& context)
{
auto const& params(context.params);
for (auto const& p : {jss::public_key, jss::channel_id, jss::amount, jss::signature})
{
if (!params.isMember(p))
return RPC::missing_field_error(p);
}
std::optional<PublicKey> pk;
{
std::string const strPk = params[jss::public_key].asString();
pk = parseBase58<PublicKey>(TokenType::AccountPublic, strPk);
if (!pk)
{
auto pkHex = strUnHex(strPk);
if (!pkHex)
return rpcError(rpcPUBLIC_MALFORMED);
auto const pkType = publicKeyType(makeSlice(*pkHex));
if (!pkType)
return rpcError(rpcPUBLIC_MALFORMED);
pk.emplace(makeSlice(*pkHex));
}
}
uint256 channelId;
if (!channelId.parseHex(params[jss::channel_id].asString()))
return rpcError(rpcCHANNEL_MALFORMED);
std::optional<std::uint64_t> const optDrops =
params[jss::amount].isString() ? to_uint64(params[jss::amount].asString()) : std::nullopt;
if (!optDrops)
return rpcError(rpcCHANNEL_AMT_MALFORMED);
std::uint64_t const drops = *optDrops;
auto sig = strUnHex(params[jss::signature].asString());
if (!sig || sig->empty())
return rpcError(rpcINVALID_PARAMS);
Serializer msg;
serializePayChanAuthorization(msg, channelId, XRPAmount(drops));
Json::Value result;
result[jss::signature_verified] = verify(*pk, msg.slice(), makeSlice(*sig));
return result;
}
} // namespace xrpl

View File

@@ -1,6 +1,6 @@
#pragma once
#include <xrpld/rpc/handlers/LedgerHandler.h>
#include <xrpld/rpc/handlers/ledger/Ledger.h>
namespace xrpl {
@@ -19,7 +19,7 @@ doAccountObjects(RPC::JsonContext&);
Json::Value
doAccountOffers(RPC::JsonContext&);
Json::Value
doAccountTxJson(RPC::JsonContext&);
doAccountTx(RPC::JsonContext&);
Json::Value
doAMMInfo(RPC::JsonContext&);
Json::Value

View File

@@ -0,0 +1,160 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/detail/RPCHelpers.h>
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
#include <xrpld/rpc/detail/Tuning.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/RPCErr.h>
#include <xrpl/protocol/jss.h>
#include <xrpl/protocol/nftPageMask.h>
#include <xrpl/resource/Fees.h>
#include <xrpl/tx/transactors/nft/NFTokenUtils.h>
namespace xrpl {
/** General RPC command that can retrieve objects in the account root.
{
account: <account>
ledger_hash: <string> // optional
ledger_index: <string | unsigned integer> // optional
type: <string> // optional, defaults to all account objects types
limit: <integer> // optional
marker: <opaque> // optional, resume previous query
}
*/
Json::Value
doAccountNFTs(RPC::JsonContext& context)
{
auto const& params = context.params;
if (!params.isMember(jss::account))
return RPC::missing_field_error(jss::account);
if (!params[jss::account].isString())
return RPC::invalid_field_error(jss::account);
auto id = parseBase58<AccountID>(params[jss::account].asString());
if (!id)
{
return rpcError(rpcACT_MALFORMED);
}
std::shared_ptr<ReadView const> ledger;
auto result = RPC::lookupLedger(ledger, context);
if (ledger == nullptr)
return result;
auto const accountID{id.value()};
if (!ledger->exists(keylet::account(accountID)))
return rpcError(rpcACT_NOT_FOUND);
unsigned int limit = 0;
if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
return *err;
uint256 marker;
bool const markerSet = params.isMember(jss::marker);
if (markerSet)
{
auto const& m = params[jss::marker];
if (!m.isString())
return RPC::expected_field_error(jss::marker, "string");
if (!marker.parseHex(m.asString()))
return RPC::invalid_field_error(jss::marker);
}
auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
auto const last = keylet::nftpage_max(accountID);
auto cp = ledger->read(
Keylet(ltNFTOKEN_PAGE, ledger->succ(first.key, last.key.next()).value_or(last.key)));
std::uint32_t cnt = 0;
auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
// Continue iteration from the current page:
bool pastMarker = marker.isZero();
bool markerFound = false;
uint256 const maskedMarker = marker & nft::pageMask;
while (cp)
{
auto arr = cp->getFieldArray(sfNFTokens);
for (auto const& o : arr)
{
// Scrolling past the marker gets weird. We need to look at
// a couple of conditions.
//
// 1. If the low 96-bits don't match, then we compare only
// against the low 96-bits, since that's what determines
// the sort order of the pages.
//
// 2. However, within one page there can be a number of
// NFTokenIDs that all have the same low 96 bits. If we're
// in that case then we need to compare against the full
// 256 bits.
uint256 const nftokenID = o[sfNFTokenID];
uint256 const maskedNftokenID = nftokenID & nft::pageMask;
if (!pastMarker)
{
if (maskedNftokenID < maskedMarker)
continue;
if (maskedNftokenID == maskedMarker && nftokenID < marker)
continue;
if (nftokenID == marker)
{
markerFound = true;
continue;
}
}
if (markerSet && !markerFound)
return RPC::invalid_field_error(jss::marker);
pastMarker = true;
{
Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
// Pull out the components of the nft ID.
obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
obj[sfNFTokenTaxon.jsonName] = nft::toUInt32(nft::getTaxon(nftokenID));
obj[jss::nft_serial] = nft::getSerial(nftokenID);
if (std::uint16_t const xferFee = {nft::getTransferFee(nftokenID)})
obj[sfTransferFee.jsonName] = xferFee;
}
if (++cnt == limit)
{
result[jss::limit] = limit;
result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
return result;
}
}
if (auto npm = (*cp)[~sfNextPageMin])
{
cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
}
else
{
cp = nullptr;
}
}
if (markerSet && !markerFound)
return RPC::invalid_field_error(jss::marker);
result[jss::account] = toBase58(accountID);
context.loadType = Resource::feeMediumBurdenRPC;
return result;
}
} // namespace xrpl

View File

@@ -11,156 +11,11 @@
#include <xrpl/protocol/jss.h>
#include <xrpl/protocol/nftPageMask.h>
#include <xrpl/resource/Fees.h>
#include <xrpl/tx/transactors/nft/NFTokenUtils.h>
#include <string>
namespace xrpl {
/** General RPC command that can retrieve objects in the account root.
{
account: <account>
ledger_hash: <string> // optional
ledger_index: <string | unsigned integer> // optional
type: <string> // optional, defaults to all account objects types
limit: <integer> // optional
marker: <opaque> // optional, resume previous query
}
*/
Json::Value
doAccountNFTs(RPC::JsonContext& context)
{
auto const& params = context.params;
if (!params.isMember(jss::account))
return RPC::missing_field_error(jss::account);
if (!params[jss::account].isString())
return RPC::invalid_field_error(jss::account);
auto id = parseBase58<AccountID>(params[jss::account].asString());
if (!id)
{
return rpcError(rpcACT_MALFORMED);
}
std::shared_ptr<ReadView const> ledger;
auto result = RPC::lookupLedger(ledger, context);
if (ledger == nullptr)
return result;
auto const accountID{id.value()};
if (!ledger->exists(keylet::account(accountID)))
return rpcError(rpcACT_NOT_FOUND);
unsigned int limit = 0;
if (auto err = readLimitField(limit, RPC::Tuning::accountNFTokens, context))
return *err;
uint256 marker;
bool const markerSet = params.isMember(jss::marker);
if (markerSet)
{
auto const& m = params[jss::marker];
if (!m.isString())
return RPC::expected_field_error(jss::marker, "string");
if (!marker.parseHex(m.asString()))
return RPC::invalid_field_error(jss::marker);
}
auto const first = keylet::nftpage(keylet::nftpage_min(accountID), marker);
auto const last = keylet::nftpage_max(accountID);
auto cp = ledger->read(
Keylet(ltNFTOKEN_PAGE, ledger->succ(first.key, last.key.next()).value_or(last.key)));
std::uint32_t cnt = 0;
auto& nfts = (result[jss::account_nfts] = Json::arrayValue);
// Continue iteration from the current page:
bool pastMarker = marker.isZero();
bool markerFound = false;
uint256 const maskedMarker = marker & nft::pageMask;
while (cp)
{
auto arr = cp->getFieldArray(sfNFTokens);
for (auto const& o : arr)
{
// Scrolling past the marker gets weird. We need to look at
// a couple of conditions.
//
// 1. If the low 96-bits don't match, then we compare only
// against the low 96-bits, since that's what determines
// the sort order of the pages.
//
// 2. However, within one page there can be a number of
// NFTokenIDs that all have the same low 96 bits. If we're
// in that case then we need to compare against the full
// 256 bits.
uint256 const nftokenID = o[sfNFTokenID];
uint256 const maskedNftokenID = nftokenID & nft::pageMask;
if (!pastMarker)
{
if (maskedNftokenID < maskedMarker)
continue;
if (maskedNftokenID == maskedMarker && nftokenID < marker)
continue;
if (nftokenID == marker)
{
markerFound = true;
continue;
}
}
if (markerSet && !markerFound)
return RPC::invalid_field_error(jss::marker);
pastMarker = true;
{
Json::Value& obj = nfts.append(o.getJson(JsonOptions::none));
// Pull out the components of the nft ID.
obj[sfFlags.jsonName] = nft::getFlags(nftokenID);
obj[sfIssuer.jsonName] = to_string(nft::getIssuer(nftokenID));
obj[sfNFTokenTaxon.jsonName] = nft::toUInt32(nft::getTaxon(nftokenID));
obj[jss::nft_serial] = nft::getSerial(nftokenID);
if (std::uint16_t const xferFee = {nft::getTransferFee(nftokenID)})
obj[sfTransferFee.jsonName] = xferFee;
}
if (++cnt == limit)
{
result[jss::limit] = limit;
result[jss::marker] = to_string(o.getFieldH256(sfNFTokenID));
return result;
}
}
if (auto npm = (*cp)[~sfNextPageMin])
{
cp = ledger->read(Keylet(ltNFTOKEN_PAGE, *npm));
}
else
{
cp = nullptr;
}
}
if (markerSet && !markerFound)
return RPC::invalid_field_error(jss::marker);
result[jss::account] = toBase58(accountID);
context.loadType = Resource::feeMediumBurdenRPC;
return result;
}
/** Gathers all objects for an account in a ledger.
@param ledger Ledger to search account objects.
@param account AccountID to find objects for.

View File

@@ -364,7 +364,7 @@ populateJsonResponse(
// resume previous query
// }
Json::Value
doAccountTxJson(RPC::JsonContext& context)
doAccountTx(RPC::JsonContext& context)
{
if (!context.app.config().useTxTables())
return rpcError(rpcNOT_ENABLED);

View File

@@ -1,6 +1,6 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/detail/RPCHelpers.h>
#include <xrpld/rpc/handlers/WalletPropose.h>
#include <xrpld/rpc/handlers/admin/keygen/WalletPropose.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/protocol/ErrorCodes.h>

View File

@@ -9,7 +9,6 @@
#include <optional>
#include <string>
#include <utility>
namespace xrpl {
@@ -66,46 +65,4 @@ doPeerReservationsAdd(RPC::JsonContext& context)
return result;
}
Json::Value
doPeerReservationsDel(RPC::JsonContext& context)
{
auto const& params = context.params;
// We repeat much of the parameter parsing from `doPeerReservationsAdd`.
if (!params.isMember(jss::public_key))
return RPC::missing_field_error(jss::public_key);
if (!params[jss::public_key].isString())
return RPC::expected_field_error(jss::public_key, "a string");
std::optional<PublicKey> optPk =
parseBase58<PublicKey>(TokenType::NodePublic, params[jss::public_key].asString());
if (!optPk)
return rpcError(rpcPUBLIC_MALFORMED);
PublicKey const& nodeId = *optPk;
auto const previous = context.app.getPeerReservations().erase(nodeId);
Json::Value result{Json::objectValue};
if (previous)
{
result[jss::previous] = previous->toJson();
}
return result;
}
Json::Value
doPeerReservationsList(RPC::JsonContext& context)
{
auto const& reservations = context.app.getPeerReservations().list();
// Enumerate the reservations in context.app.getPeerReservations()
// as a Json::Value.
Json::Value result{Json::objectValue};
Json::Value& jaReservations = result[jss::reservations] = Json::arrayValue;
for (auto const& reservation : reservations)
{
jaReservations.append(reservation.toJson());
}
return result;
}
} // namespace xrpl

View File

@@ -0,0 +1,41 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/handlers/Handlers.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/RPCErr.h>
#include <xrpl/protocol/jss.h>
#include <optional>
namespace xrpl {
Json::Value
doPeerReservationsDel(RPC::JsonContext& context)
{
auto const& params = context.params;
// We repeat much of the parameter parsing from `doPeerReservationsAdd`.
if (!params.isMember(jss::public_key))
return RPC::missing_field_error(jss::public_key);
if (!params[jss::public_key].isString())
return RPC::expected_field_error(jss::public_key, "a string");
std::optional<PublicKey> optPk =
parseBase58<PublicKey>(TokenType::NodePublic, params[jss::public_key].asString());
if (!optPk)
return rpcError(rpcPUBLIC_MALFORMED);
PublicKey const& nodeId = *optPk;
auto const previous = context.app.getPeerReservations().erase(nodeId);
Json::Value result{Json::objectValue};
if (previous)
{
result[jss::previous] = previous->toJson();
}
return result;
}
} // namespace xrpl

View File

@@ -0,0 +1,24 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/handlers/Handlers.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/jss.h>
namespace xrpl {
Json::Value
doPeerReservationsList(RPC::JsonContext& context)
{
auto const& reservations = context.app.getPeerReservations().list();
// Enumerate the reservations in context.app.getPeerReservations()
// as a Json::Value.
Json::Value result{Json::objectValue};
Json::Value& jaReservations = result[jss::reservations] = Json::arrayValue;
for (auto const& reservation : reservations)
{
jaReservations.append(reservation.toJson());
}
return result;
}
} // namespace xrpl

View File

@@ -3,7 +3,6 @@
#include <xrpld/rpc/detail/RPCHelpers.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/PayChan.h>
#include <xrpl/protocol/RPCErr.h>
@@ -83,61 +82,4 @@ doChannelAuthorize(RPC::JsonContext& context)
return result;
}
// {
// public_key: <public_key>
// channel_id: 256-bit channel id
// drops: 64-bit uint (as string)
// signature: signature to verify
// }
Json::Value
doChannelVerify(RPC::JsonContext& context)
{
auto const& params(context.params);
for (auto const& p : {jss::public_key, jss::channel_id, jss::amount, jss::signature})
{
if (!params.isMember(p))
return RPC::missing_field_error(p);
}
std::optional<PublicKey> pk;
{
std::string const strPk = params[jss::public_key].asString();
pk = parseBase58<PublicKey>(TokenType::AccountPublic, strPk);
if (!pk)
{
auto pkHex = strUnHex(strPk);
if (!pkHex)
return rpcError(rpcPUBLIC_MALFORMED);
auto const pkType = publicKeyType(makeSlice(*pkHex));
if (!pkType)
return rpcError(rpcPUBLIC_MALFORMED);
pk.emplace(makeSlice(*pkHex));
}
}
uint256 channelId;
if (!channelId.parseHex(params[jss::channel_id].asString()))
return rpcError(rpcCHANNEL_MALFORMED);
std::optional<std::uint64_t> const optDrops =
params[jss::amount].isString() ? to_uint64(params[jss::amount].asString()) : std::nullopt;
if (!optDrops)
return rpcError(rpcCHANNEL_AMT_MALFORMED);
std::uint64_t const drops = *optDrops;
auto sig = strUnHex(params[jss::signature].asString());
if (!sig || sig->empty())
return rpcError(rpcINVALID_PARAMS);
Serializer msg;
serializePayChanAuthorization(msg, channelId, XRPAmount(drops));
Json::Value result;
result[jss::signature_verified] = verify(*pk, msg.slice(), makeSlice(*sig));
return result;
}
} // namespace xrpl

View File

@@ -3,7 +3,7 @@
#include <xrpld/rpc/GRPCHandlers.h>
#include <xrpld/rpc/Role.h>
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
#include <xrpld/rpc/handlers/LedgerHandler.h>
#include <xrpld/rpc/handlers/ledger/Ledger.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/jss.h>

View File

@@ -1,7 +1,7 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/GRPCHandlers.h>
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
#include <xrpld/rpc/handlers/LedgerEntryHelpers.h>
#include <xrpld/rpc/handlers/ledger/LedgerEntryHelpers.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/basics/strHex.h>

View File

@@ -0,0 +1,21 @@
#include <xrpld/rpc/BookChanges.h>
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
#include <xrpl/ledger/ReadView.h>
namespace xrpl {
Json::Value
doBookChanges(RPC::JsonContext& context)
{
std::shared_ptr<ReadView const> ledger;
Json::Value result = RPC::lookupLedger(ledger, context);
if (ledger == nullptr)
return result;
return RPC::computeBookChanges(ledger);
}
} // namespace xrpl

View File

@@ -1,5 +1,4 @@
#include <xrpld/app/main/Application.h>
#include <xrpld/rpc/BookChanges.h>
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/detail/RPCHelpers.h>
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
@@ -205,16 +204,4 @@ doBookOffers(RPC::JsonContext& context)
return jvResult;
}
Json::Value
doBookChanges(RPC::JsonContext& context)
{
std::shared_ptr<ReadView const> ledger;
Json::Value result = RPC::lookupLedger(ledger, context);
if (ledger == nullptr)
return result;
return RPC::computeBookChanges(ledger);
}
} // namespace xrpl

View File

@@ -0,0 +1,24 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/handlers/orderbook/NFTOffersHelpers.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/RPCErr.h>
#include <xrpl/protocol/jss.h>
namespace xrpl {
Json::Value
doNFTBuyOffers(RPC::JsonContext& context)
{
if (!context.params.isMember(jss::nft_id))
return RPC::missing_field_error(jss::nft_id);
uint256 nftId;
if (!nftId.parseHex(context.params[jss::nft_id].asString()))
return RPC::invalid_field_error(jss::nft_id);
return enumerateNFTOffers(context, nftId, keylet::nft_buys(nftId));
}
} // namespace xrpl

View File

@@ -1,3 +1,5 @@
#pragma once
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/detail/RPCHelpers.h>
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
@@ -14,7 +16,7 @@
namespace xrpl {
static void
inline void
appendNftOfferJson(
Application const& app,
std::shared_ptr<SLE const> const& offer,
@@ -42,7 +44,7 @@ appendNftOfferJson(
// limit: integer // optional
// marker: opaque // optional, resume previous query
// }
static Json::Value
inline Json::Value
enumerateNFTOffers(RPC::JsonContext& context, uint256 const& nftId, Keylet const& directory)
{
unsigned int limit = 0;
@@ -127,32 +129,4 @@ enumerateNFTOffers(RPC::JsonContext& context, uint256 const& nftId, Keylet const
return result;
}
Json::Value
doNFTSellOffers(RPC::JsonContext& context)
{
if (!context.params.isMember(jss::nft_id))
return RPC::missing_field_error(jss::nft_id);
uint256 nftId;
if (!nftId.parseHex(context.params[jss::nft_id].asString()))
return RPC::invalid_field_error(jss::nft_id);
return enumerateNFTOffers(context, nftId, keylet::nft_sells(nftId));
}
Json::Value
doNFTBuyOffers(RPC::JsonContext& context)
{
if (!context.params.isMember(jss::nft_id))
return RPC::missing_field_error(jss::nft_id);
uint256 nftId;
if (!nftId.parseHex(context.params[jss::nft_id].asString()))
return RPC::invalid_field_error(jss::nft_id);
return enumerateNFTOffers(context, nftId, keylet::nft_buys(nftId));
}
} // namespace xrpl

View File

@@ -0,0 +1,24 @@
#include <xrpld/rpc/Context.h>
#include <xrpld/rpc/handlers/orderbook/NFTOffersHelpers.h>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/RPCErr.h>
#include <xrpl/protocol/jss.h>
namespace xrpl {
Json::Value
doNFTSellOffers(RPC::JsonContext& context)
{
if (!context.params.isMember(jss::nft_id))
return RPC::missing_field_error(jss::nft_id);
uint256 nftId;
if (!nftId.parseHex(context.params[jss::nft_id].asString()))
return RPC::invalid_field_error(jss::nft_id);
return enumerateNFTOffers(context, nftId, keylet::nft_sells(nftId));
}
} // namespace xrpl