Skip to content

Commit

Permalink
feat(cat-gateway): Chain sync V2 - part 2 (#836)
Browse files Browse the repository at this point in the history
* fix(docs): Fix up docs issues

* fix(backend): Huge refactor to prep for scylladb config management

* fix(backend): Clean up logging a little, and add build info logs as required for production.

* Refactor and setup cassandra config/session

* feat(backend): Index DB schema setup seems to work

* WIP

* fix(rust): Format fixes

* fix(rust): Build fixes

* fix(rust): Adjust index DB so we can index without querying, and can optimize on first detected spend.

* fix(rust): add more docs

* fix(rust): basic new follower integration

* fix(rust): wip

* fix(ci): Bump rust compiler version to match CI

* ci(backend): Bump rust version to match CI

* fix(backend): Fix code format and lints

* feat(backend): simple new block indexer just to test the logic works

* feat(gateway): Simple indexing with cassandra seems to work

* refactor(backend): Remove lazy and once_cell in favor of new standard library replacements

* fix(backend): WIP indexing for stake addresses and unstaked ada

* fix(backend): indexing WIP

* fix(backend): Add support for log control with env vars, default to mainnet, adjust `justfile` to properly select preprod and also refresh git dependencies.

* feat(backend): Make local test scylla db run with 4 nodes, not 1

* fix(backend-lib): Add stop for cassandra db cluster

* refactor(backend-lib): Remove c509-certificate because its moved to catalyst-libs

* fix(backend): Remove dependencies from Workspace, and move into project

* fix(backend): Use temporary cat-ci branch for rust builders

* fix(backend): Remove obsolete common crates subdirectory

* fix(backend): Don't use pre-packaged mithril snapshots in integration tests

* fix(backend): Fix code so it builds with latest chain follower code.

Also eliminates redundant logic now incorporated into chain follower.

* fix(backend): Fix broken reference to catalyst libs

* ci(ci): Bump all earthfiles to latest WIP cat-ci branch

* fix(frontend-pkg): Ignore .dart_tool directory in frontend files checking markdown

* fix(ci): Fix spelling

* fix(spelling): Add more project words and properly sort list

* fix(backend): Sync rust configs and add target to make it easier in future

* fix(backend): Enable all features of Scylla for now.

* fix(frontend-pkg): Fix markdown table having too many columns

* ci(spelling): Fix spelling issues

* fix(docs): Bump docs to latest WIP cat-ci version

* feat(gateway): Add low resource scylla db instance for local testing

* feat(gateway): Add and update developer convenience functions for backend

* fix(backend): Fix code format

* fix(backend): Fix spelling issues in CQL files

* fix(spelling): Remove duplicates from the project words dictionary

* fix(backend): Get the backend building properly with earthly.

* feat(backend): remove obsoleted postgres logic for chain indexing

* revert(event-db): Revert extension changes to sql files after fixing sqlfluff version

* fix(frontend): Regenerate the dart api interface file, and add doing that to the pre-push just command

* fix(backend): temporarily disable API tests

* fix(backend): Also temporarily stop workflow consuming test reports that are disabled

* fix(ci): Try and stop coveralls running for api-tests

* ci(general): Replace temp CI branch with tagged release

* feat: Add Handler for Permissionless Auth (#825)

* docs(cips): Add Formal Defintion of auth token

* fix(docs): Fix comments in cddl file

* fix(docs): sig size

* fix(docs): Rename CDDL for the auth token

* docs(docs): Add auth-header documentation

* docs(docs): Fix markdown line length error

* docs(general): Fix spelling

* fix(backend-lib): Bump to catalyst-libs tagged version

* fix(backend): stub out obsolete code (to be removed in follow up PR).

* fix(backend-lib): code format

* fix(backend): remove unused crate dependencies

* feat: auth token (#723)

* feat(auth token encode and decode): permissionless auth

* feat(auth token encode and decode): permissionless auth

* feat(auth token encode and decode): permissionless auth

* feat(auth token encode and decode): permissionless auth

* feat(auth token encode and decode): permissionless auth

* iron out tests

* iron out tests

* refactor(auth token encode and decode): ed25519 Signature cbor fields

Sig over the preceding two fields - sig(cbor(kid), cbor(ulid))

* refactor(auth token encode and decode): ed25519 Signature cbor fields

Sig over the preceding two fields - sig(cbor(kid), cbor(ulid))

* feat(cat security scheme): open api

* feat(cat security scheme): open api

* feat(mock cert state): given kid from bearer return pub key

* feat(auth token): cache TTL

* feat(auth token): cache TTL

* feat(auth token): cache TT

* ci(spell check): fix

* ci(spell check): fix

* ci(spell check): fix

* refactor(clippy): housekeeping tidy

* refactor(clippy): housekeeping tidy

* refactor(clippy): housekeeping tidy

* refactor(clippy): housekeeping tidy

* fix(backend): Re-enable dependent crates used by this code

* fix(backend): clippy lints

* fix(backend): spelling

---------

Co-authored-by: Steven Johnson <[email protected]>
Co-authored-by: Steven Johnson <[email protected]>

* feat: Update GET staked_ada endpoint to fetch from ScyllaDB (#728)

* feat: get staked ada from scylladb

* chore: revert justfile changes

* chore: filter TXOs in rust instead of filtering in ScyllaDB query

* fix(backend): spelling

* fix(backend): Eliminate lint errors from Derived function

* fix(backend): code format

* fix(backend): Udate autogenerated dart code

* chore(cat-voices): fix tests

---------

Co-authored-by: Steven Johnson <[email protected]>
Co-authored-by: Steven Johnson <[email protected]>
Co-authored-by: Dominik Toton <[email protected]>

* feat: DB Indexing for  CIP-36 registrations (#788)

* feat: add schema for cip-36 registration tables

* feat: index cip-36 by stake address

* feat: index cip-36 registrations by vote key

* fix: use TxiInserParams::new when adding txi data

* fix: remove unused cfg attributes

* fix: refactor Cip36RegistrationInsertQuery::new

* fix(backend): Refactor queries and add multiple tables for cip36 registration indexes

* fix(backend): Cip36 Primary key is stake key. Stake Key N->1 Vote Key

* fix(backend): code format

---------

Co-authored-by: Steven Johnson <[email protected]>
Co-authored-by: Steven Johnson <[email protected]>

* docs(general): Cleanup project dictionary

* docs(spelling): Fix spelling

* fix(backend): remove obsolete clippy lint cfg

* docs(backend): Improve field documentation so its not ambiguous.

* docs(backend): Fix comment

* docs(backend): Improve comment

* fix(backend): Vote Key index logic, and update comments

* fix(backend): Earthfile needs to be executed from root of repo, to properly pick up secrets

* fix(backend): make generic saturating value converter and use it instead of type specific ones

* test(cat-gateway): Add tests for float conversion and better docs about functions limitations.

* fix(cat-gateway): Developer lints in release mode, and also refer to correct local release binary

* fix(cat-gateway): CIP36 index schema error

* fix(cat-gateway): Cip36 indexing working, improve bad cassandra query reporting.

---------

Co-authored-by: cong-or <[email protected]>
Co-authored-by: Felipe Rosa <[email protected]>
Co-authored-by: Dominik Toton <[email protected]>
Co-authored-by: Joaquín Rosales <[email protected]>
  • Loading branch information
5 people authored Sep 21, 2024
1 parent 05c5c9c commit b96002e
Show file tree
Hide file tree
Showing 24 changed files with 169 additions and 121 deletions.
16 changes: 8 additions & 8 deletions catalyst-gateway/Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ code-format:

# Lint the rust code
code-lint:
cargo lintfix
cargo lint
cargo lintfix -r
cargo lint -r

# Synchronize Rust Configs
sync-cfg:
earthly +sync-cfg
cd .. && earthly ./catalyst-gateway+sync-cfg

# Pre Push Checks
pre-push: sync-cfg code-format code-lint license-check
# Make sure we can actually build inside Earthly which needs to happen in CI.
earthly +check
earthly +build
earthly +package-cat-gateway
cd .. && earthly ./catalyst-gateway+check
cd .. && earthly ./catalyst-gateway+build
cd .. && earthly ./catalyst-gateway+package-cat-gateway

# Build Local release build of catalyst gateway
build-cat-gateway: code-format code-lint
Expand All @@ -46,10 +46,10 @@ run-cat-gateway: build-cat-gateway
CHAIN_FOLLOWER_SYNC_TASKS="16" \
RUST_LOG="error,cat-gateway=debug,cardano_chain_follower=debug,mithril-client=debug" \
CHAIN_NETWORK="Preprod" \
./catalyst-gateway/target/release/cat-gateway run --log-level debug
./target/release/cat-gateway run --log-level debug

# Run cat-gateway natively on mainnet
run-cat-gateway-mainnet: build-cat-gateway
CHAIN_FOLLOWER_SYNC_TASKS="1" \
RUST_LOG="error,cat-gateway=debug,cardano_chain_follower=debug,mithril-client=debug" \
./catalyst-gateway/target/release/cat-gateway run --log-level debug
./target/release/cat-gateway run --log-level debug
2 changes: 1 addition & 1 deletion catalyst-gateway/bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ build-info = "0.0.38"
ed25519-dalek = "2.1.1"
scylla = { version = "0.14.0", features = ["cloud", "full-serialization"] }
strum = { version = "0.26.3", features = ["derive"] }
# strum_macros = "0.26.4"
strum_macros = "0.26.4"
openssl = { version = "0.10.66", features = ["vendored"] }
num-bigint = "0.4.6"
futures = "0.3.30"
Expand Down
38 changes: 35 additions & 3 deletions catalyst-gateway/bin/src/db/index/block/certs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Index certs found in a transaction.
use std::sync::Arc;
use std::{fmt::Debug, sync::Arc};

use cardano_chain_follower::MultiEraBlock;
use pallas::ledger::primitives::{alonzo, conway};
Expand All @@ -12,7 +12,7 @@ use crate::{
queries::{FallibleQueryTasks, PreparedQueries, PreparedQuery, SizedBatch},
session::CassandraSession,
},
service::utilities::convert::u16_from_saturating,
service::utilities::convert::from_saturating,
settings::CassandraEnvVars,
};

Expand All @@ -37,6 +37,38 @@ pub(crate) struct StakeRegistrationInsertQuery {
pool_delegation: MaybeUnset<Vec<u8>>,
}

impl Debug for StakeRegistrationInsertQuery {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
let stake_address = match self.stake_address {
MaybeUnset::Unset => "UNSET",
MaybeUnset::Set(ref v) => &hex::encode(v),
};
let register = match self.register {
MaybeUnset::Unset => "UNSET",
MaybeUnset::Set(v) => &format!("{v:?}"),
};
let deregister = match self.deregister {
MaybeUnset::Unset => "UNSET",
MaybeUnset::Set(v) => &format!("{v:?}"),
};
let pool_delegation = match self.pool_delegation {
MaybeUnset::Unset => "UNSET",
MaybeUnset::Set(ref v) => &hex::encode(v),
};

f.debug_struct("StakeRegistrationInsertQuery")
.field("stake_hash", &hex::encode(hex::encode(&self.stake_hash)))
.field("slot_no", &self.slot_no)
.field("txn", &self.txn)
.field("stake_address", &stake_address)
.field("script", &self.script)
.field("register", &register)
.field("deregister", &deregister)
.field("pool_delegation", &pool_delegation)
.finish()
}
}

/// TXI by Txn hash Index
const INSERT_STAKE_REGISTRATION_QUERY: &str = include_str!("./cql/insert_stake_registration.cql");

Expand Down Expand Up @@ -130,7 +162,7 @@ impl CertInsertQuery {
let (key_hash, pubkey, script) = match cred {
pallas::ledger::primitives::conway::StakeCredential::AddrKeyhash(cred) => {
let addr = block
.witness_for_tx(cred, u16_from_saturating(txn))
.witness_for_tx(cred, from_saturating(txn))
.unwrap_or(default_addr);
// Note: it is totally possible for the Registration Certificate to not be
// witnessed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ INSERT INTO cip36_registration (
payment_address,
is_payable,
raw_nonce,
cip36,
cip36
) VALUES (
:stake_address,
:nonce,
Expand All @@ -18,5 +18,5 @@ INSERT INTO cip36_registration (
:payment_address,
:is_payable,
:raw_nonce,
:cip36,
:cip36
);
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
-- Index CIP-36 Registration (Valid)
INSERT INTO cip36_registration_for_stake_addr (
-- Index CIP-36 Registration (For each Vote Key)
INSERT INTO cip36_registration_for_vote_key (
vote_key,
stake_address,
slot_no,
txn,
valid,
valid
) VALUES (
:vote_key,
:stake_address,
:slot_no,
:txn,
:valid,
:valid
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ INSERT INTO cip36_registration_invalid (
nonce,
cip36,
signed,
error_report,
error_report
) VALUES (
:stake_address,
:slot_no,
Expand Down
22 changes: 21 additions & 1 deletion catalyst-gateway/bin/src/db/index/block/cip36/insert_cip36.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Insert CIP36 Registration Query
use std::sync::Arc;
use std::{fmt::Debug, sync::Arc};

use cardano_chain_follower::Metadata::cip36::{Cip36, VotingPubKey};
use scylla::{frame::value::MaybeUnset, SerializeRow, Session};
Expand Down Expand Up @@ -37,6 +37,26 @@ pub(super) struct Params {
cip36: bool,
}

impl Debug for Params {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let payment_address = match self.payment_address {
MaybeUnset::Unset => "UNSET",
MaybeUnset::Set(ref v) => &hex::encode(v),
};
f.debug_struct("Params")
.field("stake_address", &self.stake_address)
.field("nonce", &self.nonce)
.field("slot_no", &self.slot_no)
.field("txn", &self.txn)
.field("vote_key", &self.vote_key)
.field("payment_address", &payment_address)
.field("is_payable", &self.is_payable)
.field("raw_nonce", &self.raw_nonce)
.field("cip36", &self.cip36)
.finish()
}
}

impl Params {
/// Create a new Insert Query.
pub fn new(vote_key: &VotingPubKey, slot_no: u64, txn: i16, cip36: &Cip36) -> Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const INSERT_CIP36_REGISTRATION_FOR_VOTE_KEY_QUERY: &str =
include_str!("./cql/insert_cip36_for_vote_key.cql");

/// Insert CIP-36 Registration Invalid Query Parameters
#[derive(SerializeRow, Clone)]
#[derive(SerializeRow, Debug)]
pub(super) struct Params {
/// Voting Public Key
vote_key: Vec<u8>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Insert CIP36 Registration Query (Invalid Records)
use std::sync::Arc;
use std::{fmt::Debug, sync::Arc};

use cardano_chain_follower::Metadata::cip36::{Cip36, VotingPubKey};
use scylla::{frame::value::MaybeUnset, SerializeRow, Session};
Expand Down Expand Up @@ -42,6 +42,28 @@ pub(super) struct Params {
error_report: Vec<String>,
}

impl Debug for Params {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let cip36 = match self.cip36 {
MaybeUnset::Unset => "UNSET",
MaybeUnset::Set(v) => &format!("{v:?}"),
};
f.debug_struct("Params")
.field("stake_address", &self.stake_address)
.field("slot_no", &self.slot_no)
.field("txn", &self.txn)
.field("vote_key", &self.vote_key)
.field("payment_address", &self.payment_address)
.field("is_payable", &self.is_payable)
.field("raw_nonce", &self.raw_nonce)
.field("nonce", &self.nonce)
.field("cip36", &cip36)
.field("signed", &self.signed)
.field("error_report", &self.error_report)
.finish()
}
}

impl Params {
/// Create a new Insert Query.
pub fn new(
Expand Down
3 changes: 2 additions & 1 deletion catalyst-gateway/bin/src/db/index/block/cip36/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ impl Cip36InsertQuery {
vote_key, slot_no, txn_index, cip36, true,
));
}
} else {
} else if cip36.stake_pk.is_some() {
// We can't index an error, if there is no stake public key.
if cip36.voting_keys.is_empty() {
self.invalid.push(insert_cip36_invalid::Params::new(
None,
Expand Down
4 changes: 2 additions & 2 deletions catalyst-gateway/bin/src/db/index/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use txi::TxiInsertQuery;
use txo::TxoInsertQuery;

use super::{queries::FallibleQueryTasks, session::CassandraSession};
use crate::service::utilities::convert::i16_from_saturating;
use crate::service::utilities::convert::from_saturating;

/// Add all data needed from the block into the indexes.
pub(crate) async fn index_block(block: &MultiEraBlock) -> anyhow::Result<()> {
Expand All @@ -34,7 +34,7 @@ pub(crate) async fn index_block(block: &MultiEraBlock) -> anyhow::Result<()> {

// We add all transactions in the block to their respective index data sets.
for (txn_index, txs) in block_data.txs().iter().enumerate() {
let txn = i16_from_saturating(txn_index);
let txn = from_saturating(txn_index);

let txn_hash = txs.hash().to_vec();

Expand Down
2 changes: 1 addition & 1 deletion catalyst-gateway/bin/src/db/index/block/txi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
};

/// Insert TXI Query and Parameters
#[derive(SerializeRow)]
#[derive(SerializeRow, Debug)]
pub(crate) struct TxiInsertParams {
/// Spent Transactions Hash
txn_hash: Vec<u8>,
Expand Down
2 changes: 1 addition & 1 deletion catalyst-gateway/bin/src/db/index/block/txo/insert_txo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const INSERT_TXO_QUERY: &str = include_str!("./cql/insert_txo.cql");

/// Insert TXO Query Parameters
/// (Superset of data to support both Staked and Unstaked TXO records.)
#[derive(SerializeRow)]
#[derive(SerializeRow, Debug)]
pub(super) struct Params {
/// Stake Address - Binary 28 bytes. 0 bytes = not staked.
stake_address: Vec<u8>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const INSERT_TXO_ASSET_QUERY: &str = include_str!("./cql/insert_txo_asset.cql");

/// Insert TXO Asset Query Parameters
/// (Superset of data to support both Staked and Unstaked TXO records.)
#[derive(SerializeRow)]
#[derive(SerializeRow, Debug)]
pub(super) struct Params {
/// Stake Address - Binary 28 bytes. 0 bytes = not staked.
stake_address: Vec<u8>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const INSERT_UNSTAKED_TXO_QUERY: &str = include_str!("./cql/insert_unstaked_txo.

/// Insert TXO Unstaked Query Parameters
/// (Superset of data to support both Staked and Unstaked TXO records.)
#[derive(SerializeRow)]
#[derive(SerializeRow, Debug)]
pub(super) struct Params {
/// Transactions hash.
txn_hash: Vec<u8>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const INSERT_UNSTAKED_TXO_ASSET_QUERY: &str = include_str!("./cql/insert_unstake

/// Insert TXO Asset Query Parameters
/// (Superset of data to support both Staked and Unstaked TXO records.)
#[derive(SerializeRow)]
#[derive(SerializeRow, Debug)]
pub(super) struct Params {
/// Transactions hash.
txn_hash: Vec<u8>,
Expand Down
4 changes: 2 additions & 2 deletions catalyst-gateway/bin/src/db/index/block/txo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
queries::{FallibleQueryTasks, PreparedQuery, SizedBatch},
session::CassandraSession,
},
service::utilities::convert::i16_from_saturating,
service::utilities::convert::from_saturating,
settings::CassandraEnvVars,
};

Expand Down Expand Up @@ -150,7 +150,7 @@ impl TxoInsertQuery {
};

let staked = stake_address != NO_STAKE_ADDRESS;
let txo_index = i16_from_saturating(txo_index);
let txo_index = from_saturating(txo_index);

if staked {
let params = insert_txo::Params::new(
Expand Down
16 changes: 11 additions & 5 deletions catalyst-gateway/bin/src/db/index/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
pub(crate) mod staked_ada;

use std::sync::Arc;
use std::{fmt::Debug, sync::Arc};

use anyhow::bail;
use anyhow::{bail, Context};
use crossbeam_skiplist::SkipMap;
use scylla::{
batch::Batch, prepared_statement::PreparedStatement, serialize::row::SerializeRow,
Expand All @@ -26,7 +26,8 @@ use crate::settings::{CassandraEnvVars, CASSANDRA_MIN_BATCH_SIZE};
pub(crate) type SizedBatch = SkipMap<u16, Arc<Batch>>;

/// All Prepared Queries that we know about.
#[allow(clippy::enum_variant_names, dead_code)]
#[derive(strum_macros::Display)]
#[allow(clippy::enum_variant_names)]
pub(crate) enum PreparedQuery {
/// TXO Insert query.
TxoAdaInsertQuery,
Expand Down Expand Up @@ -206,7 +207,7 @@ impl PreparedQueries {
///
/// This will divide the batch into optimal sized chunks and execute them until all
/// values have been executed or the first error is encountered.
pub(crate) async fn execute_batch<T: SerializeRow>(
pub(crate) async fn execute_batch<T: SerializeRow + Debug>(
&self, session: Arc<Session>, cfg: Arc<CassandraEnvVars>, query: PreparedQuery,
values: Vec<T>,
) -> FallibleQueryResults {
Expand Down Expand Up @@ -238,7 +239,12 @@ impl PreparedQueries {
bail!("No batch query found for size {}", chunk_size);
};
let batch_query_statements = batch_query.value().clone();
results.push(session.batch(&batch_query_statements, chunk).await?);
results.push(
session
.batch(&batch_query_statements, chunk)
.await
.context(format!("query={query}, chunk={chunk:?}"))?,
);
}

Ok(results)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
const UPDATE_TXO_SPENT_QUERY: &str = include_str!("../cql/update_txo_spent.cql");

/// Update TXO spent query params.
#[derive(SerializeRow)]
#[derive(SerializeRow, Debug)]
pub(crate) struct UpdateTxoSpentQueryParams {
/// TXO stake address.
pub stake_address: Vec<u8>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ CREATE TABLE IF NOT EXISTS cip36_registration (

PRIMARY KEY (stake_address, nonce, slot_no, txn)
)
WITH CLUSTERING ORDER BY (nonce, DESC, slot_no DESC, txn DESC);
WITH CLUSTERING ORDER BY (nonce DESC, slot_no DESC, txn DESC);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Index of CIP-36 registrations searchable by Stake Address.
-- Full registration data needs to be queried from the man cip36 registration tables.
-- Includes both Valid and Invalid registrations.
CREATE TABLE IF NOT EXISTS cip36_registration_for_stake_addr (
CREATE TABLE IF NOT EXISTS cip36_registration_for_vote_key (
-- Primary Key Data
vote_key blob, -- 32 Bytes of Vote Key.
stake_address blob, -- 32 Bytes of Stake Address.
Expand Down
Loading

0 comments on commit b96002e

Please sign in to comment.