Skip to content

Commit

Permalink
DX: Keyreg bytes (#522)
Browse files Browse the repository at this point in the history
* Allow the various key-ish fields of a keyreg txn to be bytes

Previously, these fields were required to be base64 encoded, which
seems like a strange requirement.  Now they may be bytes or b64
strings. Either way, they are stored in the python object as b64
strings to maintain compatibility with our original decision,
regardless of how strange it was.

Added a few doc string cleanups.
  • Loading branch information
jannotti committed Dec 11, 2023
1 parent dca4bbd commit 3e64019
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 54 deletions.
88 changes: 34 additions & 54 deletions algosdk/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,8 +419,8 @@ class KeyregTxn(Transaction):
Args:
sender (str): address of sender
sp (SuggestedParams): suggested params from algod
votekey (str): participation public key in base64
selkey (str): VRF public key in base64
votekey (str|bytes): participation public key bytes, optionally encoded in base64
selkey (str|bytes): VRF public key bytes, optionally encoded in base64
votefst (int): first round to vote
votelst (int): last round to vote
votekd (int): vote key dilution
Expand All @@ -430,7 +430,7 @@ class KeyregTxn(Transaction):
transaction's valid rounds
rekey_to (str, optional): additionally rekey the sender to this address
nonpart (bool, optional): mark the account non-participating if true
StateProofPK: state proof
sprfkey (str|bytes, optional): state proof ID bytes, optionally encoded in base64
Attributes:
sender (str)
Expand All @@ -440,7 +440,7 @@ class KeyregTxn(Transaction):
note (bytes)
genesis_id (str)
genesis_hash (str)
group(bytes)
group (bytes)
votepk (str)
selkey (str)
votefst (int)
Expand Down Expand Up @@ -471,13 +471,13 @@ def __init__(
Transaction.__init__(
self, sender, sp, note, lease, constants.keyreg_txn, rekey_to
)
self.votepk = votekey
self.selkey = selkey
self.votepk = self._fixed_bytes64(votekey, 32)
self.selkey = self._fixed_bytes64(selkey, 32)
self.votefst = votefst
self.votelst = votelst
self.votekd = votekd
self.nonpart = nonpart
self.sprfkey = sprfkey
self.sprfkey = self._fixed_bytes64(sprfkey, 64)

if not sp.flat_fee:
self.fee = max(
Expand Down Expand Up @@ -520,6 +520,18 @@ def __eq__(self, other):
and self.sprfkey == other.sprfkey
)

@staticmethod
def _fixed_bytes64(key, size):
if key is None:
return None
if isinstance(key, (bytes, bytearray)) and len(key) == size:
return base64.b64encode(key)
if len(base64.b64decode(key)) == size:
return key
assert False, "{} is not {} bytes or b64 decodable as such".format(
key, size
)


class KeyregOnlineTxn(KeyregTxn):
"""
Expand All @@ -529,8 +541,8 @@ class KeyregOnlineTxn(KeyregTxn):
Args:
sender (str): address of sender
sp (SuggestedParams): suggested params from algod
votekey (str): participation public key in base64
selkey (str): VRF public key in base64
votekey (str|bytes): participation public key bytes, optionally encoded in base64
selkey (str|bytes): VRF public key bytes, optionally encoded in base64
votefst (int): first round to vote
votelst (int): last round to vote
votekd (int): vote key dilution
Expand All @@ -539,7 +551,7 @@ class KeyregOnlineTxn(KeyregTxn):
with the same sender and lease can be confirmed in this
transaction's valid rounds
rekey_to (str, optional): additionally rekey the sender to this address
sprfkey (str, optional): state proof ID
sprfkey (str|bytes, optional): state proof ID bytes, optionally encoded in base64
Attributes:
sender (str)
Expand All @@ -549,7 +561,7 @@ class KeyregOnlineTxn(KeyregTxn):
note (bytes)
genesis_id (str)
genesis_hash (str)
group(bytes)
group (bytes)
votepk (str)
selkey (str)
votefst (int)
Expand Down Expand Up @@ -590,12 +602,6 @@ def __init__(
nonpart=False,
sprfkey=sprfkey,
)
self.votepk = votekey
self.selkey = selkey
self.votefst = votefst
self.votelst = votelst
self.votekd = votekd
self.sprfkey = sprfkey
if votekey is None:
raise error.KeyregOnlineTxnInitError("votekey")
if selkey is None:
Expand All @@ -606,37 +612,19 @@ def __init__(
raise error.KeyregOnlineTxnInitError("votelst")
if votekd is None:
raise error.KeyregOnlineTxnInitError("votekd")
if not sp.flat_fee:
self.fee = max(
self.estimate_size() * self.fee, constants.min_txn_fee
)

@staticmethod
def _undictify(d):
votekey = base64.b64encode(d["votekey"]).decode()
selkey = base64.b64encode(d["selkey"]).decode()
votefst = d["votefst"]
votelst = d["votelst"]
votekd = d["votekd"]
args = {
"votekey": base64.b64encode(d["votekey"]).decode(),
"selkey": base64.b64encode(d["selkey"]).decode(),
"votefst": d["votefst"],
"votelst": d["votelst"],
"votekd": d["votekd"],
}

if "sprfkey" in d:
sprfID = base64.b64encode(d["sprfkey"]).decode()

args = {
"votekey": votekey,
"selkey": selkey,
"votefst": votefst,
"votelst": votelst,
"votekd": votekd,
"sprfkey": sprfID,
}
else:
args = {
"votekey": votekey,
"selkey": selkey,
"votefst": votefst,
"votelst": votelst,
"votekd": votekd,
}
args["sprfkey"] = base64.b64encode(d["sprfkey"]).decode()

return args

Expand Down Expand Up @@ -668,7 +656,7 @@ class KeyregOfflineTxn(KeyregTxn):
note (bytes)
genesis_id (str)
genesis_hash (str)
group(bytes)
group (bytes)
type (str)
lease (byte[32])
rekey_to (str)
Expand All @@ -690,10 +678,6 @@ def __init__(self, sender, sp, note=None, lease=None, rekey_to=None):
nonpart=False,
sprfkey=None,
)
if not sp.flat_fee:
self.fee = max(
self.estimate_size() * self.fee, constants.min_txn_fee
)

@staticmethod
def _undictify(d):
Expand Down Expand Up @@ -728,7 +712,7 @@ class KeyregNonparticipatingTxn(KeyregTxn):
note (bytes)
genesis_id (str)
genesis_hash (str)
group(bytes)
group (bytes)
type (str)
lease (byte[32])
rekey_to (str)
Expand All @@ -750,10 +734,6 @@ def __init__(self, sender, sp, note=None, lease=None, rekey_to=None):
nonpart=True,
sprfkey=None,
)
if not sp.flat_fee:
self.fee = max(
self.estimate_size() * self.fee, constants.min_txn_fee
)

@staticmethod
def _undictify(d):
Expand Down
16 changes: 16 additions & 0 deletions tests/unit_tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,22 @@ def test_serialize_keyreg_online(self):
print(encoding.msgpack_encode(signed_txn))
self.assertEqual(golden, encoding.msgpack_encode(signed_txn))

# Test that raw bytes are also acceptable inputs for keys

txn = transaction.KeyregTxn(
pk,
sp,
base64.b64decode(votepk),
base64.b64decode(selpk),
votefirst,
votelast,
votedilution,
sprfkey=base64.b64decode(sprfKey),
)
signed_txn = txn.sign(sk)
print(encoding.msgpack_encode(signed_txn))
self.assertEqual(golden, encoding.msgpack_encode(signed_txn))

def test_serialize_keyreg_offline(self):
mn = (
"awful drop leaf tennis indoor begin mandate discover uncle seven "
Expand Down

0 comments on commit 3e64019

Please sign in to comment.