chainlib

Generic blockchain access library and tooling
Log | Files | Refs | README | LICENSE

commit b88758e48e4e916af3119f2de248d1222505d29c
parent 7d323dd62f5e390f8b603b5ad8f3fdb1cb8176bd
Author: nolash <dev@holbrook.no>
Date:   Thu,  9 Sep 2021 14:13:38 +0200

Add missing encode mod, texi doc files

Diffstat:
Achainlib/encode.py | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/texinfo/cli.texi | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/texinfo/code.texi | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/texinfo/config.texi | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/texinfo/confini.texi | 0
Adoc/texinfo/intro.texi | 16++++++++++++++++
6 files changed, 421 insertions(+), 0 deletions(-)

diff --git a/chainlib/encode.py b/chainlib/encode.py @@ -0,0 +1,49 @@ +# standard imports +import logging + +# external imports +from hexathon import ( + add_0x, + strip_0x, + uniform as hex_uniform, + ) + +logg = logging.getLogger() + + +class TxHexNormalizer: + + def tx_hash(self, tx_hash): + return self.__hex_normalize(tx_hash, 'tx hash') + + + def tx_wire(self, tx_wire): + return self.__hex_normalize(tx_wire, 'tx wire') + + + def wallet_address(self, address): + return self.__hex_normalize(address, 'wallet address') + + + def executable_address(self, address): + return self.__hex_normalize(address, 'executable address') + + + def __hex_normalize(self, data, context): + #r = add_0x(hex_uniform(strip_0x(data))) + r = hex_uniform(strip_0x(data)) + logg.debug('normalize {} {} -> {}'.format(context, data, r)) + return r + + +class NoopNormalize: + + def __init__(self): + self.tx_hash = self.__noop + self.tx_wire = self.__noop + self.wallet_address = self.__noop + self.executable_address = self.__noop + + + def __noop(self, data): + return data diff --git a/doc/texinfo/cli.texi b/doc/texinfo/cli.texi @@ -0,0 +1,164 @@ +@node chainlib-cli + +@section Command line interface provisions + +The base CLI provisions of @code{chainlib} simplifies the generation of a some base object instances by command line arguments, environment variables and configuration schemas. + +To use CLI provisions, @code{chainlib.cli} should be imported. This automatically imports the following submodules: + +@table @code +@item arg +Define and/or select command-line arguments +@item config +Process configuration from command-line arguments and environment variables +@item rpc +Create RPC connection from configuration +@item wallet +Create wallet from configuration +@end table + +Any chain implementation building on @code{chainlib} should extend one or more of the classes in these modules as needed, for example order to add more configuration directives or command line argument flags. + + +@subsection Arguments + +@code{chainlib} defines a set of arguments that are common concepts for interfacing with blockchain RPCs. Which arguments to use for a specific instantiation can be defined using flags or symbols that define groups of flags. + +This functionality is provided by the @code{chainlib.cli.args.ArgumentParser} class. It is a thin wrapper around the standard library @code{argparser.ArgumentParser} class, only adding a method to add arguments to the instance based on the aforementioned flags. + +Following is a description of all pre-defined arguments that are available with @code{chainlib}. + + +@subsubsection -c, --config + +Override configuration directives by reading ini-files in the given directory. + +Only configuration directives defined in the schema may be overridden. @xref{chainlib-config}. + + +@subsubsection --env-prefix + +Prepend the given string to configuration directives when overriding by environment variables + +Normally, if a configuration directive @code{FOO_BAR} exists, the environment variable @code{FOO_BAR} will override its value. If @code{--env-prefix BAZ} is passed, the environment variable @code{BAZ_FOO_BAR} will be used instead to override the configuration directive @code{FOO_BAR}. The environment variable @code{FOO_BAR} will in this case @emph{not} be used. + + +@subsubsection --height + +Query the chain RPC for results at a specific block height. + +Applies to @emph{read} operations only. + + +@subsubsection -i, --chain-spec + +Chain specification string for the blockchain connection. + +This informs the implementing code about the architecture and deployment of the blockchain network. It can also be relevant when creating signatures for the network (e.g. the EIP155 signature scheme for EVM). + +@subsubsection --fee-limit + +Use the exact given fee multiplier to calculate the final bid to get transaction executed on the network. + +How the fee semantics are employed depend on the chain implementation, but the final resulting bid @emph{must always} be the product of @code{price * limit}. + +If @emph{not} defined, the multiplier will be retrieved using the fees provider defined by the implementation. + + +@subsubsection --fee-price + +Use the exact given fee price as factor to calculate bid to get transaction executed on the network. + +How the fee semantics are employed depend on the chain implementation, but the final resulting bid @emph{must always} be the product of @code{price * limit}. + +If @emph{not} defined, the current recommended price will be retrieved from the fees provider defined by the implementation. + + +@subsubsection -n, --namespace + +Append the given namespace to implicit configuration override paths. + +For example, if linux xdg-basedir path is used, a namespace argument of @code{foo} in implementation domain @code{bar} will result in the configuration override path @code{$HOME/.config/bar/foo}. + + +@subsubsection --nonce + +Start at the exact given nonce for the query. + +If @emph{not} defined, the next nonce will be retrieved from the nonce provider defined by the implementation. + + +@subsubsection -p, --provider + +URL of the chain RPC provider. + + +@subsubsection -s, --send + +CLI tools building on chainlib should @emph{never} submit to the network by default. Instead, resulting transactions ready for network submission should be output to terminal. + +If the implementation wishes to allow the user to directly send to the network, the @code{-s} flag @emph{must} be used for this purpose. + + +@subsubsection --seq + +By default, a random RPC id will be generated for every RPC call. + +However, some RPCs will only allow sequential serial numbers to be used as RPC ids, in which case this flag should be used. + + +@subsubsection --raw + +Generate output suitable for passing to another command (e.g. UNIX pipes). + + +@subsubsection --rpc-auth + +Tells the implementer which RPC authentication scheme to use (e.g. "basic" for http basic). + + +@subsubsection --rpc-credentials + +Tells the implemented wich RPC authentication credentials to use for selected rpc authentication scheme (e.g. "foo:bar" for user foo pass bar in scheme "basic" a.k.a. http basic). + +Credentials may for example also be a single value, like a private key, depending on the scheme and implementation. + + +@subsubsection --rpc-dialect + +Tells the implementer to optimize query, result and error reporting for the specific chain RPC backend dialect. + + +@subsubsection -u, --unsafe + +Allow arguments with blockchain addresses that are not checksum protected. + + +@subsubsection -v, -vv + +Defines logging verbosity. + +Specifically, @code{-v} will set loglevel to @code{INFO}, wheres @code{-vv} will set loglevel to @code{DEBUG}. + +Default loglevel is up to the implementer, but it is advisable to keep it at @code{WARNING}. + + +@subsubsection -w, -ww + +Toggles blocking in relation to chain RPC calls. + +If @code{-w} is set, the implementer should only block to obtain the result of the @emph{last, and as few as possible preceding} RPC transactions. + +If @code{-ww} is set, the implementer should block to retrieve the results of @emph{all} of the preceding RPC transactions. + +If the implementation consists of a single transaction, the effect of @code{-w} and @code{-ww} will always be the same. Nonetheless, the implementation will be forced to provide both arguments. + +If neither flag is set, the typical consequence is that the network transaction hash of the last transaction will be returned. + + +@subsubsection -y, --key-file + +Read private key from the given key file. + + + diff --git a/doc/texinfo/code.texi b/doc/texinfo/code.texi @@ -0,0 +1,91 @@ +@node chainlib-lib + +@section Base library contents + + +@subsection Pluggable method interface + +The base chainlib blockchain interface is defined by the @code{chainlib.interface.ChainInterface class}. All of the methods in this class are unimplemented. Together they make up the methods necessary to interface with @emph{any} blockchain RPC. + +It is up to the implemenenter to choose which of the methods that are needed in any particular context. The implementer would then connect the method symbols with actual code. + +Most methods in this class will return objects that can be passed to an RPC connection that fits the block context. + +The available methods are: + +@table @code +@item block_latest +Retrieve the latest block from the network +@item block_by_hash +Retrieve the block corresponding to the given block hash +@item block_by_number +Retrieve the block corresponding to the given block number +@item block_from_src +Render a chainlib.block.Block derivative object from an architecture-dependent block representation source +@item block_to_src +Render an architecture dependent transaction representation from the given Block object +@item tx_by_hash +Retrieve the transaction corresponding to the given transaction hash +@item tx_by_block +Retrieve the transaction corresponding to the given block hash and transaction index +@item tx_receipt +Retrieve the details of a confirmed transaction +@item tx_raw +Generate an RPC query from raw transaction wire data +@item tx_pack +Generate raw transaction wire data from an architecture dependent transaction representation +@item tx_unpack +Generate architecture dependent transaction representation from raw transaction wire data +@item tx_from_src +Render a chainlib.tx.Tx derivative object from an architecture-dependent tx representation source +@item tx_to_src +Render an architecture dependent transaction representation from the given Tx object +@item address_safe +Generate a checksum-safe network address +@item address_normal +Generate an unambiguous network address +@item src_normalize +Generate an unambiguous dictionary from the given dictionary. For example, this can mean generating camel-case key equivalents for snake-case values. +@end table + + +@subsection The RPC interface + +@code{chainlib.connection} currently has support for HTTP(S) and UNIX socket RPC connections. Both rely on the Python @emph{standard library} only (@code{urllib} and @code{socket}). + +It provides a thread-safe connection factory mechanism where connection constructor and location pairs are associated with string labels. + +There is also explicit builtin support for the JSONRPC RPC protocol, which allows for a pluggable error translater that can be customized to every RPC "dialect" that needs to be supported (examples are "geth" and "openethereum" dialects of the Ethereum node fauna). Classes to handle JSONRPC results, requests and errors are defined in the @code{chainlib.jsonrpc} module. + + +@subsection Blocks and transactions + +Common block and transaction concepts are represented by the @code{chainlib.block.Block} and @code{chainlib.tx.Tx} objects. These are very minimal base-classes that need to be extended for every blockchain implementation that is to be supported. + +When building transactions, implementations of the @code{chainlib.sign.Signer}, @code{chainlib.nonce.NonceOracle} and @code{chainlib.fee.FeeOracle} interfaces will provide the transaction factory object of the implementation with signatures, transaction nonces and transaction fee details respectively. + + +@subsection Other code features + +This section lists features that are considered outside the core of the @code{chainlib} package + + +@subsubsection RPC authenticator + +If you are relying on an RPC provider instead of running your own node (although, you know you @emph{should} run your own node, right?), then RPC authentication may be relevant. + +@code{chainlib.auth} provides two authentication mechanisms for HTTP: + +@table @code +@item BasicAuth +The HTTP basic Authorization scheme +@item CustomHeaderTokenAuth +Define an arbitrary header name and value +@end table + + +@subsubsection Fee price aggregator + +The @code{chainlib.stat.ChainStat} class provides a simple implementation of a running average aggregator for network fee prices. This can be used to generate more precise fee price heuristics that in turn can be fed to a Fee Oracle. + + diff --git a/doc/texinfo/config.texi b/doc/texinfo/config.texi @@ -0,0 +1,101 @@ +@node chainlib-config + +@section Rendering configurations + +Configurations in @code{chainlib} are processed, rendered and interfaced using the @code{confini} python package. + +In short, @code{confini} extends the functionality of Python's standard library @code{configparser} package to allow merging of directives by parsing multiple ini-files from multiple directories. + +Furthermore, it employs this same multi-file approach when defining a configuration @emph{schema}, aswell as defining source to @emph{override} the values defined in the schema. + +See @url{https://gitlab.com/nolash/python-confini} for further details on @code{confini}. + + +@subsection Configuration schema in chainlib + +The chainlib configuration schema is, along with the provided command line arguments and environment variables, designed to cover the settings necessary for most normal chain RPC operations. + + +@subsubsection Configuration mapping + +Below follows a mapping of configuration directives to command line arguments and environment variables. + +Note that any configuration directives prefixed by @code{"_"} are not defined in the configuration schema, and are not overrideable by environment variables. These are values typically are only valid within the context of a single execution of the implemented tool. + +@multitable .40 .30 .30 +@headitem arg +@tab config +@tab env +@item --- +@tab --- +@tab CONFINI_DIR @footnote{The @code{CONFINI_DIR} environment variable defines an explicit configuration @emph{schema} path. } +@item -c. --config @footnote{The @code{-c} flag defines an explicit configuration @emph{override} path.} +@tab --- +@tab --- +@item -i, --chain-spec +@tab CHAIN_SPEC +@tab CHAIN_SPEC +@item --height +@tab _HEIGHT +@tab --- +@item --fee-limit +@tab _FEE_LIMIT +@tab --- +@item --fee-price +@tab _FEE_PRICE +@tab --- +@item -n, --namespace +@tab CONFIG_USER_NAMESPACE +@tab CONFIG_USER_NAMESPACE +@item --nonce +@tab _NONCE +@tab --- +@item -p, --rpc-provider +@tab RPC_HTTP_PROVIDER +@tab RPC_HTTP_PROVIDER +@item -a, -recipient +@tab _RECIPIENT +@tab --- +@item -e, --executable-address +@tab _EXEC_ADDRESS +@tab --- +@item --rpc-auth +@tab RPC_AUTH +@tab RPC_AUTH +@item --- +@tab RPC_PROVIDER +@tab RPC_PROVIDER @footnote{RPC_PROVIDER will always be set to the same value as RPC_HTTP_PROVIDER by default.} +@item --- +@tab RPC_SCHEME +@tab RPC_SCHEME @footnote{The RPC_SCHEME configuration directive is always set to 'http' by default.} +@item --rpc-credentials +@tab RPC_CREDENTIALS +@tab RPC_CREDENTIALS +@item --rpc-dialect +@tab RPC_DIALECT +@tab RPC_DIALECT +@item -s, --send +@tab _RPC_SEND +@tab --- +@item --seq +@tab _SEQ +@tab --- +@item -u, --unsafe +@tab _UNSAFE +@tab --- +@item -w +@tab _WAIT +@tab --- +@item -ww +@tab _WAIT_ALL +@tab --- +@item -y, --key-file +@tab WALLET_KEY_FILE +@tab WALLET_KEY_FILE +@item --- @footnote{This flag is not provided because it is simply not safe to define passphrases as an argument on the command line.} +@tab WALLET_PASSPHRASE +@tab WALLET_PASSPHRASE +@end multitable + +Currently @code{chainlib} only supports HTTP(S) when building RPC connections from command line arguments and configuration. + diff --git a/doc/texinfo/confini.texi b/doc/texinfo/confini.texi diff --git a/doc/texinfo/intro.texi b/doc/texinfo/intro.texi @@ -0,0 +1,16 @@ +@node chainlib-intro + +Chainlib is an attempt at employing a universal interface to manipulate and access blockchains regardless of underlying architecture. + +It makes the following assumptions: + +@itemize +@item A block MUST have a interpretable serializable format, and contains zero of more transactions +@item A transaction MUST have a interpretable serializable format +@item A transaction MUST have a nonce associated with a sender address. This uniquely identifies the transaction on the network. +@item A transaction MUST have a fee bid to get the transaction executed on the network (a network that does not care about bids can just ignore this property). +@item A transaction signature MAY be locked to a particular chain identifier +@item The sender key of a transaction MAY be recovered by the signature of the transaction +@end itemize + +Chainlib is specifically designed for building command line interface tools. It provides templates for handling configuration, argument parsing and environment variable processing to build RPC connections to chain nodes for network queries and signing operations.