Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dynamic = [ "version" ]
dependencies = [
"aiohttp>=3.8.3",
"aioresponses>=0.7.6",
"aleph-message>=1.0.5",
"aleph-message>=1.1",
"aleph-superfluid>=0.3",
"base58==2.1.1", # Needed now as default with _load_account changement
"coincurve; python_version>='3.9'",
Expand Down Expand Up @@ -115,6 +115,7 @@ include = [
python = [ "3.9", "3.10", "3.11" ]

[tool.hatch.envs.testing]
python = "3.13"
features = [
"cosmos",
"dns",
Expand Down
2 changes: 2 additions & 0 deletions src/aleph/sdk/client/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ async def create_store(
extra_fields: Optional[dict] = None,
channel: Optional[str] = settings.DEFAULT_CHANNEL,
sync: bool = False,
payment: Optional[Payment] = None,
) -> Tuple[AlephMessage, MessageStatus]:
"""
Create a STORE message to store a file on the aleph.im network.
Expand All @@ -404,6 +405,7 @@ async def create_store(
:param extra_fields: Extra fields to add to the STORE message (Default: None)
:param channel: Channel to post the message to (Default: "TEST")
:param sync: If true, waits for the message to be processed by the API server (Default: False)
:param payment: Payment method used to pay for storage (Default: hold on ETH)
"""
raise NotImplementedError(
"Did you mean to import `AuthenticatedAlephHttpClient`?"
Expand Down
11 changes: 10 additions & 1 deletion src/aleph/sdk/client/authenticated_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
AggregateContent,
AggregateMessage,
AlephMessage,
Chain,
ForgetContent,
ForgetMessage,
InstanceMessage,
Expand All @@ -24,7 +25,7 @@
StoreContent,
StoreMessage,
)
from aleph_message.models.execution.base import Encoding, Payment
from aleph_message.models.execution.base import Encoding, Payment, PaymentType
from aleph_message.models.execution.environment import (
HostRequirements,
HypervisorType,
Expand Down Expand Up @@ -350,8 +351,12 @@ async def create_store(
extra_fields: Optional[dict] = None,
channel: Optional[str] = settings.DEFAULT_CHANNEL,
sync: bool = False,
payment: Optional[Payment] = None,
) -> Tuple[StoreMessage, MessageStatus]:
address = address or settings.ADDRESS_TO_USE or self.account.get_address()
payment = payment or Payment(
chain=Chain.ETH, type=PaymentType.hold, receiver=None
)

extra_fields = extra_fields or {}

Expand All @@ -374,6 +379,7 @@ async def create_store(
extra_fields=extra_fields,
channel=channel,
sync=sync,
payment=payment,
)
elif storage_engine == StorageEnum.ipfs:
# We do not support authenticated upload for IPFS yet. Use the legacy method
Expand All @@ -397,6 +403,7 @@ async def create_store(
"item_type": storage_engine,
"item_hash": file_hash,
"time": time.time(),
"payment": payment,
}
if extra_fields is not None:
values.update(extra_fields)
Expand Down Expand Up @@ -660,6 +667,7 @@ async def _upload_file_native(
extra_fields: Optional[dict] = None,
channel: Optional[str] = settings.DEFAULT_CHANNEL,
sync: bool = False,
payment: Optional[Payment] = None,
) -> Tuple[StoreMessage, MessageStatus]:
file_hash = hashlib.sha256(file_content).hexdigest()
if magic and guess_mime_type:
Expand All @@ -674,6 +682,7 @@ async def _upload_file_native(
item_hash=ItemHash(file_hash),
mime_type=mime_type, # type: ignore
time=time.time(),
payment=payment,
**(extra_fields or {}),
)
message, _ = await self._storage_push_file_with_message(
Expand Down
69 changes: 69 additions & 0 deletions tests/unit/test_asynchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,72 @@ async def test_create_instance_insufficient_funds_error(
receiver=None,
),
)


@pytest.mark.asyncio
async def test_create_instance_with_credit_payment(mock_session_with_post_success):
"""Test that an instance can be created with credit payment."""
async with mock_session_with_post_success as session:
instance_message, message_status = await session.create_instance(
rootfs="cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe",
rootfs_size=1,
channel="TEST",
metadata={"tags": ["test"]},
payment=Payment(
chain=Chain.ETH,
receiver=None,
type=PaymentType.credit,
),
)

assert instance_message.content.payment.type == PaymentType.credit
assert instance_message.content.payment.chain == Chain.ETH
assert instance_message.content.payment.receiver is None

assert mock_session_with_post_success.http_session.post.assert_called_once
assert isinstance(instance_message, InstanceMessage)


@pytest.mark.asyncio
async def test_create_store_with_credit_payment(mock_session_with_post_success):
"""Test that a store message can be created with credit payment."""
mock_ipfs_push_file = AsyncMock()
mock_ipfs_push_file.return_value = "QmRTV3h1jLcACW4FRfdisokkQAk4E4qDhUzGpgdrd4JAFy"

mock_session_with_post_success.ipfs_push_file = mock_ipfs_push_file

async with mock_session_with_post_success as session:
store_message, message_status = await session.create_store(
file_content=b"HELLO",
channel="TEST",
storage_engine=StorageEnum.ipfs,
payment=Payment(
chain=Chain.ETH,
receiver=None,
type=PaymentType.credit,
),
)

assert store_message.content.payment.type == PaymentType.credit
assert store_message.content.payment.chain == Chain.ETH
assert isinstance(store_message, StoreMessage)


@pytest.mark.asyncio
async def test_create_store_default_payment(mock_session_with_post_success):
"""Test that a store message defaults to hold payment on ETH."""
mock_ipfs_push_file = AsyncMock()
mock_ipfs_push_file.return_value = "QmRTV3h1jLcACW4FRfdisokkQAk4E4qDhUzGpgdrd4JAFy"

mock_session_with_post_success.ipfs_push_file = mock_ipfs_push_file

async with mock_session_with_post_success as session:
store_message, message_status = await session.create_store(
file_content=b"HELLO",
channel="TEST",
storage_engine=StorageEnum.ipfs,
)

assert store_message.content.payment.type == PaymentType.hold
assert store_message.content.payment.chain == Chain.ETH
assert isinstance(store_message, StoreMessage)
Loading