Use pending nonce over true nonce by default for txs (#224)

* [pkg] Add GetNextPendingNonce

* [cmd] Add `--true-nonce` option for staking tx and plain tx

* Update README.md

* Update README.md

* update cookbook doc

* [cmd] consolidate nonce logic into 1 fn
pull/225/head
Daniel Van Der Maden 5 years ago committed by GitHub
parent fbb058cda5
commit 4b59bb71b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 78
      README.md
  2. 15
      cmd/subcommands/staking.go
  3. 28
      cmd/subcommands/transfer.go
  4. 2
      cmd/subcommands/values.go
  5. 15
      pkg/transaction/transaction.go

@ -47,106 +47,84 @@ Note:
with the --passphrase option. Alternatively, one can pass their own passphrase via a file
using the --passphrase-file option. If no passphrase option is selected, the default
passphrase of '' is used.
3) These examples use shard 1 of Mainnet as argument for --node
3) These examples use Shard 0 of Mainnet as argument for --node
Examples:
1. Check account balance on given chain
hmy --node="https://api.s1.t.hmny.io/" balances <SOME_ONE_ADDRESS>
./hmy --node=https://api.s0.t.hmny.io balances <SOME_ONE_ADDRESS>
2. Check sent transaction
hmy --node="https://api.s1.t.hmny.io" blockchain transaction-by-hash <SOME_TX_HASH>
./hmy --node=https://api.s0.t.hmny.io blockchain transaction-by-hash <SOME_TX_HASH>
3. List local account keys
hmy keys list
./hmy keys list
4. Sending a transaction (waits 40 seconds for transaction confirmation)
hmy --node="https://api.s1.t.hmny.io/" transfer \
--from one1yc06ghr2p8xnl2380kpfayweguuhxdtupkhqzw \
--to one1q6gkzcap0uruuu8r6sldxuu47pd4ww9w9t7tg6 \
--from-shard 0 --to-shard 1 --amount 200
./hmy --node=https://api.s0.t.hmny.io transfer \
--from <SOME_ONE_ADDRESS> --to <SOME_ONE_ADDRESS> \
--from-shard 0 --to-shard 1 --amount 200 --passphrase
5. Sending a batch of transactions as dictated from a file (the `--dry-run` options still apply)
hmy --node="https://api.s1.t.hmny.io/" transfer --file <PATH_TO_JSON_FILE>
Example of JSON file format:
[
{
"from": "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7",
"to": "one1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ur",
"from-shard" : "0",
"to-shard": "0",
"amount": "1",
"passphrase-string": "",
"nonce": "1",
"stop-on-error": true
},
{
"from": "one103q7qe5t2505lypvltkqtddaef5tzfxwsse4z7",
"to": "one1zksj3evekayy90xt4psrz8h6j2v3hla4qwz4ur",
"from-shard" : "0",
"to-shard": "0",
"amount": "1",
"passphrase-file": "./pw.txt"
}
]
./hmy --node=https://api.s0.t.hmny.io transfer --file <PATH_TO_JSON_FILE>
Check README for details on json file format.
6. Check a completed transaction receipt
hmy --node="https://api.s1.t.hmny.io" blockchain transaction-receipt <SOME_TX_HASH>
./hmy --node=https://api.s0.t.hmny.io blockchain transaction-receipt <SOME_TX_HASH>
7. Import an account using the mnemonic. Prompts the user to give the mnemonic.
hmy keys recover-from-mnemonic <ACCOUNT_NAME>
./hmy keys recover-from-mnemonic <ACCOUNT_NAME>
8. Import an existing keystore file
hmy keys import-ks <PATH_TO_KEYSTORE_JSON>.key
./hmy keys import-ks <PATH_TO_KEYSTORE_JSON>
9. Import a keystore file using a secp256k1 private key
hmy keys import-private-key <secp256k1_PRIVATE_KEY>
./hmy keys import-private-key <secp256k1_PRIVATE_KEY>
10. Export a keystore file's secp256k1 private key
hmy keys export-private-key <ACCOUNT_ADDRESS> --passphrase
10. Export a keystore file's secp256k1 private key
./hmy keys export-private-key <ACCOUNT_ADDRESS> --passphrase
11. Generate a BLS key then encrypt and save the private key to the specified location.
hmy keys generate-bls-key --bls-file-path /tmp/file.key
./hmy keys generate-bls-key --bls-file-path <PATH_FOR_BLS_KEY_FILE>
12. Create a new validator with a list of BLS keys
hmy --node="https://api.s0.t.hmny.io" staking create-validator --amount 10 --validator-addr <SOME_ONE_ADDRESS> \
./hmy --node=https://api.s0.t.hmny.io staking create-validator --amount 10 --validator-addr <SOME_ONE_ADDRESS> \
--bls-pubkeys <BLS_KEY_1>,<BLS_KEY_2>,<BLS_KEY_3> \
--identity foo --details bar --name baz --max-change-rate 0.1 --max-rate 0.1 --max-total-delegation 10 \
--min-self-delegation 10 --rate 0.1 --security-contact Leo --website harmony.one --passphrase
13. Edit an existing validator
hmy --node="https://api.s0.t.hmny.io" staking edit-validator \
./hmy --node=https://api.s0.t.hmny.io staking edit-validator \
--validator-addr <SOME_ONE_ADDRESS> --identity foo --details bar \
--name baz --security-contact EK --website harmony.one \
--min-self-delegation 0 --max-total-delegation 10 --rate 0.1\
--add-bls-key <SOME_BLS_KEY> --remove-bls-key <OTHER_BLS_KEY> --passphrase
14. Delegate an amount to a validator
hmy --node="https://api.s0.t.hmny.io" staking delegate \
./hmy --node=https://api.s0.t.hmny.io staking delegate \
--delegator-addr <SOME_ONE_ADDRESS> --validator-addr <VALIDATOR_ONE_ADDRESS> \
--amount 10 --passphrase
15. Undelegate to a validator
hmy --node="https://api.s0.t.hmny.io" staking undelegate \
./hmy --node=https://api.s0.t.hmny.io staking undelegate \
--delegator-addr <SOME_ONE_ADDRESS> --validator-addr <VALIDATOR_ONE_ADDRESS> \
--amount 10 --passphrase
16. Collect block rewards as a delegator
hmy --node="https://api.s0.t.hmny.io" staking collect-rewards \
./hmy --node=https://api.s0.t.hmny.io staking collect-rewards \
--delegator-addr <SOME_ONE_ADDRESS> --passphrase
17. Check active validators
hmy --node="https://api.s0.t.hmny.io" blockchain validator all-active
17. Check elected validators
./hmy --node=https://api.s0.t.hmny.io blockchain validator elected
18. Get current staking utility metrics
hmy --node="https://api.s0.t.hmny.io" blockchain utility-metrics
./hmy --node=https://api.s0.t.hmny.io blockchain utility-metrics
19. Check in-memory record of failed staking transactions
hmy failures staking
./hmy --node=https://api.s0.t.hmny.io failures staking
20. Check which shard your BLS public key would be assigned to as a validator
hmy utility shard-for-bls 2d61379e44a772e5757e27ee2b3874254f56073e6bd226eb8b160371cc3c18b8c4977bd3dcb71fd57dc62bf0e143fd08
./hmy --node=https://api.s0.t.hmny.io utility shard-for-bls <BLS_PUBLIC_KEY>
```
# Sending batched transactions
@ -178,6 +156,7 @@ The JSON file will be a JSON array where each element has the following attribut
| `gas-price` | string | [*Optional*] The gas price to pay in NANO (1e-9 of $ONE), default is 1. |
| `gas-limit` | string | [*Optional*] The gas limit, default is 21000. |
| `stop-on-error` | boolean | [*Optional*] If true, stop sending transactions if an error occurred, default is false. |
| `true-nonce` | boolean | [*Optional*] If true, send transaction using true on-chain nonce. Cannot be used with `nonce`. If none is provided, use tx pool nonce. |
Example of JSON file:
@ -201,7 +180,8 @@ Example of JSON file:
"amount": "1",
"passphrase-file": "./pw.txt",
"gas-price": "1",
"gas-limit": "21000"
"gas-limit": "21000",
"true-nonce": true
}
]
```

@ -388,7 +388,7 @@ Create a new validator"
}
}
nonce, err := getNonceFromInput(validatorAddress.String(), inputNonce, networkHandler)
nonce, err := getNonce(validatorAddress.String(), networkHandler)
if err != nil {
return err
}
@ -410,6 +410,7 @@ Create a new validator"
},
}
subCmdNewValidator.Flags().BoolVar(&trueNonce, "true-nonce", false, "send transaction with on-chain nonce")
subCmdNewValidator.Flags().StringVar(&validatorName, "name", "", "validator's name")
subCmdNewValidator.Flags().StringVar(&validatorIdentity, "identity", "", "validator's identity")
subCmdNewValidator.Flags().StringVar(&validatorWebsite, "website", "", "validator's website")
@ -571,7 +572,7 @@ Create a new validator"
}
}
nonce, err := getNonceFromInput(validatorAddress.String(), inputNonce, networkHandler)
nonce, err := getNonce(validatorAddress.String(), networkHandler)
if err != nil {
return err
}
@ -593,6 +594,7 @@ Create a new validator"
},
}
subCmdEditValidator.Flags().BoolVar(&trueNonce, "true-nonce", false, "send transaction with on-chain nonce")
subCmdEditValidator.Flags().StringVar(&validatorName, "name", "", "validator's name")
subCmdEditValidator.Flags().StringVar(&validatorIdentity, "identity", "", "validator's identity")
subCmdEditValidator.Flags().StringVar(&validatorWebsite, "website", "", "validator's website")
@ -646,7 +648,7 @@ Delegating to a validator
}
}
nonce, err := getNonceFromInput(delegatorAddress.String(), inputNonce, networkHandler)
nonce, err := getNonce(delegatorAddress.String(), networkHandler)
if err != nil {
return err
}
@ -668,6 +670,7 @@ Delegating to a validator
},
}
subCmdDelegate.Flags().BoolVar(&trueNonce, "true-nonce", false, "send transaction with on-chain nonce")
subCmdDelegate.Flags().Var(&delegatorAddress, "delegator-addr", "delegator's address")
subCmdDelegate.Flags().Var(&validatorAddress, "validator-addr", "validator's address")
subCmdDelegate.Flags().StringVar(&stakingAmount, "amount", "0", "staking amount")
@ -712,7 +715,7 @@ Delegating to a validator
}
}
nonce, err := getNonceFromInput(delegatorAddress.String(), inputNonce, networkHandler)
nonce, err := getNonce(delegatorAddress.String(), networkHandler)
if err != nil {
return err
}
@ -734,6 +737,7 @@ Delegating to a validator
},
}
subCmdUnDelegate.Flags().BoolVar(&trueNonce, "true-nonce", false, "send transaction with on-chain nonce")
subCmdUnDelegate.Flags().Var(&delegatorAddress, "delegator-addr", "delegator's address")
subCmdUnDelegate.Flags().Var(&validatorAddress, "validator-addr", "source validator's address")
subCmdUnDelegate.Flags().StringVar(&stakingAmount, "amount", "0", "staking amount")
@ -768,7 +772,7 @@ Collect token rewards
}
}
nonce, err := getNonceFromInput(delegatorAddress.String(), inputNonce, networkHandler)
nonce, err := getNonce(delegatorAddress.String(), networkHandler)
if err != nil {
return err
}
@ -790,6 +794,7 @@ Collect token rewards
},
}
subCmdCollectRewards.Flags().BoolVar(&trueNonce, "true-nonce", false, "send transaction with on-chain nonce")
subCmdCollectRewards.Flags().Var(&delegatorAddress, "delegator-addr", "delegator's address")
subCmdCollectRewards.Flags().StringVar(&gasPrice, "gas-price", "1", "gas price to pay")
subCmdCollectRewards.Flags().StringVar(&gasLimit, "gas-limit", "", "gas limit")

@ -33,6 +33,7 @@ var (
targetChain string
chainName chainIDWrapper
dryRun bool
trueNonce bool
inputNonce string
gasPrice string
gasLimit string
@ -62,6 +63,7 @@ type transferFlags struct {
GasPrice *string `json:"gas-price"`
GasLimit *string `json:"gas-limit"`
StopOnError bool `json:"stop-on-error"`
TrueNonce bool `json:"true-nonce"`
}
func handlerForShard(senderShard uint32, node string) (*rpc.HTTPMessenger, error) {
@ -122,13 +124,13 @@ func handlerForTransaction(txLog *transactionLog) error {
ctrlr = transaction.NewController(networkHandler, ks, acct, *chainName.chainID, opts)
}
nonce, err := getNonceFromInput(fromAddress.String(), inputNonce, networkHandler)
if handlerForError(txLog, err) != nil {
nonce, err := getNonce(fromAddress.String(), networkHandler)
if err != nil {
return err
}
amt, err := common.NewDecFromString(amount)
if err != nil {
if err != nil {
amtErr := fmt.Errorf("amount %w", err)
handlerForError(txLog, amtErr)
return amtErr
@ -251,6 +253,7 @@ func handlerForBulkTransactions(txLog *transactionLog, index int) error {
} else {
gasLimit = "" // Reset to default for subsequent transactions
}
trueNonce = txnFlags.TrueNonce
return handlerForTransaction(txLog)
}
@ -267,6 +270,14 @@ func opts(ctlr *transaction.Controller) {
}
}
func getNonce(address string, messenger rpc.T) (uint64, error) {
if trueNonce {
// cannot define nonce when using true nonce
return transaction.GetNextNonce(address, messenger), nil
}
return getNonceFromInput(address, inputNonce, messenger)
}
func getNonceFromInput(addr, inputNonce string, messenger rpc.T) (uint64, error) {
if inputNonce != "" {
if strings.HasPrefix(inputNonce, "-") {
@ -279,7 +290,7 @@ func getNonceFromInput(addr, inputNonce string, messenger rpc.T) (uint64, error)
return nonce, nil
}
} else {
return transaction.GetNextNonce(addr, messenger), nil
return transaction.GetNextPendingNonce(addr, messenger), nil
}
}
@ -318,6 +329,9 @@ Create a transaction, sign it, and send off to the Harmony blockchain
for _, flagName := range [...]string{"from", "to", "amount", "from-shard", "to-shard"} {
_ = cmd.MarkFlagRequired(flagName)
}
if trueNonce && inputNonce != "" {
return fmt.Errorf("cannot specify nonce when using true on-chain nonce")
}
} else {
data, err := ioutil.ReadFile(givenFilePath)
if err != nil {
@ -327,6 +341,11 @@ Create a transaction, sign it, and send off to the Harmony blockchain
if err != nil {
return err
}
for i, batchTx := range transferFileFlags {
if batchTx.TrueNonce && batchTx.InputNonce != nil {
return fmt.Errorf("cannot specify nonce when using true on-chain nonce for transaction number %v in batch", i+1)
}
}
}
return nil
},
@ -369,6 +388,7 @@ Create a transaction, sign it, and send off to the Harmony blockchain
cmdTransfer.Flags().Var(&fromAddress, "from", "sender's one address, keystore must exist locally")
cmdTransfer.Flags().Var(&toAddress, "to", "the destination one address")
cmdTransfer.Flags().BoolVar(&dryRun, "dry-run", false, "do not send signed transaction")
cmdTransfer.Flags().BoolVar(&trueNonce, "true-nonce", false, "send transaction with on-chain nonce")
cmdTransfer.Flags().StringVar(&amount, "amount", "0", "amount to send (ONE)")
cmdTransfer.Flags().StringVar(&gasPrice, "gas-price", "1", "gas price to pay (NANO)")
cmdTransfer.Flags().StringVar(&gasLimit, "gas-limit", "", "gas limit")

@ -101,7 +101,7 @@ Check README for details on json file format.
./hmy --node=[NODE] failures staking
%s
./hmy --node=[NODE] utility shard-for-bls 2d61379e44a772e5757e27ee2b3874254f56073e6bd226eb8b160371cc3c18b8c4977bd3dcb71fd57dc62bf0e143fd08
./hmy --node=[NODE] utility shard-for-bls <BLS_PUBLIC_KEY>
`,
g("1. Check account balance on given chain"),

@ -20,6 +20,7 @@ func NewTransaction(
return types.NewCrossShardTransaction(nonce, &to, shardID, toShardID, amount.TruncateInt(), gasLimit, gasPrice.TruncateInt(), data[:])
}
// GetNextNonce returns the nonce on-chain (finalized transactions)
func GetNextNonce(addr string, messenger rpc.T) uint64 {
transactionCountRPCReply, err :=
messenger.SendRPC(rpc.Method.GetTransactionCount, []interface{}{address.Parse(addr), "latest"})
@ -33,6 +34,20 @@ func GetNextNonce(addr string, messenger rpc.T) uint64 {
return n.Uint64()
}
// GetNextPendingNonce returns the nonce from the tx-pool (un-finalized transactions)
func GetNextPendingNonce(addr string, messenger rpc.T) uint64 {
transactionCountRPCReply, err :=
messenger.SendRPC(rpc.Method.GetTransactionCount, []interface{}{address.Parse(addr), "pending"})
if err != nil {
return 0
}
transactionCount, _ := transactionCountRPCReply["result"].(string)
n, _ := big.NewInt(0).SetString(transactionCount[2:], 16)
return n.Uint64()
}
func IsValid(tx *Transaction) bool {
return true
}

Loading…
Cancel
Save