Skip to content

Commit

Permalink
Merge pull request #23 from RGB-WG/resolver
Browse files Browse the repository at this point in the history
Remove required electrum resolver
  • Loading branch information
dr-orlovsky committed Aug 1, 2023
2 parents 9d156ca + 5ced834 commit 0b20e64
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 51 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ jobs:
with:
command: check
args: --workspace
no-default:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install rust stable
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: No features
uses: actions-rs/cargo@v1
with:
command: check
args: --workspace --no-default-features
features:
runs-on: ubuntu-latest
strategy:
Expand Down
41 changes: 22 additions & 19 deletions src/bin/rgb/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use amplify::confinement::U16;
use bitcoin::bip32::ExtendedPubKey;
use bitcoin::psbt::Psbt;
use bp::seals::txout::{CloseMethod, ExplicitSeal, TxPtr};
use rgb::{Runtime, RuntimeError};
use rgb::{BlockchainResolver, Runtime, RuntimeError};
use rgbstd::containers::{Bindle, Transfer, UniversalBindle};
use rgbstd::contract::{ContractId, GenesisSeal, GraphSeal, StateType};
use rgbstd::interface::{ContractBuilder, SchemaIfaces, TypedState};
Expand Down Expand Up @@ -224,7 +224,11 @@ pub enum Command {
}

impl Command {
pub fn exec(self, runtime: &mut Runtime) -> Result<(), RuntimeError> {
pub fn exec(
self,
runtime: &mut Runtime,
resolver: &mut BlockchainResolver,
) -> Result<(), RuntimeError> {
match self {
Command::Schemata => {
for id in runtime.schema_ids()? {
Expand Down Expand Up @@ -301,14 +305,10 @@ impl Command {
}
UniversalBindle::Contract(bindle) => {
let id = bindle.id();
let contract =
bindle
.unbindle()
.validate(runtime.resolver())
.map_err(|c| {
c.validation_status().expect("just validated").to_string()
})?;
runtime.import_contract(contract)?;
let contract = bindle.unbindle().validate(resolver).map_err(|c| {
c.validation_status().expect("just validated").to_string()
})?;
runtime.import_contract(contract, resolver)?;
eprintln!("Contract {id} imported to the stash");
}
UniversalBindle::Transfer(_) => {
Expand Down Expand Up @@ -341,7 +341,13 @@ impl Command {
contract_id,
iface,
} => {
let wallet = wallet.map(|w| runtime.wallet(&w)).transpose()?;
let wallet = wallet
.map(|w| -> Result<_, RuntimeError> {
let mut wallet = runtime.wallet(&w)?;
wallet.update(resolver)?;
Ok(wallet)
})
.transpose()?;

let iface = runtime.iface_by_name(&tn!(iface))?.clone();
let contract = runtime.contract_iface(contract_id, iface.iface_id())?;
Expand Down Expand Up @@ -516,10 +522,10 @@ impl Command {
let contract = builder.issue_contract().expect("failure issuing contract");
let id = contract.contract_id();
let validated_contract = contract
.validate(runtime.resolver())
.validate(resolver)
.map_err(|_| RuntimeError::IncompleteContract)?;
runtime
.import_contract(validated_contract)
.import_contract(validated_contract, resolver)
.expect("failure importing issued contract");
eprintln!(
"A new contract {id} is issued and added to the stash.\nUse `export` command \
Expand Down Expand Up @@ -681,7 +687,7 @@ impl Command {
}
Command::Validate { file } => {
let bindle = Bindle::<Transfer>::load(file)?;
let status = match bindle.unbindle().validate(runtime.resolver()) {
let status = match bindle.unbindle().validate(resolver) {
Ok(consignment) => consignment.into_validation_status(),
Err(consignment) => consignment.into_validation_status(),
}
Expand All @@ -690,12 +696,9 @@ impl Command {
}
Command::Accept { force, file } => {
let bindle = Bindle::<Transfer>::load(file)?;
let transfer = bindle
.unbindle()
.validate(runtime.resolver())
.unwrap_or_else(|c| c);
let transfer = bindle.unbindle().validate(resolver).unwrap_or_else(|c| c);
eprintln!("{}", transfer.validation_status().expect("just validated"));
runtime.accept_transfer(transfer, force)?;
runtime.accept_transfer(transfer, resolver, force)?;
eprintln!("Transfer accepted into the stash");
}
Command::SetHost { method, psbt_file } => {
Expand Down
7 changes: 4 additions & 3 deletions src/bin/rgb/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ mod command;
use std::process::ExitCode;

use clap::Parser;
use rgb::{DefaultResolver, Runtime, RuntimeError};
use rgb::{BlockchainResolver, DefaultResolver, Runtime, RuntimeError};

pub use crate::command::Command;
pub use crate::loglevel::LogLevel;
Expand Down Expand Up @@ -73,8 +73,9 @@ fn run() -> Result<(), RuntimeError> {
.electrum
.unwrap_or_else(|| opts.chain.default_resolver());

let mut runtime = Runtime::load(opts.data_dir.clone(), opts.chain, &electrum)?;
let mut resolver = BlockchainResolver::with(&electrum)?;
let mut runtime = Runtime::load(opts.data_dir.clone(), opts.chain)?;
debug!("Executing command: {}", opts.command);
opts.command.exec(&mut runtime)?;
opts.command.exec(&mut runtime, &mut resolver)?;
Ok(())
}
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#[macro_use]
extern crate amplify;
#[cfg(feature = "log")]
#[macro_use]
extern crate log;
#[macro_use]
Expand All @@ -36,7 +37,9 @@ pub mod prelude {
pub use rgbstd::*;
pub use rgbwallet::*;
pub use runtime::{Runtime, RuntimeError};
pub use wallet::{BlockchainResolver, DefaultResolver, RgbWallet};
#[cfg(feature = "electrum")]
pub use wallet::BlockchainResolver;
pub use wallet::{DefaultResolver, RgbWallet};

pub use super::*;
}
Expand Down
46 changes: 29 additions & 17 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ use rgbfs::StockFs;
use rgbstd::containers::{Contract, LoadError, Transfer};
use rgbstd::interface::BuilderError;
use rgbstd::persistence::{Inventory, InventoryDataError, InventoryError, StashError, Stock};
use rgbstd::resolvers::ResolveHeight;
use rgbstd::validation::ResolveTx;
use rgbstd::{validation, Chain};
use strict_types::encoding::{DeserializeError, Ident, SerializeError};

use crate::descriptor::RgbDescr;
use crate::wallet::BlockchainResolver;
use crate::{RgbWallet, Tapret};

#[derive(Debug, Display, Error, From)]
Expand Down Expand Up @@ -104,8 +105,6 @@ pub struct Runtime {
wallets: HashMap<Ident, RgbDescr>,
#[getter(as_copy)]
chain: Chain,
#[getter(skip)]
resolver: BlockchainResolver,
}

impl Deref for Runtime {
Expand All @@ -118,15 +117,20 @@ impl DerefMut for Runtime {
}

impl Runtime {
pub fn load(mut data_dir: PathBuf, chain: Chain, electrum: &str) -> Result<Self, RuntimeError> {
pub fn load(mut data_dir: PathBuf, chain: Chain) -> Result<Self, RuntimeError> {
data_dir.push(chain.to_string());
#[cfg(feature = "log")]
debug!("Using data directory '{}'", data_dir.display());
fs::create_dir_all(&data_dir)?;

let mut stock_path = data_dir.clone();
stock_path.push("stock.dat");
#[cfg(feature = "log")]
debug!("Reading stock from '{}'", stock_path.display());
let stock = if !stock_path.exists() {
#[cfg(feature = "log")]
info!("Stock file not found, creating default stock");
#[cfg(feature = "cli")]
eprintln!("Stock file not found, creating default stock");
let stock = Stock::default();
stock.store(&stock_path)?;
Expand All @@ -137,31 +141,30 @@ impl Runtime {

let mut wallets_path = data_dir.clone();
wallets_path.push("wallets.yml");
#[cfg(feature = "log")]
debug!("Reading wallets from '{}'", wallets_path.display());
let wallets = if !wallets_path.exists() {
#[cfg(feature = "log")]
info!("Wallet file not found, creating new wallet list");
#[cfg(feature = "cli")]
eprintln!("Wallet file not found, creating new wallet list");
empty!()
} else {
let wallets_fd = File::open(&wallets_path)?;
serde_yaml::from_reader(&wallets_fd)?
};

let resolver = BlockchainResolver::with(electrum)?;

Ok(Self {
stock_path,
wallets_path,
stock,
wallets,
chain,
resolver,
})
}

pub fn unload(self) -> () {}

pub fn resolver(&mut self) -> &mut BlockchainResolver { &mut self.resolver }

pub fn create_wallet(
&mut self,
name: &Ident,
Expand All @@ -183,35 +186,44 @@ impl Runtime {
.wallets
.get(name)
.ok_or(RuntimeError::WalletUnknown(name.clone()))?;
RgbWallet::with(descr.clone(), &mut self.resolver).map_err(RuntimeError::from)
Ok(RgbWallet::new(descr.clone()))
}

pub fn import_contract(
pub fn import_contract<R: ResolveHeight>(
&mut self,
contract: Contract,
) -> Result<validation::Status, RuntimeError> {
resolver: &mut R,
) -> Result<validation::Status, RuntimeError>
where
R::Error: 'static,
{
self.stock
.import_contract(contract, &mut self.resolver)
.import_contract(contract, resolver)
.map_err(RuntimeError::from)
}

pub fn validate_transfer<'transfer>(
&mut self,
transfer: Transfer,
resolver: &mut impl ResolveTx,
) -> Result<Transfer, RuntimeError> {
transfer
.validate(&mut self.resolver)
.validate(resolver)
.map_err(|invalid| invalid.validation_status().expect("just validated").clone())
.map_err(RuntimeError::from)
}

pub fn accept_transfer(
pub fn accept_transfer<R: ResolveHeight>(
&mut self,
transfer: Transfer,
resolver: &mut R,
force: bool,
) -> Result<validation::Status, RuntimeError> {
) -> Result<validation::Status, RuntimeError>
where
R::Error: 'static,
{
self.stock
.accept_transfer(transfer, &mut self.resolver, force)
.accept_transfer(transfer, resolver, force)
.map_err(RuntimeError::from)
}
}
Expand Down
29 changes: 18 additions & 11 deletions src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@

use std::collections::{BTreeMap, BTreeSet};

use amplify::RawArray;
use bitcoin::hashes::Hash;
use bitcoin::ScriptBuf;
use bp::{Outpoint, Txid};
use bp::Outpoint;

use crate::descriptor::DeriveInfo;
use crate::{RgbDescr, SpkDescriptor};
Expand Down Expand Up @@ -59,26 +57,33 @@ pub struct RgbWallet {
}

impl RgbWallet {
pub fn with(descr: RgbDescr, resolver: &mut impl Resolver) -> Result<Self, String> {
let mut utxos = BTreeSet::new();
pub fn new(descr: RgbDescr) -> Self {
Self {
descr,
utxos: empty!(),
}
}

pub fn update(&mut self, resolver: &mut impl Resolver) -> Result<(), String> {
const STEP: u32 = 20;
for app in [0, 1, 10, 20, 30, 40, 50, 60] {
for app in [0, 1, 9, 10] {
let mut index = 0;
loop {
#[cfg(feature = "log")]
debug!("Requesting {STEP} scripts from the Electrum server");
let scripts = descr.derive(app, index..(index + STEP));
let scripts = self.descr.derive(app, index..(index + STEP));
let set = resolver.resolve_utxo(scripts)?;
if set.is_empty() {
break;
}
#[cfg(feature = "log")]
debug!("Electrum server returned {} UTXOs", set.len());
utxos.extend(set);
self.utxos.extend(set);
index += STEP;
}
}

Ok(Self { descr, utxos })
Ok(())
}

pub fn utxo(&self, outpoint: Outpoint) -> Option<&Utxo> {
Expand All @@ -96,17 +101,19 @@ pub trait DefaultResolver {
#[wrapper_mut(DerefMut)]
pub struct BlockchainResolver(electrum_client::Client);

#[cfg(feature = "electrum")]
impl BlockchainResolver {
#[cfg(feature = "electrum")]
pub fn with(url: &str) -> Result<Self, electrum_client::Error> {
electrum_client::Client::new(url).map(Self)
}
}

#[cfg(feature = "electrum")]
mod _electrum {
use amplify::RawArray;
use bitcoin::hashes::Hash;
use bitcoin::{Script, ScriptBuf};
use bp::{Chain, LockTime, SeqNo, Tx, TxIn, TxOut, TxVer, VarIntArray, Witness};
use bp::{Chain, LockTime, SeqNo, Tx, TxIn, TxOut, TxVer, Txid, VarIntArray, Witness};
use electrum_client::{ElectrumApi, Error, ListUnspentRes};
use rgbstd::contract::WitnessOrd;
use rgbstd::resolvers::ResolveHeight;
Expand Down

0 comments on commit 0b20e64

Please sign in to comment.