Skip to content

My suggestions for API refactoring taken from Zebra

dimxy edited this page Nov 1, 2023 · 1 revision

Here is some my suggestions for refactoring of a few issues in Komodo DeFi borrowed from Zebra project

Create Amount type instead of several used types

In Komodo DeFi several types are used for representing amounts: MmNumber, BigDecimal, f64, u64, BigRational. In comparison, in Zebra only one Amount type is used which internally stores the value as i64. For the Amount type standard Ops are defined including checked and overflowing ops. I can see ADEX's MmNumber is similar to Zebra's Amount in that both types have Ops defined.
Suggestion: I think we could use Amount-like type for all cases where value is needed. In addition, Zebra's Amount has several constraints which make amounts negative or non-negative and also allow to check the max amount. The max amount probably is not needed for the ADEX as as I can see we do not have this param.

Reversed hash representation for UTXO coins

While in original bitcoin-like daemons hashes are printed and parsed from strings in reversed mode (MSB) ADEX does not do this. This looks unusual and a bit uncomfortable as we cannot take a hash directly from daemon's log and send it to ADEX. Also, as I noticed a used Electrum API uses hashes in the 'correct' MSB mode so ADEX needs to reverse them.
Suggestion: use MSB mode when hash is parsed from string or converted to string, like daemons do As this is relevant only to UTXO coins (Eth coins use unreversed LSB representation) make a separate hash-type for UTXO coins

Use macro for error conversion

Zebra uses 'thiserror' crate which allows to use macros to auto-implement conversions from nested errors, like:

use thiserror::Error;

#[derive(Error, Debug)]
enum ErrorNested {
    #[error("error nested type 1")]
    ErrorNested1(i32),
    #[error("error nested type 2")]
    ErrorNested2(String),
}

#[derive(Error, Debug)]
enum ErrorExt {
    #[error("Error in lower code occurred")]
    ErrLowerCode(#[from] ErrorNested)
}

Could we use it too? Of course, errors should conform to some limitations and be defined with thiserror macro (for non-typical errors we can always use a custom impl). This reduce amount of boilerplate code while allows to use error types hierarchy for better management of erroneous conditions

Use tower lib for underlying service management

Zebra uses tower lib which allows to manage services it use: add timeouts and retries, manage backpressure and buffering, organise services in pools and do balancing, async exchange data via channels. F.e. a zebra node communicates with multiply peers, downloads block headers and transactions from peers, performs non-contextual block validation in threads and sends blocks to a queue for contextual validation.
I guess we could use the tower lib to connect to the electrum service and balance over connections and do retries and reconnects.