ttENTROPY working

This commit is contained in:
Richard Holland
2026-01-03 15:19:03 +11:00
parent 55438ffc45
commit b6a23d6d3b
7 changed files with 74 additions and 46 deletions

View File

@@ -1931,13 +1931,18 @@ TxQ::tryDirectApply(
const bool isFirstImport = !sleAccount &&
view.rules().enabled(featureImport) && tx->getTxnType() == ttIMPORT;
const bool isUV =
view.rules().enabled(featureRNG) && tx->getTxnType() == ttENTROPY;
const bool accRequired = !(isFirstImport || isUV);
// Don't attempt to direct apply if the account is not in the ledger.
if (!sleAccount && !isFirstImport)
if (!sleAccount && accRequired)
return {};
std::optional<SeqProxy> txSeqProx;
if (!isFirstImport)
if (accRequired)
{
SeqProxy const acctSeqProx =
SeqProxy::sequence((*sleAccount)[sfSequence]);
@@ -1950,7 +1955,7 @@ TxQ::tryDirectApply(
}
FeeLevel64 const requiredFeeLevel =
isFirstImport ? FeeLevel64{0} : [this, &view, flags]() {
!accRequired ? FeeLevel64{0} : [this, &view, flags]() {
std::lock_guard lock(mutex_);
return getRequiredFeeLevel(
view, flags, feeMetrics_.getSnapshot(), lock);

View File

@@ -319,7 +319,7 @@ saveValidatedLedger(
*db << sql;
}
else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
!isPseudoTx(*sleTxn))
!isPseudoTx(*sleTxn) && !isUVTx(*sleTxn))
{
// It's okay for pseudo transactions to not affect any
// accounts. But otherwise...

View File

@@ -23,6 +23,7 @@
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/st.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
@@ -47,17 +48,16 @@ Entropy::preclaim(PreclaimContext const& ctx)
if (!ctx.view.rules().enabled(featureRNG))
return temDISABLED;
auto const seq = ctx.view.info().seq;
// auto const seq = ctx.view.info().seq;
auto const txLgrSeq = ctx.tx[sfLedgerSequence];
// auto const txLgrSeq = ctx.tx[sfLedgerSequence];
// we will not process and can never accept any txns that aren't introduced this ledger
// for this ledger.
if (seq != txLgrSeq)
{
JLOG(ctx.j.warn()) << "Entropy: wrong ledger seq=" << seq;
return tefFAILURE;
}
// due to circulation we'll accept up to one ledger old entropy txns
// if (seq != txLgrSeq)
// {
// JLOG(ctx.j.warn()) << "Entropy: wrong ledger txseq=" << txLgrSeq << " lgrseq=" << seq << " acc:" << ctx.tx.getAccountID(sfAccount);
// return tefFAILURE;
// }
// account must be a valid UV
if (!inUNLReport(ctx.view, ctx.tx.getAccountID(sfAccount), ctx.j))
@@ -76,10 +76,10 @@ Entropy::doApply()
auto const seq = view().info().seq;
if (seq != ctx_.tx.getFieldU32(sfLedgerSequence))
{
return tefFAILURE;
}
// if (seq != ctx_.tx.getFieldU32(sfLedgerSequence))
// {
// return tefFAILURE;
// }
auto sle = view().peek(keylet::random());
@@ -268,43 +268,33 @@ makeEntropyTxn(OpenView& view, Application& app, beast::Journal const& j_)
return out;
};
static std::map<uint32_t /* ledger seq */ , uint256 /* chosen rnd no */> rngMap;
static std::optional<uint256> prevRnd;
uint256 nextRnd = getRnd();
if (rngMap.find(seq) != rngMap.end())
return {};
rngMap[seq] = nextRnd;
std::optional<uint256> prevRnd;
if (rngMap.find(seq - 1) != rngMap.end())
prevRnd = rngMap[seq - 1];
// amortized cleanup, for every ledger attempt to delete two old entries
// even in the most desynced ridiculous state this is guaranteed prevent map growth
for (int i = 0; i < 2; ++i)
{
auto it = rngMap.begin();
if (it != rngMap.end() && it->first < seq)
rngMap.erase(it->first);
}
// create txn
auto rngTx = std::make_shared<STTx>(ttENTROPY, [&](auto& obj) {
obj.setFieldU32(sfLedgerSequence, seq);
obj.setFieldU32(sfLastLedgerSequence, seq);
obj.setAccountID(sfAccount, acc);
obj.setFieldU32(sfSequence, 0);
if (prevRnd.has_value())
obj.setFieldH256(sfRandomData, *prevRnd);
obj.setFieldH256(sfNextRandomDigest, sha512Half(nextRnd));
obj.setFieldVL(sfSigningPubKey, pk.slice());
obj.setFieldVL(sfSigningPubKey, pkSigning.slice());
obj.setFieldH256(sfParentHash, view.info().parentHash);
obj.setFieldU32(sfFlags, tfFullyCanonicalSig);
if (app.config().NETWORK_ID > 1024)
obj.setFieldU32(sfNetworkID, app.config().NETWORK_ID);
});
prevRnd = nextRnd;
// sign the txn using our ephemeral key
rngTx->sign(pk, app.getValidationSecretKey());
rngTx->sign(pkSigning, app.getValidationSecretKey());
JLOG(j_.debug()) << "ENTROPY txn: " << rngTx->getFullText();
return rngTx;
}

View File

@@ -280,13 +280,18 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
// * The additional cost of each multisignature on the transaction.
XRPAmount baseFee = view.fees().base;
if (tx.getFieldU16(sfTransactionType) == ttIMPORT)
auto const tt = tx.getFieldU16(sfTransactionType);
if (tt == ttIMPORT)
{
XRPAmount const importFee = baseFee * 10;
if (importFee > baseFee)
baseFee = importFee;
}
if (tt == ttENTROPY)
return XRPAmount{0};
// Each signer adds one more baseFee to the minimum required fee
// for the transaction.
std::size_t const signerCount =
@@ -476,6 +481,9 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
{
if (ctx.tx.getTxnType() == ttENTROPY)
return tesSUCCESS;
if (ctx.tx.getTxnType() == ttIMPORT)
{
if (!ctx.tx.isFieldPresent(sfIssuer))
@@ -650,7 +658,13 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx)
ctx.view.rules().enabled(featureImport) &&
ctx.tx.getTxnType() == ttIMPORT && !ctx.tx.isFieldPresent(sfIssuer);
if (!sle && !isFirstImport)
bool const isUV =
ctx.view.rules().enabled(featureRNG) &&
ctx.tx.getTxnType() == ttENTROPY;
bool const accRequired = !(isFirstImport || isUV);
if (!sle && accRequired)
{
JLOG(ctx.j.trace())
<< "applyTransaction: delay: source account does not exist "
@@ -806,12 +820,13 @@ Transactor::apply()
auto const sle = view().peek(keylet::account(account_));
// sle must exist except for transactions
// that allow zero account. (and ttIMPORT)
// that allow zero account. (and ttIMPORT and UV)
assert(
sle != nullptr || account_ == beast::zero ||
view().rules().enabled(featureImport) &&
ctx_.tx.getTxnType() == ttIMPORT &&
!ctx_.tx.isFieldPresent(sfIssuer));
!ctx_.tx.isFieldPresent(sfIssuer) ||
ctx_.tx.getTxnType() == ttENTROPY);
if (sle)
{

View File

@@ -171,6 +171,9 @@ sterilize(STTx const& stx);
bool
isPseudoTx(STObject const& tx);
bool
isUVTx(STObject const& tx);
inline STTx::STTx(SerialIter&& sit) : STTx(sit)
{
}

View File

@@ -324,13 +324,18 @@ STTx::checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const
fullyCanonical);
}
}
catch (std::exception const&)
catch (std::exception const & e)
{
// Assume it was a signature failure.
validSig = false;
std::cout << "Invalid cause: " << e.what() << "\n";
}
if (validSig == false)
{
std::cout << "Invalid signature on tx: " << this->getFullText() << "\n";
return Unexpected("Invalid signature.");
}
// Signature was verified.
return {};
}
@@ -618,4 +623,15 @@ isPseudoTx(STObject const& tx)
tt == ttEMIT_FAILURE || tt == ttUNL_REPORT || tt == ttCRON || tt == ttSHUFFLE;
}
bool
isUVTx(STObject const& tx)
{
auto t = tx[~sfTransactionType];
if (!t)
return false;
auto tt = safe_cast<TxType>(*t);
return tt == ttENTROPY;
}
} // namespace ripple

View File

@@ -496,7 +496,6 @@ TxFormats::TxFormats()
{
{sfRandomData, soeREQUIRED},
{sfNextRandomDigest, soeREQUIRED},
{sfLedgerSequence, soeREQUIRED},
{sfParentHash, soeREQUIRED},
},
commonFields);