mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-04 01:06:48 +00:00
Add PermissionDelegation feature (#5354)
This change implements the account permission delegation described in XLS-75d, see https://github.com/XRPLF/XRPL-Standards/pull/257. * Introduces transaction-level and granular permissions that can be delegated to other accounts. * Adds `DelegateSet` transaction to grant specified permissions to another account. * Adds `ltDelegate` ledger object to maintain the permission list for delegating/delegated account pair. * Adds an optional `Delegate` field in common fields, allowing a delegated account to send transactions on behalf of the delegating account within the granted permission scope. The `Account` field remains the delegating account; the `Delegate` field specifies the delegated account. The transaction is signed by the delegated account.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/Oracle.h>
|
||||
#include <test/jtx/attester.h>
|
||||
#include <test/jtx/delegate.h>
|
||||
#include <test/jtx/multisign.h>
|
||||
#include <test/jtx/xchain_bridge.h>
|
||||
|
||||
@@ -439,6 +440,116 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryDelegate()
|
||||
{
|
||||
testcase("ledger_entry Delegate");
|
||||
|
||||
using namespace test::jtx;
|
||||
|
||||
Env env{*this};
|
||||
Account const alice{"alice"};
|
||||
Account const bob{"bob"};
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
env.close();
|
||||
env(delegate::set(alice, bob, {"Payment", "CheckCreate"}));
|
||||
env.close();
|
||||
std::string const ledgerHash{to_string(env.closed()->info().hash)};
|
||||
std::string delegateIndex;
|
||||
{
|
||||
// Request by account and authorize
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::delegate][jss::account] = alice.human();
|
||||
jvParams[jss::delegate][jss::authorize] = bob.human();
|
||||
jvParams[jss::ledger_hash] = ledgerHash;
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate);
|
||||
BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
|
||||
BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.human());
|
||||
delegateIndex = jrr[jss::node][jss::index].asString();
|
||||
}
|
||||
{
|
||||
// Request by index.
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::delegate] = delegateIndex;
|
||||
jvParams[jss::ledger_hash] = ledgerHash;
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Delegate);
|
||||
BEAST_EXPECT(jrr[jss::node][sfAccount.jsonName] == alice.human());
|
||||
BEAST_EXPECT(jrr[jss::node][sfAuthorize.jsonName] == bob.human());
|
||||
}
|
||||
{
|
||||
// Malformed request: delegate neither object nor string.
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::delegate] = 5;
|
||||
jvParams[jss::ledger_hash] = ledgerHash;
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
checkErrorValue(jrr, "malformedRequest", "");
|
||||
}
|
||||
{
|
||||
// Malformed request: delegate not hex string.
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::delegate] = "0123456789ABCDEFG";
|
||||
jvParams[jss::ledger_hash] = ledgerHash;
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
checkErrorValue(jrr, "malformedRequest", "");
|
||||
}
|
||||
{
|
||||
// Malformed request: account not a string
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::delegate][jss::account] = 5;
|
||||
jvParams[jss::delegate][jss::authorize] = bob.human();
|
||||
jvParams[jss::ledger_hash] = ledgerHash;
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
checkErrorValue(jrr, "malformedAddress", "");
|
||||
}
|
||||
{
|
||||
// Malformed request: authorize not a string
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::delegate][jss::account] = alice.human();
|
||||
jvParams[jss::delegate][jss::authorize] = 5;
|
||||
jvParams[jss::ledger_hash] = ledgerHash;
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
checkErrorValue(jrr, "malformedAddress", "");
|
||||
}
|
||||
{
|
||||
// this lambda function is used test malformed account and authroize
|
||||
auto testMalformedAccount =
|
||||
[&](std::optional<std::string> const& account,
|
||||
std::optional<std::string> const& authorize,
|
||||
std::string const& error) {
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::ledger_hash] = ledgerHash;
|
||||
if (account)
|
||||
jvParams[jss::delegate][jss::account] = *account;
|
||||
if (authorize)
|
||||
jvParams[jss::delegate][jss::authorize] = *authorize;
|
||||
auto const jrr = env.rpc(
|
||||
"json",
|
||||
"ledger_entry",
|
||||
to_string(jvParams))[jss::result];
|
||||
checkErrorValue(jrr, error, "");
|
||||
};
|
||||
// missing account
|
||||
testMalformedAccount(std::nullopt, bob.human(), "malformedRequest");
|
||||
// missing authorize
|
||||
testMalformedAccount(
|
||||
alice.human(), std::nullopt, "malformedRequest");
|
||||
// malformed account
|
||||
testMalformedAccount("-", bob.human(), "malformedAddress");
|
||||
// malformed authorize
|
||||
testMalformedAccount(alice.human(), "-", "malformedAddress");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryDepositPreauth()
|
||||
{
|
||||
@@ -2266,6 +2377,7 @@ public:
|
||||
testLedgerEntryAccountRoot();
|
||||
testLedgerEntryCheck();
|
||||
testLedgerEntryCredentials();
|
||||
testLedgerEntryDelegate();
|
||||
testLedgerEntryDepositPreauth();
|
||||
testLedgerEntryDepositPreauthCred();
|
||||
testLedgerEntryDirectory();
|
||||
|
||||
Reference in New Issue
Block a user