mirror of
https://github.com/Xahau/xahaud.git
synced 2026-06-02 16:26:37 +00:00
first part of featRNG
This commit is contained in:
@@ -103,6 +103,46 @@ applyTransactions(
|
||||
bool certainRetry = true;
|
||||
std::size_t count = 0;
|
||||
|
||||
if (view.rules.enabled(featureRNG))
|
||||
{
|
||||
// apply the ttRNG txns first in the ledger to ensure no one can predict the outcome
|
||||
for (it = txns.begin(); it != txns.end();)
|
||||
{
|
||||
if (it->second->getFieldU16(sfTransactionType) != ttRNG)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
switch (applyTransaction(
|
||||
app, view, *it->second, certainRetry, tapNONE, j))
|
||||
{
|
||||
case ApplyResult::Success:
|
||||
it = txns.erase(it);
|
||||
++count;
|
||||
break;
|
||||
|
||||
case ApplyResult::Fail:
|
||||
failed.insert(txid);
|
||||
it = txns.erase(it);
|
||||
break;
|
||||
|
||||
case ApplyResult::Retry:
|
||||
++it;
|
||||
}
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Transaction " << txid << " throws: " << ex.what();
|
||||
failed.insert(txid);
|
||||
it = txns.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to apply all of the retriable transactions
|
||||
for (int pass = 0; pass < LEDGER_TOTAL_PASSES; ++pass)
|
||||
{
|
||||
|
||||
@@ -1477,6 +1477,104 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
}
|
||||
}
|
||||
|
||||
// Inject an RNG psuedo if we're on the UNL
|
||||
if (view.rules().enabled(featureRNG))
|
||||
{
|
||||
do
|
||||
{
|
||||
// if we're not a validator we do nothing here
|
||||
if (app.getValidationPublicKey().empty())
|
||||
break;
|
||||
|
||||
auto const& keys = app.getValidatorKeys();
|
||||
|
||||
if (keys.configInvalid())
|
||||
break;
|
||||
|
||||
// and if we're not on the UNLReport we also do nothing
|
||||
|
||||
auto const unlRep = view.read(keylet::UNLReport());
|
||||
if (!unlRep || !unlRep->isFieldPresent(sfActiveValidators))
|
||||
{
|
||||
// nothing to do without a unlreport object
|
||||
break;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
auto const& avs = unlRep->getFieldArray(sfActiveValidators);
|
||||
for (auto const& av : avs)
|
||||
{
|
||||
if (PublicKey(av[sfPublicKey]) == keys.masterPublicKey)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
break;
|
||||
|
||||
auto const seq = view.info().seq;
|
||||
|
||||
AccountID acc = calcAccountID(keys.masterPublicKey);
|
||||
|
||||
static auto getRnd = []() -> uint256 {
|
||||
static std::ifstream rng("/dev/urandom", std::ios::binary);
|
||||
uint256 out;
|
||||
if (rng && rng.read(reinterpret_cast<char*>(out.data()), 32))
|
||||
return out;
|
||||
std::random_device rd;
|
||||
for (auto& word : out)
|
||||
word = rd();
|
||||
return out;
|
||||
};
|
||||
|
||||
static std::map<uint32_t /* ledger seq */ , uint256 /* chosen rnd no */> rngMap;
|
||||
|
||||
uint256 nextRnd = getRnd();
|
||||
|
||||
if (rngMap.find(seq) != rngMap.end())
|
||||
break; // should never happen
|
||||
|
||||
rngMap[seq] = nextRnd;
|
||||
|
||||
std::optional<uint256> prevRnd;
|
||||
|
||||
if (rngMap.find(seq - 1))
|
||||
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
|
||||
STTx rngTx(ttRNG, [&](auto& obj) {
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
obj.setAccountID(sfValidator, acc);
|
||||
if (prevRnd.has_value())
|
||||
obj.setFieldH256(sfLastSolution, *prevRnd);
|
||||
obj.setFieldH256(sfDigest, sha512Half(nextRnd);
|
||||
});
|
||||
|
||||
// submit to the ledger
|
||||
{
|
||||
uint256 txID = rngTx.getTransactionID();
|
||||
auto s = std::make_shared<ripple::Serializer>();
|
||||
exportTx.add(*s);
|
||||
app.getHashRouter().setFlags(txID, SF_PRIVATE2);
|
||||
app.getHashRouter().setFlags(txID, SF_EMITTED);
|
||||
view.rawTxInsert(txID, std::move(s), nullptr);
|
||||
ledgerChanged = true;
|
||||
}
|
||||
|
||||
} while (0);
|
||||
}
|
||||
|
||||
// Inject cron transactions, if any
|
||||
if (view.rules().enabled(featureCron))
|
||||
{
|
||||
|
||||
@@ -154,6 +154,7 @@ Change::preclaim(PreclaimContext const& ctx)
|
||||
case ttAMENDMENT:
|
||||
case ttUNL_MODIFY:
|
||||
case ttEMIT_FAILURE:
|
||||
case ttRNG:
|
||||
return tesSUCCESS;
|
||||
case ttUNL_REPORT: {
|
||||
if (!ctx.tx.isFieldPresent(sfImportVLKey) ||
|
||||
@@ -209,6 +210,8 @@ Change::doApply()
|
||||
return applyEmitFailure();
|
||||
case ttUNL_REPORT:
|
||||
return applyUNLReport();
|
||||
case ttRNG:
|
||||
return applyRNG();
|
||||
default:
|
||||
assert(0);
|
||||
return tefFAILURE;
|
||||
|
||||
@@ -152,6 +152,7 @@ invoke_preflight(PreflightContext const& ctx)
|
||||
case ttUNL_MODIFY:
|
||||
case ttUNL_REPORT:
|
||||
case ttEMIT_FAILURE:
|
||||
case ttRNG:
|
||||
return invoke_preflight_helper<Change>(ctx);
|
||||
case ttHOOK_SET:
|
||||
return invoke_preflight_helper<SetHook>(ctx);
|
||||
@@ -283,6 +284,7 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
case ttUNL_MODIFY:
|
||||
case ttUNL_REPORT:
|
||||
case ttEMIT_FAILURE:
|
||||
case ttRNG:
|
||||
return invoke_preclaim<Change>(ctx);
|
||||
case ttNFTOKEN_MINT:
|
||||
return invoke_preclaim<NFTokenMint>(ctx);
|
||||
@@ -374,6 +376,7 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
case ttUNL_MODIFY:
|
||||
case ttUNL_REPORT:
|
||||
case ttEMIT_FAILURE:
|
||||
case ttRNG:
|
||||
return Change::calculateBaseFee(view, tx);
|
||||
case ttNFTOKEN_MINT:
|
||||
return NFTokenMint::calculateBaseFee(view, tx);
|
||||
@@ -544,6 +547,7 @@ invoke_apply(ApplyContext& ctx)
|
||||
case ttFEE:
|
||||
case ttUNL_MODIFY:
|
||||
case ttUNL_REPORT:
|
||||
case ttRNG:
|
||||
case ttEMIT_FAILURE: {
|
||||
Change p(ctx);
|
||||
return p();
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 90;
|
||||
static constexpr std::size_t numFeatures = 91;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -378,6 +378,7 @@ extern uint256 const fixInvalidTxFlags;
|
||||
extern uint256 const featureExtendedHookState;
|
||||
extern uint256 const fixCronStacking;
|
||||
extern uint256 const fixHookAPI20251128;
|
||||
extern uint256 const featureRNG;
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -563,6 +563,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 sfValidator;
|
||||
|
||||
// path set
|
||||
extern SField const sfPaths;
|
||||
|
||||
@@ -149,6 +149,10 @@ enum TxType : std::uint16_t
|
||||
ttURITOKEN_CREATE_SELL_OFFER = 48,
|
||||
ttURITOKEN_CANCEL_SELL_OFFER = 49,
|
||||
|
||||
/* A pseudo-txn used by featureRNG which allows validators to submit blinded entropy
|
||||
* to a consensus based random number system */
|
||||
ttRNG = 89,
|
||||
|
||||
/* A pseudo-txn alarm signal for invoking a hook, emitted by validators after alarm set conditions are met */
|
||||
ttCRON = 92,
|
||||
|
||||
|
||||
@@ -484,6 +484,7 @@ REGISTER_FIX (fixInvalidTxFlags, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(ExtendedHookState, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixCronStacking, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixHookAPI20251128, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(RNG, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -316,6 +316,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(sfValidator, "Validator", ACCOUNT, 98);
|
||||
|
||||
// vector of 256-bit
|
||||
CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never);
|
||||
|
||||
Reference in New Issue
Block a user