mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-05 08:47:53 +00:00
start of featureAttestations
This commit is contained in:
@@ -455,6 +455,7 @@ target_sources (rippled PRIVATE
|
||||
src/ripple/app/tx/impl/GenesisMint.cpp
|
||||
src/ripple/app/tx/impl/Import.cpp
|
||||
src/ripple/app/tx/impl/Invoke.cpp
|
||||
src/ripple/app/tx/impl/Attestation.cpp
|
||||
src/ripple/app/tx/impl/SetSignerList.cpp
|
||||
src/ripple/app/tx/impl/SetTrust.cpp
|
||||
src/ripple/app/tx/impl/SignerEntries.cpp
|
||||
|
||||
150
src/ripple/app/tx/impl/Attest.cpp
Normal file
150
src/ripple/app/tx/impl/Attest.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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/Attest.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
Attest::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
return TxConsequences{ctx.tx, TxConsequences::normal};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
Attest::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
auto const flags = ctx.tx.getFlags();
|
||||
|
||||
if (ctx.rules.enabled(fix1543) && (flags & tfAttestMask))
|
||||
return temINVALID_FLAG;
|
||||
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
TER
|
||||
Attest::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
if (!ctx.view.rules().enabled(featureAttestations))
|
||||
return temDISABLED;
|
||||
|
||||
auto const id = ctx.tx[sfAccount];
|
||||
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
Keylet kl =
|
||||
keylet::attestation(id, ctx.tx.getFieldH256(sfAttestedTxnId));
|
||||
|
||||
uint32_t flags = ctx.tx.getFlags();
|
||||
|
||||
bool const isDelete = (flags | tfDeleteAttestation) == tfDeleteAttestation;
|
||||
bool const exists = ctx.view.exists(kl);
|
||||
|
||||
if (exists && !isDelete)
|
||||
return tecDUPLICATE;
|
||||
else if (!exists && isDelete)
|
||||
return tecNO_ENTRY;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
Attest::doApply()
|
||||
{
|
||||
auto j = ctx_.app.journal("View");
|
||||
|
||||
auto const sle = view().peek(keylet::account(account_));
|
||||
if (!sle)
|
||||
return tefINTERNAL;
|
||||
|
||||
Keylet kl =
|
||||
keylet::attestation(account_, ctx.tx.getFieldH256(sfAttestedTxnId));
|
||||
|
||||
uint32_t flags = ctx_.tx.getFlags();
|
||||
|
||||
bool const isDelete = (flags | tfDeleteAttestation) == tfDeleteAttestation;
|
||||
bool const exists = view().exists(kl);
|
||||
|
||||
// delete mode
|
||||
if (exists && isDelete)
|
||||
{
|
||||
auto sleA = view().peek(kl)
|
||||
|
||||
AccountID owner = sleA->getAccountID(sfOwner);
|
||||
|
||||
auto const page = (*sleA)[sfOwnerNode];
|
||||
if (!view().dirRemove(
|
||||
keylet::ownerDir(owner), page, kl.key, true))
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Could not remove Attestation from owner directory";
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
view().erase(sleA);
|
||||
adjustOwnerCount(view(), sle, -1, j);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
// create mode
|
||||
else if (!exists && !isDelete)
|
||||
{
|
||||
auto sleA = std::make_shared<SLE>(kl);
|
||||
|
||||
sleA->setAccountID(sfOwner, account_);
|
||||
|
||||
sleA->setFieldH256(sfAttestedTxnID, ctx_.tx.getFieldH256(sfAttestedTxnID));
|
||||
|
||||
auto const page = view().dirInsert(
|
||||
keylet::ownerDir(account_), kl, describeOwnerDir(account_));
|
||||
|
||||
JLOG(j_.trace())
|
||||
<< "Adding Attestation to owner directory " << to_string(kl.key)
|
||||
<< ": " << (page ? "success" : "failure");
|
||||
|
||||
if (!page)
|
||||
return tecDIR_FULL;
|
||||
|
||||
sleA->setFieldU64(sfOwnerNode, *page);
|
||||
view().insert(sleA);
|
||||
|
||||
adjustOwnerCount(view(), sle, 1, j);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
// everything else is invalid
|
||||
else
|
||||
return tecINTRERNAL;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
Attest::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
return Transactor::calculateBaseFee(view, tx);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
57
src/ripple/app/tx/impl/Attest.h
Normal file
57
src/ripple/app/tx/impl/Attest.h
Normal file
@@ -0,0 +1,57 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ATTEST_H_INCLUDED
|
||||
#define RIPPLE_TX_ATTEST_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Attest : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit Attest(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <ripple/app/tx/impl/GenesisMint.h>
|
||||
#include <ripple/app/tx/impl/Import.h>
|
||||
#include <ripple/app/tx/impl/Invoke.h>
|
||||
#include <ripple/app/tx/impl/Attest.h>
|
||||
#include <ripple/app/tx/impl/NFTokenAcceptOffer.h>
|
||||
#include <ripple/app/tx/impl/NFTokenBurn.h>
|
||||
#include <ripple/app/tx/impl/NFTokenCancelOffer.h>
|
||||
@@ -164,6 +165,8 @@ invoke_preflight(PreflightContext const& ctx)
|
||||
return invoke_preflight_helper<Import>(ctx);
|
||||
case ttINVOKE:
|
||||
return invoke_preflight_helper<Invoke>(ctx);
|
||||
case ttATTEST:
|
||||
return invoke_preflight_helper<Attest>(ctx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -283,6 +286,8 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
return invoke_preclaim<Import>(ctx);
|
||||
case ttINVOKE:
|
||||
return invoke_preclaim<Invoke>(ctx);
|
||||
case ttATTEST:
|
||||
return invoke_preclaim<Attest>(ctx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -364,6 +369,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
return Import::calculateBaseFee(view, tx);
|
||||
case ttINVOKE:
|
||||
return Invoke::calculateBaseFee(view, tx);
|
||||
case ttATTEST:
|
||||
return Attest::calculateBaseFee(view, tx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -544,6 +551,10 @@ invoke_apply(ApplyContext& ctx)
|
||||
Invoke p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttATTEST: {
|
||||
Attest p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// 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
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 66;
|
||||
static constexpr std::size_t numFeatures = 67;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -354,7 +354,7 @@ extern uint256 const featureImport;
|
||||
extern uint256 const featureXahauGenesis;
|
||||
extern uint256 const featureHooksUpdate1;
|
||||
extern uint256 const fixURITokenV1;
|
||||
|
||||
extern uint256 const featureAttestations;
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -295,7 +295,10 @@ Keylet
|
||||
import_vlseq(PublicKey const& key) noexcept;
|
||||
|
||||
Keylet
|
||||
uritoken(AccountID const& issuer, Blob const& uri);
|
||||
uritoken(AccountID const& issuer, Blob const& uri) noexcept;
|
||||
|
||||
Keylet
|
||||
attestation(AccountID const& issuer, uint256 const& txnid) noexcept;
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
|
||||
@@ -52,6 +52,12 @@ namespace ripple {
|
||||
// clang-format off
|
||||
enum LedgerEntryType : std::uint16_t
|
||||
{
|
||||
/** A ledger object which describes an attested txn
|
||||
|
||||
\sa kelet::attestation
|
||||
*/
|
||||
ltATTESTATION = 0x0041,
|
||||
|
||||
/** A ledger object which describes an account.
|
||||
|
||||
\sa keylet::account
|
||||
|
||||
@@ -483,6 +483,7 @@ extern SF_UINT256 const sfURITokenID;
|
||||
extern SF_UINT256 const sfGovernanceFlags;
|
||||
extern SF_UINT256 const sfGovernanceMarks;
|
||||
extern SF_UINT256 const sfEmittedTxnID;
|
||||
extern SF_UINT256 const sfAttestedTxnID;
|
||||
|
||||
// currency amount (common)
|
||||
extern SF_AMOUNT const sfAmount;
|
||||
|
||||
@@ -132,6 +132,10 @@ constexpr std::uint32_t const tfStrongTSH = 0x00008000;
|
||||
constexpr std::uint32_t const tfNFTokenMintOldMask =
|
||||
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfStrongTSH);
|
||||
|
||||
// Attest flags:
|
||||
constexpr std::uint32_t tfDeleteAttestation = 0x00000001;
|
||||
constexpr std::uint32_t tfAttestMask = ~tfDeleteAttestation;
|
||||
|
||||
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between
|
||||
// accounts allowed a TrustLine to be added to the issuer of that token
|
||||
// without explicit permission from that issuer. This was enabled by
|
||||
|
||||
@@ -146,6 +146,10 @@ enum TxType : std::uint16_t
|
||||
ttURITOKEN_CREATE_SELL_OFFER = 48,
|
||||
ttURITOKEN_CANCEL_SELL_OFFER = 49,
|
||||
|
||||
/** This transaction acts as an attestation for another txn currently in the TxQ */
|
||||
ttATTEST = 94,
|
||||
|
||||
|
||||
/** This transaction can only be used by the genesis account, which is controlled exclusively by
|
||||
* rewards/governance hooks, to print new XRP to be delivered directly to an array of destinations,
|
||||
* according to reward schedule */
|
||||
|
||||
@@ -460,7 +460,7 @@ REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
REGISTER_FEATURE(Attestations, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace ripple {
|
||||
*/
|
||||
enum class LedgerNameSpace : std::uint16_t {
|
||||
ACCOUNT = 'a',
|
||||
ATTESTATION = 'A',
|
||||
DIR_NODE = 'd',
|
||||
TRUST_LINE = 'r',
|
||||
OFFER = 'o',
|
||||
@@ -443,6 +444,16 @@ uritoken(AccountID const& issuer, Blob const& uri)
|
||||
LedgerNameSpace::URI_TOKEN, issuer, Slice{uri.data(), uri.size()})};
|
||||
}
|
||||
|
||||
Keylet attestationDir(uint32_t ledgerSeq)
|
||||
{
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::ATTESTATION_DIR, ledgerSeq)};
|
||||
}
|
||||
|
||||
Keylet attestation(AccountID const& issuer, uint256 const& txnid)
|
||||
{
|
||||
return {ltATTESTATION, indexHash(LedgerNameSpace::ATTESTATION, issuer, txnid)};
|
||||
}
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -363,6 +363,17 @@ LedgerFormats::LedgerFormats()
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Attestation,
|
||||
ltATTESTATION,
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfAttestedTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
},
|
||||
commonField);
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
|
||||
@@ -236,6 +236,7 @@ CONSTRUCT_TYPED_SFIELD(sfURITokenID, "URITokenID", UINT256,
|
||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceFlags, "GovernanceFlags", UINT256, 99);
|
||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceMarks, "GovernanceMarks", UINT256, 98);
|
||||
CONSTRUCT_TYPED_SFIELD(sfEmittedTxnID, "EmittedTxnID", UINT256, 97);
|
||||
CONSTRUCT_TYPED_SFIELD(sfAttestedTxnID, "AttestedTxnID", UINT256, 96);
|
||||
|
||||
// currency amount (common)
|
||||
CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1);
|
||||
|
||||
@@ -441,6 +441,14 @@ TxFormats::TxFormats()
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Attest,
|
||||
ttATTEST,
|
||||
{
|
||||
{sfAttestedTxnID, soeREQUIRED},
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
}
|
||||
|
||||
TxFormats const&
|
||||
|
||||
Reference in New Issue
Block a user