From cdcf5b60219bc586dce7891445e4ddf618f9a0ef Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Fri, 4 Aug 2023 00:47:41 -0400 Subject: [PATCH] refactor: struct StackerDB --> struct StackerDBSet --- src/net/stackerdb/db.rs | 18 ++++++++------ src/net/stackerdb/mod.rs | 44 ++++++++++++++++----------------- src/net/stackerdb/tests/bits.rs | 2 +- src/net/stackerdb/tests/db.rs | 10 ++++---- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/net/stackerdb/db.rs b/src/net/stackerdb/db.rs index 3af68aeed..8e78c9966 100644 --- a/src/net/stackerdb/db.rs +++ b/src/net/stackerdb/db.rs @@ -23,7 +23,7 @@ use std::path::Path; use crate::chainstate::stacks::address::PoxAddress; use crate::net::stackerdb::{ - SlotMetadata, StackerDB, StackerDBConfig, StackerDBTx, STACKERDB_INV_MAX, + SlotMetadata, StackerDBConfig, StackerDBSet, StackerDBTx, STACKERDB_INV_MAX, }; use crate::net::Error as net_error; use crate::net::{ @@ -165,7 +165,8 @@ fn inner_get_stackerdb_id(conn: &DBConn, smart_contract: &ContractId) -> Result< Ok(query_row(conn, sql, args)?.ok_or(net_error::NoSuchStackerDB(smart_contract.clone()))?) } -/// Load up chunk metadata from the database, given the primary key. +/// Load up chunk metadata from the database, keyed by the chunk's database's smart contract and +/// its identifier. /// Inner method body for related methods in both the DB instance and the transaction instance. fn inner_get_slot_metadata( conn: &DBConn, @@ -178,7 +179,8 @@ fn inner_get_slot_metadata( query_row(conn, &sql, args).map_err(|e| e.into()) } -/// Load up validation information from the database, given the primary key +/// Load up validation information from the database, keyed by the chunk's database's smart +/// contract and its identifier. /// Inner method body for related methods in both the DB instance and the transaction instance. fn inner_get_slot_validation( conn: &DBConn, @@ -370,9 +372,9 @@ impl<'a> StackerDBTx<'a> { } } -impl StackerDB { +impl StackerDBSet { /// Instantiate the DB - fn instantiate(path: &str, readwrite: bool) -> Result { + fn instantiate(path: &str, readwrite: bool) -> Result { let mut create_flag = false; let open_flags = if path != ":memory:" { @@ -411,7 +413,7 @@ impl StackerDB { }; let conn = sqlite_open(path, open_flags, true)?; - let mut db = StackerDB { conn }; + let mut db = StackerDBSet { conn }; if create_flag { let db_tx = db.tx_begin(StackerDBConfig::noop())?; @@ -426,12 +428,12 @@ impl StackerDB { /// Connect to a stacker DB, creating it if it doesn't exist and if readwrite is true. /// Readwrite is enforced by the underling sqlite connection. - pub fn connect(path: &str, readwrite: bool) -> Result { + pub fn connect(path: &str, readwrite: bool) -> Result { Self::instantiate(path, readwrite) } #[cfg(test)] - pub fn connect_memory() -> StackerDB { + pub fn connect_memory() -> StackerDBSet { Self::instantiate(":memory:", true).unwrap() } diff --git a/src/net/stackerdb/mod.rs b/src/net/stackerdb/mod.rs index e6fb77c88..e2c0dcc14 100644 --- a/src/net/stackerdb/mod.rs +++ b/src/net/stackerdb/mod.rs @@ -19,7 +19,7 @@ /// A StackerDB is a best-effort replicated database controlled by a smart contract, which Stacks /// node operators can opt-in to hosting. Unlike a smart contract's data space, a StackerDB's /// data is not consensus-critical -- nodes do not need to read its state to validate the -/// blockchain. Instead, developers use StackerDBs to host and replicate auxiliary smart contract +/// blockchain. Instead, developers use StackerDBSet to host and replicate auxiliary smart contract /// data for the purposes of some (off-chain) application in a best-effort manner. In doing so, /// Stacks-powered applications are able to leverage the Stacks peer-to-peer node network to host /// and disseminate their data without incuring the cost and performance penalties of bundling it @@ -61,51 +61,52 @@ /// slot can be written to (in wall-clock time). This smart contract is queried once per reward cycle /// in order to configure the database. /// -/// Applications that employ StackerDBs would deploy one or more smart contracts that list out +/// Applications that employ StackerDBSet would deploy one or more smart contracts that list out /// which users can store data to the StackerDB replica, and how much space they get. /// /// ## Replication Protocol /// /// StackerDB replication proceeds in a three-part protocol: discovery, inventory query, and /// chunk exchange. The discovery protocol leverages the Stacks node's neighbor-walk algorithm to -/// discover which StackerDBs other nodes claim to replicate. On receipt of a `Handshake` message, +/// discover which StackerDBSet other nodes claim to replicate. On receipt of a `Handshake` message, /// a StackerDB-aware node replies with a `StackerDBHandshakeAccept` message which encodes both the -/// contents of a `HandshakeAccept` message as well as a list of local StackerDBs (identified by +/// contents of a `HandshakeAccept` message as well as a list of local StackerDBSet (identified by /// their smart contracts' addresses). Upon receipt of a `StackerDBHandshakeAccept`, the node /// stores the list of smart contracts in its `PeerDB` as part of the network frontier state. In -/// doing so, nodes eventually learn of all of the StackerDBs replicated by all other nodes. To +/// doing so, nodes eventually learn of all of the StackerDBSet replicated by all other nodes. To /// bound the size of this state, the protocol mandates that a node can only replicate up to 256 -/// StackerDBs. The handshake-handling code happens in net::handle_handshake(). +/// StackerDBSet. The handshake-handling code happens in net::chat::handle_handshake(). /// /// When a node begins to replicate a StackerDB, it first queries the `PeerDB` for the set of nodes /// that claim to have copies. This set, called the "DB neighbors", is distinct from the set /// of neighbors the node uses to replicate blocks and transactions. It then connects /// to these nodes with a `Handshake` / `StackerDBHandshakeAccept` exchange (if the neighbor walk -/// has not done so already), and proceeds to query each DB's inventories. +/// has not done so already), and proceeds to query each DB's inventories by sending them +/// `StackerDBGetChunkInData` messages. /// -/// The DB inventory is simply a vector of all of the remote peers' slots' versions. +/// The DB inventory (`StackerDBChunkInvData`) is simply a vector of all of the remote peers' slots' versions. /// Once the node has received all DB inventories from its neighbors, it schedules them for /// download by prioritizing them by newest-first, and then by rarest-first, in order to ensure /// that the latest, least-replicated data is downloaded first. /// /// Once the node has computed its download schedule, it queries its DB neighbors for chunks with -/// the given versions. Upon receipt of a chunk, the node verifies the signature on the chunk's -/// metadata, verifies that the chunk data hashes to the metadata's indicated data hash, and stores -/// the chunk. It will then select neighbors to which to broadcast this chunk, inferring from the +/// the given versions (via `StackerDBGetChunkData`). Upon receipt of a chunk, the node verifies the signature on the chunk's +/// metadata (via `SlotMetadata`), verifies that the chunk data hashes to the metadata's indicated data hash, and stores +/// the chunk (via `StackerDBSet` and `StackerDBTx`). It will then select neighbors to which to broadcast this chunk, inferring from the /// download schedule which DB neighbors have yet to process this particular version of the chunk. /// /// ## Comparison to other Stacks storage /// -/// StackerDBs differ from AtlasDBs in that data chunks are not authenticated by the blockchain, +/// StackerDBSet differ from AtlasDBs in that data chunks are not authenticated by the blockchain, /// but instead are authenticated by public key hashes made available from a smart contract. As /// such, a node can begin replicating a StackerDB whenever its operator wants -- it does not need /// to re-synchronize blockchain state to get the list of chunk hashes. Furthermore, StackerDB /// state can be written to as fast as the smart contract permits -- there is no need to wait for a /// corresponding transaction to confirm. /// -/// StackerDBs differ from Gaia in that Stacks nodes are the principal means of storing data. Any +/// StackerDBSet differ from Gaia in that Stacks nodes are the principal means of storing data. Any /// reachable Stacks node can fulfill requests for chunks. It is up to the StackerDB maintainer to -/// convince node operators to replicate StackerDBs on their behalf. In addition, StackerDB state +/// convince node operators to replicate StackerDBSet on their behalf. In addition, StackerDB state /// is ephemeral -- its longevity in the system depends on application endpoints re-replicating the /// state periodically (whereas Gaia stores data for as long as the back-end storage provider's SLA /// indicates). @@ -171,17 +172,14 @@ impl StackerDBConfig { } } -/// This is a replicated database that stores fixed-length opaque blobs of data from a -/// smart-contract-specified list of principals. For example, in sBTC, each Stacker gets one slot -/// per reward cycle clinched. +/// This is the set of replicated chunks in all stacker DBs that this node subscribes to. /// -/// Users can store whatever they like in their blobs. For example, in sBTC this is signature -/// generation data. -pub struct StackerDB { +/// Callers can query chunks from individual stacker DBs by supplying the smart contract address. +pub struct StackerDBSet { conn: DBConn, } -/// A transaction against the Stacker DB +/// A transaction against one or more stacker DBs (really, against StackerDBSet) pub struct StackerDBTx<'a> { sql_tx: DBTx<'a>, config: StackerDBConfig, @@ -191,9 +189,9 @@ pub struct StackerDBTx<'a> { /// This is derived state from a StackerDBChunkData message. #[derive(Clone, Debug, PartialEq)] pub struct SlotMetadata { - /// Chunk identifier (unique for each DB instance) + /// Slot identifier (unique for each DB instance) pub slot_id: u32, - /// Chunk version (a lamport clock) + /// Slot version (a lamport clock) pub slot_version: u32, /// data hash pub data_hash: Sha512Trunc256Sum, diff --git a/src/net/stackerdb/tests/bits.rs b/src/net/stackerdb/tests/bits.rs index 077d04174..4b1110aa5 100644 --- a/src/net/stackerdb/tests/bits.rs +++ b/src/net/stackerdb/tests/bits.rs @@ -16,7 +16,7 @@ use std::fs; -use crate::net::stackerdb::{SlotMetadata, StackerDB}; +use crate::net::stackerdb::{SlotMetadata, StackerDBSet}; use crate::net::StackerDBChunkData; use clarity::vm::ContractName; diff --git a/src/net/stackerdb/tests/db.rs b/src/net/stackerdb/tests/db.rs index e5d053ba5..7b705d777 100644 --- a/src/net/stackerdb/tests/db.rs +++ b/src/net/stackerdb/tests/db.rs @@ -17,7 +17,7 @@ use std::fs; use std::path::Path; -use crate::net::stackerdb::{db::SlotValidation, SlotMetadata, StackerDB, StackerDBConfig}; +use crate::net::stackerdb::{db::SlotValidation, SlotMetadata, StackerDBConfig, StackerDBSet}; use crate::net::ContractId; use crate::net::ContractIdExtension; @@ -53,7 +53,7 @@ fn test_stackerdb_connect() { let path = "/tmp/stacks-node-tests/test_stackerdb_connect.sqlite"; setup_test_path(path); - let _ = StackerDB::connect(path, true).unwrap(); + let _ = StackerDBSet::connect(path, true).unwrap(); } /// Test that we can create, enumerate, and drop StackerDB tables. @@ -62,7 +62,7 @@ fn test_stackerdb_create_list_delete() { let path = "/tmp/stacks-node-tests/test_stackerdb_create_list_delete.sqlite"; setup_test_path(path); - let mut db = StackerDB::connect(path, true).unwrap(); + let mut db = StackerDBSet::connect(path, true).unwrap(); let tx = db.tx_begin(StackerDBConfig::noop()).unwrap(); let slots = [( @@ -307,7 +307,7 @@ fn test_stackerdb_prepare_clear_slots() { ContractName::try_from("db1").unwrap(), ); - let mut db = StackerDB::connect(path, true).unwrap(); + let mut db = StackerDBSet::connect(path, true).unwrap(); let tx = db.tx_begin(StackerDBConfig::noop()).unwrap(); tx.create_stackerdb( @@ -417,7 +417,7 @@ fn test_stackerdb_insert_query_chunks() { ContractName::try_from("db1").unwrap(), ); - let mut db = StackerDB::connect(path, true).unwrap(); + let mut db = StackerDBSet::connect(path, true).unwrap(); let mut db_config = StackerDBConfig::noop(); db_config.max_writes = 3;