More docs, include backend 'abstract' interface

This commit is contained in:
nolash 2021-08-29 10:15:37 +02:00
parent c85851f370
commit 28e7842f4d
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
6 changed files with 210 additions and 11 deletions

140
chainqueue/backend.py Normal file
View File

@ -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()

View File

@ -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):

6
doc/infotex/exec.texi Normal file
View File

@ -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}.

View File

@ -4,3 +4,5 @@
@include tx.texi
@include state.texi
@include stack.texi
@include exec.texi

58
doc/infotex/stack.texi Normal file
View File

@ -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

View File

@ -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