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

DX: Keyreg bytes #522

Merged
merged 27 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
240759e
Merge branch 'release/v1.10.0b1'
algobarb Feb 15, 2022
9d5ec1b
Merge branch 'release/v1.10.0'
onetechnical Mar 2, 2022
23354e9
Merge branch 'release/v1.11.0b1'
onetechnical Mar 18, 2022
51e0364
Merge branch 'release/v1.11.0'
algobarb Mar 23, 2022
e6f5aa9
Merge branch 'release/v1.12.0'
algojack Apr 21, 2022
896d2aa
Merge branch 'release/v1.13.0'
onetechnical May 2, 2022
de80435
Merge branch 'release/v1.13.1'
onetechnical May 4, 2022
760d892
Merge branch 'release/v1.14.0'
onetechnical Jun 2, 2022
671aeb6
Merge branch 'release/v1.15.0'
algojack Jun 16, 2022
a8508ab
Merge branch 'release/v1.16.0'
algojack Jul 25, 2022
9964004
Merge branch 'release/v1.16.1'
algobarb Aug 18, 2022
7019262
Merge branch 'release/v1.17.0'
algolucky Sep 2, 2022
f030f09
Merge branch 'release/v1.18.0'
algobarb Sep 19, 2022
671e136
Merge branch 'release/v1.19.0'
algojack Oct 12, 2022
3b231ac
Merge branch 'release/v1.20.0'
algolucky Nov 2, 2022
a411457
Merge branch 'release/v1.20.1'
algojack Nov 10, 2022
9bf39f2
Merge branch 'release/v1.20.2'
algojack Dec 5, 2022
e90337d
Merge branch 'release/v2.0.0'
excalq Jan 3, 2023
a539d60
Merge branch 'release/v2.1.0'
algobarb Mar 14, 2023
b103110
Merge branch 'release/v2.1.1'
algobarb Mar 20, 2023
bd5d041
rge branch 'release/v2.1.2'
excalq Mar 23, 2023
c7639ca
Merge branch 'release/v2.2.0'
algobarb May 8, 2023
894c699
Merge branch 'release/v2.3.0'
Algo-devops-service Jun 14, 2023
fc25cc6
Merge branch 'release/v2.4.0'
Algo-devops-service Aug 17, 2023
ef2131e
Merge branch 'release/v2.5.0'
Algo-devops-service Sep 20, 2023
84b81ca
Allow the various key-ish fields of a keyreg txn to be bytes
jannotti Dec 11, 2023
b508b30
_unbearable
jannotti Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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:
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe also add isinstance(key, str) otherwise b64decode will probably throw an exception (did not check tho)

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 suppose it will, but that's life in a dynamic language, I think. Before you could have stuffed something crazy in that field, and you'd get an exception somewhere when we tried to serialize. Now it happens earlier, which I think is better.

But I don't want to try to turn Python into Go and insert type checks all over the place.

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
Loading