STObject::applyTemplate() throws with description of error:

The `STObject` member function `setType()` has been renamed to
applyTemplate() and modified to throw if there is a template
mismatch.

The error description in the exception is, in certain cases,
used, to better indicate why a particular transaction was
considered ill formed.

Fixes #2585.
This commit is contained in:
Scott Schurr
2018-11-02 17:50:27 -07:00
committed by Nik Bougalis
parent c354809e1c
commit ad5c5f1969
12 changed files with 221 additions and 132 deletions

View File

@@ -363,7 +363,7 @@ public:
BEAST_EXPECT(st[sf1] == 1);
BEAST_EXPECT(st[sf2] == 2);
except<missing_field_error>([&]()
except<STObject::FieldErr>([&]()
{ st[sf3]; });
BEAST_EXPECT(*st[~sf1] == 1);
BEAST_EXPECT(*st[~sf2] == 2);

View File

@@ -17,9 +17,11 @@
*/
//==============================================================================
#include <ripple/protocol/STAmount.h>
#include <ripple/protocol/Sign.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/STParsedJSON.h>
#include <ripple/protocol/TxFormats.h>
#include <ripple/protocol/UintTypes.h>
#include <ripple/json/to_string.h>
#include <ripple/beast/unit_test.h>
@@ -41,6 +43,9 @@ public:
testcase ("ed25519 signatures");
testSTTx (KeyType::ed25519);
testcase ("STObject constructor errors");
testObjectCtorErrors();
}
void testDeepNesting()
@@ -1229,7 +1234,7 @@ public:
try
{
ripple::SerialIter sit (Slice{payload2, sizeof(payload2)});
ripple::SerialIter sit {payload2};
auto stx = std::make_shared<ripple::STTx const>(sit);
fail("An exception should have been thrown");
}
@@ -1287,6 +1292,95 @@ public:
pass ();
}
}
void testObjectCtorErrors ()
{
auto const kp1 = randomKeyPair (KeyType::secp256k1);
auto const id1 = calcAccountID(kp1.first);
auto const kp2 = randomKeyPair (KeyType::secp256k1);
auto const id2 = calcAccountID(kp2.first);
// Lambda that returns a Payment STObject.
auto getPayment = [kp1, id1, id2] ()
{
// Account id1 pays account id2 10,000 XRP.
STObject payment (sfGeneric);
payment.setFieldU16 (sfTransactionType, ttPAYMENT);
payment.setAccountID (sfAccount, id1);
payment.setAccountID (sfDestination, id2);
payment.setFieldAmount (sfAmount, STAmount (10000000000ull));
payment.setFieldAmount (sfFee, STAmount (10ull));
payment.setFieldU32 (sfSequence, 1);
payment.setFieldVL (
sfSigningPubKey, Slice (kp1.first.data(), kp1.first.size()));
return payment;
};
{
// Verify that getPayment() returns a viable Payment.
std::string got;
try
{
STTx {getPayment()};
}
catch (STTx::FieldErr const& err)
{
got = err.what();
}
BEAST_EXPECT (got.empty());
}
{
// Make a payment with a defaulted PathSet field, which is invalid.
STObject defaultPath {getPayment()};
defaultPath.setFieldPathSet (sfPaths, STPathSet{});
std::string got;
try
{
STTx {std::move (defaultPath)};
}
catch (STTx::FieldErr const& err)
{
got = err.what();
}
BEAST_EXPECT (
got == "Field 'Paths' may not be explicitly set to default.");
}
{
// Make a Payment with an extra "SignerWeight" field.
STObject extraField {getPayment()};
extraField.setFieldU16 (sfSignerWeight, 7);
std::string got;
try
{
STTx {std::move (extraField)};
}
catch (STTx::FieldErr const& err)
{
got = err.what();
}
BEAST_EXPECT (
got == "Field 'SignerWeight' found in disallowed location.");
}
{
// Make a Payment that is missing the required Fee field.
STObject extraField {getPayment()};
extraField.delField (sfFee);
std::string got;
try
{
STTx {std::move (extraField)};
}
catch (STTx::FieldErr const& err)
{
got = err.what();
}
BEAST_EXPECT (
got == "Field 'Fee' is required but missing.");
}
}
};
class InnerObjectFormatsSerializer_test : public beast::unit_test::suite

View File

@@ -38,34 +38,43 @@ public:
{
testcase ("Deserialization");
constexpr unsigned char payload1[] =
{ // specifies an Ed25519 public key
0x72, 0x00, 0x73, 0x21, 0xed, 0x78, 0x00, 0xe6, 0x73, 0x00, 0x72, 0x00, 0x3c, 0x00, 0x00, 0x00,
0x88, 0x00, 0xe6, 0x73, 0x38, 0x00, 0x00, 0x8a, 0x00, 0x88, 0x4e, 0x31, 0x30, 0x5f, 0x5f, 0x63,
0x78, 0x78, 0x61, 0x62, 0x69, 0x76, 0x31, 0x30, 0x37, 0x5f, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73,
0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x45, 0x00, 0xe6, 0x88, 0x54, 0x72,
0x75, 0x73, 0x74, 0x53, 0x65, 0x74, 0x65, 0x61, 0x74, 0x65, 0x88, 0x00, 0xe6, 0x88, 0x00, 0xe6,
0x73, 0x00, 0x72, 0x00, 0x8a, 0x00, 0x88, 0x00, 0xe6
};
constexpr unsigned char payload2[] =
constexpr std::uint8_t payload1[] =
{
0x73, 0x21, 0xed, 0xff, 0x03, 0x1c, 0xbe, 0x65, 0x22, 0x61, 0x9c, 0x5e, 0x13, 0x12, 0x00, 0x3b,
0x43, 0x00, 0x00, 0x00, 0xf7, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x13, 0x13, 0x13,
0x3a, 0x27, 0xff
// specifies an Ed25519 public key.
0x22, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x51,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x73,
0x21, 0xed, 0x78, 0x00, 0xe6, 0x73, 0x00, 0x72, 0x00, 0x3c, 0x00,
0x00, 0x00, 0x88, 0x00, 0xe6, 0x73, 0x38, 0x00, 0x00, 0x8a, 0x00,
0x88, 0x4e, 0x31, 0x30, 0x5f, 0x5f, 0x63, 0x78, 0x78, 0x61, 0x62,
0x69
};
constexpr unsigned char payload3[] =
{ // Has no public key at all
0x72, 0x00, 0x76, 0x31, 0x30, 0x37, 0x5f, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x45, 0x00, 0xe6, 0x88, 0x54, 0x72, 0x75, 0x73, 0x74,
0x53, 0x65, 0x74, 0x65, 0x61, 0x74, 0x65, 0x88, 0x00, 0xe6, 0x88, 0x00, 0xe6, 0x73, 0x00, 0x72,
0x00, 0x8a, 0x00, 0x88, 0x00, 0xe6
constexpr std::uint8_t payload2[] =
{
0x22, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x51,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x73,
0x21, 0xed, 0xff, 0x03, 0x1c, 0xbe, 0x65, 0x22, 0x61, 0x9c, 0x5e,
0x13, 0x12, 0x00, 0x3b, 0x43, 0x00, 0x00, 0x00, 0xf7, 0x3f, 0x3f,
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x13, 0x13, 0x13, 0x3a, 0x27,
0xff
};
constexpr std::uint8_t payload3[] =
{
// Has no public key at all
0x22, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x51,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a
};
try
{
SerialIter sit{payload1, sizeof(payload1)};
SerialIter sit {payload1};
auto stx = std::make_shared<ripple::STValidation>(sit,
[](PublicKey const& pk) {
return calcNodeID(pk);
@@ -74,12 +83,13 @@ public:
}
catch (std::exception const& e)
{
BEAST_EXPECT(strcmp(e.what(), "Invalid public key in validation") == 0);
BEAST_EXPECT(strcmp(e.what(),
"Invalid public key in validation") == 0);
}
try
{
SerialIter sit{payload2, sizeof(payload2)};
SerialIter sit {payload2};
auto stx = std::make_shared<ripple::STValidation>(sit,
[](PublicKey const& pk) {
return calcNodeID(pk);
@@ -88,12 +98,13 @@ public:
}
catch (std::exception const& e)
{
BEAST_EXPECT(strcmp(e.what(), "Invalid public key in validation") == 0);
BEAST_EXPECT(strcmp(e.what(),
"Invalid public key in validation") == 0);
}
try
{
SerialIter sit{payload3, sizeof(payload3)};
SerialIter sit {payload3};
auto stx = std::make_shared<ripple::STValidation>(sit,
[](PublicKey const& pk) {
return calcNodeID(pk);
@@ -102,8 +113,8 @@ public:
}
catch (std::exception const& e)
{
log << e.what() << "\n";
BEAST_EXPECT(strcmp(e.what(), "Invalid public key in validation") == 0);
BEAST_EXPECT(strcmp(e.what(),
"Field 'SigningPubKey' is required but missing.") == 0);
}
}