Add "seed" to JSONRPC unit tests (RIPD-1099):

There was a bug in version 0.30.1 where signing with an ed25519
key and a corrupt seed would cause the "sign" and "sign_for"
commands to return an unexpected error.  That bug was fixed in
the 0.31.0 release.

These unit tests verify the fix.  The error message for a corrupt
seed is also slightly improved.
This commit is contained in:
Scott Schurr
2016-05-05 12:53:36 -07:00
committed by Nik Bougalis
parent 1cf518e82c
commit 3a1fa4a552
4 changed files with 127 additions and 18 deletions

View File

@@ -71,17 +71,17 @@ enum CommentPlacement
class StaticString
{
public:
explicit StaticString ( const char* czstring )
constexpr explicit StaticString ( const char* czstring )
: str_ ( czstring )
{
}
operator const char* () const
constexpr operator const char* () const
{
return str_;
}
const char* c_str () const
constexpr const char* c_str () const
{
return str_;
}

View File

@@ -27,7 +27,7 @@ namespace jss {
// JSON static strings
#define JSS(x) const ::Json::StaticString x ( #x )
#define JSS(x) constexpr ::Json::StaticString x ( #x )
/* The "StaticString" field names are used instead of string literals to
optimize the performance of accessing members of Json::Value objects.

View File

@@ -65,31 +65,43 @@ std::pair<PublicKey, SecretKey>
keypairForSignature (Json::Value const& params, Json::Value& error)
{
bool const has_key_type = params.isMember (jss::key_type);
bool const hasPassphrase = params.isMember (jss::passphrase);
bool const hasSecret = params.isMember (jss::secret);
bool const hasSeed = params.isMember (jss::seed);
bool const hasSeedHex = params.isMember (jss::seed_hex);
int const n_secrets =
(hasPassphrase ? 1 : 0) +
(hasSecret ? 1 : 0) +
(hasSeed ? 1 : 0) +
(hasSeedHex ? 1 : 0);
// All of the secret types we allow, but only one at a time.
// The array should be constexpr, but that makes Visual Studio unhappy.
static char const* const secretTypes[]
{
jss::passphrase.c_str(),
jss::secret.c_str(),
jss::seed.c_str(),
jss::seed_hex.c_str()
};
if (n_secrets == 0)
// Identify which secret type is in use.
char const* secretType = nullptr;
int secretCount = 0;
for (auto t : secretTypes)
{
if (params.isMember (t))
{
++secretCount;
secretType = t;
}
}
if (secretCount == 0 || secretType == nullptr)
{
error = RPC::missing_field_error (jss::secret);
return { };
}
if (n_secrets > 1)
if (secretCount > 1)
{
// `passphrase`, `secret`, `seed`, and `seed_hex` are mutually exclusive.
error = rpcError (rpcBAD_SECRET);
return { };
}
if (has_key_type && hasSecret)
if (has_key_type && (secretType == jss::secret.c_str()))
{
// `secret` is deprecated.
error = rpcError (rpcBAD_SECRET);
@@ -121,7 +133,7 @@ keypairForSignature (Json::Value const& params, Json::Value& error)
if (!seed)
{
error = RPC::make_error (rpcBAD_SEED,
RPC::invalid_field_message (jss::secret));
RPC::invalid_field_message (secretType));
return { };
}

View File

@@ -35,6 +35,15 @@ struct TxnTestData
{
char const* const description;
char const* const json;
// The JSON is applied to four different interfaces:
// 1. sign,
// 2. submit,
// 3. sign_for, and
// 4. submit_multisigned.
// The JSON is not valid for all of these interfaces, but it should
// crash none of them, and should provide reliable error messages.
//
// The expMsg array contains the expected error string for the above cases.
char const* const expMsg[4];
// Default and copy ctors should be deleted, but that displeases gcc 4.6.3.
@@ -533,6 +542,44 @@ R"({
"Missing field 'tx_json.Sequence'.",
"Missing field 'tx_json.Sequence'."}},
{ "Use 'seed' instead of 'secret'.",
R"({
"command": "doesnt_matter",
"account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"key_type": "ed25519",
"seed": "sh1yJfwoi98zCygwijUzuHmJDeVKd",
"tx_json": {
"Account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"Amount": "1000000000",
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"TransactionType": "Payment"
}
})",
{
"",
"",
"Missing field 'tx_json.Sequence'.",
"Missing field 'tx_json.Sequence'."}},
{ "Malformed 'seed'.",
R"({
"command": "doesnt_matter",
"account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"key_type": "ed25519",
"seed": "not a seed",
"tx_json": {
"Account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"Amount": "1000000000",
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"TransactionType": "Payment"
}
})",
{
"Invalid field 'seed'.",
"Invalid field 'seed'.",
"Missing field 'tx_json.Sequence'.",
"Missing field 'tx_json.Sequence'."}},
{ "'tx_json' must be present.",
R"({
"command": "doesnt_matter",
@@ -841,6 +888,52 @@ R"({
"",
"Missing field 'tx_json.Signers'."}},
{ "Offline sign_for using 'seed' instead of 'secret'.",
R"({
"command": "doesnt_matter",
"account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"key_type": "ed25519",
"seed": "sh1yJfwoi98zCygwijUzuHmJDeVKd",
"offline": 1,
"tx_json": {
"Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"Amount": "1000000000",
"Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"Fee": 50,
"Sequence": 0,
"SigningPubKey": "",
"TransactionType": "Payment"
}
})",
{
"",
"",
"",
"Missing field 'tx_json.Signers'."}},
{ "Malformed seed in sign_for.",
R"({
"command": "doesnt_matter",
"account": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"key_type": "ed25519",
"seed": "sh1yJfwoi98zCygwjUzuHmJDeVKd",
"offline": 1,
"tx_json": {
"Account": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
"Amount": "1000000000",
"Destination": "rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi",
"Fee": 50,
"Sequence": 0,
"SigningPubKey": "",
"TransactionType": "Payment"
}
})",
{
"Invalid field 'seed'.",
"Invalid field 'seed'.",
"Invalid field 'seed'.",
"Missing field 'tx_json.Signers'."}},
{ "Missing 'Account' in sign_for.",
R"({
"command": "doesnt_matter",
@@ -1840,12 +1933,16 @@ public:
test::jtx::Account const a {"a"}; // rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA
test::jtx::Account const g {"g"}; // rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4
auto const USD = g["USD"];
// Account: rJrxi4Wxev4bnAGVNP9YCdKPdAoKfAmcsi
// seed: sh1yJfwoi98zCygwijUzuHmJDeVKd
test::jtx::Account const ed {"ed", KeyType::ed25519};
// master is rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
// "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd.
// "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux.
test::jtx::Env env(*this, test::jtx::features(featureMultiSign));
env.fund(test::jtx::XRP(100000), a, g);
env.fund(test::jtx::XRP(100000), a, ed, g);
env.close();
env(trust(a, USD(1000)));