commit 28e7842f4d9d65ffeedad5867fbc51a0ae882635
parent c85851f37080ef0a529befcbabbe94814de9cbd0
Author: nolash <dev@holbrook.no>
Date:   Sun, 29 Aug 2021 10:15:37 +0200
More docs, include backend 'abstract' interface
Diffstat:
6 files changed, 210 insertions(+), 11 deletions(-)
diff --git a/chainqueue/backend.py b/chainqueue/backend.py
@@ -0,0 +1,140 @@
+# external imports
+from chainlib.error import DefaultErrorParser
+
+# local imports
+from chainqueue.encode import TxHexNormalizer
+
+
+class Backend:
+    """Base constructor for backend implementation.
+
+    :param tx_normalizer: Transaction data normalizer
+    :type tx_normalizer: Object implementing chainqueue.encode.TxHexNormalizer interface
+    :param error_parser: Error parser to use for RPC calls within the backend component
+    :type error_parser: Object implementing chainlib.error.DefaultErrorParser
+    :param debug: Activate backend debugging
+    :type debug: bool
+    """
+    def __init__(self, tx_normalizer=None, error_parser=None, debug=False):
+        if error_parser == None:
+            error_parser = DefaultErrorParser()
+        self.error_parser = error_parser
+        if tx_normalizer == None:
+            tx_normalizer = TxHexNormalizer()
+        self.tx_normalizer = tx_normalizer
+        self.debug = debug
+
+
+    def create(self, chain_spec, nonce, holder_address, tx_hash, signed_tx, obsolete_predecessors=True, session=None):
+        """Create a new transaction record in backend.
+
+        The nonce field is provided as a convenience to avoid needless resources spent on decoding the transaction data to retrieve it.
+
+        :param chain_spec: Chain spec to add record for
+        :type chain_spec: chainlib.chain.ChainSpec
+        :param nonce: Transaction nonce
+        :type nonce: int
+        :param holder_address: Address of transaction sender
+        :type holder_address: str
+        :param tx_hash: Transaction hash
+        :type tx_hash: str
+        :param signed_tx: Signed transaction data
+        :type signed_tx: str
+        :param obsolete_predecessors: If set, will mark older transactions with same nonce from holder_address as obsolete
+        :type obsolete_predecessors: bool
+        :param session: Sqlalchemy database session
+        :type session: sqlalchemy.orm.Session
+        :rtype: int
+        :returns: 0 if successfully added
+        """
+        raise NotImplementedError()
+
+
+    def cache(self, tx, session=None):
+        """Create a new cache record for existing outgoing transaction in backend.
+
+        :param tx: Transaction dict representation
+        :type tx: dict
+        :param session: Sqlalchemy database session
+        :type session: sqlalchemy.orm.Session
+        :rtype: int
+        :returns: 0 if successful
+        """
+        raise NotImplementedError()
+
+
+    def get_otx(self, chain_spec, tx_hash, session=None):
+        """Retrieve a single otx summary dictionary by transaction hash.
+
+        :param chain_spec: Chain spec context to look up transaction with
+        :type chain_spec: chainlib.chain.ChainSpec
+        :param tx_hash: Transaction hash
+        :type tx_hash: str
+        :param session: Sqlalchemy database session
+        :type session: sqlalchemy.orm.Session
+        :rtype: dict
+        :returns: otx record summary
+        """
+        raise NotImplementedError()
+
+
+    def get(self, chain_spec, decoder, session=None, requeue=False, *args, **kwargs):
+        """Gets transaction lists based on given criteria.
+
+        :param chain_spec: Chain spec context to look up transactions for
+        :type chain_spec: chainlib.chain.ChainSpec
+        :param decoder: Decoder instance to parse values from serialized transaction data in record
+        :type decoder: Function taking serialized tx as parameter
+        :param session: Sqlalchemy database session
+        :type session: sqlalchemy.orm.Session
+        :param status: Only match transaction that have the given bits set
+        :type status: int
+        :param not_status: Only match transactions that have none of the given bits set
+        :type not_status: int
+        :param recipient: Only match transactions that has the given address as recipient
+        :type recipient: str
+        :param before: Only match tranaactions that were last checked before the given time
+        :type before: datetime.datetime
+        :param limit: Return at most given number of transaction. If 0, will return all matched transactions.
+        :type limit: int
+        :rtype: dict
+        :returns: key value pairs of transaction hash and signed transaction data for all matching transactions
+        """
+        raise NotImplementedError()
+
+
+    def dispatch(self, chain_spec, rpc, tx_hash, payload, session=None):
+        """Send a single queued transaction.
+
+        :param chain_spec: Chain spec context for network send
+        :type chain_spec: chainlib.chain.ChainSpec
+        :param rpc: RPC connection to use for send
+        :type rpc: chainlib.connection.RPCConnection
+        :param tx_hash: Transaction hash of transaction to send
+        :type tx_hash: str
+        :param payload: Prepared RPC query to send
+        :type payload: any
+        :param session: Sqlalchemy database session
+        :type session: sqlalchemy.orm.Session
+        :rtype: int
+        :returns: 0 if no error
+        """
+        raise NotImplementedError()
+
+
+    def create_session(self, session=None):
+        """Create or pass on a new backend connection session.
+
+        :param session: Use existing session
+        :type session: varies
+        """
+        raise NotImplementedError()
+
+
+    def release_session(self, session):
+        """Release resources held by session.
+
+        :param session: Session to release
+        :type session: varies
+        """
+        raise NotImplementedError()
diff --git a/chainqueue/sql/backend.py b/chainqueue/sql/backend.py
@@ -10,7 +10,6 @@ from sqlalchemy.exc import (
 from chainlib.error import (
         RPCException,
         RPCNonceException,
-        DefaultErrorParser,
         )
 
 # local imports
@@ -29,12 +28,12 @@ from chainqueue.sql.state import (
         set_rejected,
         )
 from chainqueue.sql.tx import cache_tx_dict
-from chainqueue.encode import TxHexNormalizer
+from chainqueue.backend import Backend
 
 logg = logging.getLogger(__name__)
 
 
-class SQLBackend:
+class SQLBackend(Backend):
     """SQL flavor of the chainqueue backend implementation.
 
     :param conn_spec: Backend-dependent connection specification string. See chainqueue.db.models.base.SessionBase.connect
@@ -47,16 +46,10 @@ class SQLBackend:
     :type pool_size: int
     :param debug: Activate SQL engine level debug. See chainqueue.db.models.base.SessionBase.connect
     :type debug: bool
-    :todo: define a backend abstract interface class
     """
     def __init__(self, conn_spec, tx_normalizer=None, error_parser=None, pool_size=0, debug=False, *args, **kwargs):
+        super(SQLBackend, self).__init__(tx_normalizer=tx_normalizer, error_parser=error_parser, debug=debug) 
         SessionBase.connect(conn_spec, pool_size=pool_size, debug=debug)
-        if error_parser == None:
-            error_parser = DefaultErrorParser()
-        self.error_parser = error_parser
-        if tx_normalizer == None:
-            tx_normalizer = TxHexNormalizer()
-        self.tx_normalizer = tx_normalizer
 
 
     def create(self, chain_spec, nonce, holder_address, tx_hash, signed_tx, obsolete_predecessors=True, session=None):
diff --git a/doc/infotex/exec.texi b/doc/infotex/exec.texi
@@ -0,0 +1,6 @@
+@node chainqueue-executable
+@section Executables
+
+Chainqueue only provides a single executable. This executable lists items in queue based on given criteria. The available criteria more or less map to the arguments offered by @code{chainqueue.backend.Backend.get}.
+
+When installing @code{chainqueue} as a python package, the list tool will be available in @code{PATH} as the command @file{chainqueue-list}.
diff --git a/doc/infotex/index.texi b/doc/infotex/index.texi
@@ -4,3 +4,5 @@
 
 @include tx.texi
 @include state.texi
+@include stack.texi
+@include exec.texi
diff --git a/doc/infotex/stack.texi b/doc/infotex/stack.texi
@@ -0,0 +1,58 @@
+@node chainqueue-architecture
+@section State storage
+
+Chainqueue enables separate implementations of the state storage layer backend.
+
+Included in the package are state storage for sql using the SQLAlchemy dependency, as well as state using native filesystem backend (without any additional dependencies).
+
+The backend interface is defined in the @code{chainqueue.backend} module. It provides the following methods:
+
+@itemize
+@item Create a new queue item
+@item Add cached data to queue item
+@item Get a single queue item
+@item Get multiple queue items based on given criteria
+@item Dispatch a queue item to the network
+@item Connect / disconnect to backend
+@end itemize
+
+
+@subsection SQL backend
+
+This backend is Contained in the module @code{chainqueue.sql.backend.SQLBackend}. It translates high-level calls to invididual method calls in the query, state and tx submodules of @code{chainqueue.sql.backend}.
+
+The @code{SQLBackend} object should provide all methods required to make practical use of the chainqueue package. However, all other modules in @code{chainqueue.sql} are also intended for public consumption.
+
+The @code{chainqueue.sql.backend} in turn calls methods in the SQLAlchemy database model layer in @code{chainqueue.db.models}. The consumer is not intended to interface directly with @code{chainqueue.db.models}.
+
+
+@subsection Filesystem backend
+
+The filesystem state storage is provided by the @code{chainqueue.fs} module. is at the moment missing the @code{chainqueue.backend.Backend} implementation. Please refer to the code in @file{tests/tests_fs*.py} to learn how to use in its current state.
+
+
+@section Adapters
+
+The adapter layer enables chain specific code to be combined with an arbitrary storage backend. Typically, chain specific code is required to:
+
+@itemize
+@item Translate transaction wire format to generic transaction representation
+@item Send transactions to the network
+@end itemize
+
+The adapter consumes a backend, and delegates calls to it as required.
+
+Since adapters are chain specific, @code{chainqueue} only provides a base class that must be extended the chain implementer code. Specifically, the methods to extend are:
+
+@table @code
+@item Add
+Add a transaction to the queue
+@item Upcoming
+Get queued transactions ready to be sent to network
+@item Dispatch
+Send a queued transaction to the network
+@item Translate
+Decode details of a transaction
+@item Create_session, release_session
+Session management to control queue state integrity
+@end table
diff --git a/setup.cfg b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = chainqueue
-version = 0.0.4a8
+version = 0.0.5a1
 description = Generic blockchain transaction queue control
 author = Louis Holbrook
 author_email = dev@holbrook.no