mirror of
https://github.com/Xahau/xahaud.git
synced 2026-07-23 15:10:10 +00:00
fix(entropy): canonicalize dice word order
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
@@ -57,6 +58,30 @@ standaloneContributorMask(std::uint16_t denominator, std::uint16_t count)
|
||||
return mask;
|
||||
}
|
||||
|
||||
std::uint32_t
|
||||
expectedDice(uint256 block, std::uint32_t sides)
|
||||
{
|
||||
auto const sampleRange =
|
||||
std::uint64_t{std::numeric_limits<std::uint32_t>::max()} + 1;
|
||||
auto const acceptLimit = sampleRange - (sampleRange % sides);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (std::size_t i = 0; i < block.size(); i += sizeof(std::uint32_t))
|
||||
{
|
||||
auto const* candidate = block.data() + i;
|
||||
std::uint32_t const value =
|
||||
(std::uint32_t{candidate[0]} << 24U) |
|
||||
(std::uint32_t{candidate[1]} << 16U) |
|
||||
(std::uint32_t{candidate[2]} << 8U) |
|
||||
std::uint32_t{candidate[3]};
|
||||
if (value < acceptLimit)
|
||||
return value % sides;
|
||||
}
|
||||
block = sha512Half(Slice{block.data(), block.size()});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
@@ -208,6 +233,11 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
auto const entropy = env.le(keylet::consensusEntropy());
|
||||
BEAST_REQUIRE(entropy);
|
||||
auto const entropyDigest = entropy->getFieldH256(sfDigest);
|
||||
auto const drawLedgerSeq = env.current()->info().seq;
|
||||
|
||||
// Invoke the hook
|
||||
Json::Value invoke;
|
||||
invoke[jss::TransactionType] = "Invoke";
|
||||
@@ -222,10 +252,21 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
BEAST_REQUIRE(hookExecutions.size() == 1);
|
||||
|
||||
auto const returnCode = hookExecutions[0].getFieldU64(sfHookReturnCode);
|
||||
auto const firstBlock = sha512Half(
|
||||
drawLedgerSeq,
|
||||
env.tx()->getTransactionID(),
|
||||
alice.id(),
|
||||
hookExecutions[0].getFieldH256(sfHookHash),
|
||||
alice.id(),
|
||||
std::uint8_t{0},
|
||||
std::string{"strong"},
|
||||
std::string{"direct"},
|
||||
entropyDigest,
|
||||
std::uint64_t{0});
|
||||
auto const expected = expectedDice(firstBlock, 6);
|
||||
std::cerr << " dice(6) returnCode = " << returnCode << " (hex 0x"
|
||||
<< std::hex << returnCode << std::dec << ")\n";
|
||||
// dice(6) returns 0..5
|
||||
BEAST_EXPECT(returnCode <= 5);
|
||||
BEAST_EXPECT(returnCode == expected);
|
||||
|
||||
// Result should be 3 (accept)
|
||||
BEAST_EXPECT(hookExecutions[0].getFieldU8(sfHookResult) == 3);
|
||||
|
||||
@@ -230,7 +230,8 @@ entropyDigest, i)`. The counter is local to one Hook execution role and is
|
||||
post-incremented once when a draw stream passes snapshot admission; rejected
|
||||
arguments or entropy do not consume it. Further blocks are
|
||||
`sha512Half(previousBlock)`. `dice` rejects zero sides and uses deterministic
|
||||
32-bit rejection sampling rather than biased modulo reduction. `random` accepts
|
||||
unsigned big-endian 32-bit rejection sampling rather than biased modulo
|
||||
reduction. `random` accepts
|
||||
one through 512 requested bytes, rounds its internal generation length to a
|
||||
32-byte boundary, and writes only the requested prefix. Missing, malformed,
|
||||
future, older-than-one-ledger, or below-tier entropy makes either draw return
|
||||
|
||||
@@ -4204,8 +4204,12 @@ DEFINE_HOOK_FUNCTION(int64_t, dice, uint32_t sides, uint32_t min_tier)
|
||||
for (std::size_t i = 0; i + sizeof(std::uint32_t) <= bytes.size();
|
||||
i += sizeof(std::uint32_t))
|
||||
{
|
||||
std::uint32_t value;
|
||||
std::memcpy(&value, bytes.data() + i, sizeof(std::uint32_t));
|
||||
auto const* candidate = bytes.data() + i;
|
||||
std::uint32_t const value =
|
||||
(std::uint32_t{candidate[0]} << 24U) |
|
||||
(std::uint32_t{candidate[1]} << 16U) |
|
||||
(std::uint32_t{candidate[2]} << 8U) |
|
||||
std::uint32_t{candidate[3]};
|
||||
if (value < acceptLimit)
|
||||
return value % sides;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user