-
Notifications
You must be signed in to change notification settings - Fork 499
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
xdr: Add random XDR generator #3523
Conversation
997dcb2
to
66513bd
Compare
// | ||
// Note that randMarshaller is stateful because of how union types are handled. | ||
// Therefore Marshal() should not be used concurrently. | ||
func (rm *randMarshaller) Marshal(field string, i goxdr.XdrType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I feel like filepath.Walk
would be a better name and approach, than the Marshal
/XdrRecurse
combo, but that's more of a goxdr
pull request, so, c'est la vie.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bound = rm.maxBytesSize | ||
} | ||
bound++ | ||
bs := make([]byte, rm.rand.Uint32()%bound) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this OOM-kill the tests if it tries to claim 4GB of ram? Good to test though... 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, no the maxBytesSize is 256. But, should we actually test larger values? Are they possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is configured by the MaxBytesSize
field in Generator
. 256 is an arbitrary default so I'm not sure if it's the best one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we should test larger values - up to what's possible (I guess it's MAX_INT64 for xdr). Should be probably set to smaller values in envs with smaller memory (like Circle).
bound = rm.maxBytesSize | ||
} | ||
bound++ | ||
bs := make([]byte, rm.rand.Uint32()%bound) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree we should test larger values - up to what's possible (I guess it's MAX_INT64 for xdr). Should be probably set to smaller values in envs with smaller memory (like Circle).
gen.Next( | ||
shape, | ||
[]randxdr.Preset{ | ||
{randxdr.FieldEquals("type"), randxdr.SetU32(gxdr.LEDGER_ENTRY_CREATED.GetU32())}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may want to generate updated and remove changes in the future. Do you have a plan how to do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can do it in two steps. First generate a state entry containing an offer. For the update case generate an updated entry and preset the offer so it has the same id, allow the other offer fields to be random. In the remove case it would be similar except the type of the 2nd entry would be removed instead of updated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be interesting to model a state-machine around an account (e.g. create account, send a txn, updateData, etc) then generate sequences by a random walk through the state machine transitions.
{randxdr.FieldEquals("created.lastModifiedLedgerSeq"), randxdr.SetPositiveNum32()}, | ||
{randxdr.FieldEquals("created.data.offer.amount"), randxdr.SetPositiveNum64()}, | ||
{randxdr.FieldEquals("created.data.offer.price.n"), randxdr.SetPositiveNum32()}, | ||
{randxdr.FieldEquals("created.data.offer.price.d"), randxdr.SetPositiveNum32()}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is cool but we need to remove cases that would not pass Stellar-Core validation (like flags - basically reimplement doCheckValid
methods from Core here). We should probably also generate only offer changes (or at least set probability of offer change to something like 90%).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we should do more than the bare minimum of validation because it will make our ingestion implementation more robust. If we do have any assumptions implicit in the ingestion code doing this type of testing will help make those assumptions more explicit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand what you mean. I think this is basically more validation vs more false positives dillema.
shape, | ||
[]randxdr.Preset{ | ||
{randxdr.IsPtr, randxdr.SetPtrToPresent}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in offers test: we should make sure that it does not generate objects that wouldn't be accepted by Core. Ex. AbsBefore
< 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're testing if the code crashes / produces an error I don't think it's necessary to restrict the inputs more than the bare minimum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, it should generate anything which could make it through the parser, then optionally be restricted down (where needed) to just stuff that makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I think it's worth doing more in terms of validation to decrease number of false positives but maybe let's check if we get too many of them.
PR Checklist
PR Structure
otherwise).
services/friendbot
, orall
ordoc
if the changes are broad or impact manypackages.
Thoroughness
.md
files, etc... affected by this change). Take a look in the
docs
folder for a given service,like this one.
Release planning
needed with deprecations, added features, breaking changes, and DB schema changes.
semver, or if it's mainly a patch change. The PR is targeted at the next
release branch if it's not a patch change.
What
Close #3443
This commit introduces the
randxdr
package to the monorepo.randxdr
is used for generating XDR values with random data.randxdr
was built using https://github.com/xdrpp/goxdr . Check out this presentation https://drive.google.com/file/d/1NG9aTGlf3yKMfIHdxXeGMpMNMDkOfGre/view to see how goxdr is better than other xdr compilers.Why
Known limitations
Counterpoint to (1): I think goxdr has no external dependencies itself.
Counterpoint to (2): I added a script to ensure that gxdr/xdr_generated.go is always in sync with the xdr/*.x files