mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
add last ledger seq enforcement, accid attestations
This commit is contained in:
@@ -39,9 +39,18 @@ Attest::preflight(PreflightContext const& ctx)
|
||||
|
||||
auto const flags = ctx.tx.getFlags();
|
||||
|
||||
if (ctx.rules.enabled(fix1543) && (flags & tfAttestMask))
|
||||
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);
|
||||
}
|
||||
@@ -59,7 +68,9 @@ Attest::preclaim(PreclaimContext const& ctx)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
Keylet kl =
|
||||
keylet::attestation(id, ctx.tx.getFieldH256(sfAttestedTxnID));
|
||||
ctx.tx.isFieldPresent(sfAttestedTxnID)
|
||||
? keylet::attestationTxn(id, ctx.tx.getFieldH256(sfAttestedTxnID))
|
||||
: keylet::attestationAcc(id, ctx.tx.getAccountID(sfAttestedAccID));
|
||||
|
||||
uint32_t flags = ctx.tx.getFlags();
|
||||
|
||||
@@ -96,9 +107,10 @@ Attest::doApply()
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
|
||||
Keylet kl =
|
||||
keylet::attestation(account_, ctx_.tx.getFieldH256(sfAttestedTxnID));
|
||||
ctx_.tx.isFieldPresent(sfAttestedTxnID)
|
||||
? keylet::attestationTxn(account_, ctx_.tx.getFieldH256(sfAttestedTxnID))
|
||||
: keylet::attestationAcc(account_, ctx_.tx.getAccountID(sfAttestedAccID));
|
||||
|
||||
uint32_t flags = ctx_.tx.getFlags();
|
||||
|
||||
@@ -132,7 +144,11 @@ Attest::doApply()
|
||||
|
||||
sleA->setAccountID(sfOwner, account_);
|
||||
|
||||
sleA->setFieldH256(sfAttestedTxnID, ctx_.tx.getFieldH256(sfAttestedTxnID));
|
||||
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_));
|
||||
|
||||
@@ -99,7 +99,16 @@ preflight0(PreflightContext const& ctx)
|
||||
<< "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)
|
||||
@@ -111,12 +120,16 @@ preflight0(PreflightContext const& ctx)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (used.find(attester.getAccountID(sfAccount)) != used.end())
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1974,7 +1987,7 @@ Transactor::operator()()
|
||||
|
||||
for (auto const& attester : attesters)
|
||||
{
|
||||
Keylet kl = keylet::attestation(attester.getAccountID(sfAccount), txid);
|
||||
Keylet kl = keylet::attestationTxn(attester.getAccountID(sfAccount), txid);
|
||||
if (!view().exists(kl))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
@@ -1986,6 +1999,14 @@ Transactor::operator()()
|
||||
// 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));
|
||||
|
||||
|
||||
@@ -163,6 +163,14 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
@@ -171,7 +179,7 @@ public:
|
||||
// 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::attestation(attester.getAccountID(sfAccount), txid)))
|
||||
if (!ctx.view.exists(keylet::attestationTxn(attester.getAccountID(sfAccount), txid)))
|
||||
return terRETRY;
|
||||
}
|
||||
return tesSUCCESS;
|
||||
|
||||
@@ -298,7 +298,10 @@ Keylet
|
||||
uritoken(AccountID const& issuer, Blob const& uri) noexcept;
|
||||
|
||||
Keylet
|
||||
attestation(AccountID const& issuer, uint256 const& txnid) noexcept;
|
||||
attestationTxn(AccountID const& issuer, uint256 const& txnid) noexcept;
|
||||
|
||||
Keylet
|
||||
attestationAcc(AccountID const& issuer, AccountID const& issuee) noexcept;
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
|
||||
@@ -553,6 +553,7 @@ extern SF_ACCOUNT const sfEmitCallback;
|
||||
// account (uncommon)
|
||||
extern SF_ACCOUNT const sfHookAccount;
|
||||
extern SF_ACCOUNT const sfNFTokenMinter;
|
||||
extern SF_ACCOUNT const sfAttestedAccID;
|
||||
|
||||
// path set
|
||||
extern SField const sfPaths;
|
||||
|
||||
@@ -337,6 +337,7 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecXCHAIN_PAYMENT_FAILED = 184, // RESERVED - XCHAIN
|
||||
tecXCHAIN_SELF_COMMIT = 185, // RESERVED - XCHAIN
|
||||
tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR = 186, // RESERVED - XCHAIN
|
||||
tecLAST_LEDGER_SEQ_TOO_HIGH = 187,
|
||||
tecLAST_POSSIBLE_ENTRY = 255,
|
||||
};
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ namespace ripple {
|
||||
*/
|
||||
enum class LedgerNameSpace : std::uint16_t {
|
||||
ACCOUNT = 'a',
|
||||
ATTESTATION = 'A',
|
||||
ATTESTATION_ACC = 'A',
|
||||
ATTESTATION_TXN = 't',
|
||||
DIR_NODE = 'd',
|
||||
TRUST_LINE = 'r',
|
||||
OFFER = 'o',
|
||||
@@ -444,9 +445,14 @@ uritoken(AccountID const& issuer, Blob const& uri) noexcept
|
||||
LedgerNameSpace::URI_TOKEN, issuer, Slice{uri.data(), uri.size()})};
|
||||
}
|
||||
|
||||
Keylet attestation(AccountID const& issuer, uint256 const& txnid) noexcept
|
||||
Keylet attestationTxn(AccountID const& issuer, uint256 const& txnid) noexcept
|
||||
{
|
||||
return {ltATTESTATION, indexHash(LedgerNameSpace::ATTESTATION, issuer, txnid)};
|
||||
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
|
||||
|
||||
@@ -368,7 +368,8 @@ LedgerFormats::LedgerFormats()
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfAttestedTxnID, soeREQUIRED},
|
||||
{sfAttestedTxnID, soeOPTIONAL},
|
||||
{sfAttestedAccID, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
},
|
||||
|
||||
@@ -306,6 +306,7 @@ CONSTRUCT_TYPED_SFIELD(sfEmitCallback, "EmitCallback", ACCOUNT,
|
||||
|
||||
// account (uncommon)
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookAccount, "HookAccount", ACCOUNT, 16);
|
||||
CONSTRUCT_TYPED_SFIELD(sfAttestedAccID, "AttestedAccID", ACCOUNT, 98);
|
||||
|
||||
// vector of 256-bit
|
||||
CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never);
|
||||
|
||||
@@ -91,6 +91,7 @@ transResults()
|
||||
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(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(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
MAKE_ERROR(tefBAD_AUTH, "Transaction's public key is not authorized."),
|
||||
|
||||
@@ -446,7 +446,8 @@ TxFormats::TxFormats()
|
||||
add(jss::Attest,
|
||||
ttATTEST,
|
||||
{
|
||||
{sfAttestedTxnID, soeREQUIRED},
|
||||
{sfAttestedTxnID, soeOPTIONAL},
|
||||
{sfAttestedAccID, soeOPTIONAL},
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
Reference in New Issue
Block a user