Skip to content

Commit

Permalink
Merge pull request #40 from zksync-sdk/zsdk_73_port_closes_greater_or…
Browse files Browse the repository at this point in the history
…_eq_packable_methods

added implementation for closest_greater_or_eq_packable_amount & closest_greater_or_eq_packable_fee methods based on JS SDK implementation
  • Loading branch information
StanislavBreadless authored Nov 3, 2021
2 parents 6929b7d + fe751d0 commit f2c28e1
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 3 deletions.
52 changes: 52 additions & 0 deletions tests/test_numeric_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from unittest import TestCase

from zksync_sdk.serializers import \
num_to_bits, bits_into_bytes_in_be_order, reverse_bits, \
closest_greater_or_eq_packable_amount, closest_greater_or_eq_packable_fee, closest_packable_transaction_fee


class TestNumberToBinaryArray(TestCase):

def test_simple_conversion(self):
bin_representation = num_to_bits(8, 4)
self.assertListEqual(bin_representation, [0, 0, 0, 1])

bin_representation = num_to_bits(32 + 5, 6)
self.assertListEqual(bin_representation, [1, 0, 1, 0, 0, 1])

def test_binary_list_to_bytes(self):
# INFO: 32
byte_array = bits_into_bytes_in_be_order([0, 0, 0, 1, 0, 0, 0, 0])
self.assertEqual(byte_array[0], 0x10)

values = [0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0
]
byte_array = bits_into_bytes_in_be_order(values)
self.assertEqual(len(byte_array), 5)
self.assertEqual(byte_array[0], 8)
self.assertEqual(byte_array[1], 16)
self.assertEqual(byte_array[2], 32)
self.assertEqual(byte_array[3], 64)
self.assertEqual(byte_array[4], 128)

def test_revers_bits(self):
reverted = reverse_bits([1, 0, 0, 0, 1, 1, 0, 0])
self.assertListEqual(reverted, [0, 0, 1, 1, 0, 0, 0, 1])

def test_closest_greater_or_packable_all(self):
nums = [0, 1, 2, 2047000, 1000000000000000000000000000000000]
for num in nums:
ret = closest_greater_or_eq_packable_amount(num)
self.assertEqual(ret, num)
ret = closest_greater_or_eq_packable_fee(num)
self.assertEqual(ret, num)

def test_closest_greater_or_packable_fee(self):
ret = closest_greater_or_eq_packable_fee(2048)
self.assertEqual(ret, 2050)
ret = closest_packable_transaction_fee(2048)
self.assertEqual(ret, 2047)
52 changes: 49 additions & 3 deletions zksync_sdk/serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import List
from math import ceil

AMOUNT_EXPONENT_BIT_WIDTH = 5
AMOUNT_MANTISSA_BIT_WIDTH = 35
Expand Down Expand Up @@ -33,6 +34,9 @@ def int_to_bytes(val: int, length=4):


def num_to_bits(integer: int, bits: int):
"""
INFO: Can't be used without correct input data of value & corresponded amount of bits, take care
"""
results = []
for i in range(bits):
results.append(integer & 1)
Expand Down Expand Up @@ -62,15 +66,35 @@ def integer_to_float(integer: int, exp_bits: int, mantissa_bits: int, exp_base:
mantissa = max_mantissa
exponent -= 1

data = []
data.extend(num_to_bits(exponent, exp_bits))
data.extend(num_to_bits(mantissa, mantissa_bits))
data = num_to_bits(exponent, exp_bits) + num_to_bits(mantissa, mantissa_bits)
data = list(reversed(data))
result = list(reversed(bits_into_bytes_in_be_order(data)))

return result


def integer_to_float_up(integer: int, exp_bits: int, mantissa_bits: int, exp_base) -> List[int]:
max_exponent_power = 2 ** exp_bits - 1
max_exponent = exp_base ** max_exponent_power
max_mantissa = 2 ** mantissa_bits - 1

if integer > max_mantissa * max_exponent:
raise WrongIntegerError("Integer is too big")

exponent = 0
exponent_temp = 1
while integer > max_mantissa * exponent_temp:
exponent_temp = exponent_temp * exp_base
exponent += 1

mantissa = int(ceil(integer / exponent_temp))
encoding = num_to_bits(exponent, exp_bits) + num_to_bits(mantissa, mantissa_bits)
data = list(reversed(encoding))
result = list(reversed(bits_into_bytes_in_be_order(data)))

return result


def bits_into_bytes_in_be_order(bits: List[int]):
if len(bits) % 8 != 0:
raise WrongBitsError("wrong number of bits")
Expand Down Expand Up @@ -135,6 +159,18 @@ def float_to_integer(float_bytes: bytes, exp_bits, mantissa_bits, exp_base_numbe
return exponent * mantissa


def pack_amount_up(amount: int):
return bytes(reverse_bits(
integer_to_float_up(amount, AMOUNT_EXPONENT_BIT_WIDTH, AMOUNT_MANTISSA_BIT_WIDTH, 10)
))


def pack_fee_up(fee: int):
return bytes(reverse_bits(
integer_to_float_up(fee, FEE_EXPONENT_BIT_WIDTH, FEE_MANTISSA_BIT_WIDTH, 10)
))


def closest_packable_amount(amount: int) -> int:
packed_amount = pack_amount(amount)
return float_to_integer(
Expand All @@ -145,6 +181,11 @@ def closest_packable_amount(amount: int) -> int:
)


def closest_greater_or_eq_packable_amount(amount: int) -> int:
packed_amount = pack_amount_up(amount)
return float_to_integer(packed_amount, AMOUNT_EXPONENT_BIT_WIDTH, AMOUNT_MANTISSA_BIT_WIDTH, 10)


def closest_packable_transaction_fee(fee: int) -> int:
packed_fee = pack_fee(fee)
return float_to_integer(
Expand All @@ -155,6 +196,11 @@ def closest_packable_transaction_fee(fee: int) -> int:
)


def closest_greater_or_eq_packable_fee(fee: int) -> int:
packed_fee = pack_fee_up(fee)
return float_to_integer(packed_fee, FEE_EXPONENT_BIT_WIDTH, FEE_MANTISSA_BIT_WIDTH, 10)


def packed_fee_checked(fee: int):
if closest_packable_transaction_fee(fee) != fee:
raise ValueNotPackedError
Expand Down

0 comments on commit f2c28e1

Please sign in to comment.