Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
overcat committed Aug 24, 2023
1 parent 32098bf commit 81bc96f
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 10 deletions.
55 changes: 45 additions & 10 deletions stellar_sdk/scval.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
from typing import Union, List
from typing import Union, List, Dict

from . import xdr as stellar_xdr
from .address import Address
from collections import OrderedDict


__all__ = [
"to_address",
"from_address",
"to_bool",
"from_bool",
"to_bytes",
"from_bytes",
"to_duration",
"from_duration",
"to_int32",
"from_int32",
"to_int64",
"from_int64",
"to_int128",
"from_int128",
"to_int256",
"from_int256",
"to_map",
"from_map",
"to_string",
"from_string",
"to_symbol",
"from_symbol",
"to_timepoint",
"from_timepoint",
"to_uint32",
"from_uint32",
"to_uint64",
"from_uint64",
"to_uint128",
"from_uint128",
"to_uint256",
"from_uint256",
"to_vec",
"from_vec"
]

def to_address(value: Union[Address, str]) -> stellar_xdr.SCVal:
"""Creates a new :class:`stellar_sdk.xdr.SCVal` XDR object from an :class:`stellar_sdk.address.Address` object.
Expand Down Expand Up @@ -95,8 +131,7 @@ def from_duration(sc_val: stellar_xdr.SCVal) -> int:
"""
if sc_val.type != stellar_xdr.SCValType.SCV_DURATION:
raise ValueError(f"Invalid sc_val type, must be SCV_DURATION, got {sc_val.type}")
assert sc_val.timepoint is not None
return sc_val.timepoint.time_point.uint64
return sc_val.duration.duration.uint64


def to_int32(value: int) -> stellar_xdr.SCVal:
Expand Down Expand Up @@ -234,27 +269,27 @@ def from_int256(sc_val: stellar_xdr.SCVal) -> int:
return int.from_bytes(value_bytes, "big", signed=True)


def to_map(value: OrderedDict[stellar_xdr.SCVal, stellar_xdr.SCVal]) -> stellar_xdr.SCVal:
def to_map(value: Dict[stellar_xdr.SCVal, stellar_xdr.SCVal]) -> stellar_xdr.SCVal:
"""Creates a new :class:`stellar_sdk.xdr.SCVal` XDR object from an OrderedDict value.
:param value: The OrderedDict value.
:param value: The value.
:return: A new :class:`stellar_sdk.xdr.SCVal` XDR object with type :class:`stellar_sdk.xdr.SCValType.SCV_MAP`.
"""
return stellar_xdr.SCVal.from_scv_map(
stellar_xdr.SCMap(sc_map=[stellar_xdr.SCMapEntry(key=key, val=value) for key, value in value.items()]))


def from_map(sc_val: stellar_xdr.SCVal) -> OrderedDict[stellar_xdr.SCVal, stellar_xdr.SCVal]:
"""Creates an OrderedDict value from a :class:`stellar_sdk.xdr.SCVal` XDR object.
def from_map(sc_val: stellar_xdr.SCVal) -> Dict[stellar_xdr.SCVal, stellar_xdr.SCVal]:
"""Creates an dict value from a :class:`stellar_sdk.xdr.SCVal` XDR object.
:param sc_val: The :class:`stellar_sdk.xdr.SCVal` XDR object.
:return: An OrderedDict value.
:return: The map value.
:raises: :exc:`ValueError` if ``sc_val`` is not of type :class:`stellar_sdk.xdr.SCValType.SCV_MAP`.
"""
if sc_val.type != stellar_xdr.SCValType.SCV_MAP:
raise ValueError(f"Invalid sc_val type, must be SCV_MAP, got {sc_val.type}")
assert sc_val.map is not None
return OrderedDict([(entry.key, entry.val) for entry in sc_val.map.sc_map])
return dict([(entry.key, entry.val) for entry in sc_val.map.sc_map])

def to_string(value: Union[str, bytes]) -> stellar_xdr.SCVal:
"""Creates a new :class:`stellar_sdk.xdr.SCVal` XDR object from a string value.
Expand Down
203 changes: 203 additions & 0 deletions tests/test_scval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
from collections import OrderedDict

import pytest

from stellar_sdk.address import Address
from stellar_sdk.scval import *
from stellar_sdk import xdr


def test_address():
addr = Address("GAHJJJKMOKYE4RVPZEWZTKH5FVI4PA3VL7GK2LFNUBSGBV6OJP7TQSLX")
scval = to_address(addr)

expected_scval = addr.to_xdr_sc_val()
assert scval == expected_scval
assert from_address(scval) == addr


def test_bool():
scval = to_bool(True)
expected_scval = xdr.SCVal.from_scv_bool(True)
assert scval == expected_scval
assert from_bool(scval) is True


def test_bytes():
v = b"hello"
scval = to_bytes(v)
expected_scval = xdr.SCVal.from_scv_bytes(xdr.SCBytes(v))
assert scval == expected_scval
assert from_bytes(scval) == v


@pytest.mark.parametrize(
"v", [
(2 ** 64) - 1,
0
]
)
def test_duration(v):
scval = to_duration(v)
expected_scval = xdr.SCVal.from_scv_duration(xdr.Duration(xdr.Uint64(v)))

assert scval == expected_scval
assert from_duration(scval) == v


@pytest.mark.parametrize(
"v", [
2 ** 64,
-1
]
)
def test_duration_out_of_range_raise(v):
v = (2 ** 64)
with pytest.raises(ValueError, match="Invalid value"):
to_duration(v)


@pytest.mark.parametrize(
"v", [
2 ** 31 - 1,
-(2 ** 31)
]
)
def test_int32(v):
scval = to_int32(v)
expected_scval = xdr.SCVal.from_scv_i32(xdr.Int32(v))
assert scval == expected_scval
assert from_int32(scval) == v


@pytest.mark.parametrize(
"v", [
2 ** 31,
-(2 ** 31) - 1]
)
def test_int32_out_of_range_raise(v):
with pytest.raises(ValueError, match="Invalid value"):
to_int32(v)


@pytest.mark.parametrize(
"v", [
2 ** 63 - 1,
-(2 ** 63)]
)
def test_int64(v):
scval = to_int64(v)
expected_scval = xdr.SCVal.from_scv_i64(xdr.Int64(v))
assert scval == expected_scval
assert from_int64(scval) == v


@pytest.mark.parametrize(
"v", [
2 ** 63,
-(2 ** 63) - 1]
)
def test_int64_out_of_range_raise(v):
with pytest.raises(ValueError, match="Invalid value"):
to_int64(v)


@pytest.mark.parametrize(
"v, expected_xdr", [
(0, 'AAAACgAAAAAAAAAAAAAAAAAAAAA='),
(1, 'AAAACgAAAAAAAAAAAAAAAAAAAAE='),
(-1, 'AAAACv////////////////////8='),
(2 ** 64, 'AAAACgAAAAAAAAABAAAAAAAAAAA='),
(-(2 ** 64), 'AAAACv//////////AAAAAAAAAAA='),
(2 ** 127 - 1, 'AAAACn////////////////////8='), # TODO: recheck
(-(2 ** 127), 'AAAACoAAAAAAAAAAAAAAAAAAAAA='),
]
)
def test_int128(v, expected_xdr):
scval = to_int128(v)
assert scval.to_xdr() == expected_xdr
assert from_int128(scval) == v


@pytest.mark.parametrize(
"v", [
2 ** 127,
-(2 ** 127) - 1]
)
def test_int128_out_of_range_raise(v):
with pytest.raises(ValueError, match="Invalid value"):
to_int128(v)


@pytest.mark.parametrize(
"v, expected_xdr", [
(0, 'AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
(1, 'AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB'),
(-1, 'AAAADP//////////////////////////////////////////'),
(2 ** 64, 'AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAA'),
(-(2 ** 64), 'AAAADP///////////////////////////////wAAAAAAAAAA'),
(2 ** 128, 'AAAADAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAA'),
(-(2 ** 128), 'AAAADP////////////////////8AAAAAAAAAAAAAAAAAAAAA'),
(2 ** 192, 'AAAADAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
(-(2 ** 192), 'AAAADP//////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
(2 ** 255 - 1, 'AAAADH//////////////////////////////////////////'), # TODO: recheck
(-(2 ** 255), 'AAAADIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
]
)
def test_int256(v, expected_xdr):
scval = to_int256(v)
assert scval.to_xdr() == expected_xdr
assert from_int256(scval) == v


@pytest.mark.parametrize(
"v", [
2 ** 255,
-(2 ** 255) - 1]
)
def test_int256_out_of_range_raise(v):
with pytest.raises(ValueError, match="Invalid value"):
to_int256(v)


def test_map():
v = {
to_symbol("hello3"): to_int32(1),
to_symbol("hello1"): to_int256(23423432),
to_string("hello2"): to_string('world'),
}
scval = to_map(v)
expected_scval = xdr.SCVal.from_scv_map(
xdr.SCMap([
xdr.SCMapEntry(to_symbol("hello3"), to_int32(1)),
xdr.SCMapEntry(to_symbol("hello1"), to_int256(23423432)),
xdr.SCMapEntry(to_string("hello2"), to_string('world'))
])
)
assert scval == expected_scval
assert from_map(scval) == v


@pytest.mark.parametrize(
"v, expected_xdr", [
(0, 'AAAACQAAAAAAAAAAAAAAAAAAAAA='),
(1, 'AAAACQAAAAAAAAAAAAAAAAAAAAE='),
(2 ** 64, 'AAAACQAAAAAAAAABAAAAAAAAAAA='),
(2 ** 128 - 1, 'AAAACf////////////////////8='), # TODO: recheck
]
)
def test_uint128(v, expected_xdr):
scval = to_uint128(v)
assert scval.to_xdr() == expected_xdr
assert from_uint128(scval) == v


@pytest.mark.parametrize(
"v", [
-1,
2 ** 128]
)
def test_uint128_out_of_range_raise(v):
with pytest.raises(ValueError, match="Invalid value"):
to_uint128(v)

0 comments on commit 81bc96f

Please sign in to comment.