Initial DA API Spec structure (#72)

* Initial da_api spec structure

* Node definition for testing different actors in da api

* Connect zone, producer and da nodes in tests

* Remove da mock module

* Add da api module with flow tests

* Comments for read and write methods in BlobStore

* Fix nitpicks (formatting and typing)

---------

Co-authored-by: Daniel Sanchez Quiros <sanchez.quiros.daniel@gmail.com>
This commit is contained in:
gusto 2024-03-15 12:37:56 +02:00 committed by GitHub
parent 0e142c0888
commit b1e13f79c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 122 additions and 0 deletions

0
da/api/__init__.py Normal file
View File

50
da/api/common.py Normal file
View File

@ -0,0 +1,50 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional, List, Sequence
from da.common import Certificate
from da.verifier import DABlob
@dataclass
class Metadata:
# index of VID certificate blob
index: int
# app identifier
app_id: bytes
class BlobStore(ABC):
@abstractmethod
def add(self, certificate: Certificate, metadata: Metadata):
"""
Raises: ValueError if there is already a registered certificate fot the given metadata
"""
pass
@abstractmethod
def get_multiple(self, app_id: bytes, indexes: Sequence[int]) -> List[Optional[DABlob]]:
pass
class DAApi:
def __init__(self, bs: BlobStore):
self.store = bs
def write(self, certificate: Certificate, metadata: Metadata):
"""
Write method should be used by a service that is able to retrieve verified certificates
from the latest Block. Once a certificate is retrieved, api creates a relation between
the blob of an original data, certificate and index for the app_id of the certificate.
Raises: ValueError if there is already a registered certificate for a given metadata
"""
self.store.add(certificate, metadata)
def read(self, app_id, indexes) -> List[Optional[DABlob]]:
"""
Read method should accept only `app_id` and a list of indexes. The returned list of
blobs should be ordered in the same sequence as `indexes` in a request.
If node does not have the blob for some indexes, then it should add None object as an
item.
"""
return self.store.get_multiple(app_id, indexes)

72
da/api/test_flow.py Normal file
View File

@ -0,0 +1,72 @@
from unittest import TestCase
from collections import defaultdict
from da.api.common import *
@dataclass
class MockCertificate:
cert_id: int
class MockStore(BlobStore):
def __init__(self):
self.blob_store = {}
self.app_id_store = defaultdict(dict)
def populate(self, blob, cert_id: bytes):
self.blob_store[cert_id] = blob
# Implements `add` method from BlobStore abstract class.
def add(self, cert_id: bytes, metadata: Metadata):
if metadata.index in self.app_id_store[metadata.app_id]:
raise ValueError("index already written")
blob = self.blob_store.pop(cert_id)
self.app_id_store[metadata.app_id][metadata.index] = blob
# Implements `get_multiple` method from BlobStore abstract class.
def get_multiple(self, app_id, indexes) -> List[Optional[DABlob]]:
return [
self.app_id_store[app_id].get(i) for i in indexes
]
class TestFlow(TestCase):
def test_api_write_read(self):
expected_blob = "hello"
cert_id = b"11"*32
app_id = 1
idx = 1
mock_meta = Metadata(1, 1)
mock_store = MockStore()
mock_store.populate(expected_blob, cert_id)
api = DAApi(mock_store)
api.write(cert_id, mock_meta)
blobs = api.read(app_id, [idx])
self.assertEqual([expected_blob], blobs)
def test_same_index(self):
expected_blob = "hello"
cert_id = b"11"*32
app_id = 1
idx = 1
mock_meta = Metadata(1, 1)
mock_store = MockStore()
mock_store.populate(expected_blob, cert_id)
api = DAApi(mock_store)
api.write(cert_id, mock_meta)
with self.assertRaises(ValueError):
api.write(cert_id, mock_meta)
blobs = api.read(app_id, [idx])
self.assertEqual([expected_blob], blobs)