mirror of
https://github.com/Xahau/xahaud.git
synced 2026-01-25 00:55:17 +00:00
Compare commits
8 Commits
remit_squa
...
attestatio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738a4c1e87 | ||
|
|
df9ed403ad | ||
|
|
deb4b34b9b | ||
|
|
d0baeab32f | ||
|
|
72016c3e0e | ||
|
|
54211fb63b | ||
|
|
27f43ba9ee | ||
|
|
7881b7f69f |
@@ -455,7 +455,7 @@ target_sources (rippled PRIVATE
|
||||
src/ripple/app/tx/impl/GenesisMint.cpp
|
||||
src/ripple/app/tx/impl/Import.cpp
|
||||
src/ripple/app/tx/impl/Invoke.cpp
|
||||
src/ripple/app/tx/impl/Remit.cpp
|
||||
src/ripple/app/tx/impl/Attest.cpp
|
||||
src/ripple/app/tx/impl/SetSignerList.cpp
|
||||
src/ripple/app/tx/impl/SetTrust.cpp
|
||||
src/ripple/app/tx/impl/SignerEntries.cpp
|
||||
@@ -741,7 +741,6 @@ if (tests)
|
||||
src/test/app/RCLCensorshipDetector_test.cpp
|
||||
src/test/app/RCLValidations_test.cpp
|
||||
src/test/app/Regression_test.cpp
|
||||
src/test/app/Remit_test.cpp
|
||||
src/test/app/SHAMapStore_test.cpp
|
||||
src/test/app/SetAuth_test.cpp
|
||||
src/test/app/SetRegularKey_test.cpp
|
||||
@@ -757,6 +756,7 @@ if (tests)
|
||||
src/test/app/ValidatorList_test.cpp
|
||||
src/test/app/ValidatorSite_test.cpp
|
||||
src/test/app/SetHook_test.cpp
|
||||
src/test/app/SetHookTSH_test.cpp
|
||||
src/test/app/Wildcard_test.cpp
|
||||
src/test/app/XahauGenesis_test.cpp
|
||||
src/test/app/tx/apply_test.cpp
|
||||
@@ -890,7 +890,6 @@ if (tests)
|
||||
src/test/jtx/impl/rate.cpp
|
||||
src/test/jtx/impl/regkey.cpp
|
||||
src/test/jtx/impl/reward.cpp
|
||||
src/test/jtx/impl/remit.cpp
|
||||
src/test/jtx/impl/sendmax.cpp
|
||||
src/test/jtx/impl/seq.cpp
|
||||
src/test/jtx/impl/sig.cpp
|
||||
@@ -899,6 +898,7 @@ if (tests)
|
||||
src/test/jtx/impl/token.cpp
|
||||
src/test/jtx/impl/trust.cpp
|
||||
src/test/jtx/impl/txflags.cpp
|
||||
src/test/jtx/impl/unl.cpp
|
||||
src/test/jtx/impl/uritoken.cpp
|
||||
src/test/jtx/impl/utility.cpp
|
||||
|
||||
|
||||
182
src/ripple/app/tx/impl/Attest.cpp
Normal file
182
src/ripple/app/tx/impl/Attest.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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/tx/impl/Attest.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
Attest::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
return TxConsequences{ctx.tx, TxConsequences::normal};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
Attest::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto const flags = ctx.tx.getFlags();
|
||||
|
||||
if (flags & tfAttestMask)
|
||||
return temINVALID_FLAG;
|
||||
|
||||
bool const hasTxnID = ctx.tx.isFieldPresent(sfAttestedTxnID);
|
||||
bool const hasAccID = ctx.tx.isFieldPresent(sfAttestedAccID);
|
||||
|
||||
if ((hasTxnID && hasAccID) || (!hasTxnID && !hasAccID))
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Attest: must specify exactly one of: AttestedTxnID, AttestedAccID";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
TER
|
||||
Attest::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
if (!ctx.view.rules().enabled(featureAttestations))
|
||||
return temDISABLED;
|
||||
|
||||
auto const id = ctx.tx[sfAccount];
|
||||
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
Keylet kl =
|
||||
ctx.tx.isFieldPresent(sfAttestedTxnID)
|
||||
? keylet::attestationTxn(id, ctx.tx.getFieldH256(sfAttestedTxnID))
|
||||
: keylet::attestationAcc(id, ctx.tx.getAccountID(sfAttestedAccID));
|
||||
|
||||
uint32_t flags = ctx.tx.getFlags();
|
||||
|
||||
bool const isDelete = (flags & tfDeleteAttestation) == tfDeleteAttestation;
|
||||
bool const exists = ctx.view.exists(kl);
|
||||
|
||||
if (exists && !isDelete)
|
||||
return tecDUPLICATE;
|
||||
else if (!exists && isDelete)
|
||||
return tecNO_ENTRY;
|
||||
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
Attest::doApply()
|
||||
{
|
||||
auto j = ctx_.app.journal("View");
|
||||
|
||||
auto const sle = view().peek(keylet::account(account_));
|
||||
if (!sle)
|
||||
return tefINTERNAL;
|
||||
|
||||
Keylet kl =
|
||||
ctx_.tx.isFieldPresent(sfAttestedTxnID)
|
||||
? keylet::attestationTxn(account_, ctx_.tx.getFieldH256(sfAttestedTxnID))
|
||||
: keylet::attestationAcc(account_, ctx_.tx.getAccountID(sfAttestedAccID));
|
||||
|
||||
uint32_t flags = ctx_.tx.getFlags();
|
||||
|
||||
bool const isDelete = (flags & tfDeleteAttestation) == tfDeleteAttestation;
|
||||
bool const exists = view().exists(kl);
|
||||
|
||||
// check for sufficient reserves
|
||||
if (!isDelete)
|
||||
{
|
||||
STAmount const reserve{
|
||||
view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
|
||||
|
||||
STAmount const afterFee =
|
||||
mPriorBalance - ctx_.tx.getFieldAmount(sfFee).xrp();
|
||||
|
||||
if (afterFee > mPriorBalance || afterFee < reserve)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
// delete mode
|
||||
if (exists && isDelete)
|
||||
{
|
||||
auto sleA = view().peek(kl);
|
||||
|
||||
AccountID owner = sleA->getAccountID(sfOwner);
|
||||
|
||||
auto const page = (*sleA)[sfOwnerNode];
|
||||
if (!view().dirRemove(
|
||||
keylet::ownerDir(owner), page, kl.key, true))
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Could not remove Attestation from owner directory";
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
view().erase(sleA);
|
||||
adjustOwnerCount(view(), sle, -1, j);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
// create mode
|
||||
else if (!exists && !isDelete)
|
||||
{
|
||||
auto sleA = std::make_shared<SLE>(kl);
|
||||
|
||||
sleA->setFieldU16(sfLedgerEntryType, ltATTESTATION);
|
||||
sleA->setAccountID(sfOwner, account_);
|
||||
|
||||
if (ctx_.tx.isFieldPresent(sfAttestedTxnID))
|
||||
sleA->setFieldH256(sfAttestedTxnID, ctx_.tx.getFieldH256(sfAttestedTxnID));
|
||||
else
|
||||
sleA->setAccountID(sfAttestedAccID, ctx_.tx.getAccountID(sfAttestedAccID));
|
||||
|
||||
|
||||
auto const page = view().dirInsert(
|
||||
keylet::ownerDir(account_), kl, describeOwnerDir(account_));
|
||||
|
||||
JLOG(j_.trace())
|
||||
<< "Adding Attestation to owner directory " << to_string(kl.key)
|
||||
<< ": " << (page ? "success" : "failure");
|
||||
|
||||
if (!page)
|
||||
return tecDIR_FULL;
|
||||
|
||||
sleA->setFieldU64(sfOwnerNode, *page);
|
||||
view().insert(sleA);
|
||||
|
||||
adjustOwnerCount(view(), sle, 1, j);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
// everything else is invalid
|
||||
else
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
Attest::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
return Transactor::calculateBaseFee(view, tx);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TX_SIMPLE_PAYMENT_H_INCLUDED
|
||||
#define RIPPLE_TX_SIMPLE_PAYMENT_H_INCLUDED
|
||||
#ifndef RIPPLE_TX_ATTEST_H_INCLUDED
|
||||
#define RIPPLE_TX_ATTEST_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
@@ -27,12 +27,12 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Remit : public Transactor
|
||||
class Attest : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit Remit(ApplyContext& ctx) : Transactor(ctx)
|
||||
explicit Attest(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ public:
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
@@ -492,6 +492,7 @@ LedgerEntryTypesMatch::visitEntry(
|
||||
case ltURI_TOKEN:
|
||||
case ltIMPORT_VLSEQ:
|
||||
case ltUNL_REPORT:
|
||||
case ltATTESTATION:
|
||||
break;
|
||||
default:
|
||||
invalidTypeAdded_ = true;
|
||||
@@ -597,8 +598,7 @@ ValidNewAccountRoot::finalize(
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((tt == ttPAYMENT || tt == ttIMPORT || tt == ttGENESIS_MINT ||
|
||||
tt == ttREMIT) &&
|
||||
if ((tt == ttPAYMENT || tt == ttIMPORT || tt == ttGENESIS_MINT) &&
|
||||
result == tesSUCCESS)
|
||||
{
|
||||
std::uint32_t const startingSeq{
|
||||
|
||||
@@ -1,501 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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/tx/impl/Remit.h>
|
||||
#include <ripple/app/tx/impl/URIToken.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
Remit::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
return TxConsequences{ctx.tx, TxConsequences::normal};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
Remit::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (ctx.tx.getFlags() & tfUniversalMask)
|
||||
{
|
||||
// There are no flags (other than universal).
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
AccountID const dstID = ctx.tx.getAccountID(sfDestination);
|
||||
AccountID const srcID = ctx.tx.getAccountID(sfAccount);
|
||||
|
||||
if (dstID == srcID)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Remit to self.";
|
||||
return temREDUNDANT;
|
||||
}
|
||||
|
||||
// sanity check amounts
|
||||
if (ctx.tx.isFieldPresent(sfAmounts))
|
||||
{
|
||||
std::map<Currency, std::set<AccountID>> already;
|
||||
bool nativeAlready = false;
|
||||
|
||||
STArray const& sEntries(ctx.tx.getFieldArray(sfAmounts));
|
||||
for (STObject const& sEntry : sEntries)
|
||||
{
|
||||
// Validate the AmountEntry.
|
||||
if (sEntry.getFName() != sfAmountEntry)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed: Expected AmountEntry.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
STAmount const amount = sEntry.getFieldAmount(sfAmount);
|
||||
if (!isLegalNet(amount) || amount.signum() <= 0)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: bad amount: "
|
||||
<< amount.getFullText();
|
||||
return temBAD_AMOUNT;
|
||||
}
|
||||
|
||||
if (isBadCurrency(amount.getCurrency()))
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
|
||||
return temBAD_CURRENCY;
|
||||
}
|
||||
|
||||
if (isXRP(amount))
|
||||
{
|
||||
if (nativeAlready)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Native "
|
||||
"Currency appears more than once.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
nativeAlready = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto found = already.find(amount.getCurrency());
|
||||
if (found == already.end())
|
||||
{
|
||||
already.emplace(
|
||||
amount.getCurrency(),
|
||||
std::set<AccountID>{amount.getIssuer()});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (found->second.find(amount.getIssuer()) != found->second.end())
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Issued Currency "
|
||||
"appears more than once.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
found->second.emplace(amount.getIssuer());
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check minturitoken
|
||||
if (ctx.tx.isFieldPresent(sfMintURIToken))
|
||||
{
|
||||
STObject const& mint = const_cast<ripple::STTx&>(ctx.tx)
|
||||
.getField(sfMintURIToken)
|
||||
.downcast<STObject>();
|
||||
// RH TODO: iterate mint fields detect any that shouldnt be there
|
||||
|
||||
Blob const uri = mint.getFieldVL(sfURI);
|
||||
if (uri.size() < 1 || uri.size() > 256)
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: URI was too short/long.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (!URIToken::validateUTF8(mint.getFieldVL(sfURI)))
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: Invalid UTF8 inside MintURIToken.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (mint.isFieldPresent(sfFlags))
|
||||
{
|
||||
if (mint.getFieldU32(sfFlags) & tfURITokenMintMask)
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
// check uritokenids for duplicates
|
||||
if (ctx.tx.isFieldPresent(sfURITokenIDs))
|
||||
{
|
||||
STVector256 ids = ctx.tx.getFieldV256(sfURITokenIDs);
|
||||
std::sort(ids.begin(), ids.end());
|
||||
if (std::adjacent_find(ids.begin(), ids.end()) != ids.end())
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: Duplicate URITokenID.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
}
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
TER
|
||||
Remit::doApply()
|
||||
{
|
||||
if (!view().rules().enabled(featureRemit) || !view().rules().enabled(featureURIToken))
|
||||
return temDISABLED;
|
||||
|
||||
Sandbox sb(&ctx_.view());
|
||||
|
||||
beast::Journal const& j = ctx_.journal;
|
||||
|
||||
auto const srcAccID = ctx_.tx[sfAccount];
|
||||
|
||||
auto sleSrcAcc = sb.peek(keylet::account(srcAccID));
|
||||
if (!sleSrcAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
XRPAmount const accountReserve{sb.fees().accountReserve(0)};
|
||||
XRPAmount const objectReserve{sb.fees().accountReserve(1) - accountReserve};
|
||||
|
||||
// amount of native tokens we will transfer to cover reserves for the
|
||||
// tls/acc/uritokens created, and native tokens listed in amounts
|
||||
XRPAmount nativeRemit{0};
|
||||
|
||||
AccountID const dstAccID{ctx_.tx[sfDestination]};
|
||||
auto sleDstAcc = sb.peek(keylet::account(dstAccID));
|
||||
auto const flags = !sleDstAcc ? 0 : sleDstAcc->getFlags();
|
||||
|
||||
// Check if the destination has disallowed incoming
|
||||
if (sb.rules().enabled(featureDisallowIncoming) &&
|
||||
(flags & lsfDisallowIncomingRemit))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// the destination may require a dest tag
|
||||
if ((flags & lsfRequireDestTag) &&
|
||||
!ctx_.tx.isFieldPresent(sfDestinationTag))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Remit: DestinationTag required for this destination.";
|
||||
return tecDST_TAG_NEEDED;
|
||||
}
|
||||
|
||||
// if the destination doesn't exist, create it.
|
||||
bool const createDst = !sleDstAcc;
|
||||
if (createDst)
|
||||
{
|
||||
// sender will pay the reserve
|
||||
nativeRemit += accountReserve;
|
||||
|
||||
// Create the account.
|
||||
std::uint32_t const seqno{
|
||||
sb.rules().enabled(featureXahauGenesis)
|
||||
? sb.info().parentCloseTime.time_since_epoch().count()
|
||||
: sb.rules().enabled(featureDeletableAccounts) ? sb.seq() : 1};
|
||||
|
||||
sleDstAcc = std::make_shared<SLE>(keylet::account(dstAccID));
|
||||
sleDstAcc->setAccountID(sfAccount, dstAccID);
|
||||
|
||||
sleDstAcc->setFieldU32(sfSequence, seqno);
|
||||
sleDstAcc->setFieldU32(sfOwnerCount, 0);
|
||||
|
||||
if (sb.exists(keylet::fees()) && sb.rules().enabled(featureXahauGenesis))
|
||||
{
|
||||
auto sleFees = sb.peek(keylet::fees());
|
||||
uint64_t accIdx = sleFees->isFieldPresent(sfAccountCount)
|
||||
? sleFees->getFieldU64(sfAccountCount)
|
||||
: 0;
|
||||
sleDstAcc->setFieldU64(sfAccountIndex, accIdx);
|
||||
sleFees->setFieldU64(sfAccountCount, accIdx + 1);
|
||||
sb.update(sleFees);
|
||||
}
|
||||
|
||||
// we'll fix this up at the end
|
||||
sleDstAcc->setFieldAmount(sfBalance, STAmount{XRPAmount{0}});
|
||||
sb.insert(sleDstAcc);
|
||||
}
|
||||
|
||||
// if theres a minted uritoken the sender pays for that
|
||||
if (ctx_.tx.isFieldPresent(sfMintURIToken))
|
||||
{
|
||||
nativeRemit += objectReserve;
|
||||
STObject const& mint = const_cast<ripple::STTx&>(ctx_.tx)
|
||||
.getField(sfMintURIToken)
|
||||
.downcast<STObject>();
|
||||
|
||||
Blob const& mintURI = mint.getFieldVL(sfURI);
|
||||
|
||||
std::optional<uint256> mintDigest;
|
||||
if (mint.isFieldPresent(sfDigest))
|
||||
mintDigest = mint.getFieldH256(sfDigest);
|
||||
|
||||
Keylet kl = keylet::uritoken(srcAccID, mintURI);
|
||||
|
||||
// check that it doesn't already exist
|
||||
if (sb.exists(kl))
|
||||
{
|
||||
JLOG(j.trace()) << "Remit: tried to creat duplicate URIToken. Tx: "
|
||||
<< ctx_.tx.getTransactionID();
|
||||
return tecDUPLICATE;
|
||||
}
|
||||
|
||||
auto sleMint = std::make_shared<SLE>(kl);
|
||||
|
||||
sleMint->setAccountID(sfOwner, dstAccID);
|
||||
sleMint->setAccountID(sfIssuer, srcAccID);
|
||||
|
||||
sleMint->setFieldVL(sfURI, mintURI);
|
||||
|
||||
if (mint.isFieldPresent(sfDigest))
|
||||
sleMint->setFieldH256(sfDigest, mint.getFieldH256(sfDigest));
|
||||
|
||||
sleMint->setFieldU32(
|
||||
sfFlags,
|
||||
mint.isFieldPresent(sfFlags) ? mint.getFieldU32(sfFlags) : 0);
|
||||
|
||||
auto const page = view().dirInsert(
|
||||
keylet::ownerDir(dstAccID), kl, describeOwnerDir(dstAccID));
|
||||
|
||||
JLOG(j_.trace()) << "Adding URIToken to owner directory "
|
||||
<< to_string(kl.key) << ": "
|
||||
<< (page ? "success" : "failure");
|
||||
|
||||
if (!page)
|
||||
return tecDIR_FULL;
|
||||
|
||||
sleMint->setFieldU64(sfOwnerNode, *page);
|
||||
sb.insert(sleMint);
|
||||
|
||||
// ensure there is a deletion blocker against the issuer now
|
||||
sleSrcAcc->setFieldU32(
|
||||
sfFlags, sleSrcAcc->getFlags() | lsfURITokenIssuer);
|
||||
|
||||
adjustOwnerCount(sb, sleDstAcc, 1, j);
|
||||
}
|
||||
|
||||
// iterate uritokens
|
||||
if (ctx_.tx.isFieldPresent(sfURITokenIDs))
|
||||
{
|
||||
STVector256 ids = ctx_.tx.getFieldV256(sfURITokenIDs);
|
||||
for (uint256 const klRaw : ids)
|
||||
{
|
||||
Keylet kl = keylet::unchecked(klRaw);
|
||||
auto sleU = sb.peek(kl);
|
||||
|
||||
// does it exist
|
||||
if (!sleU)
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: one or more uritokens did not exist "
|
||||
"on the source account.";
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
}
|
||||
|
||||
// is it a uritoken?
|
||||
if (sleU->getFieldU16(sfLedgerEntryType) != ltURI_TOKEN)
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: one or more supplied URITokenIDs was "
|
||||
"not actually a uritoken.";
|
||||
return tecNO_ENTRY;
|
||||
}
|
||||
|
||||
// is it our uritoken?
|
||||
if (sleU->getAccountID(sfOwner) != srcAccID)
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: one or more supplied URITokenIDs was "
|
||||
"not owned by sender.";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
// erase current sale offers, if any
|
||||
if (sleU->isFieldPresent(sfAmount))
|
||||
sleU->makeFieldAbsent(sfAmount);
|
||||
if (sleU->isFieldPresent(sfDestination))
|
||||
sleU->makeFieldAbsent(sfDestination);
|
||||
|
||||
// pay the reserve
|
||||
nativeRemit += objectReserve;
|
||||
|
||||
// remove from sender dir
|
||||
{
|
||||
auto const page = (*sleU)[sfOwnerNode];
|
||||
if (!sb.dirRemove(
|
||||
keylet::ownerDir(srcAccID), page, kl.key, true))
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Could not remove URIToken from owner directory";
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
adjustOwnerCount(sb, sleSrcAcc, -1, j);
|
||||
}
|
||||
|
||||
// add to dest dir
|
||||
{
|
||||
auto const page = sb.dirInsert(
|
||||
keylet::ownerDir(dstAccID), kl, describeOwnerDir(dstAccID));
|
||||
|
||||
JLOG(j_.trace()) << "Adding URIToken to owner directory "
|
||||
<< to_string(kl.key) << ": "
|
||||
<< (page ? "success" : "failure");
|
||||
|
||||
if (!page)
|
||||
return tecDIR_FULL;
|
||||
|
||||
sleU->setFieldU64(sfOwnerNode, *page);
|
||||
|
||||
adjustOwnerCount(sb, sleDstAcc, 1, j);
|
||||
}
|
||||
|
||||
// change the owner
|
||||
sleU->setAccountID(sfOwner, dstAccID);
|
||||
|
||||
sb.update(sleU);
|
||||
}
|
||||
}
|
||||
|
||||
// iterate trustlines
|
||||
if (ctx_.tx.isFieldPresent(sfAmounts))
|
||||
{
|
||||
// process trustline remits
|
||||
STArray const& sEntries(ctx_.tx.getFieldArray(sfAmounts));
|
||||
for (STObject const& sEntry : sEntries)
|
||||
{
|
||||
STAmount const amount = sEntry.getFieldAmount(sfAmount);
|
||||
if (isXRP(amount))
|
||||
{
|
||||
// since we have to pay for all the created objects including
|
||||
// possibly the account itself this is paid right at the end,
|
||||
// and only if there is balance enough to cover.
|
||||
nativeRemit += amount.xrp();
|
||||
continue;
|
||||
}
|
||||
|
||||
AccountID const issuerAccID = amount.getIssuer();
|
||||
|
||||
// check permissions
|
||||
if (issuerAccID == srcAccID || issuerAccID == dstAccID)
|
||||
{
|
||||
// no permission check needed when the issuer sends out or a
|
||||
// subscriber sends back RH TODO: move this condition into
|
||||
// trustTransferAllowed, guarded by an amendment
|
||||
}
|
||||
else if (TER canXfer = trustTransferAllowed(
|
||||
sb,
|
||||
std::vector<AccountID>{srcAccID, dstAccID},
|
||||
amount.issue(),
|
||||
j);
|
||||
canXfer != tesSUCCESS)
|
||||
return canXfer;
|
||||
|
||||
// compute the amount the source will need to send
|
||||
// in remit the sender pays all transfer fees, so that
|
||||
// the destination can always be assured they got the exact amount
|
||||
// specified. therefore we need to compute the amount + transfer fee
|
||||
auto const srcAmt =
|
||||
issuerAccID != srcAccID && issuerAccID != dstAccID
|
||||
? multiply(amount, transferRate(sb, issuerAccID))
|
||||
: amount;
|
||||
|
||||
auto const dstAmt = amount;
|
||||
|
||||
STAmount availableFunds{
|
||||
accountFunds(sb, srcAccID, srcAmt, fhZERO_IF_FROZEN, j)};
|
||||
|
||||
if (availableFunds < srcAmt)
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
// if the target trustline doesn't exist we need to create it and
|
||||
// pay its reserve
|
||||
if (!sb.exists(keylet::line(
|
||||
issuerAccID == dstAccID ? srcAccID : dstAccID,
|
||||
issuerAccID,
|
||||
amount.getCurrency())))
|
||||
nativeRemit += objectReserve;
|
||||
|
||||
// action the transfer
|
||||
STAmount sentAmt;
|
||||
if (TER result =
|
||||
rippleSend(sb, srcAccID, dstAccID, dstAmt, sentAmt, j);
|
||||
result != tesSUCCESS)
|
||||
return result;
|
||||
|
||||
if (sentAmt != srcAmt)
|
||||
return tecINTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (nativeRemit < beast::zero)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (nativeRemit > beast::zero)
|
||||
{
|
||||
// ensure the account can cover the native remit
|
||||
if (mSourceBalance < nativeRemit)
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
// subtract the balance from the sender
|
||||
{
|
||||
STAmount bal = mSourceBalance;
|
||||
bal -= nativeRemit;
|
||||
if (bal < beast::zero || bal > mSourceBalance)
|
||||
return tecINTERNAL;
|
||||
sleSrcAcc->setFieldAmount(sfBalance, bal);
|
||||
}
|
||||
|
||||
// add the balance to the destination
|
||||
{
|
||||
STAmount bal = sleDstAcc->getFieldAmount(sfBalance);
|
||||
STAmount prior = bal;
|
||||
bal += nativeRemit;
|
||||
if (bal < beast::zero || bal < prior)
|
||||
return tecINTERNAL;
|
||||
sleDstAcc->setFieldAmount(sfBalance, bal);
|
||||
}
|
||||
}
|
||||
|
||||
// apply
|
||||
sb.update(sleSrcAcc);
|
||||
sb.update(sleDstAcc);
|
||||
sb.apply(ctx_.rawView());
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
Remit::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
XRPAmount extraFee{0};
|
||||
|
||||
if (tx.isFieldPresent(sfBlob))
|
||||
extraFee +=
|
||||
XRPAmount{static_cast<XRPAmount>(tx.getFieldVL(sfBlob).size())};
|
||||
|
||||
// RH TODO: add fees
|
||||
|
||||
return Transactor::calculateBaseFee(view, tx) + extraFee;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -577,14 +577,6 @@ SetAccount::doApply()
|
||||
uFlagsOut |= lsfDisallowIncomingTrustline;
|
||||
else if (uClearFlag == asfDisallowIncomingTrustline)
|
||||
uFlagsOut &= ~lsfDisallowIncomingTrustline;
|
||||
|
||||
if (ctx_.view().rules().enabled(featureRemit))
|
||||
{
|
||||
if (uSetFlag == asfDisallowIncomingRemit)
|
||||
uFlagsOut |= lsfDisallowIncomingRemit;
|
||||
else if (uClearFlag == asfDisallowIncomingRemit)
|
||||
uFlagsOut &= ~lsfDisallowIncomingRemit;
|
||||
}
|
||||
}
|
||||
|
||||
if (uFlagsIn != uFlagsOut)
|
||||
|
||||
@@ -85,6 +85,54 @@ preflight0(PreflightContext const& ctx)
|
||||
return temINVALID;
|
||||
}
|
||||
|
||||
// don't allow attestations unless enabled
|
||||
if (ctx.tx.isFieldPresent(sfAttesters))
|
||||
{
|
||||
if (!ctx.rules.enabled(featureAttestations))
|
||||
return temDISABLED;
|
||||
|
||||
// make sure they can't spam millions of attesters
|
||||
auto const& attesters = ctx.tx.getFieldArray(sfAttesters);
|
||||
if (attesters.empty() || attesters.size() > 32)
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "applyTransaction: attesters array too big (max 32) or empty.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
|
||||
// enforce that it must specify a last ledger seq
|
||||
if (!ctx.tx.isFieldPresent(sfLastLedgerSequence))
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "applyTransaction: txns with attesters must specify a last ledger sequence <= cur + 256";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// sanity check entries
|
||||
std::set<AccountID> used;
|
||||
for (auto const& attester: attesters)
|
||||
{
|
||||
if (attester.getFName() != sfAttesterEntry)
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "applyTransaction: attesters array contained non AttesterEntry object.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
AccountID const& id = attester.getAccountID(sfAccount);
|
||||
|
||||
if (used.find(id) != used.end())
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "applyTransaction: attesters array contained duplicate attester ID.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
used.emplace(id);
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -1928,6 +1976,62 @@ Transactor::operator()()
|
||||
}
|
||||
}
|
||||
|
||||
if (applied && ctx_.tx.isFieldPresent(sfAttesters) && view().rules().enabled(featureAttestations))
|
||||
{
|
||||
// delete used attestation objects
|
||||
|
||||
auto const& attesters = ctx_.tx.getFieldArray(sfAttesters);
|
||||
auto const txid = ctx_.tx.getTransactionID();
|
||||
|
||||
auto const& j = ctx_.app.journal("View");
|
||||
|
||||
for (auto const& attester : attesters)
|
||||
{
|
||||
Keylet kl = keylet::attestationTxn(attester.getAccountID(sfAccount), txid);
|
||||
if (!view().exists(kl))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Transactor: Warning!!! Attestation does not exist at end of attested txn "
|
||||
<< txid;
|
||||
continue;
|
||||
}
|
||||
|
||||
// remove from dir
|
||||
auto sleA = view().peek(kl);
|
||||
|
||||
if (!sleA->isFieldPresent(sfAttestedTxnID))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Transactor: Warning!!! Attestation is of the wrong type at end of attested txn "
|
||||
<< txid;
|
||||
continue;
|
||||
}
|
||||
|
||||
AccountID owner = sleA->getAccountID(sfOwner);
|
||||
auto sle = view().peek(keylet::account(owner));
|
||||
|
||||
if (!sle)
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Transactor: Warning!!! Attester account does not exist at the end of attested txn "
|
||||
<< txid;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const page = (*sleA)[sfOwnerNode];
|
||||
if (!view().dirRemove(
|
||||
keylet::ownerDir(owner), page, kl.key, true))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Could not remove Attestation from owner directory";
|
||||
continue;
|
||||
}
|
||||
|
||||
view().erase(sleA);
|
||||
adjustOwnerCount(view(), sle, -1, j);
|
||||
}
|
||||
}
|
||||
|
||||
// Post-application (Weak TSH/AAW) Hooks are executed here.
|
||||
// These TSH do not have the ability to rollback.
|
||||
// The callback, if any, is also executed here.
|
||||
|
||||
@@ -160,6 +160,7 @@ public:
|
||||
{
|
||||
// Most transactors do nothing
|
||||
// after checkSeq/Fee/Sign.
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@@ -103,7 +103,57 @@ URIToken::preflight(PreflightContext const& ctx)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (!validateUTF8(uri))
|
||||
if (!([](std::vector<uint8_t> const& u) -> bool {
|
||||
// this code is from
|
||||
// https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
|
||||
uint8_t const* s = (uint8_t const*)u.data();
|
||||
uint8_t const* end = s + u.size();
|
||||
while (s < end)
|
||||
{
|
||||
if (*s < 0x80)
|
||||
/* 0xxxxxxx */
|
||||
s++;
|
||||
else if ((s[0] & 0xe0) == 0xc0)
|
||||
{
|
||||
/* 110XXXXx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[0] & 0xfe) == 0xc0) /* overlong? */
|
||||
return false;
|
||||
else
|
||||
s += 2;
|
||||
}
|
||||
else if ((s[0] & 0xf0) == 0xe0)
|
||||
{
|
||||
/* 1110XXXX 10Xxxxxx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xe0 &&
|
||||
(s[1] & 0xe0) == 0x80) || /* overlong? */
|
||||
(s[0] == 0xed &&
|
||||
(s[1] & 0xe0) == 0xa0) || /* surrogate? */
|
||||
(s[0] == 0xef && s[1] == 0xbf &&
|
||||
(s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
|
||||
return false;
|
||||
else
|
||||
s += 3;
|
||||
}
|
||||
else if ((s[0] & 0xf8) == 0xf0)
|
||||
{
|
||||
/* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
|
||||
(s[3] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xf0 &&
|
||||
(s[1] & 0xf0) == 0x80) || /* overlong? */
|
||||
(s[0] == 0xf4 && s[1] > 0x8f) ||
|
||||
s[0] > 0xf4) /* > U+10FFFF? */
|
||||
return false;
|
||||
else
|
||||
s += 4;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})(uri))
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction. URI must be a "
|
||||
"valid utf-8 string.";
|
||||
|
||||
@@ -30,56 +30,6 @@ namespace ripple {
|
||||
class URIToken : public Transactor
|
||||
{
|
||||
public:
|
||||
bool inline static validateUTF8(std::vector<uint8_t> const& u)
|
||||
{
|
||||
// this code is from
|
||||
// https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
|
||||
uint8_t const* s = (uint8_t const*)u.data();
|
||||
uint8_t const* end = s + u.size();
|
||||
while (s < end)
|
||||
{
|
||||
if (*s < 0x80)
|
||||
/* 0xxxxxxx */
|
||||
s++;
|
||||
else if ((s[0] & 0xe0) == 0xc0)
|
||||
{
|
||||
/* 110XXXXx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[0] & 0xfe) == 0xc0) /* overlong? */
|
||||
return false;
|
||||
else
|
||||
s += 2;
|
||||
}
|
||||
else if ((s[0] & 0xf0) == 0xe0)
|
||||
{
|
||||
/* 1110XXXX 10Xxxxxx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
|
||||
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
|
||||
(s[0] == 0xef && s[1] == 0xbf &&
|
||||
(s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
|
||||
return false;
|
||||
else
|
||||
s += 3;
|
||||
}
|
||||
else if ((s[0] & 0xf8) == 0xf0)
|
||||
{
|
||||
/* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 ||
|
||||
(s[3] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */
|
||||
(s[0] == 0xf4 && s[1] > 0x8f) ||
|
||||
s[0] > 0xf4) /* > U+10FFFF? */
|
||||
return false;
|
||||
else
|
||||
s += 4;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};
|
||||
|
||||
explicit URIToken(ApplyContext& ctx) : Transactor(ctx)
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <ripple/app/tx/impl/GenesisMint.h>
|
||||
#include <ripple/app/tx/impl/Import.h>
|
||||
#include <ripple/app/tx/impl/Invoke.h>
|
||||
#include <ripple/app/tx/impl/Attest.h>
|
||||
#include <ripple/app/tx/impl/NFTokenAcceptOffer.h>
|
||||
#include <ripple/app/tx/impl/NFTokenBurn.h>
|
||||
#include <ripple/app/tx/impl/NFTokenCancelOffer.h>
|
||||
@@ -164,8 +165,8 @@ invoke_preflight(PreflightContext const& ctx)
|
||||
return invoke_preflight_helper<Import>(ctx);
|
||||
case ttINVOKE:
|
||||
return invoke_preflight_helper<Invoke>(ctx);
|
||||
case ttREMIT:
|
||||
return invoke_preflight_helper<Remit>(ctx);
|
||||
case ttATTEST:
|
||||
return invoke_preflight_helper<Attest>(ctx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -211,6 +212,27 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
return result;
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfAttesters) && ctx.view.rules().enabled(featureAttestations))
|
||||
{
|
||||
// check last ledger sequence
|
||||
if (!ctx.tx.isFieldPresent(sfLastLedgerSequence))
|
||||
return tecINTERNAL;
|
||||
|
||||
if (ctx.tx.getFieldU32(sfLastLedgerSequence) > ctx.view.seq() + 256)
|
||||
return tecLAST_LEDGER_SEQ_TOO_HIGH;
|
||||
|
||||
// check if the required attestations are present on ledger
|
||||
auto const& attesters = ctx.tx.getFieldArray(sfAttesters);
|
||||
|
||||
auto const txid = ctx.tx.getTransactionID();
|
||||
|
||||
// each required attestation must exist on the ledger to allow the txn through
|
||||
// otherwise it gets marked retry
|
||||
for (auto const& attester : attesters)
|
||||
if (!ctx.view.exists(keylet::attestationTxn(attester.getAccountID(sfAccount), txid)))
|
||||
return terAWAITING_ATTESTATION;
|
||||
}
|
||||
}
|
||||
|
||||
return T::preclaim(ctx);
|
||||
@@ -285,8 +307,8 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
return invoke_preclaim<Import>(ctx);
|
||||
case ttINVOKE:
|
||||
return invoke_preclaim<Invoke>(ctx);
|
||||
case ttREMIT:
|
||||
return invoke_preclaim<Remit>(ctx);
|
||||
case ttATTEST:
|
||||
return invoke_preclaim<Attest>(ctx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -368,8 +390,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
return Import::calculateBaseFee(view, tx);
|
||||
case ttINVOKE:
|
||||
return Invoke::calculateBaseFee(view, tx);
|
||||
case ttREMIT:
|
||||
return Remit::calculateBaseFee(view, tx);
|
||||
case ttATTEST:
|
||||
return Attest::calculateBaseFee(view, tx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -550,8 +572,8 @@ invoke_apply(ApplyContext& ctx)
|
||||
Invoke p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttREMIT: {
|
||||
Remit p(ctx);
|
||||
case ttATTEST: {
|
||||
Attest p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttURITOKEN_MINT:
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <ripple/ledger/RawView.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/ledger/Sandbox.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
@@ -389,18 +388,6 @@ rippleCredit(
|
||||
bool bCheckIssuer,
|
||||
beast::Journal j);
|
||||
|
||||
// Send regardless of limits.
|
||||
// --> saAmount: Amount/currency/issuer to deliver to receiver.
|
||||
// <-- saActual: Amount actually cost. Sender pays fees.
|
||||
TER
|
||||
rippleSend(
|
||||
ApplyView& view,
|
||||
AccountID const& uSenderID,
|
||||
AccountID const& uReceiverID,
|
||||
STAmount const& saAmount,
|
||||
STAmount& saActual,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] TER
|
||||
accountSend(
|
||||
ApplyView& view,
|
||||
@@ -640,12 +627,12 @@ trustTransferAllowed(
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<V, ReadView const>::value ||
|
||||
std::is_same<V, ApplyView>::value || std::is_same<V, Sandbox>::value);
|
||||
std::is_same<V, ApplyView>::value);
|
||||
|
||||
typedef typename std::conditional<
|
||||
std::is_same<V, ReadView const>::value,
|
||||
std::shared_ptr<SLE const>,
|
||||
std::shared_ptr<SLE>>::type SLEPtr;
|
||||
std::is_same<V, ApplyView>::value,
|
||||
std::shared_ptr<SLE>,
|
||||
std::shared_ptr<SLE const>>::type SLEPtr;
|
||||
|
||||
if (isBadCurrency(issue.currency))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
@@ -1150,7 +1150,7 @@ rippleCredit(
|
||||
// Send regardless of limits.
|
||||
// --> saAmount: Amount/currency/issuer to deliver to receiver.
|
||||
// <-- saActual: Amount actually cost. Sender pays fees.
|
||||
TER
|
||||
static TER
|
||||
rippleSend(
|
||||
ApplyView& view,
|
||||
AccountID const& uSenderID,
|
||||
|
||||
@@ -354,8 +354,7 @@ extern uint256 const featureImport;
|
||||
extern uint256 const featureXahauGenesis;
|
||||
extern uint256 const featureHooksUpdate1;
|
||||
extern uint256 const fixURITokenV1;
|
||||
extern uint256 const featureRemit;
|
||||
|
||||
extern uint256 const featureAttestations;
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -295,7 +295,13 @@ Keylet
|
||||
import_vlseq(PublicKey const& key) noexcept;
|
||||
|
||||
Keylet
|
||||
uritoken(AccountID const& issuer, Blob const& uri);
|
||||
uritoken(AccountID const& issuer, Blob const& uri) noexcept;
|
||||
|
||||
Keylet
|
||||
attestationTxn(AccountID const& issuer, uint256 const& txnid) noexcept;
|
||||
|
||||
Keylet
|
||||
attestationAcc(AccountID const& issuer, AccountID const& issuee) noexcept;
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
|
||||
@@ -52,6 +52,12 @@ namespace ripple {
|
||||
// clang-format off
|
||||
enum LedgerEntryType : std::uint16_t
|
||||
{
|
||||
/** A ledger object which describes an attested txn
|
||||
|
||||
\sa kelet::attestation
|
||||
*/
|
||||
ltATTESTATION = 0x0041,
|
||||
|
||||
/** A ledger object which describes an account.
|
||||
|
||||
\sa keylet::account
|
||||
@@ -285,8 +291,6 @@ enum LedgerSpecificFlags {
|
||||
0x20000000, // True, reject new trustlines (only if no issued assets)
|
||||
lsfURITokenIssuer =
|
||||
0x40000000, // True, has minted tokens in the past
|
||||
lsfDisallowIncomingRemit = // True, no remits allowed to this account
|
||||
0x80000000,
|
||||
|
||||
// ltOFFER
|
||||
lsfPassive = 0x00010000,
|
||||
|
||||
@@ -483,6 +483,7 @@ extern SF_UINT256 const sfURITokenID;
|
||||
extern SF_UINT256 const sfGovernanceFlags;
|
||||
extern SF_UINT256 const sfGovernanceMarks;
|
||||
extern SF_UINT256 const sfEmittedTxnID;
|
||||
extern SF_UINT256 const sfAttestedTxnID;
|
||||
|
||||
// currency amount (common)
|
||||
extern SF_AMOUNT const sfAmount;
|
||||
@@ -553,6 +554,7 @@ extern SF_ACCOUNT const sfEmitCallback;
|
||||
extern SF_ACCOUNT const sfHookAccount;
|
||||
extern SF_ACCOUNT const sfNFTokenMinter;
|
||||
extern SF_ACCOUNT const sfInform;
|
||||
extern SF_ACCOUNT const sfAttestedAccID;
|
||||
|
||||
// path set
|
||||
extern SField const sfPaths;
|
||||
@@ -594,6 +596,7 @@ extern SField const sfImportVLKey;
|
||||
extern SField const sfHookEmission;
|
||||
extern SField const sfMintURIToken;
|
||||
extern SField const sfAmountEntry;
|
||||
extern SField const sfAttesterEntry;
|
||||
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -622,6 +625,7 @@ extern SField const sfActiveValidators;
|
||||
extern SField const sfImportVLKeys;
|
||||
extern SField const sfHookEmissions;
|
||||
extern SField const sfAmounts;
|
||||
extern SField const sfAttesters;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -223,8 +223,9 @@ enum TERcodes : TERUnderlyingType {
|
||||
terQUEUED, // Transaction is being held in TxQ until fee drops
|
||||
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
||||
terNO_AMM, // RESERVED - AMM
|
||||
terNO_HOOK // Transaction requires a non-existent hook definition
|
||||
terNO_HOOK, // Transaction requires a non-existent hook definition
|
||||
// (referenced by sfHookHash)
|
||||
terAWAITING_ATTESTATION,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -337,6 +338,7 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecXCHAIN_PAYMENT_FAILED = 184, // RESERVED - XCHAIN
|
||||
tecXCHAIN_SELF_COMMIT = 185, // RESERVED - XCHAIN
|
||||
tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR = 186, // RESERVED - XCHAIN
|
||||
tecLAST_LEDGER_SEQ_TOO_HIGH = 187,
|
||||
tecLAST_POSSIBLE_ENTRY = 255,
|
||||
};
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ constexpr std::uint32_t asfDisallowIncomingNFTokenOffer = 12;
|
||||
constexpr std::uint32_t asfDisallowIncomingCheck = 13;
|
||||
constexpr std::uint32_t asfDisallowIncomingPayChan = 14;
|
||||
constexpr std::uint32_t asfDisallowIncomingTrustline = 15;
|
||||
constexpr std::uint32_t asfDisallowIncomingRemit = 16;
|
||||
|
||||
// OfferCreate flags:
|
||||
constexpr std::uint32_t tfPassive = 0x00010000;
|
||||
@@ -133,6 +132,10 @@ constexpr std::uint32_t const tfStrongTSH = 0x00008000;
|
||||
constexpr std::uint32_t const tfNFTokenMintOldMask =
|
||||
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfStrongTSH);
|
||||
|
||||
// Attest flags:
|
||||
constexpr std::uint32_t tfDeleteAttestation = 0x00000001;
|
||||
constexpr std::uint32_t tfAttestMask = ~tfDeleteAttestation;
|
||||
|
||||
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between
|
||||
// accounts allowed a TrustLine to be added to the issuer of that token
|
||||
// without explicit permission from that issuer. This was enabled by
|
||||
|
||||
@@ -146,6 +146,9 @@ enum TxType : std::uint16_t
|
||||
ttURITOKEN_CREATE_SELL_OFFER = 48,
|
||||
ttURITOKEN_CANCEL_SELL_OFFER = 49,
|
||||
|
||||
/** This transaction acts as an attestation for another txn currently in the TxQ */
|
||||
ttATTEST = 94,
|
||||
|
||||
/* A payment transactor that delivers only the exact amounts specified, creating accounts and TLs as needed
|
||||
* that the sender pays for. */
|
||||
ttREMIT = 95,
|
||||
|
||||
@@ -460,7 +460,7 @@ REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(Remit, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(Attestations, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -45,6 +45,8 @@ namespace ripple {
|
||||
*/
|
||||
enum class LedgerNameSpace : std::uint16_t {
|
||||
ACCOUNT = 'a',
|
||||
ATTESTATION_ACC = 'A',
|
||||
ATTESTATION_TXN = 't',
|
||||
DIR_NODE = 'd',
|
||||
TRUST_LINE = 'r',
|
||||
OFFER = 'o',
|
||||
@@ -435,7 +437,7 @@ nft_sells(uint256 const& id) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
uritoken(AccountID const& issuer, Blob const& uri)
|
||||
uritoken(AccountID const& issuer, Blob const& uri) noexcept
|
||||
{
|
||||
return {
|
||||
ltURI_TOKEN,
|
||||
@@ -443,6 +445,16 @@ uritoken(AccountID const& issuer, Blob const& uri)
|
||||
LedgerNameSpace::URI_TOKEN, issuer, Slice{uri.data(), uri.size()})};
|
||||
}
|
||||
|
||||
Keylet attestationTxn(AccountID const& issuer, uint256 const& txnid) noexcept
|
||||
{
|
||||
return {ltATTESTATION, indexHash(LedgerNameSpace::ATTESTATION_TXN, issuer, txnid)};
|
||||
}
|
||||
|
||||
Keylet attestationAcc(AccountID const& issuer, AccountID const& issuee) noexcept
|
||||
{
|
||||
return {ltATTESTATION, indexHash(LedgerNameSpace::ATTESTATION_ACC, issuer, issuee)};
|
||||
}
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -156,6 +156,12 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfDigest, soeOPTIONAL},
|
||||
{sfFlags, soeOPTIONAL},
|
||||
});
|
||||
|
||||
add(sfAttesterEntry.jsonName.c_str(),
|
||||
sfAttesterEntry.getCode(),
|
||||
{
|
||||
{sfAccount, soeREQUIRED},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
@@ -363,6 +363,18 @@ LedgerFormats::LedgerFormats()
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Attestation,
|
||||
ltATTESTATION,
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfAttestedTxnID, soeOPTIONAL},
|
||||
{sfAttestedAccID, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
|
||||
@@ -236,6 +236,7 @@ CONSTRUCT_TYPED_SFIELD(sfURITokenID, "URITokenID", UINT256,
|
||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceFlags, "GovernanceFlags", UINT256, 99);
|
||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceMarks, "GovernanceMarks", UINT256, 98);
|
||||
CONSTRUCT_TYPED_SFIELD(sfEmittedTxnID, "EmittedTxnID", UINT256, 97);
|
||||
CONSTRUCT_TYPED_SFIELD(sfAttestedTxnID, "AttestedTxnID", UINT256, 96);
|
||||
|
||||
// currency amount (common)
|
||||
CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1);
|
||||
@@ -306,6 +307,7 @@ CONSTRUCT_TYPED_SFIELD(sfEmitCallback, "EmitCallback", ACCOUNT,
|
||||
// account (uncommon)
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookAccount, "HookAccount", ACCOUNT, 16);
|
||||
CONSTRUCT_TYPED_SFIELD(sfInform, "Inform", ACCOUNT, 99);
|
||||
CONSTRUCT_TYPED_SFIELD(sfAttestedAccID, "AttestedAccID", ACCOUNT, 98);
|
||||
|
||||
// vector of 256-bit
|
||||
CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never);
|
||||
@@ -348,8 +350,9 @@ CONSTRUCT_UNTYPED_SFIELD(sfGenesisMint, "GenesisMint", OBJECT,
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfActiveValidator, "ActiveValidator", OBJECT, 95);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKey, "ImportVLKey", OBJECT, 94);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfHookEmission, "HookEmission", OBJECT, 93);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfMintURIToken, "MintURIToken", OBJECT, 92);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfMintURIToken, "MintURIToken", OBJECT, 92);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfAmountEntry, "AmountEntry", OBJECT, 91);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfAttesterEntry, "AttesterEntry", OBJECT, 90);
|
||||
|
||||
// array of objects
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -375,6 +378,7 @@ CONSTRUCT_UNTYPED_SFIELD(sfActiveValidators, "ActiveValidators", ARRAY,
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKeys, "ImportVLKeys", ARRAY, 94);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfHookEmissions, "HookEmissions", ARRAY, 93);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfAmounts, "Amounts", ARRAY, 92);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfAttesters, "Attesters", ARRAY, 91);
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ transResults()
|
||||
MAKE_ERROR(tecHOOK_REJECTED, "Rejected by hook on sending or receiving account."),
|
||||
MAKE_ERROR(tecREQUIRES_FLAG, "The transaction or part-thereof requires a flag that wasn't set."),
|
||||
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
||||
MAKE_ERROR(tecLAST_LEDGER_SEQ_TOO_HIGH, "The sfLastLedgerSequence was higher than seq + 256."),
|
||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
MAKE_ERROR(tefBAD_AUTH, "Transaction's public key is not authorized."),
|
||||
@@ -188,6 +189,7 @@ transResults()
|
||||
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
|
||||
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
|
||||
MAKE_ERROR(terNO_HOOK, "No hook with that hash exists on the ledger."),
|
||||
MAKE_ERROR(terAWAITING_ATTESTATION, "Transaction is waiting for attesters to attest."),
|
||||
|
||||
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
||||
};
|
||||
|
||||
@@ -44,6 +44,7 @@ TxFormats::TxFormats()
|
||||
{sfNetworkID, soeOPTIONAL},
|
||||
{sfHookParameters, soeOPTIONAL},
|
||||
{sfOperationLimit, soeOPTIONAL},
|
||||
{sfAttesters, soeOPTIONAL},
|
||||
};
|
||||
|
||||
add(jss::AccountSet,
|
||||
@@ -456,6 +457,15 @@ TxFormats::TxFormats()
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Attest,
|
||||
ttATTEST,
|
||||
{
|
||||
{sfAttestedTxnID, soeOPTIONAL},
|
||||
{sfAttestedAccID, soeOPTIONAL},
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
}
|
||||
|
||||
TxFormats const&
|
||||
|
||||
@@ -50,6 +50,9 @@ JSS(AccountSet); // transaction type.
|
||||
JSS(Amendments); // ledger type.
|
||||
JSS(Amount); // in: TransactionSign; field.
|
||||
JSS(Authorize); // field
|
||||
JSS(Attest);
|
||||
JSS(AttesterEntry);
|
||||
JSS(Attestation);
|
||||
JSS(Blob);
|
||||
JSS(Check); // ledger type.
|
||||
JSS(CheckCancel); // transaction type.
|
||||
|
||||
@@ -422,11 +422,11 @@ doServerDefinitions(RPC::JsonContext& context)
|
||||
uint32_t curLgrSeq = context.ledgerMaster.getValidatedLedger()->info().seq;
|
||||
|
||||
// static values used for cache
|
||||
static thread_local uint32_t lastGenerated = 0; // last ledger seq it was generated
|
||||
static thread_local Json::Value lastFeatures{
|
||||
Json::objectValue}; // the actual features JSON last generated
|
||||
static thread_local uint256 lastFeatureHash; // the hash of the features JSON last time
|
||||
// it was generated
|
||||
static uint32_t lastGenerated = 0; // last ledger seq it was generated
|
||||
static Json::Value lastFeatures{
|
||||
Json::objectValue}; // the actual features JSON last generated
|
||||
static uint256 lastFeatureHash; // the hash of the features JSON last time
|
||||
// it was generated
|
||||
|
||||
// if a flag ledger has passed since it was last generated, regenerate it,
|
||||
// update the cache above
|
||||
|
||||
@@ -5549,73 +5549,6 @@ class Import_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
// std::unique_ptr<Config>
|
||||
// network::makeGenesisConfig(
|
||||
// FeatureBitset features,
|
||||
// uint32_t networkID,
|
||||
// std::string fee,
|
||||
// std::string a_res,
|
||||
// std::string o_res,
|
||||
// uint32_t ledgerID)
|
||||
// {
|
||||
// using namespace jtx;
|
||||
|
||||
// // IMPORT VL KEY
|
||||
// std::vector<std::string> const keys = {
|
||||
// "ED74D4036C6591A4BDF9C54CEFA39B996A"
|
||||
// "5DCE5F86D11FDA1874481CE9D5A1CDC1"};
|
||||
|
||||
// Json::Value jsonValue;
|
||||
// Json::Reader reader;
|
||||
// reader.parse(ImportTCHalving::base_genesis, jsonValue);
|
||||
|
||||
// foreachFeature(features, [&](uint256 const& feature) {
|
||||
// std::string featureName = featureToName(feature);
|
||||
// std::optional<uint256> featureHash =
|
||||
// getRegisteredFeature(featureName);
|
||||
// if (featureHash.has_value())
|
||||
// {
|
||||
// std::string hashString = to_string(featureHash.value());
|
||||
// jsonValue["ledger"]["accountState"][1]["Amendments"].append(
|
||||
// hashString);
|
||||
// }
|
||||
// });
|
||||
|
||||
// jsonValue["ledger_current_index"] = ledgerID;
|
||||
// jsonValue["ledger"]["ledger_index"] = to_string(ledgerID);
|
||||
// jsonValue["ledger"]["seqNum"] = to_string(ledgerID);
|
||||
|
||||
// return envconfig([&](std::unique_ptr<Config> cfg) {
|
||||
// cfg->NETWORK_ID = networkID;
|
||||
// cfg->START_LEDGER = jsonValue.toStyledString();
|
||||
// cfg->START_UP = Config::LOAD_JSON;
|
||||
// Section config;
|
||||
// config.append(
|
||||
// {"reference_fee = " + fee,
|
||||
// "account_reserve = " + a_res,
|
||||
// "owner_reserve = " + o_res});
|
||||
// auto setup = setup_FeeVote(config);
|
||||
// cfg->FEES = setup;
|
||||
|
||||
// for (auto const& strPk : keys)
|
||||
// {
|
||||
// auto pkHex = strUnHex(strPk);
|
||||
// if (!pkHex)
|
||||
// Throw<std::runtime_error>(
|
||||
// "Import VL Key '" + strPk + "' was not valid hex.");
|
||||
|
||||
// auto const pkType = publicKeyType(makeSlice(*pkHex));
|
||||
// if (!pkType)
|
||||
// Throw<std::runtime_error>(
|
||||
// "Import VL Key '" + strPk +
|
||||
// "' was not a valid key type.");
|
||||
|
||||
// cfg->IMPORT_VL_KEYS.emplace(strPk, makeSlice(*pkHex));
|
||||
// }
|
||||
// return cfg;
|
||||
// });
|
||||
// }
|
||||
|
||||
void
|
||||
testHalving(FeatureBitset features)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
4815
src/test/app/SetHookTSH_test.cpp
Normal file
4815
src/test/app/SetHookTSH_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -42,52 +42,6 @@ namespace test {
|
||||
* are put in their existing unit test files.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test the size of the negative UNL in a ledger,
|
||||
* also test if the ledger has ToDisalbe and/or ToReEnable
|
||||
*
|
||||
* @param l the ledger
|
||||
* @param size the expected negative UNL size
|
||||
* @param hasToDisable if expect ToDisable in ledger
|
||||
* @param hasToReEnable if expect ToDisable in ledger
|
||||
* @return true if meet all three expectation
|
||||
*/
|
||||
bool inline negUnlSizeTest(
|
||||
std::shared_ptr<ripple::Ledger const> const& l,
|
||||
size_t size,
|
||||
bool hasToDisable,
|
||||
bool hasToReEnable)
|
||||
{
|
||||
bool sameSize = l->negativeUNL().size() == size;
|
||||
bool sameToDisable =
|
||||
(l->validatorToDisable() != std::nullopt) == hasToDisable;
|
||||
bool sameToReEnable =
|
||||
(l->validatorToReEnable() != std::nullopt) == hasToReEnable;
|
||||
|
||||
return sameSize && sameToDisable && sameToReEnable;
|
||||
}
|
||||
/**
|
||||
* Try to apply a ttUNL_MODIFY Tx, and test the apply result
|
||||
*
|
||||
* @param env the test environment
|
||||
* @param view the OpenView of the ledger
|
||||
* @param tx the ttUNL_MODIFY Tx
|
||||
* @param pass if the Tx should be applied successfully
|
||||
* @return true if meet the expectation of apply result
|
||||
*/
|
||||
bool inline applyAndTestResult(
|
||||
jtx::Env& env,
|
||||
ripple::OpenView& view,
|
||||
ripple::STTx const& tx,
|
||||
bool pass)
|
||||
{
|
||||
auto res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
|
||||
if (pass)
|
||||
return res.first == tesSUCCESS;
|
||||
else
|
||||
return res.first == tefFAILURE || res.first == temDISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the content of negative UNL entries (public key and ledger sequence)
|
||||
* of a ledger
|
||||
@@ -102,15 +56,6 @@ VerifyPubKeyAndSeq(
|
||||
std::shared_ptr<Ledger const> const& l,
|
||||
hash_map<PublicKey, std::uint32_t> nUnlLedgerSeq);
|
||||
|
||||
/**
|
||||
* Count the number of Tx in a TxSet
|
||||
*
|
||||
* @param txSet the TxSet
|
||||
* @return the number of Tx
|
||||
*/
|
||||
std::size_t
|
||||
countTx(std::shared_ptr<SHAMap> const& txSet);
|
||||
|
||||
/**
|
||||
* Create fake public keys
|
||||
*
|
||||
@@ -120,17 +65,6 @@ countTx(std::shared_ptr<SHAMap> const& txSet);
|
||||
std::vector<PublicKey>
|
||||
createPublicKeys(std::size_t n);
|
||||
|
||||
/**
|
||||
* Create ttUNL_MODIFY Tx
|
||||
*
|
||||
* @param disabling disabling or re-enabling a validator
|
||||
* @param seq current ledger seq
|
||||
* @param txKey the public key of the validator
|
||||
* @return the ttUNL_MODIFY Tx
|
||||
*/
|
||||
STTx
|
||||
createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey);
|
||||
|
||||
class NegativeUNL_test : public beast::unit_test::suite
|
||||
{
|
||||
/**
|
||||
@@ -262,14 +196,16 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
l = std::make_shared<Ledger>(
|
||||
*l, env.app().timeKeeper().closeTime());
|
||||
|
||||
auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_1 = createTx(false, l->seq(), publicKeys[1]);
|
||||
auto txDisable_0 = unl::createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_1 = unl::createTx(false, l->seq(), publicKeys[1]);
|
||||
|
||||
OpenView accum(&*l);
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_0, false));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_1, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txDisable_0, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_1, false));
|
||||
accum.apply(*l);
|
||||
BEAST_EXPECT(negUnlSizeTest(l, 0, false, false));
|
||||
BEAST_EXPECT(unl::negUnlSizeTest(l, 0, false, false));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -283,18 +219,21 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(l->isFlagLedger());
|
||||
l->updateNegativeUNL();
|
||||
|
||||
auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txDisable_1 = createTx(true, l->seq(), publicKeys[1]);
|
||||
auto txReEnable_2 = createTx(false, l->seq(), publicKeys[2]);
|
||||
auto txDisable_0 = unl::createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txDisable_1 = unl::createTx(true, l->seq(), publicKeys[1]);
|
||||
auto txReEnable_2 = unl::createTx(false, l->seq(), publicKeys[2]);
|
||||
|
||||
// can apply 1 and only 1 ToDisable Tx,
|
||||
// cannot apply ToReEnable Tx, since negative UNL is empty
|
||||
OpenView accum(&*l);
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_0, true));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_1, false));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_2, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txDisable_0, true));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txDisable_1, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_2, false));
|
||||
accum.apply(*l);
|
||||
auto good_size = negUnlSizeTest(l, 0, true, false);
|
||||
auto good_size = unl::negUnlSizeTest(l, 0, true, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -309,7 +248,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
//(3) ledgers before the next flag ledger
|
||||
for (auto i = 0; i < 256; ++i)
|
||||
{
|
||||
auto good_size = negUnlSizeTest(l, 0, true, false);
|
||||
auto good_size = unl::negUnlSizeTest(l, 0, true, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
BEAST_EXPECT(l->validatorToDisable() == publicKeys[0]);
|
||||
@@ -321,7 +260,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
|
||||
//(4) next flag ledger
|
||||
// test if the ledger updated correctly
|
||||
auto good_size = negUnlSizeTest(l, 1, false, false);
|
||||
auto good_size = unl::negUnlSizeTest(l, 1, false, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -329,20 +268,25 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
nUnlLedgerSeq.emplace(publicKeys[0], l->seq());
|
||||
}
|
||||
|
||||
auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txDisable_1 = createTx(true, l->seq(), publicKeys[1]);
|
||||
auto txReEnable_0 = createTx(false, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_1 = createTx(false, l->seq(), publicKeys[1]);
|
||||
auto txReEnable_2 = createTx(false, l->seq(), publicKeys[2]);
|
||||
auto txDisable_0 = unl::createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txDisable_1 = unl::createTx(true, l->seq(), publicKeys[1]);
|
||||
auto txReEnable_0 = unl::createTx(false, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_1 = unl::createTx(false, l->seq(), publicKeys[1]);
|
||||
auto txReEnable_2 = unl::createTx(false, l->seq(), publicKeys[2]);
|
||||
|
||||
OpenView accum(&*l);
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_0, false));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_1, true));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_1, false));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_2, false));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_0, true));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txDisable_0, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txDisable_1, true));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_1, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_2, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_0, true));
|
||||
accum.apply(*l);
|
||||
good_size = negUnlSizeTest(l, 1, true, true);
|
||||
good_size = unl::negUnlSizeTest(l, 1, true, true);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -358,7 +302,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
//(5) ledgers before the next flag ledger
|
||||
for (auto i = 0; i < 256; ++i)
|
||||
{
|
||||
auto good_size = negUnlSizeTest(l, 1, true, true);
|
||||
auto good_size = unl::negUnlSizeTest(l, 1, true, true);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -374,19 +318,20 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
|
||||
//(6) next flag ledger
|
||||
// test if the ledger updated correctly
|
||||
auto good_size = negUnlSizeTest(l, 1, false, false);
|
||||
auto good_size = unl::negUnlSizeTest(l, 1, false, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
BEAST_EXPECT(l->negativeUNL().count(publicKeys[1]));
|
||||
}
|
||||
|
||||
auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txDisable_0 = unl::createTx(true, l->seq(), publicKeys[0]);
|
||||
|
||||
OpenView accum(&*l);
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_0, true));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txDisable_0, true));
|
||||
accum.apply(*l);
|
||||
good_size = negUnlSizeTest(l, 1, true, false);
|
||||
good_size = unl::negUnlSizeTest(l, 1, true, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -402,7 +347,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
//(7) ledgers before the next flag ledger
|
||||
for (auto i = 0; i < 256; ++i)
|
||||
{
|
||||
auto good_size = negUnlSizeTest(l, 1, true, false);
|
||||
auto good_size = unl::negUnlSizeTest(l, 1, true, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -417,7 +362,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
|
||||
//(8) next flag ledger
|
||||
// test if the ledger updated correctly
|
||||
auto good_size = negUnlSizeTest(l, 2, false, false);
|
||||
auto good_size = unl::negUnlSizeTest(l, 2, false, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -427,16 +372,19 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(VerifyPubKeyAndSeq(l, nUnlLedgerSeq));
|
||||
}
|
||||
|
||||
auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_0 = createTx(false, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_1 = createTx(false, l->seq(), publicKeys[1]);
|
||||
auto txDisable_0 = unl::createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_0 = unl::createTx(false, l->seq(), publicKeys[0]);
|
||||
auto txReEnable_1 = unl::createTx(false, l->seq(), publicKeys[1]);
|
||||
|
||||
OpenView accum(&*l);
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_0, true));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_1, false));
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_0, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_0, true));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_1, false));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txDisable_0, false));
|
||||
accum.apply(*l);
|
||||
good_size = negUnlSizeTest(l, 2, false, true);
|
||||
good_size = unl::negUnlSizeTest(l, 2, false, true);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -451,7 +399,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
//(9) ledgers before the next flag ledger
|
||||
for (auto i = 0; i < 256; ++i)
|
||||
{
|
||||
auto good_size = negUnlSizeTest(l, 2, false, true);
|
||||
auto good_size = unl::negUnlSizeTest(l, 2, false, true);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -467,7 +415,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
|
||||
//(10) next flag ledger
|
||||
// test if the ledger updated correctly
|
||||
auto good_size = negUnlSizeTest(l, 1, false, false);
|
||||
auto good_size = unl::negUnlSizeTest(l, 1, false, false);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -476,12 +424,13 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(VerifyPubKeyAndSeq(l, nUnlLedgerSeq));
|
||||
}
|
||||
|
||||
auto txReEnable_1 = createTx(false, l->seq(), publicKeys[1]);
|
||||
auto txReEnable_1 = unl::createTx(false, l->seq(), publicKeys[1]);
|
||||
|
||||
OpenView accum(&*l);
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txReEnable_1, true));
|
||||
BEAST_EXPECT(
|
||||
unl::applyAndTestResult(env, accum, txReEnable_1, true));
|
||||
accum.apply(*l);
|
||||
good_size = negUnlSizeTest(l, 1, false, true);
|
||||
good_size = unl::negUnlSizeTest(l, 1, false, true);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -495,7 +444,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
//(11) ledgers before the next flag ledger
|
||||
for (auto i = 0; i < 256; ++i)
|
||||
{
|
||||
auto good_size = negUnlSizeTest(l, 1, false, true);
|
||||
auto good_size = unl::negUnlSizeTest(l, 1, false, true);
|
||||
BEAST_EXPECT(good_size);
|
||||
if (good_size)
|
||||
{
|
||||
@@ -509,14 +458,14 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
l->updateNegativeUNL();
|
||||
|
||||
//(12) next flag ledger
|
||||
BEAST_EXPECT(negUnlSizeTest(l, 0, false, false));
|
||||
BEAST_EXPECT(unl::negUnlSizeTest(l, 0, false, false));
|
||||
}
|
||||
|
||||
{
|
||||
//(13) ledgers before the next flag ledger
|
||||
for (auto i = 0; i < 256; ++i)
|
||||
{
|
||||
BEAST_EXPECT(negUnlSizeTest(l, 0, false, false));
|
||||
BEAST_EXPECT(unl::negUnlSizeTest(l, 0, false, false));
|
||||
l = std::make_shared<Ledger>(
|
||||
*l, env.app().timeKeeper().closeTime());
|
||||
}
|
||||
@@ -524,7 +473,7 @@ class NegativeUNL_test : public beast::unit_test::suite
|
||||
l->updateNegativeUNL();
|
||||
|
||||
//(14) next flag ledger
|
||||
BEAST_EXPECT(negUnlSizeTest(l, 0, false, false));
|
||||
BEAST_EXPECT(unl::negUnlSizeTest(l, 0, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,11 +508,11 @@ class NegativeUNLNoAmendment_test : public beast::unit_test::suite
|
||||
*l, env.app().timeKeeper().closeTime());
|
||||
}
|
||||
BEAST_EXPECT(l->seq() == 256);
|
||||
auto txDisable_0 = createTx(true, l->seq(), publicKeys[0]);
|
||||
auto txDisable_0 = unl::createTx(true, l->seq(), publicKeys[0]);
|
||||
OpenView accum(&*l);
|
||||
BEAST_EXPECT(applyAndTestResult(env, accum, txDisable_0, false));
|
||||
BEAST_EXPECT(unl::applyAndTestResult(env, accum, txDisable_0, false));
|
||||
accum.apply(*l);
|
||||
BEAST_EXPECT(negUnlSizeTest(l, 0, false, false));
|
||||
BEAST_EXPECT(unl::negUnlSizeTest(l, 0, false, false));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -651,8 +600,8 @@ struct NetworkHistory
|
||||
OpenView accum(&*l);
|
||||
if (l->negativeUNL().size() < param.negUNLSize)
|
||||
{
|
||||
auto tx = createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!applyAndTestResult(env, accum, tx, true))
|
||||
auto tx = unl::createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!unl::applyAndTestResult(env, accum, tx, true))
|
||||
break;
|
||||
++nidx;
|
||||
}
|
||||
@@ -660,15 +609,15 @@ struct NetworkHistory
|
||||
{
|
||||
if (param.hasToDisable)
|
||||
{
|
||||
auto tx = createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!applyAndTestResult(env, accum, tx, true))
|
||||
auto tx = unl::createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!unl::applyAndTestResult(env, accum, tx, true))
|
||||
break;
|
||||
++nidx;
|
||||
}
|
||||
if (param.hasToReEnable)
|
||||
{
|
||||
auto tx = createTx(false, l->seq(), UNLKeys[0]);
|
||||
if (!applyAndTestResult(env, accum, tx, true))
|
||||
auto tx = unl::createTx(false, l->seq(), UNLKeys[0]);
|
||||
if (!unl::applyAndTestResult(env, accum, tx, true))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -676,7 +625,7 @@ struct NetworkHistory
|
||||
}
|
||||
l->updateSkipList();
|
||||
}
|
||||
return negUnlSizeTest(
|
||||
return unl::negUnlSizeTest(
|
||||
l, param.negUNLSize, param.hasToDisable, param.hasToReEnable);
|
||||
}
|
||||
|
||||
@@ -776,7 +725,7 @@ voteAndCheck(
|
||||
vote.doVoting(
|
||||
history.lastLedger(), history.UNLKeySet, history.validations, txSet);
|
||||
|
||||
return countTx(txSet) >= expect;
|
||||
return unl::countTx(txSet) >= expect;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -799,11 +748,11 @@ class NegativeUNLVoteInternal_test : public beast::unit_test::suite
|
||||
PublicKey toDisableKey;
|
||||
PublicKey toReEnableKey;
|
||||
LedgerIndex seq(1234);
|
||||
BEAST_EXPECT(countTx(txSet) == 0);
|
||||
BEAST_EXPECT(unl::countTx(txSet) == 0);
|
||||
vote.addTx(seq, toDisableKey, NegativeUNLVote::ToDisable, txSet);
|
||||
BEAST_EXPECT(countTx(txSet) == 1);
|
||||
BEAST_EXPECT(unl::countTx(txSet) == 1);
|
||||
vote.addTx(seq, toReEnableKey, NegativeUNLVote::ToReEnable, txSet);
|
||||
BEAST_EXPECT(countTx(txSet) == 2);
|
||||
BEAST_EXPECT(unl::countTx(txSet) == 2);
|
||||
// content of a tx is implicitly tested after applied to a ledger
|
||||
// in later test cases
|
||||
}
|
||||
@@ -1967,34 +1916,6 @@ VerifyPubKeyAndSeq(
|
||||
return nUnlLedgerSeq.size() == 0;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
countTx(std::shared_ptr<SHAMap> const& txSet)
|
||||
{
|
||||
/*uint64_t counter = 0;
|
||||
if (txSet)
|
||||
for (auto const& item : *txSet)
|
||||
{
|
||||
|
||||
SerialIter sit(item.slice());
|
||||
auto tx = std::make_shared<STTx
|
||||
const>(SerialIter{sit.getSlice(sit.getVLDataLength())});
|
||||
|
||||
if (tx->getFieldU16(sfTransactionType) == ttUNL_MODIFY)
|
||||
counter++;
|
||||
}
|
||||
*/
|
||||
|
||||
std::size_t count = 0;
|
||||
for (auto i = txSet->begin(); i != txSet->end(); ++i)
|
||||
{
|
||||
// RH TODO: why does the above parse??
|
||||
auto raw = i->slice();
|
||||
if (raw[0] == 0x12U && raw[1] == 0 && raw[2] == 0x66U)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
std::vector<PublicKey>
|
||||
createPublicKeys(std::size_t n)
|
||||
{
|
||||
@@ -2011,16 +1932,5 @@ createPublicKeys(std::size_t n)
|
||||
return keys;
|
||||
}
|
||||
|
||||
STTx
|
||||
createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey)
|
||||
{
|
||||
auto fill = [&](auto& obj) {
|
||||
obj.setFieldU8(sfUNLModifyDisabling, disabling ? 1 : 0);
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
obj.setFieldVL(sfUNLModifyValidator, txKey);
|
||||
};
|
||||
return STTx(ttUNL_MODIFY, fill);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
|
||||
@@ -52,66 +52,20 @@ namespace test {
|
||||
// */
|
||||
|
||||
// /**
|
||||
// * Test the size of the negative UNL in a ledger,
|
||||
// * also test if the ledger has ToDisalbe and/or ToReEnable
|
||||
// * Try to apply a ttUNL_MODIFY Tx, and test the apply result
|
||||
// *
|
||||
// * @param l the ledger
|
||||
// * @param size the expected negative UNL size
|
||||
// * @param hasToDisable if expect ToDisable in ledger
|
||||
// * @param hasToReEnable if expect ToDisable in ledger
|
||||
// * @return true if meet all three expectation
|
||||
// * @param env the test environment
|
||||
// * @param view the OpenView of the ledger
|
||||
// * @param tx the ttUNL_MODIFY Tx
|
||||
// * @param pass if the Tx should be applied successfully
|
||||
// * @return true if meet the expectation of apply result
|
||||
// */
|
||||
/*
|
||||
bool
|
||||
inline
|
||||
negUnlSizeTest(
|
||||
std::shared_ptr<ripple::Ledger const> const& l,
|
||||
size_t size,
|
||||
bool hasToDisable,
|
||||
bool hasToReEnable)
|
||||
{
|
||||
bool sameSize = l->negativeUNL().size() == size;
|
||||
bool sameToDisable =
|
||||
(l->validatorToDisable() != std::nullopt) == hasToDisable;
|
||||
bool sameToReEnable =
|
||||
(l->validatorToReEnable() != std::nullopt) == hasToReEnable;
|
||||
|
||||
return sameSize && sameToDisable && sameToReEnable;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Try to apply a ttUNL_MODIFY Tx, and test the apply result
|
||||
*
|
||||
* @param env the test environment
|
||||
* @param view the OpenView of the ledger
|
||||
* @param tx the ttUNL_MODIFY Tx
|
||||
* @param pass if the Tx should be applied successfully
|
||||
* @return true if meet the expectation of apply result
|
||||
*/
|
||||
/*
|
||||
bool
|
||||
inline
|
||||
applyAndTestResult(jtx::Env& env, ripple::OpenView& view, ripple::STTx const&
|
||||
tx, bool pass)
|
||||
{
|
||||
auto res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
|
||||
if (pass)
|
||||
return res.first == tesSUCCESS;
|
||||
else
|
||||
return res.first == tefFAILURE || res.first == temDISABLED;
|
||||
}
|
||||
*/
|
||||
inline bool
|
||||
applyAndTestUNLRResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass)
|
||||
{
|
||||
auto res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
|
||||
if (pass)
|
||||
return res.first == tesSUCCESS;
|
||||
else
|
||||
return res.first == tefFAILURE || res.first == temDISABLED ||
|
||||
res.first == temMALFORMED ||
|
||||
res.first == telIMPORT_VL_KEY_NOT_RECOGNISED;
|
||||
}
|
||||
applyAndTestUNLRResult(
|
||||
jtx::Env& env,
|
||||
OpenView& view,
|
||||
STTx const& tx,
|
||||
bool pass);
|
||||
|
||||
/**
|
||||
* Verify the content of UNL Report entries (public key and ledger sequence)
|
||||
@@ -139,9 +93,6 @@ countUNLRTx(std::shared_ptr<SHAMap> const& txSet);
|
||||
std::vector<std::string> const keys = {
|
||||
"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC1"};
|
||||
|
||||
std::unique_ptr<Config>
|
||||
makeNetworkVLConfig(uint32_t networkID, std::vector<std::string> keys);
|
||||
|
||||
/**
|
||||
* Verify if the UNL report exists
|
||||
*
|
||||
@@ -194,38 +145,6 @@ createUNLRTx(
|
||||
PublicKey const& importKey,
|
||||
PublicKey const& valKey);
|
||||
|
||||
/**
|
||||
* Count the number of Tx in a TxSet
|
||||
*
|
||||
* @param txSet the TxSet
|
||||
* @return the number of Tx
|
||||
*/
|
||||
inline std::size_t
|
||||
countTx(std::shared_ptr<SHAMap> const& txSet);
|
||||
|
||||
/**
|
||||
* Create ttUNL_MODIFY Tx
|
||||
*
|
||||
* @param disabling disabling or re-enabling a validator
|
||||
* @param seq current ledger seq
|
||||
* @param txKey the public key of the validator
|
||||
* @return the ttUNL_MODIFY Tx
|
||||
*/
|
||||
inline STTx
|
||||
createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey);
|
||||
|
||||
/**
|
||||
* Try to apply a ttUNL_MODIFY Tx, and test the apply result
|
||||
*
|
||||
* @param env the test environment
|
||||
* @param view the OpenView of the ledger
|
||||
* @param tx the ttUNL_MODIFY Tx
|
||||
* @param pass if the Tx should be applied successfully
|
||||
* @return true if meet the expectation of apply result
|
||||
*/
|
||||
inline bool
|
||||
applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass);
|
||||
|
||||
class UNLReport_test : public beast::unit_test::suite
|
||||
{
|
||||
// Import VL Keys
|
||||
@@ -374,7 +293,10 @@ class UNLReport_test : public beast::unit_test::suite
|
||||
// telIMPORT_VL_KEY_NOT_RECOGNISED
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this, makeNetworkVLConfig(21337, keys), features, nullptr};
|
||||
*this,
|
||||
jtx::network::makeNetworkVLConfig(21337, keys),
|
||||
features,
|
||||
nullptr};
|
||||
|
||||
auto l = std::make_shared<Ledger>(
|
||||
create_genesis,
|
||||
@@ -403,7 +325,10 @@ class UNLReport_test : public beast::unit_test::suite
|
||||
// SUCCESS
|
||||
{
|
||||
test::jtx::Env env{
|
||||
*this, makeNetworkVLConfig(21337, keys), features, nullptr};
|
||||
*this,
|
||||
jtx::network::makeNetworkVLConfig(21337, keys),
|
||||
features,
|
||||
nullptr};
|
||||
|
||||
auto l = std::make_shared<Ledger>(
|
||||
create_genesis,
|
||||
@@ -442,7 +367,10 @@ class UNLReport_test : public beast::unit_test::suite
|
||||
using namespace jtx;
|
||||
|
||||
test::jtx::Env env{
|
||||
*this, makeNetworkVLConfig(21337, keys), features, nullptr};
|
||||
*this,
|
||||
jtx::network::makeNetworkVLConfig(21337, keys),
|
||||
features,
|
||||
nullptr};
|
||||
|
||||
std::vector<PublicKey> ivlKeys;
|
||||
for (auto const& strPk : _ivlKeys)
|
||||
@@ -703,7 +631,8 @@ struct URNetworkHistory
|
||||
|
||||
URNetworkHistory(beast::unit_test::suite& suite, Parameter const& p)
|
||||
: env(suite,
|
||||
p.withVL ? makeNetworkVLConfig(21337, keys) : jtx::envconfig(),
|
||||
p.withVL ? jtx::network::makeNetworkVLConfig(21337, keys)
|
||||
: jtx::envconfig(),
|
||||
jtx::supported_amendments() | featureNegativeUNL)
|
||||
, param(p)
|
||||
, validations(env.app().getValidations())
|
||||
@@ -757,8 +686,8 @@ struct URNetworkHistory
|
||||
OpenView accum(&*l);
|
||||
if (l->negativeUNL().size() < param.negUNLSize)
|
||||
{
|
||||
auto tx = createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!applyAndTestResult(env, accum, tx, true))
|
||||
auto tx = unl::createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!unl::applyAndTestResult(env, accum, tx, true))
|
||||
break;
|
||||
++nidx;
|
||||
}
|
||||
@@ -766,15 +695,15 @@ struct URNetworkHistory
|
||||
{
|
||||
if (param.hasToDisable)
|
||||
{
|
||||
auto tx = createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!applyAndTestResult(env, accum, tx, true))
|
||||
auto tx = unl::createTx(true, l->seq(), UNLKeys[nidx]);
|
||||
if (!unl::applyAndTestResult(env, accum, tx, true))
|
||||
break;
|
||||
++nidx;
|
||||
}
|
||||
if (param.hasToReEnable)
|
||||
{
|
||||
auto tx = createTx(false, l->seq(), UNLKeys[0]);
|
||||
if (!applyAndTestResult(env, accum, tx, true))
|
||||
auto tx = unl::createTx(false, l->seq(), UNLKeys[0]);
|
||||
if (!unl::applyAndTestResult(env, accum, tx, true))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -782,7 +711,7 @@ struct URNetworkHistory
|
||||
}
|
||||
l->updateSkipList();
|
||||
}
|
||||
return negUnlSizeTest(
|
||||
return unl::negUnlSizeTest(
|
||||
l, param.negUNLSize, param.hasToDisable, param.hasToReEnable);
|
||||
}
|
||||
|
||||
@@ -883,7 +812,8 @@ voteAndCheckUNLR(
|
||||
vote.doVoting(
|
||||
history.lastLedger(), history.UNLKeySet, history.validations, txSet);
|
||||
|
||||
return countUNLRTx(txSet) == expectReport && countTx(txSet) >= expectModify;
|
||||
return countUNLRTx(txSet) == expectReport &&
|
||||
unl::countTx(txSet) >= expectModify;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1264,6 +1194,18 @@ BEAST_DEFINE_TESTSUITE(UNLReportVoteNewValidator, consensus, ripple);
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
applyAndTestUNLRResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass)
|
||||
{
|
||||
auto res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
|
||||
if (pass)
|
||||
return res.first == tesSUCCESS;
|
||||
else
|
||||
return res.first == tefFAILURE || res.first == temDISABLED ||
|
||||
res.first == temMALFORMED ||
|
||||
res.first == telIMPORT_VL_KEY_NOT_RECOGNISED;
|
||||
}
|
||||
|
||||
bool
|
||||
VerifyUNLRPubKeyAndSeq(
|
||||
std::shared_ptr<Ledger const> const& l,
|
||||
@@ -1314,38 +1256,6 @@ countUNLRTx(std::shared_ptr<SHAMap> const& txSet)
|
||||
return count;
|
||||
};
|
||||
|
||||
std::unique_ptr<Config>
|
||||
makeNetworkVLConfig(uint32_t networkID, std::vector<std::string> keys)
|
||||
{
|
||||
using namespace jtx;
|
||||
return envconfig([&](std::unique_ptr<Config> cfg) {
|
||||
cfg->NETWORK_ID = networkID;
|
||||
Section config;
|
||||
config.append(
|
||||
{"reference_fee = 10",
|
||||
"account_reserve = 1000000",
|
||||
"owner_reserve = 200000"});
|
||||
auto setup = setup_FeeVote(config);
|
||||
cfg->FEES = setup;
|
||||
|
||||
for (auto const& strPk : keys)
|
||||
{
|
||||
auto pkHex = strUnHex(strPk);
|
||||
if (!pkHex)
|
||||
Throw<std::runtime_error>(
|
||||
"Import VL Key '" + strPk + "' was not valid hex.");
|
||||
|
||||
auto const pkType = publicKeyType(makeSlice(*pkHex));
|
||||
if (!pkType)
|
||||
Throw<std::runtime_error>(
|
||||
"Import VL Key '" + strPk + "' was not a valid key type.");
|
||||
|
||||
cfg->IMPORT_VL_KEYS.emplace(strPk, makeSlice(*pkHex));
|
||||
}
|
||||
return cfg;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
hasUNLReport(jtx::Env const& env)
|
||||
{
|
||||
@@ -1413,45 +1323,5 @@ createUNLRTx(
|
||||
return STTx(ttUNL_REPORT, fill);
|
||||
}
|
||||
|
||||
/*
|
||||
inline STTx
|
||||
createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey)
|
||||
{
|
||||
auto fill = [&](auto& obj) {
|
||||
obj.setFieldU8(sfUNLModifyDisabling, disabling ? 1 : 0);
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
obj.setFieldVL(sfUNLModifyValidator, txKey);
|
||||
};
|
||||
return STTx(ttUNL_MODIFY, fill);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
inline std::size_t
|
||||
countTx(std::shared_ptr<SHAMap> const& txSet)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
for (auto i = txSet->begin(); i != txSet->end(); ++i)
|
||||
{
|
||||
auto raw = i->slice();
|
||||
if (raw[0] == 0x12U && raw[1] == 0 && raw[2] == 0x66U)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
inline bool
|
||||
applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass)
|
||||
{
|
||||
auto res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
|
||||
if (pass)
|
||||
return res.first == tesSUCCESS;
|
||||
else
|
||||
return res.first == tefFAILURE || res.first == temDISABLED;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
} // namespace ripple
|
||||
@@ -60,7 +60,6 @@
|
||||
#include <test/jtx/require.h>
|
||||
#include <test/jtx/requires.h>
|
||||
#include <test/jtx/reward.h>
|
||||
#include <test/jtx/remit.h>
|
||||
#include <test/jtx/sendmax.h>
|
||||
#include <test/jtx/seq.h>
|
||||
#include <test/jtx/sig.h>
|
||||
@@ -71,6 +70,7 @@
|
||||
#include <test/jtx/token.h>
|
||||
#include <test/jtx/trust.h>
|
||||
#include <test/jtx/txflags.h>
|
||||
#include <test/jtx/unl.h>
|
||||
#include <test/jtx/uritoken.h>
|
||||
#include <test/jtx/utility.h>
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/acctdelete.h>
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2023 XRPL Labs
|
||||
|
||||
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/protocol/jss.h>
|
||||
#include <test/jtx/remit.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
namespace remit {
|
||||
|
||||
Json::Value
|
||||
remit(jtx::Account const& account, jtx::Account const& dest)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::Remit;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[jss::Destination] = dest.human();
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
amts::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
auto& ja = jt.jv[sfAmounts.getJsonName()];
|
||||
for (std::size_t i = 0; i < amts_.size(); ++i)
|
||||
{
|
||||
ja[i][sfAmountEntry.jsonName] = Json::Value{};
|
||||
ja[i][sfAmountEntry.jsonName][jss::Amount] =
|
||||
amts_[i].getJson(JsonOptions::none);
|
||||
}
|
||||
jt.jv[sfAmounts.jsonName] = ja;
|
||||
}
|
||||
|
||||
void
|
||||
blob::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfBlob.jsonName] = blob_;
|
||||
}
|
||||
|
||||
void
|
||||
inform::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfInform.jsonName] = inform_.human();
|
||||
}
|
||||
|
||||
void
|
||||
token_ids::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
for (std::size_t i = 0; i < token_ids_.size(); ++i)
|
||||
{
|
||||
jt.jv[sfURITokenIDs.jsonName] = Json::arrayValue;
|
||||
jt.jv[sfURITokenIDs.jsonName][i] = token_ids_[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uri::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfMintURIToken.jsonName] = Json::Value{};
|
||||
jt.jv[sfMintURIToken.jsonName][sfURI.jsonName] = strHex(uri_);;
|
||||
}
|
||||
|
||||
} // namespace remit
|
||||
} // namespace jtx
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
95
src/test/jtx/impl/unl.cpp
Normal file
95
src/test/jtx/impl/unl.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2023 XRPL Labs
|
||||
|
||||
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/tx/apply.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/jtx/unl.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace unl {
|
||||
|
||||
bool
|
||||
negUnlSizeTest(
|
||||
std::shared_ptr<Ledger const> const& l,
|
||||
size_t size,
|
||||
bool hasToDisable,
|
||||
bool hasToReEnable)
|
||||
{
|
||||
bool sameSize = l->negativeUNL().size() == size;
|
||||
bool sameToDisable =
|
||||
(l->validatorToDisable() != std::nullopt) == hasToDisable;
|
||||
bool sameToReEnable =
|
||||
(l->validatorToReEnable() != std::nullopt) == hasToReEnable;
|
||||
|
||||
return sameSize && sameToDisable && sameToReEnable;
|
||||
}
|
||||
|
||||
bool
|
||||
applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass)
|
||||
{
|
||||
auto res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
|
||||
if (pass)
|
||||
return res.first == tesSUCCESS;
|
||||
else
|
||||
return res.first == tefFAILURE || res.first == temDISABLED;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
countTx(std::shared_ptr<SHAMap> const& txSet)
|
||||
{
|
||||
/*uint64_t counter = 0;
|
||||
if (txSet)
|
||||
for (auto const& item : *txSet)
|
||||
{
|
||||
|
||||
SerialIter sit(item.slice());
|
||||
auto tx = std::make_shared<STTx
|
||||
const>(SerialIter{sit.getSlice(sit.getVLDataLength())});
|
||||
|
||||
if (tx->getFieldU16(sfTransactionType) == ttUNL_MODIFY)
|
||||
counter++;
|
||||
}
|
||||
*/
|
||||
|
||||
std::size_t count = 0;
|
||||
for (auto i = txSet->begin(); i != txSet->end(); ++i)
|
||||
{
|
||||
// RH TODO: why does the above parse??
|
||||
auto raw = i->slice();
|
||||
if (raw[0] == 0x12U && raw[1] == 0 && raw[2] == 0x66U)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
STTx
|
||||
createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey)
|
||||
{
|
||||
auto fill = [&](auto& obj) {
|
||||
obj.setFieldU8(sfUNLModifyDisabling, disabling ? 1 : 0);
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
obj.setFieldVL(sfUNLModifyValidator, txKey);
|
||||
};
|
||||
return STTx(ttUNL_MODIFY, fill);
|
||||
}
|
||||
|
||||
} // namespace unl
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -1,118 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2023 XRPL Labs
|
||||
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TEST_JTX_REMIT_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_REMIT_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
namespace remit {
|
||||
|
||||
Json::Value
|
||||
remit(jtx::Account const& account, jtx::Account const& dest);
|
||||
|
||||
/** Sets the optional Amount on a JTx. */
|
||||
class amts
|
||||
{
|
||||
private:
|
||||
std::vector<STAmount> amts_;
|
||||
|
||||
public:
|
||||
explicit amts(std::vector<STAmount> const& amts) : amts_(amts)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Set the optional "Blob" on a JTx */
|
||||
class blob
|
||||
{
|
||||
private:
|
||||
std::string blob_;
|
||||
|
||||
public:
|
||||
explicit blob(std::string const& blob) : blob_(blob)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Sets the optional "Inform" on a JTx. */
|
||||
class inform
|
||||
{
|
||||
private:
|
||||
jtx::Account inform_;
|
||||
|
||||
public:
|
||||
explicit inform(jtx::Account const& inform) : inform_(inform)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Sets the optional "URITokenIDs" on a JTx. */
|
||||
class token_ids
|
||||
{
|
||||
private:
|
||||
std::vector<std::string> token_ids_;
|
||||
|
||||
public:
|
||||
explicit token_ids(std::vector<std::string> const& token_ids) : token_ids_(token_ids)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Set the optional "sfMintURIToken" on a JTx */
|
||||
class uri
|
||||
{
|
||||
private:
|
||||
std::string uri_;
|
||||
|
||||
public:
|
||||
explicit uri(std::string const& uri) : uri_(uri)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
} // namespace remit
|
||||
|
||||
} // namespace jtx
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_TEST_JTX_REMIT_H_INCLUDED
|
||||
86
src/test/jtx/unl.h
Normal file
86
src/test/jtx/unl.h
Normal file
@@ -0,0 +1,86 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2023 XRPL Labs
|
||||
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TEST_JTX_UNL_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_UNL_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
namespace unl {
|
||||
|
||||
/**
|
||||
* Test the size of the negative UNL in a ledger,
|
||||
* also test if the ledger has ToDisalbe and/or ToReEnable
|
||||
*
|
||||
* @param l the ledger
|
||||
* @param size the expected negative UNL size
|
||||
* @param hasToDisable if expect ToDisable in ledger
|
||||
* @param hasToReEnable if expect ToDisable in ledger
|
||||
* @return true if meet all three expectation
|
||||
*/
|
||||
bool
|
||||
negUnlSizeTest(
|
||||
std::shared_ptr<Ledger const> const& l,
|
||||
size_t size,
|
||||
bool hasToDisable,
|
||||
bool hasToReEnable);
|
||||
|
||||
/**
|
||||
* Try to apply a ttUNL_MODIFY Tx, and test the apply result
|
||||
*
|
||||
* @param env the test environment
|
||||
* @param view the OpenView of the ledger
|
||||
* @param tx the ttUNL_MODIFY Tx
|
||||
* @param pass if the Tx should be applied successfully
|
||||
* @return true if meet the expectation of apply result
|
||||
*/
|
||||
bool
|
||||
applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass);
|
||||
|
||||
/**
|
||||
* Count the number of Tx in a TxSet
|
||||
*
|
||||
* @param txSet the TxSet
|
||||
* @return the number of Tx
|
||||
*/
|
||||
std::size_t
|
||||
countTx(std::shared_ptr<SHAMap> const& txSet);
|
||||
|
||||
/**
|
||||
* Create ttUNL_MODIFY Tx
|
||||
*
|
||||
* @param disabling disabling or re-enabling a validator
|
||||
* @param seq current ledger seq
|
||||
* @param txKey the public key of the validator
|
||||
* @return the ttUNL_MODIFY Tx
|
||||
*/
|
||||
STTx
|
||||
createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey);
|
||||
|
||||
} // namespace unl
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_TEST_JTX_UNL_H_INCLUDED
|
||||
Reference in New Issue
Block a user