mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Introduce Credentials support (XLS-70d): (#5103)
Amendment:
- Credentials
New Transactions:
- CredentialCreate
- CredentialAccept
- CredentialDelete
Modified Transactions:
- DepositPreauth
- Payment
- EscrowFinish
- PaymentChannelClaim
- AccountDelete
New Object:
- Credential
Modified Object:
- DepositPreauth
API updates:
- ledger_entry
- account_objects
- ledger_data
- deposit_authorized
Read full spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0070d-credentials
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/app/main/Application.h>
|
||||
#include <xrpld/app/misc/CredentialHelpers.h>
|
||||
#include <xrpld/ledger/ReadView.h>
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/GRPCHandlers.h>
|
||||
@@ -34,6 +35,31 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static STArray
|
||||
parseAuthorizeCredentials(Json::Value const& jv)
|
||||
{
|
||||
STArray arr(sfAuthorizeCredentials, jv.size());
|
||||
for (auto const& jo : jv)
|
||||
{
|
||||
auto const issuer = parseBase58<AccountID>(jo[jss::issuer].asString());
|
||||
if (!issuer || !*issuer)
|
||||
return {};
|
||||
|
||||
auto const credentialType =
|
||||
strUnHex(jo[jss::credential_type].asString());
|
||||
if (!credentialType || credentialType->empty() ||
|
||||
credentialType->size() > maxCredentialTypeLength)
|
||||
return {};
|
||||
|
||||
auto credential = STObject::makeInnerObject(sfCredential);
|
||||
credential.setAccountID(sfIssuer, *issuer);
|
||||
credential.setFieldVL(sfCredentialType, *credentialType);
|
||||
arr.push_back(std::move(credential));
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
// {
|
||||
// ledger_hash : <ledger>
|
||||
// ledger_index : <ledger_index>
|
||||
@@ -84,44 +110,63 @@ doLedgerEntry(RPC::JsonContext& context)
|
||||
else if (context.params.isMember(jss::deposit_preauth))
|
||||
{
|
||||
expectedType = ltDEPOSIT_PREAUTH;
|
||||
auto const& dp = context.params[jss::deposit_preauth];
|
||||
|
||||
if (!context.params[jss::deposit_preauth].isObject())
|
||||
if (!dp.isObject())
|
||||
{
|
||||
if (!context.params[jss::deposit_preauth].isString() ||
|
||||
!uNodeIndex.parseHex(
|
||||
context.params[jss::deposit_preauth].asString()))
|
||||
if (!dp.isString() || !uNodeIndex.parseHex(dp.asString()))
|
||||
{
|
||||
uNodeIndex = beast::zero;
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
}
|
||||
// clang-format off
|
||||
else if (
|
||||
!context.params[jss::deposit_preauth].isMember(jss::owner) ||
|
||||
!context.params[jss::deposit_preauth][jss::owner].isString() ||
|
||||
!context.params[jss::deposit_preauth].isMember(
|
||||
jss::authorized) ||
|
||||
!context.params[jss::deposit_preauth][jss::authorized]
|
||||
.isString())
|
||||
(!dp.isMember(jss::owner) || !dp[jss::owner].isString()) ||
|
||||
(dp.isMember(jss::authorized) == dp.isMember(jss::authorized_credentials)) ||
|
||||
(dp.isMember(jss::authorized) && !dp[jss::authorized].isString()) ||
|
||||
(dp.isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].isArray())
|
||||
)
|
||||
// clang-format on
|
||||
{
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const owner = parseBase58<AccountID>(
|
||||
context.params[jss::deposit_preauth][jss::owner]
|
||||
.asString());
|
||||
|
||||
auto const authorized = parseBase58<AccountID>(
|
||||
context.params[jss::deposit_preauth][jss::authorized]
|
||||
.asString());
|
||||
|
||||
auto const owner =
|
||||
parseBase58<AccountID>(dp[jss::owner].asString());
|
||||
if (!owner)
|
||||
{
|
||||
jvResult[jss::error] = "malformedOwner";
|
||||
else if (!authorized)
|
||||
jvResult[jss::error] = "malformedAuthorized";
|
||||
}
|
||||
else if (dp.isMember(jss::authorized))
|
||||
{
|
||||
auto const authorized =
|
||||
parseBase58<AccountID>(dp[jss::authorized].asString());
|
||||
if (!authorized)
|
||||
jvResult[jss::error] = "malformedAuthorized";
|
||||
else
|
||||
uNodeIndex =
|
||||
keylet::depositPreauth(*owner, *authorized).key;
|
||||
}
|
||||
else
|
||||
uNodeIndex =
|
||||
keylet::depositPreauth(*owner, *authorized).key;
|
||||
{
|
||||
auto const& ac(dp[jss::authorized_credentials]);
|
||||
STArray const arr = parseAuthorizeCredentials(ac);
|
||||
|
||||
if (arr.empty() || (arr.size() > maxCredentialsArraySize))
|
||||
jvResult[jss::error] = "malformedAuthorizedCredentials";
|
||||
else
|
||||
{
|
||||
auto sorted = credentials::makeSorted(arr);
|
||||
if (sorted.empty())
|
||||
jvResult[jss::error] =
|
||||
"malformedAuthorizedCredentials";
|
||||
else
|
||||
uNodeIndex =
|
||||
keylet::depositPreauth(*owner, sorted).key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (context.params.isMember(jss::directory))
|
||||
@@ -644,6 +689,52 @@ doLedgerEntry(RPC::JsonContext& context)
|
||||
uNodeIndex = keylet::oracle(*account, *documentID).key;
|
||||
}
|
||||
}
|
||||
else if (context.params.isMember(jss::credential))
|
||||
{
|
||||
expectedType = ltCREDENTIAL;
|
||||
auto const& cred = context.params[jss::credential];
|
||||
|
||||
if (cred.isString())
|
||||
{
|
||||
if (!uNodeIndex.parseHex(cred.asString()))
|
||||
{
|
||||
uNodeIndex = beast::zero;
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
}
|
||||
else if (
|
||||
(!cred.isMember(jss::subject) ||
|
||||
!cred[jss::subject].isString()) ||
|
||||
(!cred.isMember(jss::issuer) ||
|
||||
!cred[jss::issuer].isString()) ||
|
||||
(!cred.isMember(jss::credential_type) ||
|
||||
!cred[jss::credential_type].isString()))
|
||||
{
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const subject =
|
||||
parseBase58<AccountID>(cred[jss::subject].asString());
|
||||
auto const issuer =
|
||||
parseBase58<AccountID>(cred[jss::issuer].asString());
|
||||
auto const credType =
|
||||
strUnHex(cred[jss::credential_type].asString());
|
||||
if (!subject || subject->isZero() || !issuer ||
|
||||
issuer->isZero() || !credType || credType->empty())
|
||||
{
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
else
|
||||
{
|
||||
uNodeIndex = keylet::credential(
|
||||
*subject,
|
||||
*issuer,
|
||||
Slice(credType->data(), credType->size()))
|
||||
.key;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (context.params.isMember(jss::mpt_issuance))
|
||||
{
|
||||
expectedType = ltMPTOKEN_ISSUANCE;
|
||||
|
||||
Reference in New Issue
Block a user