mirror of
https://github.com/Xahau/xahaud.git
synced 2026-06-02 16:26:37 +00:00
code complete, compiling untested
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include <ripple/app/misc/CanonicalTXSet.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -103,10 +104,10 @@ applyTransactions(
|
||||
bool certainRetry = true;
|
||||
std::size_t count = 0;
|
||||
|
||||
if (view.rules.enabled(featureRNG))
|
||||
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();)
|
||||
for (auto it = txns.begin(); it != txns.end();)
|
||||
{
|
||||
if (it->second->getFieldU16(sfTransactionType) != ttRNG)
|
||||
{
|
||||
@@ -114,6 +115,7 @@ applyTransactions(
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const txid = it->first.getTXID();
|
||||
try
|
||||
{
|
||||
switch (applyTransaction(
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <ripple/protocol/digest.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -1486,13 +1487,7 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
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))
|
||||
{
|
||||
@@ -1504,7 +1499,7 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
auto const& avs = unlRep->getFieldArray(sfActiveValidators);
|
||||
for (auto const& av : avs)
|
||||
{
|
||||
if (PublicKey(av[sfPublicKey]) == keys.masterPublicKey)
|
||||
if (PublicKey(av[sfPublicKey]) == app.getValidationPublicKey())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
@@ -1516,7 +1511,7 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
|
||||
auto const seq = view.info().seq;
|
||||
|
||||
AccountID acc = calcAccountID(keys.masterPublicKey);
|
||||
AccountID acc = calcAccountID(app.getValidationPublicKey());
|
||||
|
||||
static auto getRnd = []() -> uint256 {
|
||||
static std::ifstream rng("/dev/urandom", std::ios::binary);
|
||||
@@ -1540,7 +1535,7 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
|
||||
std::optional<uint256> prevRnd;
|
||||
|
||||
if (rngMap.find(seq - 1))
|
||||
if (rngMap.find(seq - 1) != rngMap.end())
|
||||
prevRnd = rngMap[seq - 1];
|
||||
|
||||
// amortized cleanup, for every ledger attempt to delete two old entries
|
||||
@@ -1557,15 +1552,16 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
obj.setAccountID(sfValidator, acc);
|
||||
if (prevRnd.has_value())
|
||||
obj.setFieldH256(sfLastSolution, *prevRnd);
|
||||
obj.setFieldH256(sfDigest, sha512Half(nextRnd);
|
||||
obj.setFieldH256(sfRandomData, *prevRnd);
|
||||
obj.setFieldH256(sfNextRandomDigest, sha512Half(nextRnd));
|
||||
// RH TODO: should we sign this??
|
||||
});
|
||||
|
||||
// submit to the ledger
|
||||
{
|
||||
uint256 txID = rngTx.getTransactionID();
|
||||
auto s = std::make_shared<ripple::Serializer>();
|
||||
exportTx.add(*s);
|
||||
rngTx.add(*s);
|
||||
app.getHashRouter().setFlags(txID, SF_PRIVATE2);
|
||||
app.getHashRouter().setFlags(txID, SF_EMITTED);
|
||||
view.rawTxInsert(txID, std::move(s), nullptr);
|
||||
|
||||
@@ -96,6 +96,12 @@ Change::preflight(PreflightContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.tx.getTxnType() == ttRNG && !ctx.rules.enabled(featureRNG))
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Change: FeatureRNG is not enabled.";
|
||||
return temDISABLED;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -218,6 +224,125 @@ Change::doApply()
|
||||
}
|
||||
}
|
||||
|
||||
TER
|
||||
Change::applyRNG()
|
||||
{
|
||||
|
||||
auto const seq = view().info().seq;
|
||||
|
||||
if (seq != ctx_.tx.getFieldU32(sfLedgerSequence))
|
||||
{
|
||||
JLOG(j_.warn()) << "Change: ttRNG, wrong ledger seq=" << seq;
|
||||
return tefFAILURE;
|
||||
}
|
||||
|
||||
auto sle = view().peek(keylet::random());
|
||||
|
||||
bool const created = !sle;
|
||||
|
||||
if (created)
|
||||
{
|
||||
sle = std::make_shared<SLE>(keylet::random());
|
||||
}
|
||||
|
||||
auto lastSeq = created ? 0 : sle->getFieldU32(sfLedgerSequence);
|
||||
|
||||
if (lastSeq < seq)
|
||||
{
|
||||
// update the ledger sequence of the object
|
||||
sle->setFieldU32(sfLedgerSequence, seq);
|
||||
|
||||
// reset entropy count to zero... this will probably be
|
||||
// one after the below executes but its possible the digest
|
||||
// doesn't match and the entropy count isn't incremented
|
||||
sle->setFieldU16(sfEntropyCount, 0);
|
||||
|
||||
// swap the random data out ready for this round of entropy collection
|
||||
sle->setFieldH256(sfLastRandomData, sle->getFieldH256(sfRandomData));
|
||||
sle->setFieldH256(sfRandomData, beast::zero);
|
||||
}
|
||||
|
||||
uint256 nextDigest = ctx_.tx.getFieldH256(sfNextRandomDigest);
|
||||
uint256 currentEntropy = ctx_.tx.getFieldH256(sfRandomData);
|
||||
uint256 currentDigest = sha512Half(currentEntropy);
|
||||
|
||||
AccountID const validator = ctx_.tx.getAccountID(sfValidator);
|
||||
|
||||
// RH TODO: check if they're on the UNLReport and ignore if not
|
||||
|
||||
// iterate the digest array to find the entry if it exists
|
||||
STArray digestEntries = sle->getFieldArray(sfRandomDigests);
|
||||
std::map<AccountID, STObject> entries;
|
||||
|
||||
for (auto& entry : digestEntries)
|
||||
{
|
||||
// we'll automatically clean up really old entries by just omitting them from
|
||||
// the map here
|
||||
if (entry.getFieldU32(sfLedgerSequence) < seq - 5)
|
||||
continue;
|
||||
|
||||
entries.emplace(entry.getAccountID(sfValidator), std::move(entry));
|
||||
}
|
||||
|
||||
if (auto it = entries.find(validator); it != entries.end())
|
||||
{
|
||||
auto& entry = it->second;
|
||||
|
||||
// ensure the precommitted digest matches the provided entropy
|
||||
if (entry.getFieldH256(sfNextRandomDigest) != currentDigest)
|
||||
{
|
||||
if (entry.getFieldU32(sfLedgerSequence) != seq - 1)
|
||||
{
|
||||
// this is a skip-ahead or missed last txn somehow, so ignore, but no warning.
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a clear violation so warn (and ignore the entropy)
|
||||
JLOG(j_.warn()) << "!!! Validator " << validator << " supplied entropy that "
|
||||
<< "does not match precommitment value !!!";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// contribute the new entropy to the random data field
|
||||
sle->setFieldH256(sfRandomData, sha512Half(validator, sle->getFieldH256(sfRandomData), currentEntropy));
|
||||
|
||||
// increment entropy count
|
||||
sle->setFieldU16(sfEntropyCount, sle->getFieldU16(sfEntropyCount) + 1);
|
||||
}
|
||||
|
||||
// update the digest entry
|
||||
entry.setFieldH256(sfNextRandomDigest, nextDigest);
|
||||
entry.setFieldU32(sfLedgerSequence, seq);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this validator doesn't have an entry so create one
|
||||
STObject entry{sfRandomDigestEntry};
|
||||
entry.setAccountID(sfValidator, validator);
|
||||
entry.setFieldH256(sfNextRandomDigest, nextDigest);
|
||||
entry.setFieldU32(sfLedgerSequence, seq);
|
||||
entries.emplace(validator, std::move(entry));
|
||||
}
|
||||
|
||||
// update the array
|
||||
STArray newEntries(sfRandomDigests);
|
||||
newEntries.reserve(entries.size());
|
||||
for (auto& [_, entry] : entries)
|
||||
newEntries.push_back(std::move(entry));
|
||||
|
||||
sle->setFieldArray(sfRandomDigests, std::move(newEntries));
|
||||
|
||||
// send it off to the ledger
|
||||
if (!created)
|
||||
view().update(sle);
|
||||
else
|
||||
view().insert(sle);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
Change::applyUNLReport()
|
||||
{
|
||||
|
||||
@@ -76,6 +76,9 @@ private:
|
||||
|
||||
TER
|
||||
applyUNLReport();
|
||||
|
||||
TER
|
||||
applyRNG();
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -51,6 +51,9 @@ class SeqProxy;
|
||||
*/
|
||||
namespace keylet {
|
||||
|
||||
Keylet const&
|
||||
random() noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing the emitted txns for the ledger.
|
||||
*/
|
||||
Keylet const&
|
||||
|
||||
@@ -260,6 +260,13 @@ enum LedgerEntryType : std::uint16_t
|
||||
\sa keylet::emitted
|
||||
*/
|
||||
ltEMITTED_TXN = 'E',
|
||||
|
||||
|
||||
/** A ledger object containing a consensus-generated random number, operated on by ttRNG
|
||||
|
||||
\sa keylet::rng
|
||||
*/
|
||||
ltRANDOM = 0x526EU, // Rn
|
||||
};
|
||||
// clang-format off
|
||||
|
||||
|
||||
@@ -355,6 +355,7 @@ extern SF_UINT16 const sfHookEmitCount;
|
||||
extern SF_UINT16 const sfHookExecutionIndex;
|
||||
extern SF_UINT16 const sfHookApiVersion;
|
||||
extern SF_UINT16 const sfHookStateScale;
|
||||
extern SF_UINT16 const sfEntropyCount;
|
||||
|
||||
// 32-bit integers (common)
|
||||
extern SF_UINT32 const sfNetworkID;
|
||||
@@ -491,6 +492,9 @@ extern SF_UINT256 const sfGovernanceFlags;
|
||||
extern SF_UINT256 const sfGovernanceMarks;
|
||||
extern SF_UINT256 const sfEmittedTxnID;
|
||||
extern SF_UINT256 const sfCron;
|
||||
extern SF_UINT256 const sfRandomData;
|
||||
extern SF_UINT256 const sfLastRandomData;
|
||||
extern SF_UINT256 const sfNextRandomDigest;
|
||||
|
||||
// currency amount (common)
|
||||
extern SF_AMOUNT const sfAmount;
|
||||
@@ -606,6 +610,7 @@ extern SField const sfHookEmission;
|
||||
extern SField const sfMintURIToken;
|
||||
extern SField const sfAmountEntry;
|
||||
extern SField const sfRemark;
|
||||
extern SField const sfRandomDigestEntry;
|
||||
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -635,6 +640,7 @@ extern SField const sfImportVLKeys;
|
||||
extern SField const sfHookEmissions;
|
||||
extern SField const sfAmounts;
|
||||
extern SField const sfRemarks;
|
||||
extern SField const sfRandomDigests;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
IMPORT_VLSEQ = 'I',
|
||||
UNL_REPORT = 'R',
|
||||
CRON = 'L',
|
||||
RANDOM = 0x526E, // Rn
|
||||
|
||||
// No longer used or supported. Left here to reserve the space
|
||||
// to avoid accidental reuse.
|
||||
@@ -496,6 +497,14 @@ cron(uint32_t timestamp, std::optional<AccountID> const& id)
|
||||
return {ltCRON, uint256::fromVoid(h)};
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
random() noexcept
|
||||
{
|
||||
static Keylet const ret{
|
||||
ltRANDOM, indexHash(LedgerNameSpace::RANDOM)};
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -167,6 +167,14 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfRemarkValue, soeOPTIONAL},
|
||||
{sfFlags, soeOPTIONAL},
|
||||
});
|
||||
|
||||
add(sfRandomDigestEntry.jsonName.c_str(),
|
||||
sfRandomDigestEntry.getCode(),
|
||||
{
|
||||
{sfValidator, soeREQUIRED},
|
||||
{sfNextRandomDigest, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
@@ -381,6 +381,20 @@ LedgerFormats::LedgerFormats()
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Random,
|
||||
ltRANDOM,
|
||||
{
|
||||
{sfRandomData, soeREQUIRED},
|
||||
{sfLastRandomData, soeREQUIRED},
|
||||
{sfEntropyCount, soeREQUIRED},
|
||||
{sfRandomDigests, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ CONSTRUCT_TYPED_SFIELD(sfHookEmitCount, "HookEmitCount", UINT16,
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookExecutionIndex, "HookExecutionIndex", UINT16, 19);
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookApiVersion, "HookApiVersion", UINT16, 20);
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookStateScale, "HookStateScale", UINT16, 21);
|
||||
CONSTRUCT_TYPED_SFIELD(sfEntropyCount, "EntropyCount", UINT16, 99);
|
||||
|
||||
// 32-bit integers (common)
|
||||
CONSTRUCT_TYPED_SFIELD(sfNetworkID, "NetworkID", UINT32, 1);
|
||||
@@ -244,6 +245,9 @@ CONSTRUCT_TYPED_SFIELD(sfGovernanceMarks, "GovernanceMarks", UINT256,
|
||||
CONSTRUCT_TYPED_SFIELD(sfEmittedTxnID, "EmittedTxnID", UINT256, 97);
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookCanEmit, "HookCanEmit", UINT256, 96);
|
||||
CONSTRUCT_TYPED_SFIELD(sfCron, "Cron", UINT256, 95);
|
||||
CONSTRUCT_TYPED_SFIELD(sfRandomData, "RandomData", UINT256, 94);
|
||||
CONSTRUCT_TYPED_SFIELD(sfLastRandomData, "LastRandomData", UINT256, 93);
|
||||
CONSTRUCT_TYPED_SFIELD(sfNextRandomDigest, "NextRandomDigest", UINT256, 92);
|
||||
|
||||
// currency amount (common)
|
||||
CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1);
|
||||
@@ -362,6 +366,7 @@ CONSTRUCT_UNTYPED_SFIELD(sfImportVLKey, "ImportVLKey", OBJECT,
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfHookEmission, "HookEmission", OBJECT, 93);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfMintURIToken, "MintURIToken", OBJECT, 92);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfAmountEntry, "AmountEntry", OBJECT, 91);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfRandomDigestEntry, "RandomDigestEntry", OBJECT, 89);
|
||||
|
||||
// array of objects
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -388,6 +393,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(sfRandomDigests, "RandomDigests", ARRAY, 91);
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -615,7 +615,8 @@ isPseudoTx(STObject const& tx)
|
||||
|
||||
auto tt = safe_cast<TxType>(*t);
|
||||
return tt == ttAMENDMENT || tt == ttFEE || tt == ttUNL_MODIFY ||
|
||||
tt == ttEMIT_FAILURE || tt == ttUNL_REPORT || tt == ttCRON;
|
||||
tt == ttEMIT_FAILURE || tt == ttUNL_REPORT || tt == ttCRON ||
|
||||
tt == ttRNG;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -490,6 +490,16 @@ TxFormats::TxFormats()
|
||||
{sfStartTime, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Rng,
|
||||
ttRNG,
|
||||
{
|
||||
{sfValidator, soeREQUIRED},
|
||||
{sfRandomData, soeREQUIRED},
|
||||
{sfNextRandomDigest, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
},
|
||||
commonFields);
|
||||
}
|
||||
|
||||
TxFormats const&
|
||||
|
||||
@@ -123,6 +123,8 @@ JSS(PaymentChannelCreate); // transaction type.
|
||||
JSS(PaymentChannelFund); // transaction type.
|
||||
JSS(Remit); // transaction type.
|
||||
JSS(RippleState); // ledger type.
|
||||
JSS(Rng);
|
||||
JSS(Random);
|
||||
JSS(SLE_hit_rate); // out: GetCounts.
|
||||
JSS(SetFee); // transaction type.
|
||||
JSS(SetRemarks); // transaction type
|
||||
|
||||
Reference in New Issue
Block a user