-
Notifications
You must be signed in to change notification settings - Fork 344
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
feat: tx simulator #1613
feat: tx simulator #1613
Conversation
Looks like there's some data race occurring but I'm not sure if it's actually triggered from the new code I wrote |
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.
mostly non blocking comments and questions
ideally we can use the testing framework here to replace the integration test (and the smoke test)
I think it would also help to simply clarify the different testing directories, such as testutil, testing, and the test directory in app
.
testing/txsim/client.go
Outdated
pollTime time.Duration | ||
|
||
mtx sync.Mutex | ||
sequence int |
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.
can we somehow clarify what type of sequence this is referring to? is this a testing sequence? a cosmos-sdk sequence (nonce)? a local count of successfully submitted txs?
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.
Yup, sorry for the misunderstanding. This is simply used to multiplex queries across multiple RPC clients (via round robin)
testing/txsim/client.go
Outdated
func (tc *TxClient) next() { | ||
tc.sequence = (tc.sequence + 1) % len(tc.rpcClients) | ||
} |
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.
please add a comment describing the purpose of this logic. also, in other places we use the mutex before mutating local txclient state (such as the height), do we need to do that here? if not, can we include that in the comment?
testing/txsim/send.go
Outdated
sendAmount int | ||
maxHeightDelay int | ||
accounts []types.AccAddress | ||
sequence int |
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.
similar to above, we're using the word sequence for multiple things, which is fine but preferably we document what we mean here
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.
or rename variable to disambiguate. One candidate rename for the Sequence
interface is OperatorGenerator
testing/txsim/client.go
Outdated
func (qc *QueryClient) next() { | ||
qc.sequence = (qc.sequence + 1) % len(qc.connections) | ||
} |
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.
should we document with these that they are relying on the callers to handle mutexes since these are mutating state?
testing/txsim/account.go
Outdated
// increment the sequence number for all the signers | ||
for _, signer := range signers { | ||
am.accounts[signer.String()].Sequence++ | ||
} |
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.
does this action need to be protected by a mutex?
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.
Yeah perhaps. The same accounts should never be used by any two concurrent processes but because there could be concurrent writes to the map, this may panic
testing/txsim/account.go
Outdated
|
||
builder.SetFeeAmount(types.NewCoins(types.NewInt64Coin(app.BondDenom, feeAmount))) | ||
// the master account is responsible for paying the fees | ||
builder.SetFeeGranter(am.masterAccount.Address) |
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.
is there a benefit to using fee granter for every tx instead of funding the accounts in some other mechansim (either by including them in the genesis via the existing tooling in testnode or just sending them funds)?
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.
Ideally, I would like the developer implementing a sequence to not have to worry about fees (they simply state the transactions they want to execute) thus I felt using feegrant to be the best solution. Do you have a problem with feegrant?
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.
that makes sense, but what is the difference if their account is adequately funded? They still don't have to worry about gas limit or the specifying a fee, since we're doing that here.
I highly highly doubt it, but there might be some weird scenario where all of our tests use feegrant, so we missed some bug that would otherwise occur in a normal scenario.
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's a valid point. Perhaps it does make the most sense if we leak that complexity to the sequence developers so that they have to over fund their accounts and manage the gas limits (we can hardcode the gas price to the minimum)
Codecov Report
@@ Coverage Diff @@
## main #1613 +/- ##
==========================================
+ Coverage 49.05% 50.89% +1.84%
==========================================
Files 85 92 +7
Lines 4964 5739 +775
==========================================
+ Hits 2435 2921 +486
- Misses 2290 2518 +228
- Partials 239 300 +61
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
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! 👍 👍 can't wait to write some sequences!
testing/txsim/account.go
Outdated
// set default gas limit to cover the costs of most transactions | ||
// At 0.001 utia per gas, this equates to 1000utia per transaction | ||
// In the future we may want to give some access to the sequence itself | ||
gasLimit = 1000000 |
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 might want to increase this so that we can test blobs larger than ~240 shares, so +1 that having the sequence control this later would be a good idea, or increasing it to about 8 million should be sufficient for the near term
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.
Overall LGTM, really cool testing tool
type Range struct { | ||
Min int | ||
Max int | ||
} |
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.
👍
// generate a random namespace for the blob | ||
namespace := make([]byte, ns.NamespaceVersionZeroIDSize) | ||
_, err := rand.Read(namespace) | ||
if err != nil { | ||
return Operation{}, fmt.Errorf("generating random namespace: %w", err) | ||
} | ||
namespaces[i] = ns.MustNewV0(namespace) |
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.
[optional] can use
celestia-app/pkg/namespace/random_blob.go
Line 11 in dd19531
func RandomBlobNamespace() Namespace { |
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.
Thanks but I want to use the random source provided in the method so that by having a specific seed it should always reproduce the same sequence
@@ -177,7 +177,7 @@ func (c *Context) FillBlock(squareSize int, accounts []string, broadcastMode str | |||
// in order to get the square size that we want, we need to fill half the | |||
// square minus a few for the tx (see the square estimation logic in | |||
// app/estimate_square_size.go) | |||
shareCount := (squareSize * squareSize / 2) - 1 | |||
shareCount := (squareSize * squareSize / 2) - 2 |
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.
[out of curiosity] why did the size of one transaction occupy change from 1 to 2 shares? Did this PR fix a bug?
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.
Did this PR fix a bug?
Yes it added math.Ceil to this line because our uint64 conversion was rounding down the number meaning occasionally we estimated too small of a square:
celestia-app/app/estimate_square_size.go
Line 37 in 11374a6
minSize := uint64(math.Ceil(math.Sqrt(float64(totalSharesUsed)))) |
I was thinking of extracting it out into a separate PR but we're about to overwrite this method entirely with ADR020
Ref: #1256, #1535
This PR introduces a new package
txsim
for contolled fuzz testing at a transaction level. It's purpose is to simulate a wide range of possible user interactions while also being able to apply a considerable load to the network.How it works
The package is designed in a way to make it easy to compose new fuzzing scenarios, removing the complexity around account nonces and balances, signing, encoding and broadcasting. The basic element is a
Sequence
. This is an interface that represents a pattern of recursive messages (one could be I send 5 dollars to you and you send 5 dollars back and so forth). Each sequence is provisioned a set of accounts that are responsible for formulating the messages. The accounts are isolated, allowing for a single sequence to be replicated hundreds of times. Sequences are also provided access to the current state as well as a deterministic source of randomness for constructing their output messages.There are three current sequences:
Remaining work: