diff --git a/hook/govern.c b/hook/govern.c index 39f6dc9bc..d6e73c131 100644 --- a/hook/govern.c +++ b/hook/govern.c @@ -21,18 +21,22 @@ * There may be multiple L2 tables. * * Hook Parameters: + * + * // both table types uses these parameters V + * * Parameter Name: {'I', 'M', 'C'} * Parameter Value: Initial Member Count <1 byte> * + * Parameter Name: {'I', 'S', '\0'} + * Parameter Value: Initial seat #0's member's 20 byte Account ID. + * + * // only L1 table uses these parameters V + * * Parameter Name: {'I', 'R', 'R'} * Parameter Value: Initial Reward Rate <8 byte XFL fraction between 0 and 1, LE> * * Parameter Name: {'I', 'R', 'D'} * Parameter Value: Initial Reward Delay <8 byte LE int seconds between rewards> - * - * Parameter Name: {'I', 'S', '\0'} - * Parameter Value: Initial seat #0's member's 20 byte Account ID. - * * ... * * Topics: @@ -46,10 +50,10 @@ * State Data: Current member count <1 byte> * * State Key: {0..0, 'R', 'R'} - * State Data: Current reward rate <8 byte LE XFL> + * State Data: Current reward rate <8 byte LE XFL> (L1 table only) * * State Key: {0..0, 'R', 'D'} - * State Data: Current reward delay <8 byte LE int> + * State Data: Current reward delay <8 byte LE int> (L1 table only) * * State Key: {0..0, '\0 + seat id'} * State Data: 20 byte account ID for the member who occupies this seat. If absent unoccupied. @@ -57,10 +61,10 @@ * State Key: {0..0, <20 byte account id>} * State Data: Seat number this member occupies <1 byte> * - * State Key: {'V', 'H|R|S' , '\0 + topic id', 0..0, } + * State Key: {'V', 'H|R|S' , '\0 + topic id', , 0..0, } * State Data: A vote by a member for a topic and topic data * - * State Key: {'C', 'H|R|S' , '\0 + topic id', 0*, } + * State Key: {'C', 'H|R|S' , '\0 + topic id', , 0*, } * State Data: The number of members who have voted for that topic data and topic combination <1 byte> * * Hook Invocation: @@ -72,7 +76,7 @@ * Behaviour: Vote on a topic, if the votes meet the topic vote threshold, action the topic. * * Parameter Name: {'L'} - * Parameter Value: Which layer the vote is inteded for + * Parameter Value: Which layer the vote is inteded for (ONLY L2 TABLES USE THIS PARAMETER) * { '1' a vote cast by an L2 member about an L1 topic }, or * { '2' a vote cast by an L2 member about an L2 topic } * @@ -156,20 +160,23 @@ int64_t hook(uint32_t r) if (imc > SEAT_COUNT) NOPE("Governance: Initial Member Count must be <= Seat Count (20)."); - if (hook_param(SVAR(irr), "IRR", 3) < 0) - NOPE("Governance: Initial Reward Rate Parameter missing (IRR)."); - - if (hook_param(SVAR(ird), "IRD", 3) < 0) - NOPE("Governance: Initial Reward Delay Parameter miss (IRD)."); + if (is_L1_table) + { + if (hook_param(SVAR(irr), "IRR", 3) < 0) + NOPE("Governance: Initial Reward Rate Parameter missing (IRR)."); + + if (hook_param(SVAR(ird), "IRD", 3) < 0) + NOPE("Governance: Initial Reward Delay Parameter miss (IRD)."); - if (ird == 0) - NOPE("Governance: Initial Reward Delay must be > 0."); + if (ird == 0) + NOPE("Governance: Initial Reward Delay must be > 0."); - // set reward rate - ASSERT(state_set(SVAR(irr), "RR", 2)); + // set reward rate + ASSERT(state_set(SVAR(irr), "RR", 2)); - // set reward delay - ASSERT(state_set(SVAR(ird), "RD", 2)); + // set reward delay + ASSERT(state_set(SVAR(ird), "RD", 2)); + } // set member count ASSERT(state_set(SBUF(imc), "MC", 2)); @@ -336,7 +343,9 @@ int64_t hook(uint32_t r) TRACEVAR(member_count); trace(SBUF("topic"), topic, 2, 1); } - + + // this flag is used to determine if a L2 table should send a "nulling" vote to remove its existing vote + // from the L1 table it sits at. int64_t lost_majority = 0; int64_t q80 = member_count * 0.8; diff --git a/src/ripple/app/tx/impl/Import.cpp b/src/ripple/app/tx/impl/Import.cpp index 4f7c377d0..24c9fafb6 100644 --- a/src/ripple/app/tx/impl/Import.cpp +++ b/src/ripple/app/tx/impl/Import.cpp @@ -1023,7 +1023,7 @@ Import::doApply() bool const create = !sle; // compute the amount they receive first because the amount is maybe needed for computing setsignerlist later - STAmount startBal = create ? STAmount(INITIAL_IMPORT_XRP) : sle->getFieldAmount(sfBalance); + STAmount startBal = create ? STAmount(computeStartingBonus(view())) : sle->getFieldAmount(sfBalance); STAmount finalBal = startBal + burn; // this should never happen diff --git a/src/ripple/app/tx/impl/Import.h b/src/ripple/app/tx/impl/Import.h index de82af58e..aefd31cd8 100644 --- a/src/ripple/app/tx/impl/Import.h +++ b/src/ripple/app/tx/impl/Import.h @@ -32,8 +32,47 @@ class Import : public Transactor { public: // newly imported accounts get 2 XRP - static constexpr XRPAmount INITIAL_IMPORT_XRP{2 * DROPS_PER_XRP}; + template + static + XRPAmount computeStartingBonus(V const& v) + { + auto const& fees = v.read(keylet::fees()); + uint64_t b = 1'000'000; + uint64_t i = 200'000; + + // new fee object format + if (fees && + fees->isFieldPresent(sfReserveBaseDrops) && + fees->isFieldPresent(sfReserveIncrementDrops)) + { + auto const base = fees->getFieldAmount(sfReserveBaseDrops); + auto const incr = fees->getFieldAmount(sfReserveIncrementDrops); + + if (isXRP(base) && isXRP(incr)) + { + b = base.xrp().drops(); + i = incr.xrp().drops(); + } + } + + // old object format + if (fees && + fees->isFieldPresent(sfReserveBase) && + fees->isFieldPresent(sfReserveIncrement)) + { + b = fees->getFieldU32(sfReserveBase); + i = fees->getFieldU32(sfReserveIncrement); + } + + uint64_t x = b + i * 5U; + if (x > i && x > b) + return XRPAmount{x}; + + // fallback in case of overflow + return XRPAmount{2 * DROPS_PER_XRP}; + } + static constexpr ConsequencesFactoryType ConsequencesFactory{Custom}; static std::pair< diff --git a/src/ripple/app/tx/impl/InvariantCheck.cpp b/src/ripple/app/tx/impl/InvariantCheck.cpp index f67715989..7df95850b 100644 --- a/src/ripple/app/tx/impl/InvariantCheck.cpp +++ b/src/ripple/app/tx/impl/InvariantCheck.cpp @@ -169,7 +169,7 @@ XRPNotCreated::finalize( : beast::zero; // if the txn didnt burn a fee we add nothing if (accountsCreated_ == 1) - dropsAdded += Import::INITIAL_IMPORT_XRP; // welcome amount for new imports + dropsAdded += Import::computeStartingBonus(view); JLOG(j.trace()) << "Invariant XRPNotCreated Import: "