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

R4R: Implement a simulate-only CLI flag/field for REST endpoints #2181

Merged
merged 5 commits into from
Aug 31, 2018

Conversation

alessio
Copy link
Contributor

@alessio alessio commented Aug 29, 2018

Add an extra simulate flag support to both CLI tx commands and RESTful endpoints to trigger the simulation of an unsigned transaction. Relevant changes:

  • Turning --dry-run causes the --gas flag to be ignored. The simulation will return the estimate of the gas required to actually run the transaction.
  • Adjustment is no longer required. It now defaults to 1.0.
  • In some test cases accounts retrieved from the state do not come with a PubKey. In such cases, a fake secp256k1 key is generated and gas consumption calculated accordingly.

Closes: #2110

  • Linked to github-issue with discussion and accepted design OR link to spec that describes this work.
  • Wrote tests
  • Updated relevant documentation (docs/)
  • Added entries in PENDING.md with issue #
  • rereviewed Files changed in the github PR explorer

For Admin Use:

  • Added appropriate labels to PR (ex. wip, ready-for-review, docs)
  • Reviewers Assigned
  • Squashed all commits, uses message "Merge pull request #XYZ: [title]" (coding standards)

@codecov
Copy link

codecov bot commented Aug 29, 2018

Codecov Report

Merging #2181 into develop will decrease coverage by 0.09%.
The diff coverage is 26.47%.

@@            Coverage Diff             @@
##           develop    #2181     +/-   ##
==========================================
- Coverage    63.58%   63.48%   -0.1%     
==========================================
  Files          137      137             
  Lines         8419     8444     +25     
==========================================
+ Hits          5353     5361      +8     
- Misses        2699     2717     +18     
+ Partials       367      366      -1

Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

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

@alessio I left some initial feedback. Thanks!

client/flags.go Outdated
@@ -58,6 +59,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().Bool(FlagJson, false, "return output in json format")
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
c.Flags().Bool(FlagDryRun, false, "no action; ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can remove no action; as the description gives a good enough...description 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I usually aim to make command line flags docs stupid-proof :)
Removing "no action" is not a big deal though 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh and btw, I took inspiration from man apt-get:

   -s, --simulate, --just-print, --dry-run, --recon, --no-act
        No action; perform a simulation of events that would occur based on the current system state but do not actually change the system. [snip]

Copy link
Contributor

Choose a reason for hiding this comment

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

#defeated

Copy link
Contributor Author

Choose a reason for hiding this comment

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

LOL sorry, amended now

client/utils/rest.go Outdated Show resolved Hide resolved
@@ -15,57 +15,35 @@ import (
// DefaultGasAdjustment is applied to gas estimates to avoid tx
// execution failures due to state changes that might
// occur between the tx simulation and the actual run.
const DefaultGasAdjustment = 1.2
const DefaultGasAdjustment = 1.0
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it useful or maybe even potentially dangerous to have this defined in two places? Seems its already part of the CLIContext?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IMHO we should remove the adjustment once and for all. The estimate is accurate and It Just Works™.
@cwgoes @jaekwon any thoughts on this?

Copy link
Contributor

Choose a reason for hiding this comment

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

It may not just work for staking transactions, where previous txs in the same block would adjust the gas required.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see. What would you suggest then?

Copy link
Contributor

Choose a reason for hiding this comment

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

Well the gas adjustment is part of the CLIContext. Why not just set it upstream (where the default can be used)? Is that not possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A sane default (i.e. != 0) is required for REST endpoints too.

Copy link
Contributor

Choose a reason for hiding this comment

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

We can really choose any number and revisit during code freeze time.

func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) {
txBytes, err := BuildAndSignTxWithZeroGas(txCtx, name, passphrase, msgs)
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
func SimulateMsgs(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg, gas int64) (int64, int64, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it'll help understanding if the return arguments are named.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, will amend

x/auth/ante.go Outdated
@@ -68,6 +68,9 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
sigs := stdTx.GetSignatures()
signerAddrs := stdTx.GetSigners()
msgs := tx.GetMsgs()
if simulate {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment explaining this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACKd

x/auth/ante.go Outdated
@@ -160,14 +159,14 @@ func processSig(

// Check account number.
accnum := acc.GetAccountNumber()
if accnum != sig.AccountNumber {
if !simulate && (accnum != sig.AccountNumber) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Im thinking in the following functions, things might be easer to comprehend if there was just a single simulate or !simulate condition and group everything in that code block.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACKd

x/auth/ante.go Show resolved Hide resolved
x/auth/ante.go Outdated
return nil, sdk.ErrInternal("setting PubKey on signer's account").Result()
}

// Check sig.
Copy link
Contributor

Choose a reason for hiding this comment

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

Redundant comment I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ACKd


// BuildWithPubKey builds a single message to be signed and
// attach the public key associated to the given name.
func (ctx TxContext) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't plan on signing this do we?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope, nonetheless I needed it to build a spec of signature-less transaction

Copy link
Contributor

Choose a reason for hiding this comment

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

Ohhh, I was referring to the godoc 👍 . It might need to be updated.

@alessio
Copy link
Contributor Author

alessio commented Aug 29, 2018

I've addressed your comments @alexanderbez, thanks!

@@ -15,57 +15,35 @@ import (
// DefaultGasAdjustment is applied to gas estimates to avoid tx
// execution failures due to state changes that might
// occur between the tx simulation and the actual run.
const DefaultGasAdjustment = 1.2
const DefaultGasAdjustment = 1.0
Copy link
Contributor

Choose a reason for hiding this comment

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

It may not just work for staking transactions, where previous txs in the same block would adjust the gas required.

client/utils/rest.go Outdated Show resolved Hide resolved
x/auth/ante.go Outdated
return nil, sdk.ErrInvalidSequence(
fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result()
}

// Check and increment sequence number.
seq := acc.GetSequence()
if seq != sig.Sequence {
if !simulate && (seq != sig.Sequence) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused, you should still have the correct sequence number when simulating a tx?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When simulating, sig would be empty - line 68, sigs := stdTx.GetSignatures(), sigs would just be a 0-length slice.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense, can you add a comment here explaining that?

@ValarDragon
Copy link
Contributor

Approach so far LGTM

@alessio
Copy link
Contributor Author

alessio commented Aug 29, 2018 via email

@alessio alessio changed the title WIP: Implement a simulate-only CLI flag/field for REST endpoints Implement a simulate-only CLI flag/field for REST endpoints Aug 29, 2018
@alessio alessio requested a review from zramsay as a code owner August 30, 2018 04:37
@alessio alessio removed the wip label Aug 30, 2018
@alexanderbez alexanderbez changed the title Implement a simulate-only CLI flag/field for REST endpoints R4R: Implement a simulate-only CLI flag/field for REST endpoints Aug 30, 2018
Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

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

Left some more feedback @alessio -- thanks!

PENDING.md Outdated Show resolved Hide resolved
client/flags.go Outdated
@@ -58,6 +59,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().Bool(FlagJson, false, "return output in json format")
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
c.Flags().Bool(FlagDryRun, false, "no action; ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
Copy link
Contributor

Choose a reason for hiding this comment

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

#defeated

client/utils/rest.go Outdated Show resolved Hide resolved
@@ -15,57 +15,35 @@ import (
// DefaultGasAdjustment is applied to gas estimates to avoid tx
// execution failures due to state changes that might
// occur between the tx simulation and the actual run.
const DefaultGasAdjustment = 1.2
const DefaultGasAdjustment = 1.0
Copy link
Contributor

Choose a reason for hiding this comment

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

Well the gas adjustment is part of the CLIContext. Why not just set it upstream (where the default can be used)? Is that not possible?

client/utils/utils.go Outdated Show resolved Hide resolved
x/auth/ante.go Show resolved Hide resolved
x/auth/ante.go Show resolved Hide resolved

// BuildWithPubKey builds a single message to be signed and
// attach the public key associated to the given name.
func (ctx TxContext) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Ohhh, I was referring to the godoc 👍 . It might need to be updated.

@alessio alessio force-pushed the alessio/2110-dry-run branch 2 times, most recently from e460e3e to afe48fc Compare August 31, 2018 07:48
x/auth/ante.go Outdated Show resolved Hide resolved
Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

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

One small remark on a comment section, but otherwise utACK 👍

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

Pretty good, just a few suggestions.

client/utils/rest.go Outdated Show resolved Hide resolved
x/auth/ante.go Outdated Show resolved Hide resolved
x/auth/ante.go Outdated Show resolved Hide resolved
Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

utACK pending merge conflict resolution

Add a simulate only flag '--dry-run' to both CLI tx commands
and RESTful endpoints to trigger the simulation of unsigned
transactions.

* Turning --dry-run on causes the --gas flag to be ignored.
  The simulation will return the estimate of the gas required
  to actually run the transaction.
* Adjustment is no longer required. It now defaults to 1.0.
* In some test cases accounts retrieved from the state do not
  come with a PubKey. In such cases, a fake secp256k1 key is
  generated and gas consumption calculated accordingly.

Closes: #2110
@alessio
Copy link
Contributor Author

alessio commented Aug 31, 2018

@cwgoes ready to go 👍

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

utACK, thanks @alessio

Let's make sure to test this out by hand prior to the 0.25 release.

@cwgoes cwgoes merged commit e1981d4 into develop Aug 31, 2018
@cwgoes cwgoes deleted the alessio/2110-dry-run branch August 31, 2018 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants