js-algorand-sdk icon indicating copy to clipboard operation
js-algorand-sdk copied to clipboard

keyreg transactions with `voteFirst: 0` fail to send

Open neilcampbell opened this issue 10 months ago • 5 comments

Subject of the issue

An online key registration transaction with voteFirst: 0 fails to send to the network.

Your environment

  • JS SDK version: 3.1.0
  • Software version: 4.0.1.stable

Steps to reproduce

  1. Create a key registration transaction with voteFirst: 0. The transaction is created without any issues.
const suggestedParams = await algod.getTransactionParams().do()
const sender = localnet.context.testAccount
const txn = new algosdk.Transaction({
  type: algosdk.TransactionType.keyreg,
  sender: sender.addr,
  keyregParams: {
    voteKey: algosdk.base64ToBytes('5/D4TQaBHfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKE='),
    selectionKey: algosdk.base64ToBytes('oImqaSLjuZj63/bNSAjd+eAh5JROOJ6j1cY4eGaJGX4='),
    stateProofKey: algosdk.base64ToBytes('mgh7ddGf7dF1Z5/9RDzN/JZZF9yA7XYCKJXvqhwPdvI7pLKh7hizaM5rTC2kizVOpVRIU9PXSLeapvBJ/OxQYA=='),
    voteFirst: 0,
    voteLast: 61,
    voteKeyDilution: 1234,
  },
  suggestedParams,
})
const signedTxn = algosdk.signTransaction(txn, sender.sk)
  1. Send the transaction
const res = await algod.sendRawTransaction(signedTxn.blob).do()

Expected behaviour

The transaction is successfully sent.

Actual behaviour

An exception with message "Online key registration missing at least one of the following fields: voteKey, selectionKey, voteFirst, voteLast, voteKeyDilution" is thrown when sending

Additionally, the same error is thrown when fetching a block containing a keyreg transaction sent (via another mechanism) with voteFirst: 0. For example:

// round 66 contains a keyreg sent with `voteFirst: 0`
const res = await algod.block(66).do()

neilcampbell avatar Jan 31 '25 14:01 neilcampbell

voteFirst == 0 doesn't really make sense, since it's supposed to be a round in which the given key can vote. But 0 is not an actual round. (Even if you call the genesis round 0, there's no voting there.)

However, the protocol does not require voteFirst to not be 0, so at the very least, I agree the sdk should decode such transactions. Do we really want to stop erroring on trying to send them though? It seems like this is likely to catch more problems than it causes, since 0 is never needed to send.

jannotti avatar Jan 31 '25 19:01 jannotti

@nullun What's the scenario you had for sending a voteFirst: 0?

neilcampbell avatar Feb 02 '25 13:02 neilcampbell

I encounted this specifically when working with a local network, running tests, and trying to view the results on Lora.

I started a fresh network and immediately generated a partkey for a genesis funded account using goal. My test (and network) would last less than 1000 rounds, so the partkey had a --roundFirstValid of 0, with a --roundLastValid of 1000, and I submitted keyreg for it.

I'm aware I could set the roundFirstValid to 1, but 0 is still a valid transaction and as a result Lora fails to parse the transaction or process blocks which come after it. I don't think you could submit such a transaction on Mainnet or Testnet now, but things like Fnet and other local environments with lower round numbers would still potentially hiccup on this.

nullun avatar Mar 03 '25 11:03 nullun

So we want Lora (through the sdk) to be able to read such a transaction, but I'm not hearing enthusiasm for sending such transactions. (Of course, I'd argue for simplicity, so if it's easier to support both because it's a single code path, I'd be ok with that.)

jannotti avatar Mar 03 '25 12:03 jannotti

That sounds reasonable. I agree it probably shouldn't be encouraged to create a transaction with the first valid round set to 0, but in the event a transaction like that appears, the SDK should be able to handle it.

nullun avatar Mar 03 '25 12:03 nullun