mirror of
https://github.com/Xahau/xahaud.git
synced 2026-07-25 16:10:15 +00:00
feat: simplify entropy Hook quality gates
This commit is contained in:
@@ -357,24 +357,30 @@ xport_cancel(uint32_t read_ptr, uint32_t read_len, uint32_t flags);
|
||||
/*
|
||||
Consensus entropy APIs.
|
||||
|
||||
min_tier is a fail-closed floor:
|
||||
1 = consensus_fallback, 2 = participant_aligned, 3 = validator_quorum.
|
||||
min_count is the minimum validator/reveal count the caller accepts.
|
||||
min_tier is a required fail-closed floor:
|
||||
1 = consensus_fallback, 2 = participant_aligned,
|
||||
3 = validator_quorum, 4 = validator_full.
|
||||
|
||||
If the most recent finalized entropy object does not satisfy both floors,
|
||||
these APIs return TOO_LITTLE_ENTROPY. Open-ledger and simulate execution
|
||||
are provisional previews over the entropy currently visible to the node;
|
||||
final ordered ledger execution may see a different entropy object.
|
||||
entropy_status writes five big-endian bytes:
|
||||
tier:u8, count:u16, denominator:u16
|
||||
and returns ledger age (0 current, 1 previous, >1 stale).
|
||||
|
||||
Classify tier before count/denominator arithmetic: fallback is tier 1
|
||||
with count=denominator=0. Common policies are denominator-count <= 1,
|
||||
5*count >= 4*denominator (use widened arithmetic), or count >= floor.
|
||||
|
||||
dice/random return TOO_LITTLE_ENTROPY if fresh visible entropy is below
|
||||
min_tier. Open-ledger and simulate execution are provisional previews;
|
||||
final ordered execution may see a different entropy object.
|
||||
*/
|
||||
extern int64_t
|
||||
dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
dice(uint32_t sides, uint32_t min_tier);
|
||||
|
||||
extern int64_t
|
||||
random(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t min_tier,
|
||||
uint32_t min_count);
|
||||
random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier);
|
||||
|
||||
extern int64_t
|
||||
entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -46,14 +46,21 @@ APPLY_HOOK="$SCRIPT_DIR/../include/xrpl/hook/hook_api.macro"
|
||||
print "/*";
|
||||
print " Consensus entropy APIs.";
|
||||
print "";
|
||||
print " min_tier is a fail-closed floor:";
|
||||
print " 1 = consensus_fallback, 2 = participant_aligned, 3 = validator_quorum.";
|
||||
print " min_count is the minimum validator/reveal count the caller accepts.";
|
||||
print " min_tier is a required fail-closed floor:";
|
||||
print " 1 = consensus_fallback, 2 = participant_aligned,";
|
||||
print " 3 = validator_quorum, 4 = validator_full.";
|
||||
print "";
|
||||
print " If the most recent finalized entropy object does not satisfy both floors,";
|
||||
print " these APIs return TOO_LITTLE_ENTROPY. Open-ledger and simulate execution";
|
||||
print " are provisional previews over the entropy currently visible to the node;";
|
||||
print " final ordered ledger execution may see a different entropy object.";
|
||||
print " entropy_status writes five big-endian bytes:";
|
||||
print " tier:u8, count:u16, denominator:u16";
|
||||
print " and returns ledger age (0 current, 1 previous, >1 stale).";
|
||||
print "";
|
||||
print " Classify tier before count/denominator arithmetic: fallback is tier 1";
|
||||
print " with count=denominator=0. Common policies are denominator-count <= 1,";
|
||||
print " 5*count >= 4*denominator (use widened arithmetic), or count >= floor.";
|
||||
print "";
|
||||
print " dice/random return TOO_LITTLE_ENTROPY if fresh visible entropy is below";
|
||||
print " min_tier. Open-ledger and simulate execution are provisional previews;";
|
||||
print " final ordered execution may see a different entropy object.";
|
||||
print "*/";
|
||||
}
|
||||
|
||||
|
||||
@@ -388,12 +388,17 @@ HOOK_API_DEFINITION(
|
||||
int64_t, xport_cancel, (uint32_t, uint32_t, uint32_t),
|
||||
featureExport)
|
||||
|
||||
// int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
// int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, dice, (uint32_t, uint32_t, uint32_t),
|
||||
int64_t, dice, (uint32_t, uint32_t),
|
||||
featureConsensusEntropy)
|
||||
|
||||
// int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier, uint32_t min_count);
|
||||
// int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, random, (uint32_t, uint32_t, uint32_t, uint32_t),
|
||||
int64_t, random, (uint32_t, uint32_t, uint32_t),
|
||||
featureConsensusEntropy)
|
||||
|
||||
// int64_t entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
HOOK_API_DEFINITION(
|
||||
int64_t, entropy_status, (uint32_t, uint32_t),
|
||||
featureConsensusEntropy)
|
||||
|
||||
@@ -181,7 +181,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
@@ -189,7 +189,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
_g(1,1);
|
||||
|
||||
// dice(6) should return 0..5
|
||||
int64_t result = dice(6, 3, 5);
|
||||
int64_t result = dice(6, 3);
|
||||
|
||||
// negative means error
|
||||
if (result < 0)
|
||||
@@ -256,7 +256,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
@@ -267,7 +267,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
for (int i = 0; GUARD(32), i < 32; ++i)
|
||||
buf[i] = 0;
|
||||
|
||||
int64_t result = random((uint32_t)buf, 32, 3, 5);
|
||||
int64_t result = random((uint32_t)buf, 32, 3);
|
||||
|
||||
// Should return 32 (bytes written)
|
||||
if (result != 32)
|
||||
@@ -332,16 +332,16 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t r1 = dice(1000000, 3, 5);
|
||||
int64_t r1 = dice(1000000, 3);
|
||||
if (r1 < 0)
|
||||
rollback(0, 0, r1);
|
||||
|
||||
int64_t r2 = dice(1000000, 3, 5);
|
||||
int64_t r2 = dice(1000000, 3);
|
||||
if (r2 < 0)
|
||||
rollback(0, 0, r2);
|
||||
|
||||
@@ -409,12 +409,12 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(0, 3, 5);
|
||||
int64_t result = dice(0, 3);
|
||||
// dice(0) should return negative error code, pass it through
|
||||
return accept(0, 0, result);
|
||||
}
|
||||
@@ -450,9 +450,9 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testDiceRequirementNotMet()
|
||||
testEntropyStatus()
|
||||
{
|
||||
testcase("Hook dice() returns TOO_LITTLE_ENTROPY below requirement");
|
||||
testcase("Hook entropy_status() metadata and policy recipes");
|
||||
using namespace jtx;
|
||||
|
||||
Env env{
|
||||
@@ -461,41 +461,78 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
supported_amendments() | featureConsensusEntropy,
|
||||
nullptr};
|
||||
|
||||
ConsensusTestConfig cfg;
|
||||
cfg.standaloneEntropyTier = entropyTierValidatorQuorum;
|
||||
cfg.standaloneEntropyCount = 19;
|
||||
cfg.standaloneEntropyDenominator = 20;
|
||||
env.app().getRuntimeConfig().setGlobalConfig(cfg);
|
||||
|
||||
auto const alice = Account{"alice"};
|
||||
env.fund(XRP(10000), alice);
|
||||
env.close();
|
||||
|
||||
BEAST_REQUIRE(env.le(keylet::consensusEntropy()));
|
||||
auto const sle = env.le(keylet::consensusEntropy());
|
||||
BEAST_REQUIRE(sle);
|
||||
BEAST_EXPECT(
|
||||
sle->getFieldU8(sfEntropyTier) == entropyTierValidatorQuorum);
|
||||
BEAST_EXPECT(sle->getFieldU16(sfEntropyCount) == 19);
|
||||
BEAST_EXPECT(sle->getFieldU16(sfEntropyDenominator) == 20);
|
||||
|
||||
// Standalone entropy carries EntropyCount=20,
|
||||
// EntropyDenominator=20, and tier validator_full.
|
||||
// A hook demanding min_count=21 states a requirement this ledger
|
||||
// cannot meet, so dice must fail closed with TOO_LITTLE_ENTROPY (-48)
|
||||
// rather than silently serving weaker entropy.
|
||||
TestHook hook = consensusentropy_test_wasm[R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
#define OUT_OF_BOUNDS (-1)
|
||||
#define TOO_SMALL (-4)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(6, 3, 21);
|
||||
// requirement unmet: pass the error code through
|
||||
return accept(0, 0, result);
|
||||
uint8_t status[5] = {0xA5, 0xA5, 0xA5, 0xA5, 0xA5};
|
||||
|
||||
if (entropy_status((uint32_t)status, 4) != TOO_SMALL)
|
||||
return accept(0, 0, 10);
|
||||
for (int i = 0; GUARD(5), i < 5; ++i)
|
||||
if (status[i] != 0xA5)
|
||||
return accept(0, 0, 11);
|
||||
|
||||
if (entropy_status(0xFFFFFFFEU, 5) != OUT_OF_BOUNDS)
|
||||
return accept(0, 0, 12);
|
||||
|
||||
int64_t age = entropy_status((uint32_t)status, 5);
|
||||
if (age < 0 || age > 1)
|
||||
return accept(0, 0, 13);
|
||||
|
||||
uint32_t count = ((uint32_t)status[1] << 8) | status[2];
|
||||
uint32_t denominator =
|
||||
((uint32_t)status[3] << 8) | status[4];
|
||||
if (status[0] != 3 || count != 19 || denominator != 20)
|
||||
return accept(0, 0, 14);
|
||||
|
||||
// Common caller-side policies: tolerate one absent, require
|
||||
// 4/5 participation, and require an absolute floor of 19.
|
||||
if (status[0] < 2 || denominator - count > 1)
|
||||
return accept(0, 0, 15);
|
||||
if ((uint64_t)5 * count < (uint64_t)4 * denominator)
|
||||
return accept(0, 0, 16);
|
||||
if (count < 19)
|
||||
return accept(0, 0, 17);
|
||||
|
||||
return accept(0, 0, age);
|
||||
}
|
||||
)[test.hook]"];
|
||||
|
||||
env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0),
|
||||
M("set dice-requirement hook"),
|
||||
M("set entropy-status hook"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
Json::Value invoke;
|
||||
invoke[jss::TransactionType] = "Invoke";
|
||||
invoke[jss::Account] = alice.human();
|
||||
env(invoke, M("test dice min_count unmet"), fee(XRP(1)));
|
||||
env(invoke, M("test entropy status"), fee(XRP(1)));
|
||||
|
||||
auto meta = env.meta();
|
||||
BEAST_REQUIRE(meta);
|
||||
@@ -504,13 +541,86 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
auto const hookExecutions = meta->getFieldArray(sfHookExecutions);
|
||||
BEAST_REQUIRE(hookExecutions.size() == 1);
|
||||
|
||||
auto const rawCode = hookExecutions[0].getFieldU64(sfHookReturnCode);
|
||||
int64_t returnCode = (rawCode & 0x8000000000000000ULL)
|
||||
? -static_cast<int64_t>(rawCode & 0x7FFFFFFFFFFFFFFFULL)
|
||||
: static_cast<int64_t>(rawCode);
|
||||
std::cerr << " dice(6,3,21) returnCode = " << returnCode << " (raw 0x"
|
||||
<< std::hex << rawCode << std::dec << ")\n";
|
||||
BEAST_EXPECT(returnCode == -48); // TOO_LITTLE_ENTROPY
|
||||
// Open-ledger preview accepts age 1; final ordered execution sees the
|
||||
// current-ledger pseudo first and records age 0 in final metadata.
|
||||
BEAST_EXPECT(hookReturnCode(hookExecutions[0]) == 0);
|
||||
BEAST_EXPECT(hookExecutions[0].getFieldU8(sfHookResult) == 3);
|
||||
}
|
||||
|
||||
void
|
||||
testEntropyStatusFallback()
|
||||
{
|
||||
testcase("Hook entropy_status() classifies fallback before arithmetic");
|
||||
using namespace jtx;
|
||||
|
||||
Env env{
|
||||
*this,
|
||||
envconfig(),
|
||||
supported_amendments() | featureConsensusEntropy,
|
||||
nullptr};
|
||||
|
||||
ConsensusTestConfig cfg;
|
||||
cfg.standaloneEntropyTier = entropyTierConsensusFallback;
|
||||
cfg.standaloneEntropyCount = 0;
|
||||
cfg.standaloneEntropyDenominator = 0;
|
||||
env.app().getRuntimeConfig().setGlobalConfig(cfg);
|
||||
|
||||
auto const alice = Account{"alice"};
|
||||
env.fund(XRP(10000), alice);
|
||||
env.close();
|
||||
|
||||
auto const sle = env.le(keylet::consensusEntropy());
|
||||
BEAST_REQUIRE(sle);
|
||||
BEAST_EXPECT(
|
||||
sle->getFieldU8(sfEntropyTier) == entropyTierConsensusFallback);
|
||||
BEAST_EXPECT(sle->getFieldU16(sfEntropyCount) == 0);
|
||||
BEAST_EXPECT(sle->getFieldU16(sfEntropyDenominator) == 0);
|
||||
|
||||
TestHook hook = consensusentropy_test_wasm[R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
extern int64_t entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
#define TOO_LITTLE_ENTROPY (-48)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
uint8_t status[5];
|
||||
int64_t age = entropy_status((uint32_t)status, 5);
|
||||
if (age < 0 || age > 1)
|
||||
return accept(0, 0, 20);
|
||||
if (status[0] != 1 || status[1] != 0 || status[2] != 0 ||
|
||||
status[3] != 0 || status[4] != 0)
|
||||
return accept(0, 0, 21);
|
||||
|
||||
int64_t allowed = dice(6, 1);
|
||||
if (allowed < 0 || allowed > 5)
|
||||
return accept(0, 0, 22);
|
||||
if (dice(6, 2) != TOO_LITTLE_ENTROPY)
|
||||
return accept(0, 0, 23);
|
||||
|
||||
return accept(0, 0, age);
|
||||
}
|
||||
)[test.hook]"];
|
||||
|
||||
env(ripple::test::jtx::hook(alice, {{hso(hook, overrideFlag)}}, 0),
|
||||
M("set fallback entropy-status hook"),
|
||||
HSFEE);
|
||||
env.close();
|
||||
|
||||
Json::Value invoke;
|
||||
invoke[jss::TransactionType] = "Invoke";
|
||||
invoke[jss::Account] = alice.human();
|
||||
env(invoke, M("test fallback entropy status"), fee(XRP(1)));
|
||||
|
||||
auto meta = env.meta();
|
||||
BEAST_REQUIRE(meta);
|
||||
BEAST_REQUIRE(meta->isFieldPresent(sfHookExecutions));
|
||||
auto const hookExecutions = meta->getFieldArray(sfHookExecutions);
|
||||
BEAST_REQUIRE(hookExecutions.size() == 1);
|
||||
BEAST_EXPECT(hookReturnCode(hookExecutions[0]) == 0);
|
||||
BEAST_EXPECT(hookExecutions[0].getFieldU8(sfHookResult) == 3);
|
||||
}
|
||||
|
||||
@@ -550,12 +660,12 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(6, 4, 0);
|
||||
int64_t result = dice(6, 4);
|
||||
return accept(0, 0, result);
|
||||
}
|
||||
)[test.hook]"];
|
||||
@@ -602,12 +712,16 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
extern int64_t entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(6, 3, 0);
|
||||
uint8_t status[5];
|
||||
int64_t result = entropy_status((uint32_t)status, 5);
|
||||
if (result >= 0)
|
||||
result = dice(6, 3);
|
||||
return accept(0, 0, result);
|
||||
}
|
||||
)[test.hook]"];
|
||||
@@ -640,8 +754,8 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier);
|
||||
#define INVALID_ARGUMENT (-7)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
@@ -649,25 +763,25 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
_g(1,1);
|
||||
uint8_t buf[32];
|
||||
|
||||
int64_t bad_min_tier = dice(6, 0, 0);
|
||||
int64_t bad_min_tier = dice(6, 0);
|
||||
if (bad_min_tier != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_min_tier);
|
||||
|
||||
int64_t ok_full_tier = dice(6, 4, 0);
|
||||
int64_t ok_full_tier = dice(6, 4);
|
||||
if (ok_full_tier < 0 || ok_full_tier > 5)
|
||||
return accept(0, 0, ok_full_tier);
|
||||
|
||||
int64_t bad_high_tier = dice(6, 5, 0);
|
||||
int64_t bad_high_tier = dice(6, 5);
|
||||
if (bad_high_tier != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_high_tier);
|
||||
|
||||
int64_t bad_min_count = dice(6, 3, 70000);
|
||||
if (bad_min_count != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_min_count);
|
||||
int64_t bad_random_low = random((uint32_t)buf, 32, 0);
|
||||
if (bad_random_low != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_random_low);
|
||||
|
||||
int64_t bad_random_tier = random((uint32_t)buf, 32, 5, 0);
|
||||
if (bad_random_tier != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_random_tier);
|
||||
int64_t bad_random_high = random((uint32_t)buf, 32, 5);
|
||||
if (bad_random_high != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_random_high);
|
||||
|
||||
// Sentinel distinct from any dice (0..5) / random result and
|
||||
// from INVALID_ARGUMENT, so a regression that lets a bad
|
||||
@@ -693,7 +807,7 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
auto const hookExecutions = meta->getFieldArray(sfHookExecutions);
|
||||
BEAST_REQUIRE(hookExecutions.size() == 1);
|
||||
|
||||
// 42 only if all four invalid requirements were rejected; any bad
|
||||
// 42 only if all invalid requirements were rejected; any bad
|
||||
// requirement leaking through returns its own (non-42) code.
|
||||
BEAST_EXPECT(hookReturnCode(hookExecutions[0]) == 42);
|
||||
BEAST_EXPECT(hookExecutions[0].getFieldU8(sfHookResult) == 3);
|
||||
@@ -707,7 +821,8 @@ class ConsensusEntropy_test : public beast::unit_test::suite
|
||||
testNoSLEWithoutAmendment();
|
||||
testDice();
|
||||
testDiceZeroSides();
|
||||
testDiceRequirementNotMet();
|
||||
testEntropyStatus();
|
||||
testEntropyStatusFallback();
|
||||
testDiceTierRequirementNotMet();
|
||||
testDiceWithoutAmendment();
|
||||
testInvalidEntropyRequirements();
|
||||
|
||||
@@ -16,7 +16,7 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
@@ -24,7 +24,7 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
_g(1,1);
|
||||
|
||||
// dice(6) should return 0..5
|
||||
int64_t result = dice(6, 3, 5);
|
||||
int64_t result = dice(6, 3);
|
||||
|
||||
// negative means error
|
||||
if (result < 0)
|
||||
@@ -39,25 +39,24 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x1AU, 0x04U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU,
|
||||
0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU,
|
||||
0x02U, 0x31U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU,
|
||||
0x67U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U,
|
||||
0x69U, 0x63U, 0x65U, 0x00U, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x08U, 0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU,
|
||||
0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U,
|
||||
0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U,
|
||||
0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U, 0x07U, 0x08U, 0x01U,
|
||||
0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, 0x40U,
|
||||
0x01U, 0x3EU, 0x01U, 0x02U, 0x7EU, 0x41U, 0x01U, 0x41U, 0x01U,
|
||||
0x10U, 0x00U, 0x1AU, 0x41U, 0x06U, 0x41U, 0x03U, 0x41U, 0x05U,
|
||||
0x10U, 0x01U, 0x22U, 0x01U, 0x21U, 0x02U, 0x02U, 0x40U, 0x20U,
|
||||
0x01U, 0x42U, 0x00U, 0x59U, 0x04U, 0x40U, 0x42U, 0x7FU, 0x21U,
|
||||
0x02U, 0x20U, 0x01U, 0x42U, 0x06U, 0x54U, 0x0DU, 0x01U, 0x0BU,
|
||||
0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x02U, 0x10U, 0x02U, 0x1AU,
|
||||
0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x03U,
|
||||
0x0BU,
|
||||
0x19U, 0x04U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU,
|
||||
0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x02U, 0x7FU,
|
||||
0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x31U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U, 0x69U,
|
||||
0x63U, 0x65U, 0x00U, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x08U,
|
||||
0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU, 0x00U,
|
||||
0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U,
|
||||
0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x03U,
|
||||
0x05U, 0x03U, 0x01U, 0x00U, 0x01U, 0x07U, 0x08U, 0x01U, 0x04U,
|
||||
0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, 0x3EU, 0x01U,
|
||||
0x3CU, 0x01U, 0x02U, 0x7EU, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U,
|
||||
0x00U, 0x1AU, 0x41U, 0x06U, 0x41U, 0x03U, 0x10U, 0x01U, 0x22U,
|
||||
0x01U, 0x21U, 0x02U, 0x02U, 0x40U, 0x20U, 0x01U, 0x42U, 0x00U,
|
||||
0x59U, 0x04U, 0x40U, 0x42U, 0x7FU, 0x21U, 0x02U, 0x20U, 0x01U,
|
||||
0x42U, 0x06U, 0x54U, 0x0DU, 0x01U, 0x0BU, 0x41U, 0x00U, 0x41U,
|
||||
0x00U, 0x20U, 0x02U, 0x10U, 0x02U, 0x1AU, 0x0BU, 0x41U, 0x00U,
|
||||
0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x03U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 1 ==== */
|
||||
@@ -66,7 +65,7 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
@@ -77,7 +76,7 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
for (int i = 0; GUARD(32), i < 32; ++i)
|
||||
buf[i] = 0;
|
||||
|
||||
int64_t result = random((uint32_t)buf, 32, 3, 5);
|
||||
int64_t result = random((uint32_t)buf, 32, 3);
|
||||
|
||||
// Should return 32 (bytes written)
|
||||
if (result != 32)
|
||||
@@ -96,42 +95,42 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x1BU, 0x04U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU,
|
||||
0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x04U, 0x7FU,
|
||||
0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U,
|
||||
0x7EU, 0x02U, 0x33U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U,
|
||||
0x5FU, 0x67U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U,
|
||||
0x72U, 0x61U, 0x6EU, 0x64U, 0x6FU, 0x6DU, 0x00U, 0x02U, 0x03U,
|
||||
0x65U, 0x6EU, 0x76U, 0x08U, 0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U,
|
||||
0x61U, 0x63U, 0x6BU, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U,
|
||||
0x03U, 0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U,
|
||||
0x06U, 0x08U, 0x01U, 0x7FU, 0x01U, 0x41U, 0x80U, 0x80U, 0x04U,
|
||||
0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU,
|
||||
0x00U, 0x04U, 0x0AU, 0xD0U, 0x01U, 0x01U, 0xCDU, 0x01U, 0x02U,
|
||||
0x03U, 0x7FU, 0x01U, 0x7EU, 0x23U, 0x00U, 0x41U, 0x20U, 0x6BU,
|
||||
0x22U, 0x01U, 0x24U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U,
|
||||
0x00U, 0x1AU, 0x41U, 0x8EU, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U,
|
||||
0x21U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x21U, 0x00U, 0x03U,
|
||||
0x40U, 0x41U, 0x8EU, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U,
|
||||
0x10U, 0x00U, 0x1AU, 0x20U, 0x00U, 0x20U, 0x01U, 0x6AU, 0x41U,
|
||||
0x00U, 0x3AU, 0x00U, 0x00U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U,
|
||||
0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x20U, 0x00U, 0x41U,
|
||||
0x01U, 0x6AU, 0x22U, 0x00U, 0x41U, 0x20U, 0x47U, 0x0DU, 0x00U,
|
||||
0x0BU, 0x20U, 0x01U, 0x41U, 0x20U, 0x41U, 0x03U, 0x41U, 0x05U,
|
||||
0x10U, 0x01U, 0x22U, 0x04U, 0x42U, 0x20U, 0x52U, 0x04U, 0x40U,
|
||||
0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x04U, 0x10U, 0x02U, 0x1AU,
|
||||
0x0BU, 0x41U, 0x99U, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U,
|
||||
0x1AU, 0x04U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU,
|
||||
0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU,
|
||||
0x02U, 0x33U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU,
|
||||
0x67U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x72U,
|
||||
0x61U, 0x6EU, 0x64U, 0x6FU, 0x6DU, 0x00U, 0x02U, 0x03U, 0x65U,
|
||||
0x6EU, 0x76U, 0x08U, 0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U,
|
||||
0x63U, 0x6BU, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U,
|
||||
0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U,
|
||||
0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U, 0x06U,
|
||||
0x08U, 0x01U, 0x7FU, 0x01U, 0x41U, 0x80U, 0x80U, 0x04U, 0x0BU,
|
||||
0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U,
|
||||
0x04U, 0x0AU, 0xCEU, 0x01U, 0x01U, 0xCBU, 0x01U, 0x02U, 0x03U,
|
||||
0x7FU, 0x01U, 0x7EU, 0x23U, 0x00U, 0x41U, 0x20U, 0x6BU, 0x22U,
|
||||
0x01U, 0x24U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x00U,
|
||||
0x1AU, 0x41U, 0x8EU, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U,
|
||||
0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x21U, 0x00U, 0x03U, 0x40U,
|
||||
0x41U, 0x99U, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U, 0x10U,
|
||||
0x00U, 0x1AU, 0x20U, 0x00U, 0x20U, 0x01U, 0x6AU, 0x2DU, 0x00U,
|
||||
0x00U, 0x21U, 0x03U, 0x41U, 0x01U, 0x20U, 0x02U, 0x20U, 0x03U,
|
||||
0x1BU, 0x21U, 0x02U, 0x20U, 0x00U, 0x41U, 0x01U, 0x6AU, 0x22U,
|
||||
0x00U, 0x41U, 0x20U, 0x47U, 0x0DU, 0x00U, 0x0BU, 0x20U, 0x02U,
|
||||
0x45U, 0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x7EU,
|
||||
0x10U, 0x02U, 0x1AU, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U,
|
||||
0x00U, 0x10U, 0x03U, 0x21U, 0x04U, 0x20U, 0x01U, 0x41U, 0x20U,
|
||||
0x6AU, 0x24U, 0x00U, 0x20U, 0x04U, 0x0BU,
|
||||
0x41U, 0x8EU, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U, 0x10U,
|
||||
0x00U, 0x1AU, 0x20U, 0x00U, 0x20U, 0x01U, 0x6AU, 0x41U, 0x00U,
|
||||
0x3AU, 0x00U, 0x00U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x01U,
|
||||
0x01U, 0x01U, 0x01U, 0x01U, 0x01U, 0x20U, 0x00U, 0x41U, 0x01U,
|
||||
0x6AU, 0x22U, 0x00U, 0x41U, 0x20U, 0x47U, 0x0DU, 0x00U, 0x0BU,
|
||||
0x20U, 0x01U, 0x41U, 0x20U, 0x41U, 0x03U, 0x10U, 0x01U, 0x22U,
|
||||
0x04U, 0x42U, 0x20U, 0x52U, 0x04U, 0x40U, 0x41U, 0x00U, 0x41U,
|
||||
0x00U, 0x20U, 0x04U, 0x10U, 0x02U, 0x1AU, 0x0BU, 0x41U, 0x99U,
|
||||
0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x21U, 0x10U, 0x00U, 0x1AU,
|
||||
0x41U, 0x00U, 0x21U, 0x00U, 0x03U, 0x40U, 0x41U, 0x99U, 0x80U,
|
||||
0x80U, 0x80U, 0x78U, 0x41U, 0x21U, 0x10U, 0x00U, 0x1AU, 0x20U,
|
||||
0x00U, 0x20U, 0x01U, 0x6AU, 0x2DU, 0x00U, 0x00U, 0x21U, 0x03U,
|
||||
0x41U, 0x01U, 0x20U, 0x02U, 0x20U, 0x03U, 0x1BU, 0x21U, 0x02U,
|
||||
0x20U, 0x00U, 0x41U, 0x01U, 0x6AU, 0x22U, 0x00U, 0x41U, 0x20U,
|
||||
0x47U, 0x0DU, 0x00U, 0x0BU, 0x20U, 0x02U, 0x45U, 0x04U, 0x40U,
|
||||
0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x7EU, 0x10U, 0x02U, 0x1AU,
|
||||
0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x00U, 0x10U, 0x03U,
|
||||
0x21U, 0x04U, 0x20U, 0x01U, 0x41U, 0x20U, 0x6AU, 0x24U, 0x00U,
|
||||
0x20U, 0x04U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 2 ==== */
|
||||
@@ -140,16 +139,16 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t rollback(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t r1 = dice(1000000, 3, 5);
|
||||
int64_t r1 = dice(1000000, 3);
|
||||
if (r1 < 0)
|
||||
rollback(0, 0, r1);
|
||||
|
||||
int64_t r2 = dice(1000000, 3, 5);
|
||||
int64_t r2 = dice(1000000, 3);
|
||||
if (r2 < 0)
|
||||
rollback(0, 0, r2);
|
||||
|
||||
@@ -162,28 +161,28 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x1AU, 0x04U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU,
|
||||
0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU,
|
||||
0x02U, 0x31U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU,
|
||||
0x67U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U,
|
||||
0x69U, 0x63U, 0x65U, 0x00U, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x08U, 0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU,
|
||||
0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U,
|
||||
0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U,
|
||||
0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U, 0x07U, 0x08U, 0x01U,
|
||||
0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, 0x62U,
|
||||
0x01U, 0x60U, 0x01U, 0x02U, 0x7EU, 0x41U, 0x01U, 0x41U, 0x01U,
|
||||
0x10U, 0x00U, 0x1AU, 0x41U, 0xC0U, 0x84U, 0x3DU, 0x41U, 0x03U,
|
||||
0x41U, 0x05U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x00U, 0x53U,
|
||||
0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U,
|
||||
0x02U, 0x1AU, 0x0BU, 0x41U, 0xC0U, 0x84U, 0x3DU, 0x41U, 0x03U,
|
||||
0x41U, 0x05U, 0x10U, 0x01U, 0x22U, 0x02U, 0x42U, 0x00U, 0x53U,
|
||||
0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x02U, 0x10U,
|
||||
0x02U, 0x1AU, 0x0BU, 0x20U, 0x01U, 0x20U, 0x02U, 0x51U, 0x04U,
|
||||
0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x7FU, 0x10U, 0x02U,
|
||||
0x1AU, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x02U, 0x42U,
|
||||
0x14U, 0x86U, 0x20U, 0x01U, 0x84U, 0x10U, 0x03U, 0x0BU,
|
||||
0x19U, 0x04U, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7EU, 0x01U, 0x7EU,
|
||||
0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x02U, 0x7FU,
|
||||
0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x31U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U, 0x69U,
|
||||
0x63U, 0x65U, 0x00U, 0x02U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x08U,
|
||||
0x72U, 0x6FU, 0x6CU, 0x6CU, 0x62U, 0x61U, 0x63U, 0x6BU, 0x00U,
|
||||
0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U,
|
||||
0x65U, 0x70U, 0x74U, 0x00U, 0x00U, 0x03U, 0x02U, 0x01U, 0x03U,
|
||||
0x05U, 0x03U, 0x01U, 0x00U, 0x01U, 0x07U, 0x08U, 0x01U, 0x04U,
|
||||
0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, 0x5EU, 0x01U,
|
||||
0x5CU, 0x01U, 0x02U, 0x7EU, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U,
|
||||
0x00U, 0x1AU, 0x41U, 0xC0U, 0x84U, 0x3DU, 0x41U, 0x03U, 0x10U,
|
||||
0x01U, 0x22U, 0x01U, 0x42U, 0x00U, 0x53U, 0x04U, 0x40U, 0x41U,
|
||||
0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x02U, 0x1AU, 0x0BU,
|
||||
0x41U, 0xC0U, 0x84U, 0x3DU, 0x41U, 0x03U, 0x10U, 0x01U, 0x22U,
|
||||
0x02U, 0x42U, 0x00U, 0x53U, 0x04U, 0x40U, 0x41U, 0x00U, 0x41U,
|
||||
0x00U, 0x20U, 0x02U, 0x10U, 0x02U, 0x1AU, 0x0BU, 0x20U, 0x01U,
|
||||
0x20U, 0x02U, 0x51U, 0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U,
|
||||
0x42U, 0x7FU, 0x10U, 0x02U, 0x1AU, 0x0BU, 0x41U, 0x00U, 0x41U,
|
||||
0x00U, 0x20U, 0x02U, 0x42U, 0x14U, 0x86U, 0x20U, 0x01U, 0x84U,
|
||||
0x10U, 0x03U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 3 ==== */
|
||||
@@ -191,31 +190,30 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(0, 3, 5);
|
||||
int64_t result = dice(0, 3);
|
||||
// dice(0) should return negative error code, pass it through
|
||||
return accept(0, 0, result);
|
||||
}
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x1AU, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x03U, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU,
|
||||
0x02U, 0x22U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU,
|
||||
0x67U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U,
|
||||
0x69U, 0x63U, 0x65U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U,
|
||||
0x03U, 0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U,
|
||||
0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U,
|
||||
0x03U, 0x0AU, 0x19U, 0x01U, 0x17U, 0x00U, 0x41U, 0x01U, 0x41U,
|
||||
0x01U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x41U,
|
||||
0x00U, 0x41U, 0x03U, 0x41U, 0x05U, 0x10U, 0x01U, 0x10U, 0x02U,
|
||||
0x0BU,
|
||||
0x19U, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x02U, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU,
|
||||
0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x22U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U, 0x69U,
|
||||
0x63U, 0x65U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U,
|
||||
0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U, 0x03U,
|
||||
0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U, 0x07U,
|
||||
0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x03U,
|
||||
0x0AU, 0x17U, 0x01U, 0x15U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U,
|
||||
0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x41U, 0x00U,
|
||||
0x41U, 0x03U, 0x10U, 0x01U, 0x10U, 0x02U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 4 ==== */
|
||||
@@ -223,31 +221,95 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
#define GUARD(maxiter) _g((1ULL << 31U) + __LINE__, (maxiter)+1)
|
||||
#define OUT_OF_BOUNDS (-1)
|
||||
#define TOO_SMALL (-4)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(6, 3, 21);
|
||||
// requirement unmet: pass the error code through
|
||||
return accept(0, 0, result);
|
||||
uint8_t status[5] = {0xA5, 0xA5, 0xA5, 0xA5, 0xA5};
|
||||
|
||||
if (entropy_status((uint32_t)status, 4) != TOO_SMALL)
|
||||
return accept(0, 0, 10);
|
||||
for (int i = 0; GUARD(5), i < 5; ++i)
|
||||
if (status[i] != 0xA5)
|
||||
return accept(0, 0, 11);
|
||||
|
||||
if (entropy_status(0xFFFFFFFEU, 5) != OUT_OF_BOUNDS)
|
||||
return accept(0, 0, 12);
|
||||
|
||||
int64_t age = entropy_status((uint32_t)status, 5);
|
||||
if (age < 0 || age > 1)
|
||||
return accept(0, 0, 13);
|
||||
|
||||
uint32_t count = ((uint32_t)status[1] << 8) | status[2];
|
||||
uint32_t denominator =
|
||||
((uint32_t)status[3] << 8) | status[4];
|
||||
if (status[0] != 3 || count != 19 || denominator != 20)
|
||||
return accept(0, 0, 14);
|
||||
|
||||
// Common caller-side policies: tolerate one absent, require
|
||||
// 4/5 participation, and require an absolute floor of 19.
|
||||
if (status[0] < 2 || denominator - count > 1)
|
||||
return accept(0, 0, 15);
|
||||
if ((uint64_t)5 * count < (uint64_t)4 * denominator)
|
||||
return accept(0, 0, 16);
|
||||
if (count < 19)
|
||||
return accept(0, 0, 17);
|
||||
|
||||
return accept(0, 0, age);
|
||||
}
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x1AU, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x03U, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU,
|
||||
0x02U, 0x22U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU,
|
||||
0x67U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U,
|
||||
0x69U, 0x63U, 0x65U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x19U, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x02U, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU,
|
||||
0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x2CU, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0EU, 0x65U, 0x6EU,
|
||||
0x74U, 0x72U, 0x6FU, 0x70U, 0x79U, 0x5FU, 0x73U, 0x74U, 0x61U,
|
||||
0x74U, 0x75U, 0x73U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U,
|
||||
0x03U, 0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U,
|
||||
0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U,
|
||||
0x03U, 0x0AU, 0x19U, 0x01U, 0x17U, 0x00U, 0x41U, 0x01U, 0x41U,
|
||||
0x01U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x41U,
|
||||
0x06U, 0x41U, 0x03U, 0x41U, 0x15U, 0x10U, 0x01U, 0x10U, 0x02U,
|
||||
0x0BU,
|
||||
0x06U, 0x08U, 0x01U, 0x7FU, 0x01U, 0x41U, 0x80U, 0x80U, 0x04U,
|
||||
0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU,
|
||||
0x00U, 0x03U, 0x0AU, 0xB2U, 0x02U, 0x01U, 0xAFU, 0x02U, 0x01U,
|
||||
0x01U, 0x7EU, 0x23U, 0x00U, 0x41U, 0x10U, 0x6BU, 0x22U, 0x00U,
|
||||
0x24U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x00U, 0x1AU,
|
||||
0x20U, 0x00U, 0x41U, 0xA5U, 0x01U, 0x3AU, 0x00U, 0x0CU, 0x20U,
|
||||
0x00U, 0x41U, 0xA5U, 0xCBU, 0x96U, 0xADU, 0x7AU, 0x36U, 0x02U,
|
||||
0x08U, 0x02U, 0x40U, 0x20U, 0x00U, 0x41U, 0x08U, 0x6AU, 0x41U,
|
||||
0x04U, 0x10U, 0x01U, 0x42U, 0x7CU, 0x52U, 0x04U, 0x40U, 0x42U,
|
||||
0x0AU, 0x21U, 0x01U, 0x0CU, 0x01U, 0x0BU, 0x41U, 0x91U, 0x80U,
|
||||
0x80U, 0x80U, 0x78U, 0x41U, 0x06U, 0x10U, 0x00U, 0x1AU, 0x42U,
|
||||
0x0BU, 0x21U, 0x01U, 0x20U, 0x00U, 0x2DU, 0x00U, 0x08U, 0x41U,
|
||||
0xA5U, 0x01U, 0x47U, 0x0DU, 0x00U, 0x41U, 0x91U, 0x80U, 0x80U,
|
||||
0x80U, 0x78U, 0x41U, 0x06U, 0x10U, 0x00U, 0x1AU, 0x20U, 0x00U,
|
||||
0x2DU, 0x00U, 0x09U, 0x41U, 0xA5U, 0x01U, 0x47U, 0x0DU, 0x00U,
|
||||
0x41U, 0x91U, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x06U, 0x10U,
|
||||
0x00U, 0x1AU, 0x20U, 0x00U, 0x2DU, 0x00U, 0x0AU, 0x41U, 0xA5U,
|
||||
0x01U, 0x47U, 0x0DU, 0x00U, 0x41U, 0x91U, 0x80U, 0x80U, 0x80U,
|
||||
0x78U, 0x41U, 0x06U, 0x10U, 0x00U, 0x1AU, 0x20U, 0x00U, 0x2DU,
|
||||
0x00U, 0x0BU, 0x41U, 0xA5U, 0x01U, 0x47U, 0x0DU, 0x00U, 0x41U,
|
||||
0x91U, 0x80U, 0x80U, 0x80U, 0x78U, 0x41U, 0x06U, 0x10U, 0x00U,
|
||||
0x1AU, 0x20U, 0x00U, 0x2DU, 0x00U, 0x0CU, 0x41U, 0xA5U, 0x01U,
|
||||
0x47U, 0x0DU, 0x00U, 0x41U, 0x91U, 0x80U, 0x80U, 0x80U, 0x78U,
|
||||
0x41U, 0x06U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x7EU, 0x41U, 0x05U,
|
||||
0x10U, 0x01U, 0x42U, 0x7FU, 0x52U, 0x04U, 0x40U, 0x42U, 0x0CU,
|
||||
0x21U, 0x01U, 0x0CU, 0x01U, 0x0BU, 0x20U, 0x00U, 0x41U, 0x08U,
|
||||
0x6AU, 0x41U, 0x05U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x01U,
|
||||
0x56U, 0x04U, 0x40U, 0x42U, 0x0DU, 0x21U, 0x01U, 0x0CU, 0x01U,
|
||||
0x0BU, 0x42U, 0x0EU, 0x42U, 0x0EU, 0x42U, 0x0EU, 0x20U, 0x01U,
|
||||
0x20U, 0x00U, 0x2DU, 0x00U, 0x0CU, 0x20U, 0x00U, 0x2DU, 0x00U,
|
||||
0x0BU, 0x41U, 0x08U, 0x74U, 0x72U, 0x41U, 0x14U, 0x47U, 0x1BU,
|
||||
0x20U, 0x00U, 0x2DU, 0x00U, 0x0AU, 0x20U, 0x00U, 0x2DU, 0x00U,
|
||||
0x09U, 0x41U, 0x08U, 0x74U, 0x72U, 0x41U, 0x13U, 0x47U, 0x1BU,
|
||||
0x20U, 0x00U, 0x2DU, 0x00U, 0x08U, 0x41U, 0x03U, 0x47U, 0x1BU,
|
||||
0x21U, 0x01U, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U,
|
||||
0x10U, 0x02U, 0x21U, 0x01U, 0x20U, 0x00U, 0x41U, 0x10U, 0x6AU,
|
||||
0x24U, 0x00U, 0x20U, 0x01U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 5 ==== */
|
||||
@@ -255,30 +317,61 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
extern int64_t entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
#define TOO_LITTLE_ENTROPY (-48)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(6, 4, 0);
|
||||
return accept(0, 0, result);
|
||||
uint8_t status[5];
|
||||
int64_t age = entropy_status((uint32_t)status, 5);
|
||||
if (age < 0 || age > 1)
|
||||
return accept(0, 0, 20);
|
||||
if (status[0] != 1 || status[1] != 0 || status[2] != 0 ||
|
||||
status[3] != 0 || status[4] != 0)
|
||||
return accept(0, 0, 21);
|
||||
|
||||
int64_t allowed = dice(6, 1);
|
||||
if (allowed < 0 || allowed > 5)
|
||||
return accept(0, 0, 22);
|
||||
if (dice(6, 2) != TOO_LITTLE_ENTROPY)
|
||||
return accept(0, 0, 23);
|
||||
|
||||
return accept(0, 0, age);
|
||||
}
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x1AU, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x03U, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU,
|
||||
0x02U, 0x22U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU,
|
||||
0x67U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U,
|
||||
0x69U, 0x63U, 0x65U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U,
|
||||
0x03U, 0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U,
|
||||
0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U,
|
||||
0x03U, 0x0AU, 0x19U, 0x01U, 0x17U, 0x00U, 0x41U, 0x01U, 0x41U,
|
||||
0x01U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x41U,
|
||||
0x06U, 0x41U, 0x04U, 0x41U, 0x00U, 0x10U, 0x01U, 0x10U, 0x02U,
|
||||
0x0BU,
|
||||
0x19U, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U,
|
||||
0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x03U, 0x7FU, 0x7FU,
|
||||
0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x37U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0EU, 0x65U, 0x6EU,
|
||||
0x74U, 0x72U, 0x6FU, 0x70U, 0x79U, 0x5FU, 0x73U, 0x74U, 0x61U,
|
||||
0x74U, 0x75U, 0x73U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x04U, 0x64U, 0x69U, 0x63U, 0x65U, 0x00U, 0x00U, 0x03U, 0x65U,
|
||||
0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U,
|
||||
0x00U, 0x02U, 0x03U, 0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U,
|
||||
0x00U, 0x01U, 0x06U, 0x08U, 0x01U, 0x7FU, 0x01U, 0x41U, 0x80U,
|
||||
0x80U, 0x04U, 0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU,
|
||||
0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, 0x90U, 0x01U, 0x01U, 0x8DU,
|
||||
0x01U, 0x01U, 0x02U, 0x7EU, 0x23U, 0x00U, 0x41U, 0x10U, 0x6BU,
|
||||
0x22U, 0x00U, 0x24U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U,
|
||||
0x00U, 0x1AU, 0x02U, 0x40U, 0x20U, 0x00U, 0x41U, 0x0BU, 0x6AU,
|
||||
0x41U, 0x05U, 0x10U, 0x01U, 0x22U, 0x02U, 0x42U, 0x01U, 0x56U,
|
||||
0x04U, 0x40U, 0x42U, 0x14U, 0x21U, 0x01U, 0x0CU, 0x01U, 0x0BU,
|
||||
0x42U, 0x15U, 0x21U, 0x01U, 0x20U, 0x00U, 0x2DU, 0x00U, 0x0BU,
|
||||
0x41U, 0x01U, 0x47U, 0x0DU, 0x00U, 0x20U, 0x00U, 0x2DU, 0x00U,
|
||||
0x0CU, 0x0DU, 0x00U, 0x20U, 0x00U, 0x2DU, 0x00U, 0x0DU, 0x0DU,
|
||||
0x00U, 0x20U, 0x00U, 0x2DU, 0x00U, 0x0EU, 0x0DU, 0x00U, 0x20U,
|
||||
0x00U, 0x2DU, 0x00U, 0x0FU, 0x0DU, 0x00U, 0x41U, 0x06U, 0x41U,
|
||||
0x01U, 0x10U, 0x02U, 0x42U, 0x05U, 0x56U, 0x04U, 0x40U, 0x42U,
|
||||
0x16U, 0x21U, 0x01U, 0x0CU, 0x01U, 0x0BU, 0x42U, 0x17U, 0x20U,
|
||||
0x02U, 0x41U, 0x06U, 0x41U, 0x02U, 0x10U, 0x02U, 0x42U, 0x50U,
|
||||
0x52U, 0x1BU, 0x21U, 0x01U, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U,
|
||||
0x20U, 0x01U, 0x10U, 0x03U, 0x21U, 0x01U, 0x20U, 0x00U, 0x41U,
|
||||
0x10U, 0x6AU, 0x24U, 0x00U, 0x20U, 0x01U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 6 ==== */
|
||||
@@ -286,30 +379,29 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
int64_t result = dice(6, 3, 0);
|
||||
int64_t result = dice(6, 4);
|
||||
return accept(0, 0, result);
|
||||
}
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x1AU, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x03U, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU,
|
||||
0x02U, 0x22U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU,
|
||||
0x67U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U,
|
||||
0x69U, 0x63U, 0x65U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U,
|
||||
0x03U, 0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U,
|
||||
0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U,
|
||||
0x03U, 0x0AU, 0x19U, 0x01U, 0x17U, 0x00U, 0x41U, 0x01U, 0x41U,
|
||||
0x01U, 0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x41U,
|
||||
0x06U, 0x41U, 0x03U, 0x41U, 0x00U, 0x10U, 0x01U, 0x10U, 0x02U,
|
||||
0x0BU,
|
||||
0x19U, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x02U, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU,
|
||||
0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x22U, 0x03U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U, 0x69U,
|
||||
0x63U, 0x65U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U,
|
||||
0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U, 0x03U,
|
||||
0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U, 0x00U, 0x01U, 0x07U,
|
||||
0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU, 0x6BU, 0x00U, 0x03U,
|
||||
0x0AU, 0x17U, 0x01U, 0x15U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U,
|
||||
0x10U, 0x00U, 0x1AU, 0x41U, 0x00U, 0x41U, 0x00U, 0x41U, 0x06U,
|
||||
0x41U, 0x04U, 0x10U, 0x01U, 0x10U, 0x02U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 7 ==== */
|
||||
@@ -317,8 +409,50 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier, uint32_t min_count);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
extern int64_t entropy_status(uint32_t write_ptr, uint32_t write_len);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
uint8_t status[5];
|
||||
int64_t result = entropy_status((uint32_t)status, 5);
|
||||
if (result >= 0)
|
||||
result = dice(6, 3);
|
||||
return accept(0, 0, result);
|
||||
}
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x19U, 0x04U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U,
|
||||
0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U, 0x03U, 0x7FU, 0x7FU,
|
||||
0x7EU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x37U, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x0EU, 0x65U, 0x6EU,
|
||||
0x74U, 0x72U, 0x6FU, 0x70U, 0x79U, 0x5FU, 0x73U, 0x74U, 0x61U,
|
||||
0x74U, 0x75U, 0x73U, 0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U,
|
||||
0x04U, 0x64U, 0x69U, 0x63U, 0x65U, 0x00U, 0x00U, 0x03U, 0x65U,
|
||||
0x6EU, 0x76U, 0x06U, 0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U,
|
||||
0x00U, 0x02U, 0x03U, 0x02U, 0x01U, 0x03U, 0x05U, 0x03U, 0x01U,
|
||||
0x00U, 0x01U, 0x06U, 0x08U, 0x01U, 0x7FU, 0x01U, 0x41U, 0x80U,
|
||||
0x80U, 0x04U, 0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU,
|
||||
0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, 0x41U, 0x01U, 0x3FU, 0x01U,
|
||||
0x01U, 0x7EU, 0x23U, 0x00U, 0x41U, 0x10U, 0x6BU, 0x22U, 0x00U,
|
||||
0x24U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x00U, 0x1AU,
|
||||
0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x00U, 0x41U, 0x0BU, 0x6AU,
|
||||
0x41U, 0x05U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x00U, 0x59U,
|
||||
0x04U, 0x7EU, 0x41U, 0x06U, 0x41U, 0x03U, 0x10U, 0x02U, 0x05U,
|
||||
0x20U, 0x01U, 0x0BU, 0x10U, 0x03U, 0x21U, 0x01U, 0x20U, 0x00U,
|
||||
0x41U, 0x10U, 0x6AU, 0x24U, 0x00U, 0x20U, 0x01U, 0x0BU,
|
||||
}},
|
||||
|
||||
/* ==== WASM: 8 ==== */
|
||||
{R"[test.hook](
|
||||
#include <stdint.h>
|
||||
extern int32_t _g(uint32_t, uint32_t);
|
||||
extern int64_t accept(uint32_t read_ptr, uint32_t read_len, int64_t error_code);
|
||||
extern int64_t dice(uint32_t sides, uint32_t min_tier);
|
||||
extern int64_t random(uint32_t write_ptr, uint32_t write_len, uint32_t min_tier);
|
||||
#define INVALID_ARGUMENT (-7)
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
@@ -326,25 +460,25 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
_g(1,1);
|
||||
uint8_t buf[32];
|
||||
|
||||
int64_t bad_min_tier = dice(6, 0, 0);
|
||||
int64_t bad_min_tier = dice(6, 0);
|
||||
if (bad_min_tier != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_min_tier);
|
||||
|
||||
int64_t ok_full_tier = dice(6, 4, 0);
|
||||
int64_t ok_full_tier = dice(6, 4);
|
||||
if (ok_full_tier < 0 || ok_full_tier > 5)
|
||||
return accept(0, 0, ok_full_tier);
|
||||
|
||||
int64_t bad_high_tier = dice(6, 5, 0);
|
||||
int64_t bad_high_tier = dice(6, 5);
|
||||
if (bad_high_tier != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_high_tier);
|
||||
|
||||
int64_t bad_min_count = dice(6, 3, 70000);
|
||||
if (bad_min_count != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_min_count);
|
||||
int64_t bad_random_low = random((uint32_t)buf, 32, 0);
|
||||
if (bad_random_low != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_random_low);
|
||||
|
||||
int64_t bad_random_tier = random((uint32_t)buf, 32, 5, 0);
|
||||
if (bad_random_tier != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_random_tier);
|
||||
int64_t bad_random_high = random((uint32_t)buf, 32, 5);
|
||||
if (bad_random_high != INVALID_ARGUMENT)
|
||||
return accept(0, 0, bad_random_high);
|
||||
|
||||
// Sentinel distinct from any dice (0..5) / random result and
|
||||
// from INVALID_ARGUMENT, so a regression that lets a bad
|
||||
@@ -354,39 +488,38 @@ inline std::map<std::string, std::vector<uint8_t>> consensusentropy_test_wasm =
|
||||
)[test.hook]",
|
||||
{
|
||||
0x00U, 0x61U, 0x73U, 0x6DU, 0x01U, 0x00U, 0x00U, 0x00U, 0x01U,
|
||||
0x22U, 0x05U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x03U, 0x7FU, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU,
|
||||
0x7FU, 0x7EU, 0x01U, 0x7EU, 0x60U, 0x04U, 0x7FU, 0x7FU, 0x7FU,
|
||||
0x7FU, 0x01U, 0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U,
|
||||
0x2FU, 0x04U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U,
|
||||
0x00U, 0x00U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U, 0x69U,
|
||||
0x63U, 0x65U, 0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U,
|
||||
0x61U, 0x63U, 0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U, 0x03U,
|
||||
0x65U, 0x6EU, 0x76U, 0x06U, 0x72U, 0x61U, 0x6EU, 0x64U, 0x6FU,
|
||||
0x6DU, 0x00U, 0x03U, 0x03U, 0x02U, 0x01U, 0x04U, 0x05U, 0x03U,
|
||||
0x01U, 0x00U, 0x01U, 0x06U, 0x08U, 0x01U, 0x7FU, 0x01U, 0x41U,
|
||||
0x80U, 0x80U, 0x04U, 0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U,
|
||||
0x6FU, 0x6FU, 0x6BU, 0x00U, 0x04U, 0x0AU, 0xB3U, 0x01U, 0x01U,
|
||||
0xB0U, 0x01U, 0x01U, 0x01U, 0x7EU, 0x23U, 0x00U, 0x41U, 0x20U,
|
||||
0x6BU, 0x22U, 0x00U, 0x24U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U,
|
||||
0x10U, 0x00U, 0x1AU, 0x02U, 0x7EU, 0x41U, 0x06U, 0x41U, 0x00U,
|
||||
0x41U, 0x00U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x79U, 0x52U,
|
||||
0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U,
|
||||
0x02U, 0x0CU, 0x01U, 0x0BU, 0x41U, 0x06U, 0x41U, 0x04U, 0x41U,
|
||||
0x00U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x06U, 0x5AU, 0x04U,
|
||||
0x20U, 0x05U, 0x60U, 0x02U, 0x7FU, 0x7FU, 0x01U, 0x7FU, 0x60U,
|
||||
0x02U, 0x7FU, 0x7FU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU,
|
||||
0x7EU, 0x01U, 0x7EU, 0x60U, 0x03U, 0x7FU, 0x7FU, 0x7FU, 0x01U,
|
||||
0x7EU, 0x60U, 0x01U, 0x7FU, 0x01U, 0x7EU, 0x02U, 0x2FU, 0x04U,
|
||||
0x03U, 0x65U, 0x6EU, 0x76U, 0x02U, 0x5FU, 0x67U, 0x00U, 0x00U,
|
||||
0x03U, 0x65U, 0x6EU, 0x76U, 0x04U, 0x64U, 0x69U, 0x63U, 0x65U,
|
||||
0x00U, 0x01U, 0x03U, 0x65U, 0x6EU, 0x76U, 0x06U, 0x61U, 0x63U,
|
||||
0x63U, 0x65U, 0x70U, 0x74U, 0x00U, 0x02U, 0x03U, 0x65U, 0x6EU,
|
||||
0x76U, 0x06U, 0x72U, 0x61U, 0x6EU, 0x64U, 0x6FU, 0x6DU, 0x00U,
|
||||
0x03U, 0x03U, 0x02U, 0x01U, 0x04U, 0x05U, 0x03U, 0x01U, 0x00U,
|
||||
0x01U, 0x06U, 0x08U, 0x01U, 0x7FU, 0x01U, 0x41U, 0x80U, 0x80U,
|
||||
0x04U, 0x0BU, 0x07U, 0x08U, 0x01U, 0x04U, 0x68U, 0x6FU, 0x6FU,
|
||||
0x6BU, 0x00U, 0x04U, 0x0AU, 0xA9U, 0x01U, 0x01U, 0xA6U, 0x01U,
|
||||
0x01U, 0x01U, 0x7EU, 0x23U, 0x00U, 0x41U, 0x20U, 0x6BU, 0x22U,
|
||||
0x00U, 0x24U, 0x00U, 0x41U, 0x01U, 0x41U, 0x01U, 0x10U, 0x00U,
|
||||
0x1AU, 0x02U, 0x7EU, 0x41U, 0x06U, 0x41U, 0x00U, 0x10U, 0x01U,
|
||||
0x22U, 0x01U, 0x42U, 0x79U, 0x52U, 0x04U, 0x40U, 0x41U, 0x00U,
|
||||
0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x02U, 0x0CU, 0x01U, 0x0BU,
|
||||
0x41U, 0x06U, 0x41U, 0x04U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U,
|
||||
0x06U, 0x5AU, 0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U,
|
||||
0x01U, 0x10U, 0x02U, 0x0CU, 0x01U, 0x0BU, 0x41U, 0x06U, 0x41U,
|
||||
0x05U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x79U, 0x52U, 0x04U,
|
||||
0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x02U,
|
||||
0x0CU, 0x01U, 0x0BU, 0x41U, 0x06U, 0x41U, 0x05U, 0x41U, 0x00U,
|
||||
0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x79U, 0x52U, 0x04U, 0x40U,
|
||||
0x0CU, 0x01U, 0x0BU, 0x20U, 0x00U, 0x41U, 0x20U, 0x41U, 0x00U,
|
||||
0x10U, 0x03U, 0x22U, 0x01U, 0x42U, 0x79U, 0x52U, 0x04U, 0x40U,
|
||||
0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x02U, 0x0CU,
|
||||
0x01U, 0x0BU, 0x41U, 0x06U, 0x41U, 0x03U, 0x41U, 0xF0U, 0xA2U,
|
||||
0x04U, 0x10U, 0x01U, 0x22U, 0x01U, 0x42U, 0x79U, 0x52U, 0x04U,
|
||||
0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x02U,
|
||||
0x0CU, 0x01U, 0x0BU, 0x20U, 0x00U, 0x41U, 0x20U, 0x41U, 0x05U,
|
||||
0x41U, 0x00U, 0x10U, 0x03U, 0x22U, 0x01U, 0x42U, 0x79U, 0x52U,
|
||||
0x04U, 0x40U, 0x41U, 0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U,
|
||||
0x02U, 0x0CU, 0x01U, 0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U,
|
||||
0x2AU, 0x10U, 0x02U, 0x0BU, 0x21U, 0x01U, 0x20U, 0x00U, 0x41U,
|
||||
0x20U, 0x6AU, 0x24U, 0x00U, 0x20U, 0x01U, 0x0BU,
|
||||
0x01U, 0x0BU, 0x20U, 0x00U, 0x41U, 0x20U, 0x41U, 0x05U, 0x10U,
|
||||
0x03U, 0x22U, 0x01U, 0x42U, 0x79U, 0x52U, 0x04U, 0x40U, 0x41U,
|
||||
0x00U, 0x41U, 0x00U, 0x20U, 0x01U, 0x10U, 0x02U, 0x0CU, 0x01U,
|
||||
0x0BU, 0x41U, 0x00U, 0x41U, 0x00U, 0x42U, 0x2AU, 0x10U, 0x02U,
|
||||
0x0BU, 0x21U, 0x01U, 0x20U, 0x00U, 0x41U, 0x20U, 0x6AU, 0x24U,
|
||||
0x00U, 0x20U, 0x01U, 0x0BU,
|
||||
}},
|
||||
|
||||
};
|
||||
|
||||
@@ -127,14 +127,17 @@ dependency on the set that carries the pseudo-tx).
|
||||
pre-injection set hash.
|
||||
|
||||
**INV-6 — Bounded, opt-in entropy quality.**
|
||||
Hooks state `min_tier` / `min_count` explicitly (no hidden network default).
|
||||
Hooks state `min_tier` explicitly on every draw (no hidden network default).
|
||||
Entropy is served iff it is **fresh** (current or previous ledger) **and** meets
|
||||
the requirement; otherwise the call **fails closed** (`TOO_LITTLE_ENTROPY`). A
|
||||
hook never silently receives weaker-than-requested entropy. Draws are also
|
||||
domain-separated by the hook execution role that can share a transaction and
|
||||
hook hash: strong vs weak, callback vs direct dispatch, and hook chain
|
||||
position.
|
||||
*Enforced:* `fairRng` gate.
|
||||
that class floor; otherwise the call **fails closed**
|
||||
(`TOO_LITTLE_ENTROPY`). `entropy_status()` separately exposes the stored tier,
|
||||
contributor count, denominator, and ledger age so hooks can impose proportional
|
||||
or absolute policies without freezing those policies into the host ABI.
|
||||
Fallback is tier 1 with count/denominator `0/0`, so callers must classify tier
|
||||
before arithmetic. Draws are also domain-separated by the hook execution role
|
||||
that can share a transaction and hook hash: strong vs weak, callback vs direct
|
||||
dispatch, and hook chain position.
|
||||
*Enforced:* `fairRng` tier/freshness gate and metadata-only `entropy_status`.
|
||||
|
||||
**INV-7 — Inert when un-amended.**
|
||||
With `featureConsensusEntropy` off, no RNG sidecar state is consensus-visible and
|
||||
|
||||
@@ -375,20 +375,27 @@ digest/tier/count/denominator tuple. This does not make the bitmap
|
||||
non-critical: any disagreement in a ledger-written field is a ledger
|
||||
disagreement. It only keeps transaction ordering semantically tied to the
|
||||
entropy value and quality labels rather than to the accountability label. Hooks
|
||||
state their own requirements via the required
|
||||
`min_tier`/`min_count` arguments to `dice()`/`random()`: a hook that demands
|
||||
validator-tier entropy fails closed with `TOO_LITTLE_ENTROPY` on fallback
|
||||
ledgers, while a hook that opts into fallback-grade randomness must do so
|
||||
explicitly at the call site. Valid `min_tier` values are the stored entropy
|
||||
tiers 1..4; `min_count` must fit the on-ledger `EntropyCount` UINT16 field.
|
||||
Invalid requirements return `INVALID_ARGUMENT`, while valid-but-unmet
|
||||
requirements return `TOO_LITTLE_ENTROPY`.
|
||||
state their class requirement through the mandatory `min_tier` argument to
|
||||
`dice()`/`random()`: a hook that demands validator-tier entropy fails closed
|
||||
with `TOO_LITTLE_ENTROPY` on fallback ledgers, while a hook that opts into
|
||||
fallback-grade randomness must do so explicitly at the call site. Valid
|
||||
`min_tier` values are the stored entropy tiers 1..4; invalid requirements return
|
||||
`INVALID_ARGUMENT`, while valid-but-unmet requirements return
|
||||
`TOO_LITTLE_ENTROPY`.
|
||||
|
||||
`entropy_status(write_ptr, write_len)` writes the fixed five-byte big-endian
|
||||
tuple `(tier:u8, count:u16, denominator:u16)` and returns the metadata's ledger
|
||||
age. This lets Hook code implement policies such as one-absent tolerance,
|
||||
proportional participation, or an absolute floor without widening the frozen
|
||||
draw API. It exposes no digest. Callers must classify tier before count or
|
||||
denominator arithmetic because fallback deliberately reports tier 1 and
|
||||
`0/0`.
|
||||
|
||||
Open-ledger hook execution is provisional. During speculative open-ledger
|
||||
execution, `dice()`/`random()` can only use the previous ledger's finalized
|
||||
entropy; final buildLCL execution sees the current ledger's entropy pseudo-tx
|
||||
after it updates the SLE. Hooks that need final entropy must treat open-ledger
|
||||
RNG results as previews.
|
||||
execution, `dice()`/`random()` and `entropy_status()` can only use the previous
|
||||
ledger's finalized entropy (status age 1); final buildLCL execution sees the
|
||||
current ledger's entropy pseudo-tx after it updates the SLE (status age 0).
|
||||
Hooks that need final entropy must treat open-ledger RNG results as previews.
|
||||
|
||||
The fallback digest derives from the agreed pre-injection tx set hash to avoid
|
||||
circularity, and entropy pseudo-tx deduplication is value-based: if the agreed
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <xrpl/protocol/st.h>
|
||||
#include <xrpl/protocol/tokens.h>
|
||||
#include <boost/multiprecision/cpp_dec_float.hpp>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@@ -4059,24 +4060,59 @@ DEFINE_HOOK_FUNCTION(
|
||||
//@@end xport-impl
|
||||
|
||||
inline bool
|
||||
invalidEntropyRequirement(uint32_t minTier, uint32_t minCount)
|
||||
invalidEntropyRequirement(uint32_t minTier)
|
||||
{
|
||||
return minTier < entropyTierConsensusFallback ||
|
||||
minTier > entropyTierValidatorFull ||
|
||||
minCount > std::numeric_limits<std::uint16_t>::max();
|
||||
minTier > entropyTierValidatorFull;
|
||||
}
|
||||
|
||||
struct EntropySnapshot
|
||||
{
|
||||
std::shared_ptr<SLE> sle;
|
||||
std::uint32_t age;
|
||||
std::uint8_t tier;
|
||||
std::uint16_t count;
|
||||
std::uint16_t denominator;
|
||||
};
|
||||
|
||||
inline std::variant<EntropySnapshot, hook_api::hook_return_code>
|
||||
readEntropySnapshot(ApplyView& view)
|
||||
{
|
||||
auto sle = view.peek(ripple::keylet::consensusEntropy());
|
||||
if (!sle)
|
||||
return hook_api::hook_return_code::DOESNT_EXIST;
|
||||
|
||||
if (!sle->isFieldPresent(sfDigest) ||
|
||||
!sle->isFieldPresent(sfLedgerSequence) ||
|
||||
!sle->isFieldPresent(sfEntropyTier) ||
|
||||
!sle->isFieldPresent(sfEntropyCount) ||
|
||||
!sle->isFieldPresent(sfEntropyDenominator) ||
|
||||
!sle->isFieldPresent(sfEntropyContributors))
|
||||
return hook_api::hook_return_code::INTERNAL_ERROR;
|
||||
|
||||
auto const seq = view.info().seq;
|
||||
auto const entropySeq = sle->getFieldU32(sfLedgerSequence);
|
||||
if (entropySeq > seq)
|
||||
return hook_api::hook_return_code::INTERNAL_ERROR;
|
||||
|
||||
return EntropySnapshot{
|
||||
sle,
|
||||
seq - entropySeq,
|
||||
sle->getFieldU8(sfEntropyTier),
|
||||
sle->getFieldU16(sfEntropyCount),
|
||||
sle->getFieldU16(sfEntropyDenominator)};
|
||||
}
|
||||
|
||||
// byteCount must be a multiple of 32.
|
||||
// minTier/minCount are the CALLER'S stated requirements (required hook API
|
||||
// arguments — there is deliberately no network-wide default): entropy is
|
||||
// usable iff tier >= minTier && count >= minCount, in addition to freshness.
|
||||
// minTier is the CALLER'S stated class requirement (a required hook API
|
||||
// argument — there is deliberately no network-wide default). Count and
|
||||
// denominator policy is available separately through entropy_status().
|
||||
inline std::vector<uint8_t>
|
||||
fairRng(
|
||||
ApplyContext& applyCtx,
|
||||
hook::HookResult& hr,
|
||||
uint32_t byteCount,
|
||||
uint32_t minTier,
|
||||
uint32_t minCount)
|
||||
uint32_t minTier)
|
||||
{
|
||||
if (byteCount > 512)
|
||||
byteCount = 512;
|
||||
@@ -4088,28 +4124,17 @@ fairRng(
|
||||
return {};
|
||||
|
||||
auto& view = applyCtx.view();
|
||||
|
||||
auto const sleEntropy = view.peek(ripple::keylet::consensusEntropy());
|
||||
auto const seq = view.info().seq;
|
||||
|
||||
auto const entropySeq =
|
||||
sleEntropy ? sleEntropy->getFieldU32(sfLedgerSequence) : 0u;
|
||||
auto snapshot = readEntropySnapshot(view);
|
||||
if (!std::holds_alternative<EntropySnapshot>(snapshot))
|
||||
return {};
|
||||
auto const& entropy = std::get<EntropySnapshot>(snapshot);
|
||||
|
||||
// Open-ledger hook execution is provisional and can only see the previous
|
||||
// ledger's finalized entropy. Final buildLCL execution sees the current
|
||||
// ledger's entropy pseudo-tx after it updates this SLE. That open-vs-final
|
||||
// skew is inherent to speculative execution; callers that need final
|
||||
// entropy must treat open-ledger dice/random results as previews.
|
||||
// Defensive: sfEntropyTier is soeREQUIRED, so any entry this code wrote
|
||||
// carries it. A missing field can only come from a pre-tier-3 persisted
|
||||
// entry; treat that as tier 0 (none) so the requirement check fails closed.
|
||||
auto const entropyTier =
|
||||
sleEntropy && sleEntropy->isFieldPresent(sfEntropyTier)
|
||||
? sleEntropy->getFieldU8(sfEntropyTier)
|
||||
: std::uint8_t{0};
|
||||
if (!sleEntropy || entropySeq > seq || (seq - entropySeq) > 1 ||
|
||||
entropyTier < minTier ||
|
||||
sleEntropy->getFieldU16(sfEntropyCount) < minCount)
|
||||
if (entropy.age > 1 || entropy.tier < minTier)
|
||||
return {};
|
||||
|
||||
// we'll generate bytes in lots of 32
|
||||
@@ -4130,7 +4155,7 @@ fairRng(
|
||||
hr.hookChainPosition,
|
||||
hr.isStrong ? std::string("strong") : std::string("weak"),
|
||||
hr.isCallback ? std::string("callback") : std::string("direct"),
|
||||
sleEntropy->getFieldH256(sfDigest),
|
||||
entropy.sle->getFieldH256(sfDigest),
|
||||
hr.rngCallCounter++);
|
||||
|
||||
std::vector<uint8_t> bytesOut;
|
||||
@@ -4151,22 +4176,17 @@ fairRng(
|
||||
return bytesOut;
|
||||
}
|
||||
|
||||
DEFINE_HOOK_FUNCTION(
|
||||
int64_t,
|
||||
dice,
|
||||
uint32_t sides,
|
||||
uint32_t min_tier,
|
||||
uint32_t min_count)
|
||||
DEFINE_HOOK_FUNCTION(int64_t, dice, uint32_t sides, uint32_t min_tier)
|
||||
{
|
||||
HOOK_SETUP();
|
||||
|
||||
if (sides == 0)
|
||||
return INVALID_ARGUMENT;
|
||||
|
||||
if (invalidEntropyRequirement(min_tier, min_count))
|
||||
if (invalidEntropyRequirement(min_tier))
|
||||
return INVALID_ARGUMENT;
|
||||
|
||||
auto vec = fairRng(applyCtx, hookCtx.result, 32, min_tier, min_count);
|
||||
auto vec = fairRng(applyCtx, hookCtx.result, 32, min_tier);
|
||||
|
||||
if (vec.empty())
|
||||
return TOO_LITTLE_ENTROPY;
|
||||
@@ -4206,8 +4226,7 @@ DEFINE_HOOK_FUNCTION(
|
||||
random,
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t min_tier,
|
||||
uint32_t min_count)
|
||||
uint32_t min_tier)
|
||||
{
|
||||
HOOK_SETUP();
|
||||
|
||||
@@ -4233,10 +4252,10 @@ DEFINE_HOOK_FUNCTION(
|
||||
if (NOT_IN_BOUNDS(write_ptr, write_len, memory_length))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
if (invalidEntropyRequirement(min_tier, min_count))
|
||||
if (invalidEntropyRequirement(min_tier))
|
||||
return INVALID_ARGUMENT;
|
||||
|
||||
auto vec = fairRng(applyCtx, hookCtx.result, required, min_tier, min_count);
|
||||
auto vec = fairRng(applyCtx, hookCtx.result, required, min_tier);
|
||||
|
||||
if (vec.empty())
|
||||
return TOO_LITTLE_ENTROPY;
|
||||
@@ -4246,6 +4265,42 @@ DEFINE_HOOK_FUNCTION(
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
|
||||
DEFINE_HOOK_FUNCTION(
|
||||
int64_t,
|
||||
entropy_status,
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len)
|
||||
{
|
||||
HOOK_SETUP();
|
||||
|
||||
constexpr std::size_t statusSize = 5;
|
||||
if (write_len < statusSize)
|
||||
return TOO_SMALL;
|
||||
|
||||
if (NOT_IN_BOUNDS(write_ptr, statusSize, memory_length))
|
||||
return OUT_OF_BOUNDS;
|
||||
|
||||
auto snapshot = readEntropySnapshot(view);
|
||||
if (std::holds_alternative<hook_api::hook_return_code>(snapshot))
|
||||
return std::get<hook_api::hook_return_code>(snapshot);
|
||||
|
||||
auto const& entropy = std::get<EntropySnapshot>(snapshot);
|
||||
std::array<std::uint8_t, statusSize> const status{
|
||||
entropy.tier,
|
||||
static_cast<std::uint8_t>(entropy.count >> 8),
|
||||
static_cast<std::uint8_t>(entropy.count),
|
||||
static_cast<std::uint8_t>(entropy.denominator >> 8),
|
||||
static_cast<std::uint8_t>(entropy.denominator)};
|
||||
|
||||
if (!WasmEdge_ResultOK(WasmEdge_MemoryInstanceSetData(
|
||||
memoryCtx, status.data(), write_ptr, status.size())))
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
return entropy.age;
|
||||
|
||||
HOOK_TEARDOWN();
|
||||
}
|
||||
/*
|
||||
|
||||
DEFINE_HOOK_FUNCTION(
|
||||
|
||||
Reference in New Issue
Block a user