20 #include <ripple/basics/safe_cast.h>
21 #include <ripple/beast/unit_test.h>
22 #include <ripple/protocol/InnerObjectFormats.h>
23 #include <ripple/protocol/LedgerFormats.h>
24 #include <ripple/protocol/TxFormats.h>
26 #include "org/xrpl/rpc/v1/ledger_objects.pb.h"
27 #include "org/xrpl/rpc/v1/transaction.pb.h"
46 google::protobuf::FieldDescriptor::Type::TYPE_UINT32;
49 google::protobuf::FieldDescriptor::Type::TYPE_UINT64;
52 google::protobuf::FieldDescriptor::Type::TYPE_BYTES;
55 google::protobuf::FieldDescriptor::Type::TYPE_STRING;
58 google::protobuf::FieldDescriptor::Type::TYPE_MESSAGE;
68 bool prevUpper =
false;
71 char const ch = fmtName[i];
72 bool const upper = std::isupper(ch);
73 if (i > 0 && !prevUpper && upper)
84 template <
typename KeyType>
91 for (
SOElement const& element : soTemplate)
93 SField const& sField = element.sField();
111 if (excludedSFields.count(sField.
fieldCode))
125 if constexpr (std::is_same_v<KeyType, TxType>)
133 if (excludedTxFields.count(sField.
fieldCode))
138 if constexpr (std::is_same_v<KeyType, LedgerEntryType>)
148 map<LedgerEntryType, std::vector<SField const*>>
155 if (
auto const iter = gRPCOmitFields.find(fmtId);
156 iter != gRPCOmitFields.end())
164 [&sField](
SField const*
const omit) {
165 return *omit == sField;
203 {
"AccountTxnID",
"AccountTransactionID"},
204 {
"Fee",
"XRPDropsAmount"},
205 {
"PreviousTxnID",
"PreviousTransactionID"},
206 {
"PreviousTxnLgrSeq",
"PreviousTransactionLedgerSequence"},
207 {
"Signature",
"PaymentChannelSignature"},
208 {
"SigningPubKey",
"SigningPublicKey"},
209 {
"TakerGetsCurrency",
"TakerGetsCurreny"},
210 {
"TxnSignature",
"TransactionSignature"},
214 auto const iter = sFieldToGRPC.
find(sField.
getName());
216 iter != sFieldToGRPC.
end() ? iter->second : sField.
getName();
218 sFields.
insert({std::move(gRPCName), &sField});
227 google::protobuf::Descriptor
const*
const pbufDescriptor,
228 google::protobuf::Descriptor
const*
const commonFields,
233 namespace pbuf = google::protobuf;
238 auto checkFieldDesc =
239 [
this, &sFields, &knownFormatName](
240 pbuf::FieldDescriptor
const*
const fieldDesc) {
244 if (fieldDesc->is_repeated())
250 name = fieldDesc->camelcase_name();
251 name[0] = toupper(name[0]);
254 if (
size_t const i = name.
find(
"Unl");
255 i != std::string::npos)
261 if (!sFields.count(name))
265 name +
"' expected in KnownFormat '" +
266 knownFormatName +
"' and not found",
278 pbuf::Descriptor
const*
const entryDesc =
279 fieldDesc->message_type();
280 if (entryDesc ==
nullptr)
283 name = entryDesc->name();
284 if (!sFields.count(name))
289 "' expected in KnownFormat '" +
290 knownFormatName +
"' and not found",
298 entryDesc, sFields.at(entryDesc->name()));
306 for (
int i = 0; i < pbufDescriptor->field_count(); ++i)
308 pbuf::FieldDescriptor
const*
const fieldDesc =
309 pbufDescriptor->field(i);
313 checkFieldDesc(fieldDesc);
321 for (
int i = 0; i < commonFields->field_count(); ++i)
325 pbuf::FieldDescriptor
const*
const fieldDesc =
326 commonFields->field(i);
328 if (fieldDesc ==
nullptr ||
329 fieldDesc->containing_oneof() !=
nullptr ||
333 checkFieldDesc(fieldDesc);
339 if (!sFields.empty())
342 std::string(
"Protobuf Descriptor '") + pbufDescriptor->name() +
343 "' did not account for all fields in KnownFormat '" +
344 knownFormatName +
"'. Left over field: `" +
345 sFields.
begin()->first +
"'",
357 google::protobuf::Descriptor
const*
const entryDesc,
358 SField const*
const sField)
361 namespace pbuf = google::protobuf;
365 if (entryDesc->field_count() == 0 || entryDesc->oneof_decl_count() != 1)
368 std::string(
"Protobuf Descriptor '") + entryDesc->name() +
369 "' expected to have multiple OneOf fields and nothing else",
375 pbuf::FieldDescriptor
const*
const fieldDesc = entryDesc->field(0);
376 if (fieldDesc ==
nullptr)
379 std::string(
"Internal test failure. Unhandled nullptr "
380 "in FieldDescriptor for '") +
381 entryDesc->name() +
"'",
389 entryDesc->name() ==
"CurrencyAmount")
400 std::string(
"Unhandled OneOf Protobuf Descriptor '") +
401 entryDesc->name() +
"'",
408 google::protobuf::Descriptor
const*
const entryDesc,
409 SField const*
const sField)
412 namespace pbuf = google::protobuf;
414 if (entryDesc->field_count() <= 1 || entryDesc->oneof_decl_count() != 0)
417 std::string(
"Protobuf Descriptor '") + entryDesc->name() +
418 "' expected to have multiple fields and nothing else",
430 google::protobuf::FieldDescriptor::Type fieldType;
433 operator<(FieldContents
const& other)
const
435 return this->fieldName < other.fieldName;
441 return this->fieldName == other.fieldName &&
442 this->fieldType == other.fieldType;
475 specialEntries.begin(),
476 specialEntries.end(),
477 [entryDesc, sField](SpecialEntry
const& entry) {
478 return entryDesc->name() == entry.descriptorName &&
479 sField->fieldType == entry.sFieldType;
481 iter != specialEntries.end())
484 if (!BEAST_EXPECT(sField->
fieldType == iter->sFieldType))
489 entryDesc->field_count() == iter->fields.size()))
492 for (
int i = 0; i < entryDesc->field_count(); ++i)
494 pbuf::FieldDescriptor
const*
const fieldDesc =
497 FieldContents
const contents{
498 fieldDesc->name(), fieldDesc->type()};
501 iter->fields.find(contents) != iter->fields.end()))
515 if (innerFormat ==
nullptr)
518 "SOTemplate for field '" + sField->
getName() +
"' not found",
531 entryDesc,
nullptr, sField->
getName(), std::move(sFields));
537 google::protobuf::Descriptor
const*
const entryDesc,
538 SField const*
const sField)
541 namespace pbuf = google::protobuf;
545 if (entryDesc->field_count() != 1 || entryDesc->oneof_decl_count() != 0)
548 std::string(
"Protobuf Descriptor '") + entryDesc->name() +
549 "' expected to be one field and nothing else",
555 pbuf::FieldDescriptor
const*
const fieldDesc = entryDesc->field(0);
556 if (fieldDesc ==
nullptr)
559 std::string(
"Internal test failure. Unhandled nullptr "
560 "in FieldDescriptor for '") +
561 entryDesc->name() +
"'",
574 sTypeToFieldDescType{
592 if (
auto const iter = sTypeToFieldDescType.find(sField->
fieldType);
593 iter != sTypeToFieldDescType.end() &&
594 iter->second == fieldDesc->type())
602 sFieldCodeToFieldDescType{
606 if (
auto const iter = sFieldCodeToFieldDescType.find(sField->
fieldCode);
607 iter != sFieldCodeToFieldDescType.end() &&
608 iter->second == fieldDesc->type())
642 pbuf::Descriptor
const*
const entry2Desc =
643 fieldDesc->message_type();
645 if (entry2Desc ==
nullptr)
648 std::string(
"Unexpected gRPC. ") + fieldDesc->name() +
649 " MESSAGE with null Descriptor",
656 if (messageMap.at(sField->
fieldCode) != entry2Desc->name())
660 "Internal test error. Mismatch between SField '") +
661 sField->
getName() +
"' and gRPC Descriptor name '" +
662 entry2Desc->name() +
"'",
676 std::string(
"Internal test error. Unhandled FieldDescriptor '") +
677 entryDesc->name() +
"' has type `" + fieldDesc->type_name() +
686 google::protobuf::FieldDescriptor
const*
const fieldDesc,
687 SField const*
const sField)
690 namespace pbuf = google::protobuf;
692 pbuf::Descriptor
const*
const entryDesc = fieldDesc->message_type();
693 if (entryDesc ==
nullptr)
696 std::string(
"Expected Descriptor for repeated type ") +
708 if (noFurtherDetail.count(sField->
getName()))
727 if (!repeatsWhat.count(sField->
getName()))
730 std::string(
"Unexpected repeated type ") + fieldDesc->name(),
744 google::protobuf::Descriptor
const*
const entryDesc,
745 SField const*
const sField)
747 if (entryDesc->nested_type_count() != 0 ||
748 entryDesc->enum_type_count() != 0 ||
749 entryDesc->extension_range_count() != 0 ||
750 entryDesc->reserved_range_count() != 0)
753 std::string(
"Protobuf Descriptor '") + entryDesc->name() +
754 "' uses unsupported protobuf features",
761 if (entryDesc->oneof_decl_count() > 0)
764 if (entryDesc->field_count() > 1)
771 template <
typename FmtType>
774 google::protobuf::Descriptor
const*
const pbufDescriptor,
775 google::protobuf::Descriptor
const*
const commonFields,
779 namespace pbuf = google::protobuf;
783 if (knownFormatItem->
getName() != pbufDescriptor->name() &&
784 knownFormatItem->
getName() +
"Object" != pbufDescriptor->name())
787 std::string(
"Protobuf Descriptor '") + pbufDescriptor->name() +
788 "' and KnownFormat::Item '" + knownFormatItem->
getName() +
789 "' don't have the same name",
809 template <
typename FmtType>
814 google::protobuf::Descriptor
const*
const commonFields,
815 google::protobuf::OneofDescriptor
const*
const oneOfDesc)
818 namespace grpc = org::xrpl::rpc::v1;
819 namespace pbuf = google::protobuf;
821 if (!BEAST_EXPECT(oneOfDesc !=
nullptr))
828 for (
auto const& item : knownFormat)
830 if constexpr (std::is_same_v<FmtType, LedgerEntryType>)
836 notSupported.begin(),
838 item.getType()) != notSupported.end())
842 if constexpr (std::is_same_v<FmtType, TxType>)
849 notSupported.begin(),
851 item.getType()) != notSupported.end())
864 BEAST_EXPECT(formatTypes.
size() == oneOfDesc->field_count());
871 for (
auto i = 0; i < oneOfDesc->field_count(); ++i)
873 pbuf::FieldDescriptor
const*
const fieldDesc = oneOfDesc->field(i);
881 "' is not TYPE_MESSAGE",
887 auto const fmtIter = formatTypes.
find(fieldDesc->name());
889 if (fmtIter == formatTypes.
cend())
893 "' not found in " + knownFormatName,
900 validateFields<FmtType>(
901 fieldDesc->message_type(), commonFields, fmtIter->second);
905 formatTypes.
erase(fieldDesc->name());
909 for (
auto const& spare : formatTypes)
912 knownFormatName +
" '" + spare.second->getName() +
913 "' does not have a corresponding gRPC OneOf",
923 testcase(
"Ledger object validation");
925 org::xrpl::rpc::v1::LedgerObject
const ledgerObject;
930 ledgerObject.GetDescriptor(),
931 ledgerObject.GetDescriptor()->FindOneofByName(
"object"));
939 testcase(
"Transaction validation");
941 org::xrpl::rpc::v1::Transaction
const txData;
946 txData.GetDescriptor(),
947 txData.GetDescriptor()->FindOneofByName(
"transaction_data"));
const SF_Account sfRegularKey(access, STI_ACCOUNT, 8, "RegularKey")
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
const SF_U16 sfLedgerEntryType(access, STI_UINT16, 1, "LedgerEntryType", SField::sMD_Never)
const SF_U256 sfLedgerIndex(access, STI_HASH256, 6, "LedgerIndex")
const SField sfSigners(access, STI_ARRAY, 3, "Signers", SField::sMD_Default, SField::notSigning)
const SF_U32 sfOperationLimit(access, STI_UINT32, 29, "OperationLimit")
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
const SField sfMajorities(access, STI_ARRAY, 16, "Majorities")
const SF_U256 sfWalletLocator(access, STI_HASH256, 7, "WalletLocator")
const SF_Amount sfTakerPays(access, STI_AMOUNT, 4, "TakerPays")
An element in a SOTemplate.
const SField sfSigner(access, STI_OBJECT, 16, "Signer")
const SField sfDisabledValidators(access, STI_ARRAY, 17, "DisabledValidators")
const SF_U160 sfTakerGetsCurrency(access, STI_HASH160, 3, "TakerGetsCurrency")
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
const SField sfSignerEntries(access, STI_ARRAY, 4, "SignerEntries")
const SF_Amount sfHighLimit(access, STI_AMOUNT, 7, "HighLimit")
const SF_Amount sfLowLimit(access, STI_AMOUNT, 6, "LowLimit")
bool operator==(Manifest const &lhs, Manifest const &rhs)
const SField sfMajority(access, STI_OBJECT, 18, "Majority")
const SerializedTypeID fieldType
const SF_Account sfOwner(access, STI_ACCOUNT, 2, "Owner")
Defines the fields and their attributes within a STObject.
bool operator<(CanonicalTXSet::Key const &lhs, CanonicalTXSet::Key const &rhs)
const SF_Amount sfSendMax(access, STI_AMOUNT, 9, "SendMax")
const SF_U256 sfAmendment(access, STI_HASH256, 19, "Amendment")
const SF_U16 sfTransactionType(access, STI_UINT16, 2, "TransactionType")
const SF_U64 sfExchangeRate(access, STI_UINT64, 6, "ExchangeRate")
const SField sfSignerEntry(access, STI_OBJECT, 11, "SignerEntry")
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
const SF_U32 sfFirstLedgerSequence(access, STI_UINT32, 26, "FirstLedgerSequence")
const SF_Amount sfFee(access, STI_AMOUNT, 8, "Fee")
const SField sfMemo(access, STI_OBJECT, 10, "Memo")
const SF_Vec256 sfHashes(access, STI_VECTOR256, 2, "Hashes")
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
const SF_U32 sfWalletSize(access, STI_UINT32, 12, "WalletSize")
const SF_Amount sfBalance(access, STI_AMOUNT, 2, "Balance")
const SF_U160 sfTakerPaysCurrency(access, STI_HASH160, 1, "TakerPaysCurrency")
std::string const & getName() const
const SField sfPaths(access, STI_PATHSET, 1, "Paths")
const SField sfMemos(access, STI_ARRAY, 9, "Memos")
const SF_Amount sfTakerGets(access, STI_AMOUNT, 5, "TakerGets")
const SF_Account sfDestination(access, STI_ACCOUNT, 3, "Destination")
@ ltDIR_NODE
Directory node.
const SF_Vec256 sfAmendments(access, STI_VECTOR256, 3, "Amendments")
const SF_Account sfAuthorize(access, STI_ACCOUNT, 5, "Authorize")
const SF_U256 sfLedgerHash(access, STI_HASH256, 1, "LedgerHash")
const SF_U256 sfPreviousTxnID(access, STI_HASH256, 5, "PreviousTxnID", SField::sMD_DeleteFinal)
const SField sfDisabledValidator(access, STI_OBJECT, 19, "DisabledValidator")
const SF_Blob sfDomain(access, STI_VL, 7, "Domain")