Skip to content

Commit

Permalink
Update and modify files for the project
Browse files Browse the repository at this point in the history
- Added new files:
  - tests/integration/feed/test_feed.py
- Updated files:
  - src/bee_py/bee.py
  - src/bee_py/chunk/soc.py
  - src/bee_py/feed/feed.py
  - src/bee_py/feed/json.py
  - src/bee_py/feed/retrievable.py
  - src/bee_py/modules/bytes.py
  - src/bee_py/modules/feed.py
  - src/bee_py/types/type.py
  - src/bee_py/utils/reference.py
  - tests/conftest.py
  - tests/integration/chunk/conftest.py
  • Loading branch information
Aviksaikat committed Dec 4, 2023
1 parent 3ae90fe commit 880f718
Show file tree
Hide file tree
Showing 12 changed files with 486 additions and 110 deletions.
16 changes: 3 additions & 13 deletions src/bee_py/bee.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
from typing import Optional

from swarm_cid import ReferenceType

from bee_py.chunk.signer import sign
from bee_py.chunk.soc import download_single_owner_chunk, upload_single_owner_chunk_data
from bee_py.feed.feed import Index, IndexBytes
from bee_py.types.type import ( # Reference,
BatchId,
BeeRequestOptions,
FeedReader,
FeedWriter,
JsonFeedOptions,
UploadOptions,
)
from bee_py.utils.collection import assert_collection, make_collection
from bee_py.utils.urls import assert_bee_url, strip_last_slash


Expand Down Expand Up @@ -55,3 +42,6 @@ def __init__(self, url: str, options: Optional[dict] = None):
"onRequest": options.get("onRequest", None),
"adapter": options.get("adapter", None),
}

def download_chunk(self):
...
1 change: 0 additions & 1 deletion src/bee_py/chunk/soc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from ape.managers.accounts import AccountAPI
from eth_account import Account
from eth_account.messages import encode_defunct
from eth_typing import ChecksumAddress as AddressType
from pydantic import BaseModel, Field

Expand Down
199 changes: 188 additions & 11 deletions src/bee_py/feed/feed.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
from typing import NewType, Union
import datetime
from typing import NewType, Optional, Union

from ape.managers.accounts import AccountAPI
from eth_typing import ChecksumAddress as AddressType
from pydantic import BaseModel

from bee_py.chunk.serialize import serialize_bytes
from bee_py.chunk.signer import sign
from bee_py.chunk.soc import download_single_owner_chunk, upload_single_owner_chunk_data
from bee_py.chunk.soc import (
make_single_owner_chunk_from_data,
upload_single_owner_chunk_data,
)
from bee_py.feed.identifiers import make_feed_identifier
from bee_py.feed.type import FeedType
from bee_py.modules.chunk import *
from bee_py.modules.bytes import read_big_endian, write_big_endian
from bee_py.modules.chunk import download
from bee_py.modules.feed import fetch_latest_feed_update
from bee_py.types.type import ( # Reference,
FEED_INDEX_HEX_LENGTH,
BatchId,
BeeRequestOptions,
FeedReader,
FeedType,
FeedUpdateOptions,
FeedWriter,
JsonFeedOptions,
UploadOptions,
MakeFeedReader,
Reference,
Topic,
)
from bee_py.utils.collection import assert_collection, make_collection
from bee_py.utils.hash import keccak_hash
from bee_py.utils.hex import bytes_to_hex, hex_to_bytes, make_hex_string
from bee_py.utils.bytes import bytes_at_offset, make_bytes
from bee_py.utils.eth import make_hex_eth_address
from bee_py.utils.hash import keccak256_hash
from bee_py.utils.hex import bytes_to_hex, make_hex_string
from bee_py.utils.reference import make_bytes_reference

TIMESTAMP_PAYLOAD_OFFSET = 0
TIMESTAMP_PAYLOAD_SIZE = 8
TIMESTAMP_PAYLOAD_SIZE_HEX = 16
REFERENCE_PAYLOAD_OFFSET = TIMESTAMP_PAYLOAD_SIZE


Expand Down Expand Up @@ -54,3 +63,171 @@ class Index(BaseModel):
"""

index: Union[int, Epoch, bytes, str]


class FeedUpdate(BaseModel):
"""
Represents a feed update.
Attributes:
timestamp: The timestamp of the update.
reference: The reference of the update.
"""

timestamp: int
reference: bytes


def find_next_index(
request_options: BeeRequestOptions,
owner: AddressType,
topic: Topic,
options: Optional[FeedUpdateOptions] = None,
) -> bytes:
"""
Fetches the latest feed update and returns the next feed index.
Args:
request_options (AsyncClient): The HTTP client instance for making requests to the Bee API.
owner (bytes): The owner of the feed.
topic (bytes): The topic of the feed.
options (Optional[FeedUpdateOptions]): Additional options for fetching the latest feed update.
Returns:
bytes: The next feed index.
"""

try:
feed_update = fetch_latest_feed_update(request_options, owner, topic, options)
return make_hex_string(feed_update.feed_index_next, FEED_INDEX_HEX_LENGTH)
except Exception as e:
if e.response.status_code == 404: # noqa: PLR2004
return bytes_to_hex(make_bytes(8))
raise e


def update_feed(
request_options: BeeRequestOptions,
signer: AccountAPI,
topic: Topic,
reference: Reference,
postage_batch_id: BatchId,
options: Optional[FeedUpdateOptions] = None,
index: str = "latest",
):
"""
Updates a feed.
:param request_options: The request options.
:type request_options: BeeRequestOptions
:param signer: The signer.
:type signer: Signer
:param topic: The topic.
:type topic: Topic
:param reference: The reference.
:type reference: BytesReference
:param postage_batch_id: The postage batch ID.
:type postage_batch_id: BatchId
:param options: The options for uploading the feed (default is None).
:type options: FeedUploadOptions
:param index: The index (default is 'latest').
:type index: Index
:return: The reference.
:rtype: Reference
"""
owner_hex = make_hex_eth_address(signer.address)
next_index = index if index != "latest" else find_next_index(request_options, owner_hex, topic, options)

identifier = make_feed_identifier(topic, next_index)
at = options.at if options and options.at else datetime.now().timestamp()
timestamp = write_big_endian(at)
payload_bytes = serialize_bytes(timestamp, reference)

return upload_single_owner_chunk_data(request_options, signer, postage_batch_id, identifier, payload_bytes, options)


def get_feed_update_chunk_reference(owner: AddressType, topic: Topic, index: Index) -> bytes:
"""
Gets the feed update chunk reference.
:param owner: The owner.
:type owner: EthAddress
:param topic: The topic.
:type topic: Topic
:param index: The index.
:type index: Index
:return: The feed update chunk reference.
:rtype: PlainBytesReference
"""
identifier = make_feed_identifier(topic, index)

return keccak256_hash(identifier, owner)


def download_feed_update(
request_options: BeeRequestOptions, owner: AddressType, topic: Topic, index: Index
) -> FeedUpdate:
"""
Downloads a feed update.
:param request_options: The request options.
:type request_options: BeeRequestOptions
:param owner: The owner.
:type owner: EthAddress
:param topic: The topic.
:type topic: Topic
:param index: The index.
:type index: Index
:return: The feed update.
:rtype: FeedUpdate
"""
address = get_feed_update_chunk_reference(owner, topic, index)
address_hex = bytes_to_hex(address)
data = download(request_options, address_hex)
soc = make_single_owner_chunk_from_data(data, address)
payload = soc.payload
timestamp_bytes = bytes_at_offset(payload, TIMESTAMP_PAYLOAD_OFFSET, TIMESTAMP_PAYLOAD_SIZE)
timestamp = read_big_endian(timestamp_bytes)
reference = make_bytes_reference(payload, REFERENCE_PAYLOAD_OFFSET)

return FeedUpdate(timestamp=timestamp, reference=reference)


def make_feed_reader(
request_options: BeeRequestOptions,
_type: FeedType,
topic: Topic,
owner: AddressType,
options: Optional[FeedUpdateOptions] = None,
) -> MakeFeedReader:
"""
Creates a new feed reader object.
Args:
request_options (AsyncClient): The HTTP client instance for making requests to the Bee API.
type (str): The type of feed.
topic (bytes): The topic of the feed.
owner (bytes): The owner of the feed.
Returns:
FeedReader: The feed reader object.
"""
return MakeFeedReader(request_options=request_options, Type=_type, owner=owner, topic=topic, options=options)


def make_feed_writer(
request_options: BeeRequestOptions, _type: FeedType, topic: Topic, signer: AccountAPI
) -> FeedWriter:
"""
Creates a new feed writer object.
Args:
request_options (BeeRequestOptions): The HTTP client instance for making requests to the Bee API.
type (FeedType): The type of feed.
topic (Topic): The topic of the feed.
signer (AccountAPI): The account to sign.
Returns:
FeedWriter: The feed writer object.
"""
return FeedWriter(request_options=request_options, type=_type, topic=topic, signer=signer)
1 change: 1 addition & 0 deletions src/bee_py/feed/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Optional, Union

from bee_py.bee import Bee

# from bee_py.feed.type import FeedType
from bee_py.types.type import ( # Reference,
BatchId,
Expand Down
104 changes: 103 additions & 1 deletion src/bee_py/feed/retrievable.py
Original file line number Diff line number Diff line change
@@ -1 +1,103 @@
#
from ape.types import AddressType

from bee_py.bee import Bee
from bee_py.feed.feed import Index, get_feed_update_chunk_reference
from bee_py.modules.bytes import read_big_endian
from bee_py.types.type import BeeRequestOptions, Reference, Topic
from bee_py.utils.hex import bytes_to_hex


def make_numeric_index(index: Index):
"""
Converts an index to a numeric value.
:param index: The index to convert.
:type index: Index: Union[int, Epoch, bytes, str]
:return: The numeric index.
:rtype: int
:raises TypeError: If the type of the index is unknown.
"""
if isinstance(index, bytes):
return read_big_endian(index)

if isinstance(index, str):
return int(index)

if isinstance(index, int):
return index

msg = "Unknown type of index!"
raise TypeError(msg)


def is_chunk_retrievable(bee: Bee, ref: Reference, request_options: BeeRequestOptions) -> bool:
"""
Checks whether a chunk is retrievable by attempting to download it.
The `/stewardship/{reference}` endpoint does not support verifying chunks, only manifest references.
Args:
bee (Bee): The Bee client instance.
ref (Reference): The chunk reference.
request_options (BeeRequestOptions): The request options.
Returns:
bool: True if the chunk is retrievable, False otherwise.
"""

try:
bee.download_chunk(ref, request_options)
return True
except Exception as e:
if e.response.status_code == 404: # noqa: PLR2004
return False
raise e


def get_all_sequence_update_references(owner: AddressType, topic: Topic, index: Index) -> list[Reference]:
"""
Creates a list of references for all sequence updates chunk up to the given index.
Creates an array of references for all sequence updates up to the given index.
Args:
owner (AddressType): The owner of the feed.
topic (Topic): The topic of the feed.
index (Index): The index of the last sequence update to include.
Returns:
list[Reference]
"""
num_index = make_numeric_index(index)
update_references = [bytes_to_hex(get_feed_update_chunk_reference(owner, topic, i)) for i in range(num_index + 1)]

return update_references


def are_all_sequential_feeds_update_retrievable(
bee: Bee,
owner: AddressType,
topic: Topic,
index: Index,
request_options: BeeRequestOptions,
) -> bool:
"""
Checks whether all sequential feed updates up to the given index are retrievable.
Args:
bee (Bee): The Bee client instance.
owner (AddressType): The owner of the feed.
topic (Topic): The topic of the feed.
index (Index): The index of the last sequence update to check.
request_options (BeeRequestOptions): The request options.
Returns:
bool: True if all sequence updates are retrievable, False otherwise.
"""

chunk_retrievable_promises = [
is_chunk_retrievable(bee, ref, request_options)
for ref in get_all_sequence_update_references(owner, topic, index)
]

return all(chunk_retrievable_promises)
Loading

0 comments on commit 880f718

Please sign in to comment.