-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add SorobanDataBuilder to prepare soroban_data easily. (#760)
- Loading branch information
Showing
5 changed files
with
263 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
from __future__ import annotations | ||
|
||
from typing import List, Union | ||
|
||
from . import xdr as stellar_xdr | ||
|
||
__all__ = ["SorobanDataBuilder"] | ||
|
||
|
||
class SorobanDataBuilder: | ||
"""Supports building :class:`Memo <stellar_sdk.xdr.SorobanTransactionData>` structures | ||
with various items set to specific values. | ||
This is recommended for when you are building :class:`RestoreFootprint <stellar_sdk.operation.RestoreFootprint>`, | ||
:class:`BumpFootprintExpiration <stellar_sdk.operation.BumpFootprintExpiration>` operations to avoid (re)building | ||
the entire data structure from scratch. | ||
By default, an empty instance will be created. | ||
""" | ||
|
||
def __init__(self): | ||
self._data = stellar_xdr.SorobanTransactionData( | ||
ext=stellar_xdr.ExtensionPoint(0), | ||
refundable_fee=stellar_xdr.Int64(0), | ||
resources=stellar_xdr.SorobanResources( | ||
footprint=stellar_xdr.LedgerFootprint( | ||
read_only=[], | ||
read_write=[], | ||
), | ||
extended_meta_data_size_bytes=stellar_xdr.Uint32(0), | ||
read_bytes=stellar_xdr.Uint32(0), | ||
write_bytes=stellar_xdr.Uint32(0), | ||
instructions=stellar_xdr.Uint32(0), | ||
), | ||
) | ||
|
||
@classmethod | ||
def from_xdr( | ||
cls, soroban_data: Union[str, stellar_xdr.SorobanTransactionData] | ||
) -> SorobanDataBuilder: | ||
"""Create a new :class:`SorobanDataBuilder` object from an XDR object. | ||
:param soroban_data: The XDR object that represents a SorobanTransactionData. | ||
:return: This builder. | ||
""" | ||
data = cls() | ||
if isinstance(soroban_data, str): | ||
data._data = stellar_xdr.SorobanTransactionData.from_xdr(soroban_data) | ||
else: | ||
data._data = stellar_xdr.SorobanTransactionData.from_xdr_bytes( | ||
soroban_data.to_xdr_bytes() | ||
) | ||
return data | ||
|
||
def set_refundable_fee(self, fee: int) -> SorobanDataBuilder: | ||
"""Sets the "refundable" fee portion of the Soroban data. | ||
:param fee: The refundable fee to set (int64) | ||
:return: This builder. | ||
""" | ||
self._data.refundable_fee = stellar_xdr.Int64(fee) | ||
return self | ||
|
||
def set_read_only( | ||
self, read_only: List[stellar_xdr.LedgerKey] | ||
) -> SorobanDataBuilder: | ||
"""Sets the read-only portion of the storage access footprint to be a certain set of ledger keys. | ||
:param read_only: The read-only ledger keys to set. | ||
:return: This builder. | ||
""" | ||
self._data.resources.footprint.read_only = read_only or [] | ||
return self | ||
|
||
def set_read_write( | ||
self, read_write: List[stellar_xdr.LedgerKey] | ||
) -> SorobanDataBuilder: | ||
"""Sets the read-write portion of the storage access footprint to be a certain set of ledger keys. | ||
:param read_write: The read-write ledger keys to set. | ||
:return: This builder. | ||
""" | ||
self._data.resources.footprint.read_write = read_write or [] | ||
return self | ||
|
||
def set_resources( | ||
self, instructions: int, read_bytes: int, write_bytes: int, metadata_bytes: int | ||
) -> SorobanDataBuilder: | ||
"""Sets up the resource metrics. | ||
You should almost NEVER need this, as its often generated / provided to you | ||
by transaction simulation/preflight from a Soroban RPC server. | ||
:param instructions: Number of CPU instructions (uint32) | ||
:param read_bytes: Number of bytes being read (uint32) | ||
:param write_bytes: Number of bytes being written (uint32) | ||
:param metadata_bytes: Number of extended metadata bytes (uint32) | ||
:return: This builder. | ||
""" | ||
self._data.resources.instructions = stellar_xdr.Uint32(instructions) | ||
self._data.resources.read_bytes = stellar_xdr.Uint32(read_bytes) | ||
self._data.resources.write_bytes = stellar_xdr.Uint32(write_bytes) | ||
self._data.resources.extended_meta_data_size_bytes = stellar_xdr.Uint32( | ||
metadata_bytes | ||
) | ||
return self | ||
|
||
def build(self): | ||
""":return: a copy of the final data structure.""" | ||
return stellar_xdr.SorobanTransactionData.from_xdr_bytes( | ||
self._data.to_xdr_bytes() | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
from stellar_sdk import Keypair | ||
from stellar_sdk import xdr as stellar_xdr | ||
from stellar_sdk.soroban_data_builder import SorobanDataBuilder | ||
|
||
|
||
class TestSorobanDataBuilder: | ||
empty_instance = stellar_xdr.SorobanTransactionData( | ||
ext=stellar_xdr.ExtensionPoint(0), | ||
refundable_fee=stellar_xdr.Int64(0), | ||
resources=stellar_xdr.SorobanResources( | ||
footprint=stellar_xdr.LedgerFootprint( | ||
read_only=[], | ||
read_write=[], | ||
), | ||
extended_meta_data_size_bytes=stellar_xdr.Uint32(0), | ||
read_bytes=stellar_xdr.Uint32(0), | ||
write_bytes=stellar_xdr.Uint32(0), | ||
instructions=stellar_xdr.Uint32(0), | ||
), | ||
) | ||
|
||
def test_init(self): | ||
builder = SorobanDataBuilder() | ||
assert builder._data == self.empty_instance | ||
assert builder.build() == self.empty_instance | ||
|
||
def test_from_xdr_object(self): | ||
xdr_obj = stellar_xdr.SorobanTransactionData( | ||
ext=stellar_xdr.ExtensionPoint(0), | ||
refundable_fee=stellar_xdr.Int64(0), | ||
resources=stellar_xdr.SorobanResources( | ||
footprint=stellar_xdr.LedgerFootprint( | ||
read_only=[], | ||
read_write=[], | ||
), | ||
extended_meta_data_size_bytes=stellar_xdr.Uint32(1), | ||
read_bytes=stellar_xdr.Uint32(2), | ||
write_bytes=stellar_xdr.Uint32(3), | ||
instructions=stellar_xdr.Uint32(4), | ||
), | ||
) | ||
builder = SorobanDataBuilder.from_xdr(xdr_obj) | ||
assert builder._data == xdr_obj | ||
assert builder.build() == xdr_obj | ||
assert id(builder._data) != id(xdr_obj) | ||
|
||
def test_from_xdr_base64(self): | ||
xdr_obj = stellar_xdr.SorobanTransactionData( | ||
ext=stellar_xdr.ExtensionPoint(0), | ||
refundable_fee=stellar_xdr.Int64(0), | ||
resources=stellar_xdr.SorobanResources( | ||
footprint=stellar_xdr.LedgerFootprint( | ||
read_only=[], | ||
read_write=[], | ||
), | ||
extended_meta_data_size_bytes=stellar_xdr.Uint32(1), | ||
read_bytes=stellar_xdr.Uint32(2), | ||
write_bytes=stellar_xdr.Uint32(3), | ||
instructions=stellar_xdr.Uint32(4), | ||
), | ||
) | ||
builder = SorobanDataBuilder.from_xdr(xdr_obj.to_xdr()) | ||
assert builder._data == xdr_obj | ||
assert builder.build() == xdr_obj | ||
assert id(builder._data) != id(xdr_obj) | ||
|
||
def test_set_refundable_fee(self): | ||
builder = SorobanDataBuilder() | ||
builder.set_refundable_fee(100) | ||
assert builder.build().refundable_fee.int64 == 100 | ||
|
||
def test_set_resources(self): | ||
data = SorobanDataBuilder().set_resources(1, 2, 3, 4).build() | ||
assert data == stellar_xdr.SorobanTransactionData( | ||
ext=stellar_xdr.ExtensionPoint(0), | ||
refundable_fee=stellar_xdr.Int64(0), | ||
resources=stellar_xdr.SorobanResources( | ||
footprint=stellar_xdr.LedgerFootprint( | ||
read_only=[], | ||
read_write=[], | ||
), | ||
instructions=stellar_xdr.Uint32(1), | ||
read_bytes=stellar_xdr.Uint32(2), | ||
write_bytes=stellar_xdr.Uint32(3), | ||
extended_meta_data_size_bytes=stellar_xdr.Uint32(4), | ||
), | ||
) | ||
|
||
def test_set_read_only(self): | ||
ledger_key = stellar_xdr.LedgerKey( | ||
stellar_xdr.LedgerEntryType.ACCOUNT, | ||
account=stellar_xdr.LedgerKeyAccount( | ||
Keypair.from_public_key( | ||
"GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ" | ||
).xdr_account_id() | ||
), | ||
) | ||
data = SorobanDataBuilder().set_read_only([ledger_key]).build() | ||
assert data == stellar_xdr.SorobanTransactionData( | ||
ext=stellar_xdr.ExtensionPoint(0), | ||
refundable_fee=stellar_xdr.Int64(0), | ||
resources=stellar_xdr.SorobanResources( | ||
footprint=stellar_xdr.LedgerFootprint( | ||
read_only=[ledger_key], | ||
read_write=[], | ||
), | ||
extended_meta_data_size_bytes=stellar_xdr.Uint32(0), | ||
read_bytes=stellar_xdr.Uint32(0), | ||
write_bytes=stellar_xdr.Uint32(0), | ||
instructions=stellar_xdr.Uint32(0), | ||
), | ||
) | ||
|
||
def test_set_read_write(self): | ||
ledger_key = stellar_xdr.LedgerKey( | ||
stellar_xdr.LedgerEntryType.ACCOUNT, | ||
account=stellar_xdr.LedgerKeyAccount( | ||
Keypair.from_public_key( | ||
"GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ" | ||
).xdr_account_id() | ||
), | ||
) | ||
data = SorobanDataBuilder().set_read_write([ledger_key]).build() | ||
assert data == stellar_xdr.SorobanTransactionData( | ||
ext=stellar_xdr.ExtensionPoint(0), | ||
refundable_fee=stellar_xdr.Int64(0), | ||
resources=stellar_xdr.SorobanResources( | ||
footprint=stellar_xdr.LedgerFootprint( | ||
read_only=[], | ||
read_write=[ledger_key], | ||
), | ||
extended_meta_data_size_bytes=stellar_xdr.Uint32(0), | ||
read_bytes=stellar_xdr.Uint32(0), | ||
write_bytes=stellar_xdr.Uint32(0), | ||
instructions=stellar_xdr.Uint32(0), | ||
), | ||
) | ||
|
||
def test_copy(self): | ||
builder = SorobanDataBuilder() | ||
assert builder._data == self.empty_instance | ||
assert builder.build() == self.empty_instance | ||
assert id(builder._data) != id(builder.build()) |