Balance Rewards amendment (compiling not tested)

This commit is contained in:
Richard Holland
2022-12-16 11:55:53 +00:00
parent d48ac760d4
commit 44425f14f6
15 changed files with 209 additions and 3 deletions

View File

@@ -440,6 +440,7 @@ target_sources (rippled PRIVATE
src/ripple/app/tx/impl/SetAccount.cpp src/ripple/app/tx/impl/SetAccount.cpp
src/ripple/app/tx/impl/SetRegularKey.cpp src/ripple/app/tx/impl/SetRegularKey.cpp
src/ripple/app/tx/impl/SetHook.cpp src/ripple/app/tx/impl/SetHook.cpp
src/ripple/app/tx/impl/ClaimReward.cpp
src/ripple/app/tx/impl/SetSignerList.cpp src/ripple/app/tx/impl/SetSignerList.cpp
src/ripple/app/tx/impl/SetTrust.cpp src/ripple/app/tx/impl/SetTrust.cpp
src/ripple/app/tx/impl/SignerEntries.cpp src/ripple/app/tx/impl/SignerEntries.cpp

View File

@@ -65,7 +65,8 @@ namespace hook
{ttNFTOKEN_BURN, tshCOLLECT }, {ttNFTOKEN_BURN, tshCOLLECT },
{ttNFTOKEN_CREATE_OFFER, tshROLLBACK }, {ttNFTOKEN_CREATE_OFFER, tshROLLBACK },
{ttNFTOKEN_CANCEL_OFFER, tshCOLLECT }, {ttNFTOKEN_CANCEL_OFFER, tshCOLLECT },
{ttNFTOKEN_ACCEPT_OFFER, tshROLLBACK } {ttNFTOKEN_ACCEPT_OFFER, tshROLLBACK },
{ttCLAIM_REWARD, tshROLLBACK }
}; };

View File

@@ -83,6 +83,7 @@ namespace hook
// NFT // NFT
case ttNFTOKEN_MINT: case ttNFTOKEN_MINT:
case ttCLAIM_REWARD:
{ {
if (tx.isFieldPresent(sfIssuer)) if (tx.isFieldPresent(sfIssuer))
ADD_TSH(tx.getAccountID(sfIssuer), canRollback); ADD_TSH(tx.getAccountID(sfIssuer), canRollback);

View File

@@ -0,0 +1,85 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/tx/impl/ClaimReward.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/ledger/View.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/Quality.h>
#include <ripple/protocol/st.h>
namespace ripple {
TxConsequences
ClaimReward::makeTxConsequences(PreflightContext const& ctx)
{
return TxConsequences{ctx.tx, TxConsequences::normal};
}
NotTEC
ClaimReward::preflight(PreflightContext const& ctx)
{
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
return ret;
return preflight2(ctx);
}
TER
ClaimReward::preclaim(PreclaimContext const& ctx)
{
if (ctx.view.rules().enabled(featureBalanceRewards))
return temDISABLED;
auto const id = ctx.tx[sfAccount];
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
return terNO_ACCOUNT;
auto const issuer = ctx.tx[sfIssuer];
if (!ctx.view.exists(keylet::account(issuer)))
return tecNO_ISSUER;
return tesSUCCESS;
}
TER
ClaimReward::doApply()
{
auto const sle = view().peek(keylet::account(account_));
if (!sle)
return tefINTERNAL;
// all actual rewards are handled by the hook on the sfIssuer
// the tt just resets the counters
uint32_t lgrCur = view().seq();
sle->setFieldU32(sfRewardLgrFirst, lgrCur);
sle->setFieldU32(sfRewardLgrLast, lgrCur);
sle->setFieldU64(sfRewardAccumulator, 0ULL);
view().update(sle);
return tesSUCCESS;
}
} // namespace ripple

View File

@@ -0,0 +1,56 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_TX_CLAIMREWARD_H_INCLUDED
#define RIPPLE_TX_CLAIMREWARD_H_INCLUDED
#include <ripple/app/tx/impl/Transactor.h>
#include <ripple/basics/Log.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/Quality.h>
#include <ripple/protocol/TxFlags.h>
namespace ripple {
class ClaimReward : public Transactor
{
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
explicit ClaimReward(ApplyContext& ctx) : Transactor(ctx)
{
}
static TxConsequences
makeTxConsequences(PreflightContext const& ctx);
static NotTEC
preflight(PreflightContext const& ctx);
static TER
preclaim(PreclaimContext const& ctx);
TER
doApply() override;
};
} // namespace ripple
#endif

View File

@@ -584,6 +584,34 @@ Transactor::apply()
if (sle->isFieldPresent(sfAccountTxnID)) if (sle->isFieldPresent(sfAccountTxnID))
sle->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID()); sle->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID());
// accumulate rewards if the BalanceRewards amendment is enabled
if (view().rules().enabled(featureBalanceRewards) &&
ctx_.tx[sfTransactionType] != ttCLAIM_REWARD)
{
uint32_t lgrCur = view().seq();
if (!sle->isFieldPresent(sfRewardLgrFirst) ||
!sle->isFieldPresent(sfRewardLgrLast) ||
!sle->isFieldPresent(sfRewardAccumulator))
{
sle->setFieldU32(sfRewardLgrFirst, lgrCur);
sle->setFieldU32(sfRewardLgrLast, lgrCur);
sle->setFieldU64(sfRewardAccumulator, 0ULL);
}
else
{
uint64_t bal = mPriorBalance.drops();
uint32_t lgrLast = sle->getFieldU32(sfRewardLgrLast);
if (lgrCur - lgrLast != 0)
{
uint64_t accum = sle->getFieldU64(sfRewardAccumulator);
accum += bal * (lgrCur - lgrLast);
sle->setFieldU64(sfRewardAccumulator, accum);
sle->setFieldU32(sfRewardLgrLast, lgrCur);
}
}
}
view().update(sle); view().update(sle);
} }

View File

@@ -151,6 +151,8 @@ invoke_preflight(PreflightContext const& ctx)
return invoke_preflight_helper<NFTokenCancelOffer>(ctx); return invoke_preflight_helper<NFTokenCancelOffer>(ctx);
case ttNFTOKEN_ACCEPT_OFFER: case ttNFTOKEN_ACCEPT_OFFER:
return invoke_preflight_helper<NFTokenAcceptOffer>(ctx); return invoke_preflight_helper<NFTokenAcceptOffer>(ctx);
case ttCLAIM_REWARD:
return invoke_preflight_helper<ClaimReward>(ctx);
default: default:
assert(false); assert(false);
return {temUNKNOWN, TxConsequences{temUNKNOWN}}; return {temUNKNOWN, TxConsequences{temUNKNOWN}};
@@ -256,6 +258,8 @@ invoke_preclaim(PreclaimContext const& ctx)
return invoke_preclaim<NFTokenCancelOffer>(ctx); return invoke_preclaim<NFTokenCancelOffer>(ctx);
case ttNFTOKEN_ACCEPT_OFFER: case ttNFTOKEN_ACCEPT_OFFER:
return invoke_preclaim<NFTokenAcceptOffer>(ctx); return invoke_preclaim<NFTokenAcceptOffer>(ctx);
case ttCLAIM_REWARD:
return invoke_preclaim<ClaimReward>(ctx);
default: default:
assert(false); assert(false);
return temUNKNOWN; return temUNKNOWN;
@@ -322,6 +326,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
return NFTokenCancelOffer::calculateBaseFee(view, tx); return NFTokenCancelOffer::calculateBaseFee(view, tx);
case ttNFTOKEN_ACCEPT_OFFER: case ttNFTOKEN_ACCEPT_OFFER:
return NFTokenAcceptOffer::calculateBaseFee(view, tx); return NFTokenAcceptOffer::calculateBaseFee(view, tx);
case ttCLAIM_REWARD:
return ClaimReward::calculateBaseFee(view, tx);
default: default:
assert(false); assert(false);
return FeeUnit64{0}; return FeeUnit64{0};
@@ -480,6 +486,10 @@ invoke_apply(ApplyContext& ctx)
NFTokenAcceptOffer p(ctx); NFTokenAcceptOffer p(ctx);
return p(); return p();
} }
case ttCLAIM_REWARD: {
ClaimReward p(ctx);
return p();
}
default: default:
assert(false); assert(false);
return {temUNKNOWN, false}; return {temUNKNOWN, false};

View File

@@ -74,7 +74,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how // Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this. // the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 53; static constexpr std::size_t numFeatures = 54;
/** Amendments that this server supports and the default voting behavior. /** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated Whether they are enabled depends on the Rules defined in the validated
@@ -340,6 +340,7 @@ extern uint256 const featurePaychanAndEscrowForTokens;
extern uint256 const fixNFTokenNegOffer; extern uint256 const fixNFTokenNegOffer;
extern uint256 const featureNonFungibleTokensV1_1; extern uint256 const featureNonFungibleTokensV1_1;
extern uint256 const fixTrustLinesToSelf; extern uint256 const fixTrustLinesToSelf;
extern uint256 const featureBalanceRewards;
} // namespace ripple } // namespace ripple

View File

@@ -401,6 +401,8 @@ extern SF_UINT32 const sfBurnedNFTokens;
extern SF_UINT32 const sfHookStateCount; extern SF_UINT32 const sfHookStateCount;
extern SF_UINT32 const sfEmitGeneration; extern SF_UINT32 const sfEmitGeneration;
extern SF_UINT32 const sfLockCount; extern SF_UINT32 const sfLockCount;
extern SF_UINT32 const sfRewardLgrFirst;
extern SF_UINT32 const sfRewardLgrLast;
// 64-bit integers (common) // 64-bit integers (common)
extern SF_UINT64 const sfIndexNext; extern SF_UINT64 const sfIndexNext;
@@ -422,6 +424,7 @@ extern SF_UINT64 const sfHookOn;
extern SF_UINT64 const sfHookInstructionCount; extern SF_UINT64 const sfHookInstructionCount;
extern SF_UINT64 const sfHookReturnCode; extern SF_UINT64 const sfHookReturnCode;
extern SF_UINT64 const sfReferenceCount; extern SF_UINT64 const sfReferenceCount;
extern SF_UINT64 const sfRewardAccumulator;
// 128-bit // 128-bit
extern SF_UINT128 const sfEmailHash; extern SF_UINT128 const sfEmailHash;

View File

@@ -139,6 +139,10 @@ enum TxType : std::uint16_t
/** This transaction accepts an existing offer to buy or sell an existing NFT. */ /** This transaction accepts an existing offer to buy or sell an existing NFT. */
ttNFTOKEN_ACCEPT_OFFER = 29, ttNFTOKEN_ACCEPT_OFFER = 29,
/** This transaction resets accumulator/counters and claims a reward for holding an average balance
* from a specified hook */
ttCLAIM_REWARD = 98,
/** This system-generated transaction type is used to update the status of the various amendments. /** This system-generated transaction type is used to update the status of the various amendments.
For details, see: https://xrpl.org/amendments.html For details, see: https://xrpl.org/amendments.html

View File

@@ -450,6 +450,7 @@ REGISTER_FEATURE(PaychanAndEscrowForTokens, Supported::yes, DefaultVote::no)
REGISTER_FIX (fixNFTokenNegOffer, Supported::yes, DefaultVote::no); REGISTER_FIX (fixNFTokenNegOffer, Supported::yes, DefaultVote::no);
REGISTER_FEATURE(NonFungibleTokensV1_1, Supported::yes, DefaultVote::yes); REGISTER_FEATURE(NonFungibleTokensV1_1, Supported::yes, DefaultVote::yes);
REGISTER_FIX (fixTrustLinesToSelf, Supported::yes, DefaultVote::no); REGISTER_FIX (fixTrustLinesToSelf, Supported::yes, DefaultVote::no);
REGISTER_FEATURE(BalanceRewards, Supported::yes, DefaultVote::yes);
// The following amendments have been active for at least two years. Their // The following amendments have been active for at least two years. Their
// pre-amendment code has been removed and the identifiers are deprecated. // pre-amendment code has been removed and the identifiers are deprecated.

View File

@@ -56,7 +56,10 @@ LedgerFormats::LedgerFormats()
{sfMintedNFTokens, soeDEFAULT}, {sfMintedNFTokens, soeDEFAULT},
{sfBurnedNFTokens, soeDEFAULT}, {sfBurnedNFTokens, soeDEFAULT},
{sfHookStateCount, soeOPTIONAL}, {sfHookStateCount, soeOPTIONAL},
{sfHookNamespaces, soeOPTIONAL} {sfHookNamespaces, soeOPTIONAL},
{sfRewardLgrFirst, soeOPTIONAL},
{sfRewardLgrLast, soeOPTIONAL},
{sfRewardAccumulator, soeOPTIONAL}
}, },
commonFields); commonFields);

View File

@@ -152,6 +152,9 @@ CONSTRUCT_TYPED_SFIELD(sfHookStateCount, "HookStateCount", UINT32,
CONSTRUCT_TYPED_SFIELD(sfEmitGeneration, "EmitGeneration", UINT32, 46); CONSTRUCT_TYPED_SFIELD(sfEmitGeneration, "EmitGeneration", UINT32, 46);
CONSTRUCT_TYPED_SFIELD(sfLockCount, "LockCount", UINT32, 47); CONSTRUCT_TYPED_SFIELD(sfLockCount, "LockCount", UINT32, 47);
CONSTRUCT_TYPED_SFIELD(sfRewardLgrFirst, "RewardLgrFirst", UINT32, 99);
CONSTRUCT_TYPED_SFIELD(sfRewardLgrLast, "RewardLgrLast", UINT32, 100);
// 64-bit integers (common) // 64-bit integers (common)
CONSTRUCT_TYPED_SFIELD(sfIndexNext, "IndexNext", UINT64, 1); CONSTRUCT_TYPED_SFIELD(sfIndexNext, "IndexNext", UINT64, 1);
CONSTRUCT_TYPED_SFIELD(sfIndexPrevious, "IndexPrevious", UINT64, 2); CONSTRUCT_TYPED_SFIELD(sfIndexPrevious, "IndexPrevious", UINT64, 2);
@@ -172,6 +175,7 @@ CONSTRUCT_TYPED_SFIELD(sfHookOn, "HookOn", UINT64,
CONSTRUCT_TYPED_SFIELD(sfHookInstructionCount, "HookInstructionCount", UINT64, 17); CONSTRUCT_TYPED_SFIELD(sfHookInstructionCount, "HookInstructionCount", UINT64, 17);
CONSTRUCT_TYPED_SFIELD(sfHookReturnCode, "HookReturnCode", UINT64, 18); CONSTRUCT_TYPED_SFIELD(sfHookReturnCode, "HookReturnCode", UINT64, 18);
CONSTRUCT_TYPED_SFIELD(sfReferenceCount, "ReferenceCount", UINT64, 19); CONSTRUCT_TYPED_SFIELD(sfReferenceCount, "ReferenceCount", UINT64, 19);
CONSTRUCT_TYPED_SFIELD(sfRewardAccumulator, "RewardAccumulator", UINT64, 100);
// 128-bit // 128-bit
CONSTRUCT_TYPED_SFIELD(sfEmailHash, "EmailHash", UINT128, 1); CONSTRUCT_TYPED_SFIELD(sfEmailHash, "EmailHash", UINT128, 1);

View File

@@ -294,6 +294,13 @@ TxFormats::TxFormats()
}, },
commonFields); commonFields);
add(jss::ClaimReward,
ttCLAIM_REWARD,
{
{sfIssuer, soeREQUIRED}
},
commonFields);
add(jss::NFTokenMint, add(jss::NFTokenMint,
ttNFTOKEN_MINT, ttNFTOKEN_MINT,
{ {

View File

@@ -54,6 +54,7 @@ JSS(Check); // ledger type.
JSS(CheckCancel); // transaction type. JSS(CheckCancel); // transaction type.
JSS(CheckCash); // transaction type. JSS(CheckCash); // transaction type.
JSS(CheckCreate); // transaction type. JSS(CheckCreate); // transaction type.
JSS(ClaimReward); // transaction type.
JSS(ClearFlag); // field. JSS(ClearFlag); // field.
JSS(CreateCode); // field. JSS(CreateCode); // field.
JSS(DeliverMin); // in: TransactionSign JSS(DeliverMin); // in: TransactionSign