Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate definitions of fields, objects, transactions, and features #5122

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from

Conversation

thejohnfreeman
Copy link
Collaborator

Leverages a preprocessor technique to put the entire definitions of fields, objects, transactions, and features into one file for each type. When you want to add a field, object, transaction, or feature, you touch just one file. When you want to inspect a definition, you look up just one file.

@donovanhide
Copy link
Contributor

This is a useful change and would make the manual process of updating third party libraries with new field types, transactions and ledger entries a little easier.
However, an even more useful change would be to abstract the definition files into easily machine parsable formats, maybe either JSON or CSV, so that any third party API libraries can choose to auto-generate their data structures and stream encoders and decoders from those files, thereby keeping up to date much more easily than using git blame to find recent changes to the large definition files.

@thejohnfreeman
Copy link
Collaborator Author

Yes, that would be great, but the preprocessor cannot parse JSON or CSV or any other format. It would require the introduction of an additional build step to generate these headers from that definition file. I would welcome that contribution from someone else, but it's out of scope for my current work. This was a drive-by change I made while working on single asset vault.

@donovanhide
Copy link
Contributor

Thanks for the reply. I do think the pool of people who could wrangle the rippled build process to add a code generation stage is probably limited to one :-) If it's not something that appeals, fair enough.

Copy link
Collaborator

@Bronek Bronek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few initial comments, also this: I wonder if this pattern is perhaps too permissive

#pragma push_macro("FOO")
#undef FOO
#pragma push_macro("BAR")
#undef BAR

#define FOO . . .;
#define BAR . . .;

#include <xrpl/protocol/. . .>

#undef FOO
#pragma pop_macro("FOO")
#undef BAR
#pragma pop_macro("BAR")

Could this be better (i.e. more robust) ?

#if defined(FOO) || defined(BAR)
#error "Macro FOO or BAR was found to be unexpectedly defined"
#endif

#define FOO . . .;
#define BAR . . . ;

#include <xrpl/protocol/. . .>

#undef FOO
#undef BAR

ltORACLE = 0x0080,
#pragma push_macro("OBJECT")
#undef OBJECT
#define OBJECT(tag, value, name, fields) tag = value,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, please follow the same style as in Feature.h (vertical spacing)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would LEDGER_ENTRY be a more specific name for the macro? OBJECT seems very general and suggests it can be used elsewhere.

include/xrpl/protocol/SField.h Show resolved Hide resolved
include/xrpl/protocol/TxFormats.h Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put it in include/xrpl/protocol/detail . Also, how about name which clearly refers to a header it is used in, e.g. Feature_list.h or even better Feature.inl ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I much prefer the simple features.h naming.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally do not mind .ipp, or even stick with .h if you insist, but then I would very much prefer if it was moved to detail subdir as not to make clutter. These files are not standalone, like all well-written header files should be, so having a different extension is a hint to the user that IDE errors are expected when viewing them

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never mind, I see they have been moved to detail, thanks !

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved them to detail/ subdirectory.

include/xrpl/protocol/objects.h Outdated Show resolved Hide resolved
src/libxrpl/protocol/TxFormats.cpp Show resolved Hide resolved
include/xrpl/protocol/features.h Outdated Show resolved Hide resolved
include/xrpl/protocol/objects.h Outdated Show resolved Hide resolved
include/xrpl/protocol/sfields.h Outdated Show resolved Hide resolved
include/xrpl/protocol/transactions.h Outdated Show resolved Hide resolved
@mvadari
Copy link
Collaborator

mvadari commented Sep 25, 2024

This is a useful change and would make the manual process of updating third party libraries with new field types, transactions and ledger entries a little easier. However, an even more useful change would be to abstract the definition files into easily machine parsable formats, maybe either JSON or CSV, so that any third party API libraries can choose to auto-generate their data structures and stream encoders and decoders from those files, thereby keeping up to date much more easily than using git blame to find recent changes to the large definition files.

@donovanhide does the server_definitions RPC solve your problem? https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_definitions

@donovanhide
Copy link
Contributor

@mvadari Thanks for pointing it out. It is interesting and I was unaware of it, but it is not the full answer. I need to know all the fields for each ledger entry and transaction type, but that seems to be missing from that response.

@thejohnfreeman thejohnfreeman requested review from bthomee and removed request for ximinez September 27, 2024 16:24
@tequdev
Copy link
Contributor

tequdev commented Oct 1, 2024

I need to know all the fields for each ledger entry and transaction type, but that seems to be missing from that response.

Note that the internal structure of fields defined with CONSTRUCT_UNTYPED_SFIELD, such as the sfMemo field, for example, cannot be known (as before).

@donovanhide
Copy link
Contributor

Just to be clear of my use case, it is updating the data structures here:

https://github.com/rubblelabs/ripple/blob/master/data/ledgerentry.go
https://github.com/rubblelabs/ripple/blob/master/data/transaction.go
https://github.com/rubblelabs/ripple/blob/master/data/format.go
https://github.com/rubblelabs/ripple/blob/master/data/flags.go

And the canonical source of truth for these data structures, encodings and flags are the source code files being changed in this PR. It would be much more efficient if my library and others could be derived from an easily machine readable file rather than a hard to diff C++ file. Seeing as this is the essence of the Ripple protocol, it doesn't seem like an unreasonable request :-)

@mvadari
Copy link
Collaborator

mvadari commented Oct 2, 2024

Just to be clear of my use case, it is updating the data structures here:

https://github.com/rubblelabs/ripple/blob/master/data/ledgerentry.go https://github.com/rubblelabs/ripple/blob/master/data/transaction.go https://github.com/rubblelabs/ripple/blob/master/data/format.go https://github.com/rubblelabs/ripple/blob/master/data/flags.go

And the canonical source of truth for these data structures, encodings and flags are the source code files being changed in this PR. It would be much more efficient if my library and others could be derived from an easily machine readable file rather than a hard to diff C++ file. Seeing as this is the essence of the Ripple protocol, it doesn't seem like an unreasonable request :-)

@donovanhide that's a fair statement, but I think it should be in an RPC rather than in the source code (perhaps added to server_definitions). Let's move this discussion to this issue I just opened on the topic.

Copy link

codecov bot commented Oct 2, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 76.2%. Comparing base (bf4a7b6) to head (cf73cd1).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##           develop   #5122     +/-   ##
=========================================
- Coverage     76.2%   76.2%   -0.0%     
=========================================
  Files          760     762      +2     
  Lines        61568   61478     -90     
  Branches      8126    8121      -5     
=========================================
- Hits         46898   46816     -82     
+ Misses       14670   14662      -8     
Files with missing lines Coverage Δ
include/xrpl/protocol/Feature.h 100.0% <ø> (ø)
include/xrpl/protocol/SField.h 100.0% <ø> (ø)
include/xrpl/protocol/detail/ledger_entries.m 100.0% <100.0%> (ø)
include/xrpl/protocol/detail/transactions.m 100.0% <100.0%> (ø)
src/libxrpl/protocol/Feature.cpp 94.6% <ø> (ø)
src/libxrpl/protocol/LedgerFormats.cpp 100.0% <ø> (ø)
src/libxrpl/protocol/SField.cpp 77.5% <ø> (ø)
src/libxrpl/protocol/TxFormats.cpp 100.0% <ø> (ø)
src/xrpld/app/tx/detail/CancelCheck.h 100.0% <ø> (ø)
src/xrpld/app/tx/detail/CancelOffer.h 100.0% <ø> (ø)
... and 14 more

... and 4 files with indirect coverage changes

Impacted file tree graph

@thejohnfreeman
Copy link
Collaborator Author

Whenever it comes time to merge this branch with the changes in #5143, regardless of whichever lands in develop first, the conflict resolutions can be cherry picked from my vault branch.

Copy link
Collaborator

@gregtatcam gregtatcam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea of changing just one file a lot but IMHO there are two inconvenient issues:

  • Because of the macros, some IDE (I have CLion) are not going to be able to resolve the references. For instance, clicking on a field name in transactions.m or ledger_entries.m doesn't navigate to the fields declaration. And searching for the field with the sf prefix is not going to be helpful either - see the next issue.

  • I'd prefer that the fields keep sf prefix. For instance, when I search for sfAmount I can see the field type and the occurrences. But try to search for Amount and you'll get huge number of hits. Of course I know where to find the field declaration but I have to navigate to this file separately.

@@ -0,0 +1,112 @@
//------------------------------------------------------------------------------
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the .m files be .h? It's confusing since .m is usually associated with Objective-C.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked to use a different extension that cannot be confused with a header, because these files are not headers in normal sense of the word (because of macros they rely on) - they cannot be included as-is, they won't parse in an IDE, they cannot be formatted with clang-format. I suggested .inl as that's typically used for "inline files" but @thejohnfreeman chose different.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's confusing IMO, but I'm fine with this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This : https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html suggests headers can be used for macros.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, headers are often used for macro definitions. Also the language attaches no meaning to file extension. However things get a little tricky for IDEs and other tools when, what appears to be a header file from extension, does not work like one. In this case the apparent header files rely on a macro definitions brought from the outside without the relevant #include inside the file, which is not normal practice of how header files work.

If that helps to get the PR approved, I am happy for @thejohnfreeman to rename these files to any extension, including .h. I guess it does not matter much.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.m feels odd but not a showstopper I guess. I'm more concerned about two other issues that I mentioned.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would everyone like .macro more than both .m and .h?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If for some reason .h is not an option then .macro is better.
But as I mentioned earlier, using macros in general prevents IDE (at least CLion) resolving the fields reference. I find this really inconvenient.

//==============================================================================

#if !defined(LEDGER_ENTRY)
#error "undefined macro: LEDGER_ENTRY"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just occurred to me that in order to make this file (and others) similar to a regular header, we could do this instead of #error :

#define LEDGER_ENTRY(...)
#pragma message("using dummy LEDGER_ENTRY")

Note the dummy macro is empty. This in turn would make the file well-behaved in IDEs and other tools, meaning it could be renamed back to .h if you so desire.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gregtatcam any comments on this ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It still doesn't solve the issue of resolving the fields reference by IDE, does it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right - it does not. An actual macro doing something could do that, maybe ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants