1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
// LNP/BP Rust Library
// Written in 2020-2021 by
// Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the MIT License
// along with this software.
// If not, see <https://opensource.org/licenses/MIT>.
//! API for working with stash: storage of RGB contract client-side-validated
//! data and data containers.
//!
//! Client-side-validated data, and (especially) data containers may grow large
//! (multiple gigabytes) and can't be fit in a memory as a single data
//! structure. Thus, we utilize a special API which abstracts the specific stash
//! storage mechanism (file-based, SQL or NoSQL database, special disk
//! partitions, cloud-provided storage, like with Bifrost protocol, etc).
//! With this API the data can be accessed using iterators or by providing the
//! specific data id.
//!
//! NB: Stash implementations must be able to operate multiple independent RGB
//! contract.
use std::collections::BTreeSet;
use bitcoin::OutPoint;
use bp::seals::OutpointReveal;
use wallet::resolvers::TxResolver;
use crate::{
Anchor, AnchorId, Consignment, ContractId, Disclosure, Extension, Genesis,
Node, NodeId, Schema, SchemaId, SealEndpoint, Transition,
};
/// Top-level structure used by client wallets to manage all known RGB smart
/// contracts and related data.
///
/// Stash operates blobs, so it does not keep in the memory whole copy of all
/// data. Access to the underlying data structures happens through iterators:
/// - [`Stash::ContractIterator`]
///
/// Stash API is an alternative to the RGB contract data access API provided by
/// [`crate::GraphApi`], which is implemented by the structures keeping all the
/// data in memory ([`Consignment`] and [`Disclosure`]).
pub trait Stash {
/// Error type returned by different stash functions
type Error: std::error::Error;
/// Iterator implementation able to run over known schemata and subschemata
type SchemaIterator: Iterator<Item = Schema>;
/// Iterator implementation able to run over all contract geneses
type GenesisIterator: Iterator<Item = Genesis>;
/// Iterator implementation able to run over all known anchors
type AnchorIterator: Iterator<Item = Anchor>;
/// Iterator implementation able to run over all state transitions under
/// particular contract
type TransitionIterator: Iterator<Item = Transition>;
/// Iterator implementation able to run over all state extensions under
/// particular contract
type ExtensionIterator: Iterator<Item = Extension>;
/// Iterator implementation able to run over all node ids under
/// particular contract
type NodeIdIterator: Iterator<Item = NodeId>;
/// Returns schema or subschema matching the provided id, if any, or
/// storage-specific error otherwise
fn get_schema(&self, schema_id: SchemaId) -> Result<Schema, Self::Error>;
/// Returns genesis matching the provided id, if any, or storage-specific
/// error otherwise
fn get_genesis(
&self,
contract_id: ContractId,
) -> Result<Genesis, Self::Error>;
/// Returns state transition matching the provided `node_id`, if any, or
/// storage-specific error otherwise.
///
/// NB: Here the state transition is identified by the node id and not
/// relates to a specific contract_id. To get the transitions by a contract
/// id please use transition iterator.
fn get_transition(
&self,
node_id: NodeId,
) -> Result<Transition, Self::Error>;
/// Returns state extension matching the provided `node_id`, if any, or
/// storage-specific error otherwise.
///
/// NB: Here the state extension is identified by the node id and not
/// relates to a specific contract_id. To get the extensions by a contract
/// id please use extension iterator.
fn get_extension(&self, node_id: NodeId) -> Result<Extension, Self::Error>;
/// Returns anchor matching the provided `anchor_id`, if any, or
/// storage-specific error otherwise.
///
/// NB: Anchors may be related to multiple contract ids; specific set of the
/// contracts to which this anchor is related to may be known from the
/// anchor data, unless they are kept in the confidential form. See
/// [`Anchor`] documentation for the details.
fn get_anchor(&self, anchor_id: AnchorId) -> Result<Anchor, Self::Error>;
/// Iterator over all contract geneses (i.e. iterator over all known RGB
/// contracts).
fn genesis_iter(&self) -> Self::GenesisIterator;
/// Iterator over all known anchors
///
/// NB: each anchor may be related to multiple contracts, thus here we do
/// not provide contract id constraint for the iterator.
fn anchor_iter(&self) -> Self::AnchorIterator;
/// Iterator over all known state transition under particular RGB contract
fn transition_iter(
&self,
contract_id: ContractId,
) -> Self::TransitionIterator;
/// Iterator over all known state extensions under particular RGB contract
fn extension_iter(
&self,
contract_id: ContractId,
) -> Self::ExtensionIterator;
/// When we need to send over to somebody else an update (like we have
/// transferred him some state, for instance an asset) for each transfer we
/// ask [`Stash`] to create a new [`Consignment`] for the given set of seals
/// (`endpoints`) under some specific [`ContractId`], starting from a graph
/// vertex `node`. If the node is state transition, we must also include
/// `anchor` information.
fn consign(
&self,
contract_id: ContractId,
node: &impl Node,
anchor: Option<&Anchor>,
endpoints: &BTreeSet<SealEndpoint>,
) -> Result<Consignment, Self::Error>;
/// When we have received data from other peer (which usually relate to our
/// newly owned state, like assets) we do `accept` a [`Consignment`],
/// and it gets into the known data.
fn accept(
&mut self,
consignment: &Consignment,
known_seals: &Vec<OutpointReveal>,
) -> Result<(), Self::Error>;
/// Acquire knowledge from a given disclosure (**enclose** procedure)
fn enclose(&mut self, disclosure: &Disclosure) -> Result<(), Self::Error>;
/// Clears all data that are not related to the contract state owned by
/// us in this moment — under all known contracts. Uses provided
/// `tx_resolver` to resolve validity of the related transactions (witness
/// and single-use-seal) and `ownership_resolver` for checking whether
/// specific transaction output is owned by the current user (stash data
/// holder)
fn prune(
&mut self,
tx_resolver: &mut impl TxResolver,
ownership_resolver: impl Fn(OutPoint) -> bool,
) -> Result<usize, Self::Error>;
}