mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-04 18:55:49 +00:00
Compare commits
6 Commits
sfcode-gen
...
attestatio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738a4c1e87 | ||
|
|
df9ed403ad | ||
|
|
deb4b34b9b | ||
|
|
d0baeab32f | ||
|
|
72016c3e0e | ||
|
|
54211fb63b |
@@ -455,6 +455,7 @@ target_sources (rippled PRIVATE
|
|||||||
src/ripple/app/tx/impl/GenesisMint.cpp
|
src/ripple/app/tx/impl/GenesisMint.cpp
|
||||||
src/ripple/app/tx/impl/Import.cpp
|
src/ripple/app/tx/impl/Import.cpp
|
||||||
src/ripple/app/tx/impl/Invoke.cpp
|
src/ripple/app/tx/impl/Invoke.cpp
|
||||||
|
src/ripple/app/tx/impl/Attest.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
|
||||||
|
|||||||
182
src/ripple/app/tx/impl/Attest.cpp
Normal file
182
src/ripple/app/tx/impl/Attest.cpp
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
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 (flags & tfAttestMask)
|
||||||
|
return temINVALID_FLAG;
|
||||||
|
|
||||||
|
bool const hasTxnID = ctx.tx.isFieldPresent(sfAttestedTxnID);
|
||||||
|
bool const hasAccID = ctx.tx.isFieldPresent(sfAttestedAccID);
|
||||||
|
|
||||||
|
if ((hasTxnID && hasAccID) || (!hasTxnID && !hasAccID))
|
||||||
|
{
|
||||||
|
JLOG(ctx.j.warn())
|
||||||
|
<< "Attest: must specify exactly one of: AttestedTxnID, AttestedAccID";
|
||||||
|
return temMALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 =
|
||||||
|
ctx.tx.isFieldPresent(sfAttestedTxnID)
|
||||||
|
? keylet::attestationTxn(id, ctx.tx.getFieldH256(sfAttestedTxnID))
|
||||||
|
: keylet::attestationAcc(id, ctx.tx.getAccountID(sfAttestedAccID));
|
||||||
|
|
||||||
|
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 =
|
||||||
|
ctx_.tx.isFieldPresent(sfAttestedTxnID)
|
||||||
|
? keylet::attestationTxn(account_, ctx_.tx.getFieldH256(sfAttestedTxnID))
|
||||||
|
: keylet::attestationAcc(account_, ctx_.tx.getAccountID(sfAttestedAccID));
|
||||||
|
|
||||||
|
uint32_t flags = ctx_.tx.getFlags();
|
||||||
|
|
||||||
|
bool const isDelete = (flags & tfDeleteAttestation) == tfDeleteAttestation;
|
||||||
|
bool const exists = view().exists(kl);
|
||||||
|
|
||||||
|
// check for sufficient reserves
|
||||||
|
if (!isDelete)
|
||||||
|
{
|
||||||
|
STAmount const reserve{
|
||||||
|
view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
|
||||||
|
|
||||||
|
STAmount const afterFee =
|
||||||
|
mPriorBalance - ctx_.tx.getFieldAmount(sfFee).xrp();
|
||||||
|
|
||||||
|
if (afterFee > mPriorBalance || afterFee < reserve)
|
||||||
|
return tecINSUFFICIENT_RESERVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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->setFieldU16(sfLedgerEntryType, ltATTESTATION);
|
||||||
|
sleA->setAccountID(sfOwner, account_);
|
||||||
|
|
||||||
|
if (ctx_.tx.isFieldPresent(sfAttestedTxnID))
|
||||||
|
sleA->setFieldH256(sfAttestedTxnID, ctx_.tx.getFieldH256(sfAttestedTxnID));
|
||||||
|
else
|
||||||
|
sleA->setAccountID(sfAttestedAccID, ctx_.tx.getAccountID(sfAttestedAccID));
|
||||||
|
|
||||||
|
|
||||||
|
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 tecINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@@ -492,6 +492,7 @@ LedgerEntryTypesMatch::visitEntry(
|
|||||||
case ltURI_TOKEN:
|
case ltURI_TOKEN:
|
||||||
case ltIMPORT_VLSEQ:
|
case ltIMPORT_VLSEQ:
|
||||||
case ltUNL_REPORT:
|
case ltUNL_REPORT:
|
||||||
|
case ltATTESTATION:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
invalidTypeAdded_ = true;
|
invalidTypeAdded_ = true;
|
||||||
|
|||||||
@@ -85,6 +85,54 @@ preflight0(PreflightContext const& ctx)
|
|||||||
return temINVALID;
|
return temINVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// don't allow attestations unless enabled
|
||||||
|
if (ctx.tx.isFieldPresent(sfAttesters))
|
||||||
|
{
|
||||||
|
if (!ctx.rules.enabled(featureAttestations))
|
||||||
|
return temDISABLED;
|
||||||
|
|
||||||
|
// make sure they can't spam millions of attesters
|
||||||
|
auto const& attesters = ctx.tx.getFieldArray(sfAttesters);
|
||||||
|
if (attesters.empty() || attesters.size() > 32)
|
||||||
|
{
|
||||||
|
JLOG(ctx.j.warn())
|
||||||
|
<< "applyTransaction: attesters array too big (max 32) or empty.";
|
||||||
|
return temMALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// enforce that it must specify a last ledger seq
|
||||||
|
if (!ctx.tx.isFieldPresent(sfLastLedgerSequence))
|
||||||
|
{
|
||||||
|
JLOG(ctx.j.warn())
|
||||||
|
<< "applyTransaction: txns with attesters must specify a last ledger sequence <= cur + 256";
|
||||||
|
return temMALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sanity check entries
|
||||||
|
std::set<AccountID> used;
|
||||||
|
for (auto const& attester: attesters)
|
||||||
|
{
|
||||||
|
if (attester.getFName() != sfAttesterEntry)
|
||||||
|
{
|
||||||
|
JLOG(ctx.j.warn())
|
||||||
|
<< "applyTransaction: attesters array contained non AttesterEntry object.";
|
||||||
|
return temMALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountID const& id = attester.getAccountID(sfAccount);
|
||||||
|
|
||||||
|
if (used.find(id) != used.end())
|
||||||
|
{
|
||||||
|
JLOG(ctx.j.warn())
|
||||||
|
<< "applyTransaction: attesters array contained duplicate attester ID.";
|
||||||
|
return temMALFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
used.emplace(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1928,6 +1976,62 @@ Transactor::operator()()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (applied && ctx_.tx.isFieldPresent(sfAttesters) && view().rules().enabled(featureAttestations))
|
||||||
|
{
|
||||||
|
// delete used attestation objects
|
||||||
|
|
||||||
|
auto const& attesters = ctx_.tx.getFieldArray(sfAttesters);
|
||||||
|
auto const txid = ctx_.tx.getTransactionID();
|
||||||
|
|
||||||
|
auto const& j = ctx_.app.journal("View");
|
||||||
|
|
||||||
|
for (auto const& attester : attesters)
|
||||||
|
{
|
||||||
|
Keylet kl = keylet::attestationTxn(attester.getAccountID(sfAccount), txid);
|
||||||
|
if (!view().exists(kl))
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "Transactor: Warning!!! Attestation does not exist at end of attested txn "
|
||||||
|
<< txid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove from dir
|
||||||
|
auto sleA = view().peek(kl);
|
||||||
|
|
||||||
|
if (!sleA->isFieldPresent(sfAttestedTxnID))
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "Transactor: Warning!!! Attestation is of the wrong type at end of attested txn "
|
||||||
|
<< txid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountID owner = sleA->getAccountID(sfOwner);
|
||||||
|
auto sle = view().peek(keylet::account(owner));
|
||||||
|
|
||||||
|
if (!sle)
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "Transactor: Warning!!! Attester account does not exist at the end of attested txn "
|
||||||
|
<< txid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const page = (*sleA)[sfOwnerNode];
|
||||||
|
if (!view().dirRemove(
|
||||||
|
keylet::ownerDir(owner), page, kl.key, true))
|
||||||
|
{
|
||||||
|
JLOG(j.warn())
|
||||||
|
<< "Could not remove Attestation from owner directory";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
view().erase(sleA);
|
||||||
|
adjustOwnerCount(view(), sle, -1, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Post-application (Weak TSH/AAW) Hooks are executed here.
|
// Post-application (Weak TSH/AAW) Hooks are executed here.
|
||||||
// These TSH do not have the ability to rollback.
|
// These TSH do not have the ability to rollback.
|
||||||
// The callback, if any, is also executed here.
|
// The callback, if any, is also executed here.
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ public:
|
|||||||
{
|
{
|
||||||
// Most transactors do nothing
|
// Most transactors do nothing
|
||||||
// after checkSeq/Fee/Sign.
|
// after checkSeq/Fee/Sign.
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <ripple/app/tx/impl/GenesisMint.h>
|
#include <ripple/app/tx/impl/GenesisMint.h>
|
||||||
#include <ripple/app/tx/impl/Import.h>
|
#include <ripple/app/tx/impl/Import.h>
|
||||||
#include <ripple/app/tx/impl/Invoke.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/NFTokenAcceptOffer.h>
|
||||||
#include <ripple/app/tx/impl/NFTokenBurn.h>
|
#include <ripple/app/tx/impl/NFTokenBurn.h>
|
||||||
#include <ripple/app/tx/impl/NFTokenCancelOffer.h>
|
#include <ripple/app/tx/impl/NFTokenCancelOffer.h>
|
||||||
@@ -164,6 +165,8 @@ invoke_preflight(PreflightContext const& ctx)
|
|||||||
return invoke_preflight_helper<Import>(ctx);
|
return invoke_preflight_helper<Import>(ctx);
|
||||||
case ttINVOKE:
|
case ttINVOKE:
|
||||||
return invoke_preflight_helper<Invoke>(ctx);
|
return invoke_preflight_helper<Invoke>(ctx);
|
||||||
|
case ttATTEST:
|
||||||
|
return invoke_preflight_helper<Attest>(ctx);
|
||||||
case ttURITOKEN_MINT:
|
case ttURITOKEN_MINT:
|
||||||
case ttURITOKEN_BURN:
|
case ttURITOKEN_BURN:
|
||||||
case ttURITOKEN_BUY:
|
case ttURITOKEN_BUY:
|
||||||
@@ -209,6 +212,27 @@ invoke_preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
if (ctx.tx.isFieldPresent(sfAttesters) && ctx.view.rules().enabled(featureAttestations))
|
||||||
|
{
|
||||||
|
// check last ledger sequence
|
||||||
|
if (!ctx.tx.isFieldPresent(sfLastLedgerSequence))
|
||||||
|
return tecINTERNAL;
|
||||||
|
|
||||||
|
if (ctx.tx.getFieldU32(sfLastLedgerSequence) > ctx.view.seq() + 256)
|
||||||
|
return tecLAST_LEDGER_SEQ_TOO_HIGH;
|
||||||
|
|
||||||
|
// check if the required attestations are present on ledger
|
||||||
|
auto const& attesters = ctx.tx.getFieldArray(sfAttesters);
|
||||||
|
|
||||||
|
auto const txid = ctx.tx.getTransactionID();
|
||||||
|
|
||||||
|
// each required attestation must exist on the ledger to allow the txn through
|
||||||
|
// otherwise it gets marked retry
|
||||||
|
for (auto const& attester : attesters)
|
||||||
|
if (!ctx.view.exists(keylet::attestationTxn(attester.getAccountID(sfAccount), txid)))
|
||||||
|
return terAWAITING_ATTESTATION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return T::preclaim(ctx);
|
return T::preclaim(ctx);
|
||||||
@@ -283,6 +307,8 @@ invoke_preclaim(PreclaimContext const& ctx)
|
|||||||
return invoke_preclaim<Import>(ctx);
|
return invoke_preclaim<Import>(ctx);
|
||||||
case ttINVOKE:
|
case ttINVOKE:
|
||||||
return invoke_preclaim<Invoke>(ctx);
|
return invoke_preclaim<Invoke>(ctx);
|
||||||
|
case ttATTEST:
|
||||||
|
return invoke_preclaim<Attest>(ctx);
|
||||||
case ttURITOKEN_MINT:
|
case ttURITOKEN_MINT:
|
||||||
case ttURITOKEN_BURN:
|
case ttURITOKEN_BURN:
|
||||||
case ttURITOKEN_BUY:
|
case ttURITOKEN_BUY:
|
||||||
@@ -364,6 +390,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
|
|||||||
return Import::calculateBaseFee(view, tx);
|
return Import::calculateBaseFee(view, tx);
|
||||||
case ttINVOKE:
|
case ttINVOKE:
|
||||||
return Invoke::calculateBaseFee(view, tx);
|
return Invoke::calculateBaseFee(view, tx);
|
||||||
|
case ttATTEST:
|
||||||
|
return Attest::calculateBaseFee(view, tx);
|
||||||
case ttURITOKEN_MINT:
|
case ttURITOKEN_MINT:
|
||||||
case ttURITOKEN_BURN:
|
case ttURITOKEN_BURN:
|
||||||
case ttURITOKEN_BUY:
|
case ttURITOKEN_BUY:
|
||||||
@@ -544,6 +572,10 @@ invoke_apply(ApplyContext& ctx)
|
|||||||
Invoke p(ctx);
|
Invoke p(ctx);
|
||||||
return p();
|
return p();
|
||||||
}
|
}
|
||||||
|
case ttATTEST: {
|
||||||
|
Attest p(ctx);
|
||||||
|
return p();
|
||||||
|
}
|
||||||
case ttURITOKEN_MINT:
|
case ttURITOKEN_MINT:
|
||||||
case ttURITOKEN_BURN:
|
case ttURITOKEN_BURN:
|
||||||
case ttURITOKEN_BUY:
|
case ttURITOKEN_BUY:
|
||||||
|
|||||||
@@ -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 = 66;
|
static constexpr std::size_t numFeatures = 67;
|
||||||
|
|
||||||
/** 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
|
||||||
@@ -354,7 +354,7 @@ extern uint256 const featureImport;
|
|||||||
extern uint256 const featureXahauGenesis;
|
extern uint256 const featureXahauGenesis;
|
||||||
extern uint256 const featureHooksUpdate1;
|
extern uint256 const featureHooksUpdate1;
|
||||||
extern uint256 const fixURITokenV1;
|
extern uint256 const fixURITokenV1;
|
||||||
|
extern uint256 const featureAttestations;
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -295,7 +295,13 @@ Keylet
|
|||||||
import_vlseq(PublicKey const& key) noexcept;
|
import_vlseq(PublicKey const& key) noexcept;
|
||||||
|
|
||||||
Keylet
|
Keylet
|
||||||
uritoken(AccountID const& issuer, Blob const& uri);
|
uritoken(AccountID const& issuer, Blob const& uri) noexcept;
|
||||||
|
|
||||||
|
Keylet
|
||||||
|
attestationTxn(AccountID const& issuer, uint256 const& txnid) noexcept;
|
||||||
|
|
||||||
|
Keylet
|
||||||
|
attestationAcc(AccountID const& issuer, AccountID const& issuee) noexcept;
|
||||||
|
|
||||||
} // namespace keylet
|
} // namespace keylet
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ namespace ripple {
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
enum LedgerEntryType : std::uint16_t
|
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.
|
/** A ledger object which describes an account.
|
||||||
|
|
||||||
\sa keylet::account
|
\sa keylet::account
|
||||||
|
|||||||
@@ -483,6 +483,7 @@ extern SF_UINT256 const sfURITokenID;
|
|||||||
extern SF_UINT256 const sfGovernanceFlags;
|
extern SF_UINT256 const sfGovernanceFlags;
|
||||||
extern SF_UINT256 const sfGovernanceMarks;
|
extern SF_UINT256 const sfGovernanceMarks;
|
||||||
extern SF_UINT256 const sfEmittedTxnID;
|
extern SF_UINT256 const sfEmittedTxnID;
|
||||||
|
extern SF_UINT256 const sfAttestedTxnID;
|
||||||
|
|
||||||
// currency amount (common)
|
// currency amount (common)
|
||||||
extern SF_AMOUNT const sfAmount;
|
extern SF_AMOUNT const sfAmount;
|
||||||
@@ -552,6 +553,8 @@ extern SF_ACCOUNT const sfEmitCallback;
|
|||||||
// account (uncommon)
|
// account (uncommon)
|
||||||
extern SF_ACCOUNT const sfHookAccount;
|
extern SF_ACCOUNT const sfHookAccount;
|
||||||
extern SF_ACCOUNT const sfNFTokenMinter;
|
extern SF_ACCOUNT const sfNFTokenMinter;
|
||||||
|
extern SF_ACCOUNT const sfInform;
|
||||||
|
extern SF_ACCOUNT const sfAttestedAccID;
|
||||||
|
|
||||||
// path set
|
// path set
|
||||||
extern SField const sfPaths;
|
extern SField const sfPaths;
|
||||||
@@ -562,6 +565,7 @@ extern SF_VECTOR256 const sfHashes;
|
|||||||
extern SF_VECTOR256 const sfAmendments;
|
extern SF_VECTOR256 const sfAmendments;
|
||||||
extern SF_VECTOR256 const sfNFTokenOffers;
|
extern SF_VECTOR256 const sfNFTokenOffers;
|
||||||
extern SF_VECTOR256 const sfHookNamespaces;
|
extern SF_VECTOR256 const sfHookNamespaces;
|
||||||
|
extern SF_VECTOR256 const sfURITokenIDs;
|
||||||
|
|
||||||
// inner object
|
// inner object
|
||||||
// OBJECT/1 is reserved for end of object
|
// OBJECT/1 is reserved for end of object
|
||||||
@@ -590,6 +594,9 @@ extern SField const sfHookGrant;
|
|||||||
extern SField const sfActiveValidator;
|
extern SField const sfActiveValidator;
|
||||||
extern SField const sfImportVLKey;
|
extern SField const sfImportVLKey;
|
||||||
extern SField const sfHookEmission;
|
extern SField const sfHookEmission;
|
||||||
|
extern SField const sfMintURIToken;
|
||||||
|
extern SField const sfAmountEntry;
|
||||||
|
extern SField const sfAttesterEntry;
|
||||||
|
|
||||||
// array of objects (common)
|
// array of objects (common)
|
||||||
// ARRAY/1 is reserved for end of array
|
// ARRAY/1 is reserved for end of array
|
||||||
@@ -617,6 +624,8 @@ extern SField const sfGenesisMints;
|
|||||||
extern SField const sfActiveValidators;
|
extern SField const sfActiveValidators;
|
||||||
extern SField const sfImportVLKeys;
|
extern SField const sfImportVLKeys;
|
||||||
extern SField const sfHookEmissions;
|
extern SField const sfHookEmissions;
|
||||||
|
extern SField const sfAmounts;
|
||||||
|
extern SField const sfAttesters;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -223,8 +223,9 @@ enum TERcodes : TERUnderlyingType {
|
|||||||
terQUEUED, // Transaction is being held in TxQ until fee drops
|
terQUEUED, // Transaction is being held in TxQ until fee drops
|
||||||
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
||||||
terNO_AMM, // RESERVED - AMM
|
terNO_AMM, // RESERVED - AMM
|
||||||
terNO_HOOK // Transaction requires a non-existent hook definition
|
terNO_HOOK, // Transaction requires a non-existent hook definition
|
||||||
// (referenced by sfHookHash)
|
// (referenced by sfHookHash)
|
||||||
|
terAWAITING_ATTESTATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -337,6 +338,7 @@ enum TECcodes : TERUnderlyingType {
|
|||||||
tecXCHAIN_PAYMENT_FAILED = 184, // RESERVED - XCHAIN
|
tecXCHAIN_PAYMENT_FAILED = 184, // RESERVED - XCHAIN
|
||||||
tecXCHAIN_SELF_COMMIT = 185, // RESERVED - XCHAIN
|
tecXCHAIN_SELF_COMMIT = 185, // RESERVED - XCHAIN
|
||||||
tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR = 186, // RESERVED - XCHAIN
|
tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR = 186, // RESERVED - XCHAIN
|
||||||
|
tecLAST_LEDGER_SEQ_TOO_HIGH = 187,
|
||||||
tecLAST_POSSIBLE_ENTRY = 255,
|
tecLAST_POSSIBLE_ENTRY = 255,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -132,6 +132,10 @@ constexpr std::uint32_t const tfStrongTSH = 0x00008000;
|
|||||||
constexpr std::uint32_t const tfNFTokenMintOldMask =
|
constexpr std::uint32_t const tfNFTokenMintOldMask =
|
||||||
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfStrongTSH);
|
~(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
|
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between
|
||||||
// accounts allowed a TrustLine to be added to the issuer of that token
|
// accounts allowed a TrustLine to be added to the issuer of that token
|
||||||
// without explicit permission from that issuer. This was enabled by
|
// without explicit permission from that issuer. This was enabled by
|
||||||
|
|||||||
@@ -146,6 +146,13 @@ enum TxType : std::uint16_t
|
|||||||
ttURITOKEN_CREATE_SELL_OFFER = 48,
|
ttURITOKEN_CREATE_SELL_OFFER = 48,
|
||||||
ttURITOKEN_CANCEL_SELL_OFFER = 49,
|
ttURITOKEN_CANCEL_SELL_OFFER = 49,
|
||||||
|
|
||||||
|
/** This transaction acts as an attestation for another txn currently in the TxQ */
|
||||||
|
ttATTEST = 94,
|
||||||
|
|
||||||
|
/* A payment transactor that delivers only the exact amounts specified, creating accounts and TLs as needed
|
||||||
|
* that the sender pays for. */
|
||||||
|
ttREMIT = 95,
|
||||||
|
|
||||||
/** This transaction can only be used by the genesis account, which is controlled exclusively by
|
/** 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,
|
* rewards/governance hooks, to print new XRP to be delivered directly to an array of destinations,
|
||||||
* according to reward schedule */
|
* according to reward schedule */
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::De
|
|||||||
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
|
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
|
||||||
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
|
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
|
||||||
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
|
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||||
|
REGISTER_FEATURE(Attestations, Supported::yes, VoteBehavior::DefaultNo);
|
||||||
|
|
||||||
// The following amendments are obsolete, but must remain supported
|
// The following amendments are obsolete, but must remain supported
|
||||||
// because they could potentially get enabled.
|
// because they could potentially get enabled.
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ namespace ripple {
|
|||||||
*/
|
*/
|
||||||
enum class LedgerNameSpace : std::uint16_t {
|
enum class LedgerNameSpace : std::uint16_t {
|
||||||
ACCOUNT = 'a',
|
ACCOUNT = 'a',
|
||||||
|
ATTESTATION_ACC = 'A',
|
||||||
|
ATTESTATION_TXN = 't',
|
||||||
DIR_NODE = 'd',
|
DIR_NODE = 'd',
|
||||||
TRUST_LINE = 'r',
|
TRUST_LINE = 'r',
|
||||||
OFFER = 'o',
|
OFFER = 'o',
|
||||||
@@ -435,7 +437,7 @@ nft_sells(uint256 const& id) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
Keylet
|
Keylet
|
||||||
uritoken(AccountID const& issuer, Blob const& uri)
|
uritoken(AccountID const& issuer, Blob const& uri) noexcept
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
ltURI_TOKEN,
|
ltURI_TOKEN,
|
||||||
@@ -443,6 +445,16 @@ uritoken(AccountID const& issuer, Blob const& uri)
|
|||||||
LedgerNameSpace::URI_TOKEN, issuer, Slice{uri.data(), uri.size()})};
|
LedgerNameSpace::URI_TOKEN, issuer, Slice{uri.data(), uri.size()})};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keylet attestationTxn(AccountID const& issuer, uint256 const& txnid) noexcept
|
||||||
|
{
|
||||||
|
return {ltATTESTATION, indexHash(LedgerNameSpace::ATTESTATION_TXN, issuer, txnid)};
|
||||||
|
}
|
||||||
|
|
||||||
|
Keylet attestationAcc(AccountID const& issuer, AccountID const& issuee) noexcept
|
||||||
|
{
|
||||||
|
return {ltATTESTATION, indexHash(LedgerNameSpace::ATTESTATION_ACC, issuer, issuee)};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace keylet
|
} // namespace keylet
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
@@ -141,6 +141,27 @@ InnerObjectFormats::InnerObjectFormats()
|
|||||||
{sfPublicKey, soeREQUIRED},
|
{sfPublicKey, soeREQUIRED},
|
||||||
{sfAccount, soeOPTIONAL},
|
{sfAccount, soeOPTIONAL},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add(sfAmountEntry.jsonName.c_str(),
|
||||||
|
sfAmountEntry.getCode(),
|
||||||
|
{
|
||||||
|
{sfAmount, soeREQUIRED},
|
||||||
|
{sfFlags, soeOPTIONAL},
|
||||||
|
});
|
||||||
|
|
||||||
|
add(sfMintURIToken.jsonName.c_str(),
|
||||||
|
sfMintURIToken.getCode(),
|
||||||
|
{
|
||||||
|
{sfURI, soeREQUIRED},
|
||||||
|
{sfDigest, soeOPTIONAL},
|
||||||
|
{sfFlags, soeOPTIONAL},
|
||||||
|
});
|
||||||
|
|
||||||
|
add(sfAttesterEntry.jsonName.c_str(),
|
||||||
|
sfAttesterEntry.getCode(),
|
||||||
|
{
|
||||||
|
{sfAccount, soeREQUIRED},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
InnerObjectFormats const&
|
InnerObjectFormats const&
|
||||||
|
|||||||
@@ -363,6 +363,18 @@ LedgerFormats::LedgerFormats()
|
|||||||
},
|
},
|
||||||
commonFields);
|
commonFields);
|
||||||
|
|
||||||
|
add(jss::Attestation,
|
||||||
|
ltATTESTATION,
|
||||||
|
{
|
||||||
|
{sfOwner, soeREQUIRED},
|
||||||
|
{sfOwnerNode, soeREQUIRED},
|
||||||
|
{sfAttestedTxnID, soeOPTIONAL},
|
||||||
|
{sfAttestedAccID, soeOPTIONAL},
|
||||||
|
{sfPreviousTxnID, soeREQUIRED},
|
||||||
|
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||||
|
},
|
||||||
|
commonFields);
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ CONSTRUCT_TYPED_SFIELD(sfURITokenID, "URITokenID", UINT256,
|
|||||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceFlags, "GovernanceFlags", UINT256, 99);
|
CONSTRUCT_TYPED_SFIELD(sfGovernanceFlags, "GovernanceFlags", UINT256, 99);
|
||||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceMarks, "GovernanceMarks", UINT256, 98);
|
CONSTRUCT_TYPED_SFIELD(sfGovernanceMarks, "GovernanceMarks", UINT256, 98);
|
||||||
CONSTRUCT_TYPED_SFIELD(sfEmittedTxnID, "EmittedTxnID", UINT256, 97);
|
CONSTRUCT_TYPED_SFIELD(sfEmittedTxnID, "EmittedTxnID", UINT256, 97);
|
||||||
|
CONSTRUCT_TYPED_SFIELD(sfAttestedTxnID, "AttestedTxnID", UINT256, 96);
|
||||||
|
|
||||||
// currency amount (common)
|
// currency amount (common)
|
||||||
CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1);
|
CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1);
|
||||||
@@ -305,6 +306,8 @@ CONSTRUCT_TYPED_SFIELD(sfEmitCallback, "EmitCallback", ACCOUNT,
|
|||||||
|
|
||||||
// account (uncommon)
|
// account (uncommon)
|
||||||
CONSTRUCT_TYPED_SFIELD(sfHookAccount, "HookAccount", ACCOUNT, 16);
|
CONSTRUCT_TYPED_SFIELD(sfHookAccount, "HookAccount", ACCOUNT, 16);
|
||||||
|
CONSTRUCT_TYPED_SFIELD(sfInform, "Inform", ACCOUNT, 99);
|
||||||
|
CONSTRUCT_TYPED_SFIELD(sfAttestedAccID, "AttestedAccID", ACCOUNT, 98);
|
||||||
|
|
||||||
// vector of 256-bit
|
// vector of 256-bit
|
||||||
CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never);
|
CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never);
|
||||||
@@ -312,6 +315,7 @@ CONSTRUCT_TYPED_SFIELD(sfHashes, "Hashes", VECTOR25
|
|||||||
CONSTRUCT_TYPED_SFIELD(sfAmendments, "Amendments", VECTOR256, 3);
|
CONSTRUCT_TYPED_SFIELD(sfAmendments, "Amendments", VECTOR256, 3);
|
||||||
CONSTRUCT_TYPED_SFIELD(sfNFTokenOffers, "NFTokenOffers", VECTOR256, 4);
|
CONSTRUCT_TYPED_SFIELD(sfNFTokenOffers, "NFTokenOffers", VECTOR256, 4);
|
||||||
CONSTRUCT_TYPED_SFIELD(sfHookNamespaces, "HookNamespaces", VECTOR256, 5);
|
CONSTRUCT_TYPED_SFIELD(sfHookNamespaces, "HookNamespaces", VECTOR256, 5);
|
||||||
|
CONSTRUCT_TYPED_SFIELD(sfURITokenIDs, "URITokenIDs", VECTOR256, 99);
|
||||||
|
|
||||||
// path set
|
// path set
|
||||||
CONSTRUCT_UNTYPED_SFIELD(sfPaths, "Paths", PATHSET, 1);
|
CONSTRUCT_UNTYPED_SFIELD(sfPaths, "Paths", PATHSET, 1);
|
||||||
@@ -346,6 +350,9 @@ CONSTRUCT_UNTYPED_SFIELD(sfGenesisMint, "GenesisMint", OBJECT,
|
|||||||
CONSTRUCT_UNTYPED_SFIELD(sfActiveValidator, "ActiveValidator", OBJECT, 95);
|
CONSTRUCT_UNTYPED_SFIELD(sfActiveValidator, "ActiveValidator", OBJECT, 95);
|
||||||
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKey, "ImportVLKey", OBJECT, 94);
|
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKey, "ImportVLKey", OBJECT, 94);
|
||||||
CONSTRUCT_UNTYPED_SFIELD(sfHookEmission, "HookEmission", OBJECT, 93);
|
CONSTRUCT_UNTYPED_SFIELD(sfHookEmission, "HookEmission", OBJECT, 93);
|
||||||
|
CONSTRUCT_UNTYPED_SFIELD(sfMintURIToken, "MintURIToken", OBJECT, 92);
|
||||||
|
CONSTRUCT_UNTYPED_SFIELD(sfAmountEntry, "AmountEntry", OBJECT, 91);
|
||||||
|
CONSTRUCT_UNTYPED_SFIELD(sfAttesterEntry, "AttesterEntry", OBJECT, 90);
|
||||||
|
|
||||||
// array of objects
|
// array of objects
|
||||||
// ARRAY/1 is reserved for end of array
|
// ARRAY/1 is reserved for end of array
|
||||||
@@ -370,6 +377,8 @@ CONSTRUCT_UNTYPED_SFIELD(sfGenesisMints, "GenesisMints", ARRAY,
|
|||||||
CONSTRUCT_UNTYPED_SFIELD(sfActiveValidators, "ActiveValidators", ARRAY, 95);
|
CONSTRUCT_UNTYPED_SFIELD(sfActiveValidators, "ActiveValidators", ARRAY, 95);
|
||||||
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKeys, "ImportVLKeys", ARRAY, 94);
|
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKeys, "ImportVLKeys", ARRAY, 94);
|
||||||
CONSTRUCT_UNTYPED_SFIELD(sfHookEmissions, "HookEmissions", ARRAY, 93);
|
CONSTRUCT_UNTYPED_SFIELD(sfHookEmissions, "HookEmissions", ARRAY, 93);
|
||||||
|
CONSTRUCT_UNTYPED_SFIELD(sfAmounts, "Amounts", ARRAY, 92);
|
||||||
|
CONSTRUCT_UNTYPED_SFIELD(sfAttesters, "Attesters", ARRAY, 91);
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ transResults()
|
|||||||
MAKE_ERROR(tecHOOK_REJECTED, "Rejected by hook on sending or receiving account."),
|
MAKE_ERROR(tecHOOK_REJECTED, "Rejected by hook on sending or receiving account."),
|
||||||
MAKE_ERROR(tecREQUIRES_FLAG, "The transaction or part-thereof requires a flag that wasn't set."),
|
MAKE_ERROR(tecREQUIRES_FLAG, "The transaction or part-thereof requires a flag that wasn't set."),
|
||||||
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
||||||
|
MAKE_ERROR(tecLAST_LEDGER_SEQ_TOO_HIGH, "The sfLastLedgerSequence was higher than seq + 256."),
|
||||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||||
MAKE_ERROR(tefBAD_AUTH, "Transaction's public key is not authorized."),
|
MAKE_ERROR(tefBAD_AUTH, "Transaction's public key is not authorized."),
|
||||||
@@ -188,6 +189,7 @@ transResults()
|
|||||||
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
|
MAKE_ERROR(terQUEUED, "Held until escalated fee drops."),
|
||||||
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
|
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
|
||||||
MAKE_ERROR(terNO_HOOK, "No hook with that hash exists on the ledger."),
|
MAKE_ERROR(terNO_HOOK, "No hook with that hash exists on the ledger."),
|
||||||
|
MAKE_ERROR(terAWAITING_ATTESTATION, "Transaction is waiting for attesters to attest."),
|
||||||
|
|
||||||
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ TxFormats::TxFormats()
|
|||||||
{sfNetworkID, soeOPTIONAL},
|
{sfNetworkID, soeOPTIONAL},
|
||||||
{sfHookParameters, soeOPTIONAL},
|
{sfHookParameters, soeOPTIONAL},
|
||||||
{sfOperationLimit, soeOPTIONAL},
|
{sfOperationLimit, soeOPTIONAL},
|
||||||
|
{sfAttesters, soeOPTIONAL},
|
||||||
};
|
};
|
||||||
|
|
||||||
add(jss::AccountSet,
|
add(jss::AccountSet,
|
||||||
@@ -116,6 +117,21 @@ TxFormats::TxFormats()
|
|||||||
},
|
},
|
||||||
commonFields);
|
commonFields);
|
||||||
|
|
||||||
|
add(jss::Remit,
|
||||||
|
ttREMIT,
|
||||||
|
{
|
||||||
|
{sfDestination, soeREQUIRED},
|
||||||
|
{sfAmounts, soeOPTIONAL},
|
||||||
|
{sfURITokenIDs, soeOPTIONAL},
|
||||||
|
{sfMintURIToken, soeOPTIONAL},
|
||||||
|
{sfInvoiceID, soeOPTIONAL},
|
||||||
|
{sfDestinationTag, soeOPTIONAL},
|
||||||
|
{sfTicketSequence, soeOPTIONAL},
|
||||||
|
{sfBlob, soeOPTIONAL},
|
||||||
|
{sfInform, soeOPTIONAL},
|
||||||
|
},
|
||||||
|
commonFields);
|
||||||
|
|
||||||
add(jss::EscrowCreate,
|
add(jss::EscrowCreate,
|
||||||
ttESCROW_CREATE,
|
ttESCROW_CREATE,
|
||||||
{
|
{
|
||||||
@@ -441,6 +457,15 @@ TxFormats::TxFormats()
|
|||||||
{sfTicketSequence, soeOPTIONAL},
|
{sfTicketSequence, soeOPTIONAL},
|
||||||
},
|
},
|
||||||
commonFields);
|
commonFields);
|
||||||
|
|
||||||
|
add(jss::Attest,
|
||||||
|
ttATTEST,
|
||||||
|
{
|
||||||
|
{sfAttestedTxnID, soeOPTIONAL},
|
||||||
|
{sfAttestedAccID, soeOPTIONAL},
|
||||||
|
{sfTicketSequence, soeOPTIONAL},
|
||||||
|
},
|
||||||
|
commonFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
TxFormats const&
|
TxFormats const&
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ JSS(AccountSet); // transaction type.
|
|||||||
JSS(Amendments); // ledger type.
|
JSS(Amendments); // ledger type.
|
||||||
JSS(Amount); // in: TransactionSign; field.
|
JSS(Amount); // in: TransactionSign; field.
|
||||||
JSS(Authorize); // field
|
JSS(Authorize); // field
|
||||||
|
JSS(Attest);
|
||||||
|
JSS(AttesterEntry);
|
||||||
|
JSS(Attestation);
|
||||||
JSS(Blob);
|
JSS(Blob);
|
||||||
JSS(Check); // ledger type.
|
JSS(Check); // ledger type.
|
||||||
JSS(CheckCancel); // transaction type.
|
JSS(CheckCancel); // transaction type.
|
||||||
@@ -117,6 +120,7 @@ JSS(Payment); // transaction type.
|
|||||||
JSS(PaymentChannelClaim); // transaction type.
|
JSS(PaymentChannelClaim); // transaction type.
|
||||||
JSS(PaymentChannelCreate); // transaction type.
|
JSS(PaymentChannelCreate); // transaction type.
|
||||||
JSS(PaymentChannelFund); // transaction type.
|
JSS(PaymentChannelFund); // transaction type.
|
||||||
|
JSS(Remit); // transaction type.
|
||||||
JSS(RippleState); // ledger type.
|
JSS(RippleState); // ledger type.
|
||||||
JSS(SLE_hit_rate); // out: GetCounts.
|
JSS(SLE_hit_rate); // out: GetCounts.
|
||||||
JSS(SetFee); // transaction type.
|
JSS(SetFee); // transaction type.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <ripple/protocol/jss.h>
|
||||||
#include <test/jtx/Env.h>
|
#include <test/jtx/Env.h>
|
||||||
#include <test/jtx/acctdelete.h>
|
#include <test/jtx/acctdelete.h>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user