diff --git a/Cargo.lock b/Cargo.lock index d78469b..b1c38cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3648,7 +3648,7 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain_bitassets" -version = "0.6.1" +version = "0.6.2" dependencies = [ "addr", "anyhow", @@ -3689,7 +3689,7 @@ dependencies = [ [[package]] name = "plain_bitassets_app" -version = "0.6.1" +version = "0.6.2" dependencies = [ "anyhow", "async_zmq", diff --git a/Cargo.toml b/Cargo.toml index 9499a43..519d804 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ [workspace.package] authors = [ "Ash Manning " ] edition = "2021" -version = "0.6.1" +version = "0.6.2" [workspace.dependencies.bip300301] git = "https://github.com/Ash-L2L/bip300301.git" diff --git a/app/rpc_api.rs b/app/rpc_api.rs index f40a10c..b483bcc 100644 --- a/app/rpc_api.rs +++ b/app/rpc_api.rs @@ -1,5 +1,7 @@ //! RPC API +use std::net::SocketAddr; + use bip300301::bitcoin; use fraction::Fraction; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; @@ -14,35 +16,13 @@ use plain_bitassets::{ #[rpc(client, server)] pub trait Rpc { - #[method(name = "stop")] - async fn stop(&self); - - /// Balance in sats - #[method(name = "bitcoin_balance")] - async fn bitcoin_balance(&self) -> RpcResult; - - #[method(name = "format_deposit_address")] - async fn format_deposit_address( - &self, - address: Address, - ) -> RpcResult; - - #[method(name = "getblockcount")] - async fn getblockcount(&self) -> RpcResult; - - #[method(name = "get_amm_price")] - async fn get_amm_price( - &self, - base: AssetId, - quote: AssetId, - ) -> RpcResult>; - - #[method(name = "get_amm_pool_state")] - async fn get_amm_pool_state( + #[method(name = "amm_burn")] + async fn amm_burn( &self, asset0: AssetId, asset1: AssetId, - ) -> RpcResult; + lp_token_amount: u64, + ) -> RpcResult<()>; #[method(name = "amm_mint")] async fn amm_mint( @@ -53,14 +33,6 @@ pub trait Rpc { amount1: u64, ) -> RpcResult<()>; - #[method(name = "amm_burn")] - async fn amm_burn( - &self, - asset0: AssetId, - asset1: AssetId, - lp_token_amount: u64, - ) -> RpcResult<()>; - /// Returns the amount of `asset_receive` to receive #[method(name = "amm_swap")] async fn amm_swap( @@ -76,17 +48,13 @@ pub trait Rpc { &self, ) -> RpcResult>; - /// List all Dutch auctions - #[method(name = "dutch_auctions")] - async fn dutch_auctions( - &self, - ) -> RpcResult>; + /// Balance in sats + #[method(name = "bitcoin_balance")] + async fn bitcoin_balance(&self) -> RpcResult; - #[method(name = "dutch_auction_create")] - async fn dutch_auction_create( - &self, - dutch_auction_params: DutchAuctionParams, - ) -> RpcResult<()>; + /// Connect to a peer + #[method(name = "connect_peer")] + async fn connect_peer(&self, addr: SocketAddr) -> RpcResult<()>; /// Returns the amount of the base asset to receive #[method(name = "dutch_auction_bid")] @@ -96,6 +64,12 @@ pub trait Rpc { bid_size: u64, ) -> RpcResult; + #[method(name = "dutch_auction_create")] + async fn dutch_auction_create( + &self, + dutch_auction_params: DutchAuctionParams, + ) -> RpcResult<()>; + /// Returns the amount of the base asset and quote asset to receive #[method(name = "dutch_auction_collect")] async fn dutch_auction_collect( @@ -103,12 +77,47 @@ pub trait Rpc { dutch_auction_id: DutchAuctionId, ) -> RpcResult<(u64, u64)>; - #[method(name = "get_block_hash")] - async fn get_block_hash(&self, height: u32) -> RpcResult; + /// List all Dutch auctions + #[method(name = "dutch_auctions")] + async fn dutch_auctions( + &self, + ) -> RpcResult>; + + #[method(name = "format_deposit_address")] + async fn format_deposit_address( + &self, + address: Address, + ) -> RpcResult; + + #[method(name = "generate_mnemonic")] + async fn generate_mnemonic(&self) -> RpcResult; + + #[method(name = "get_amm_pool_state")] + async fn get_amm_pool_state( + &self, + asset0: AssetId, + asset1: AssetId, + ) -> RpcResult; + + #[method(name = "get_amm_price")] + async fn get_amm_price( + &self, + base: AssetId, + quote: AssetId, + ) -> RpcResult>; #[method(name = "get_block")] async fn get_block(&self, block_hash: BlockHash) -> RpcResult; + #[method(name = "get_block_hash")] + async fn get_block_hash(&self, height: u32) -> RpcResult; + + #[method(name = "get_new_address")] + async fn get_new_address(&self) -> RpcResult
; + + #[method(name = "getblockcount")] + async fn getblockcount(&self) -> RpcResult; + #[method(name = "mine")] async fn mine(&self, fee: Option) -> RpcResult<()>; @@ -123,11 +132,8 @@ pub trait Rpc { #[method(name = "my_utxos")] async fn my_utxos(&self) -> RpcResult>; - #[method(name = "get_new_address")] - async fn get_new_address(&self) -> RpcResult
; - - #[method(name = "generate_mnemonic")] - async fn generate_mnemonic(&self) -> RpcResult; + #[method(name = "reserve_bitasset")] + async fn reserve_bitasset(&self, plain_name: String) -> RpcResult<()>; #[method(name = "set_seed_from_mnemonic")] async fn set_seed_from_mnemonic(&self, mnemonic: String) -> RpcResult<()>; @@ -135,6 +141,9 @@ pub trait Rpc { #[method(name = "sidechain_wealth")] async fn sidechain_wealth(&self) -> RpcResult; + #[method(name = "stop")] + async fn stop(&self); + #[method(name = "transfer")] async fn transfer( &self, @@ -143,7 +152,4 @@ pub trait Rpc { fee: u64, memo: Option, ) -> RpcResult<()>; - - #[method(name = "reserve_bitasset")] - async fn reserve_bitasset(&self, plain_name: String) -> RpcResult<()>; } diff --git a/app/rpc_server.rs b/app/rpc_server.rs index 84ae96e..d11f685 100644 --- a/app/rpc_server.rs +++ b/app/rpc_server.rs @@ -45,73 +45,31 @@ fn convert_wallet_err(err: wallet::Error) -> ErrorObject<'static> { #[async_trait] impl RpcServer for RpcServerImpl { - async fn stop(&self) { - std::process::exit(0); - } - - async fn bitcoin_balance(&self) -> RpcResult { - self.app - .wallet - .get_bitcoin_balance() - .map_err(convert_wallet_err) - } - - async fn format_deposit_address( - &self, - address: Address, - ) -> RpcResult { - let deposit_address = plain_bitassets::format_deposit_address( - node::THIS_SIDECHAIN, - &address.to_string(), - ); - Ok(deposit_address) - } - - async fn getblockcount(&self) -> RpcResult { - self.app.node.get_height().map_err(convert_node_err) - } - - async fn get_amm_price( - &self, - base: AssetId, - quote: AssetId, - ) -> RpcResult> { - self.app - .node - .try_get_amm_price(base, quote) - .map_err(convert_node_err) - } - - async fn get_amm_pool_state( - &self, - asset0: AssetId, - asset1: AssetId, - ) -> RpcResult { - let amm_pair = AmmPair::new(asset0, asset1); - self.app - .node - .get_amm_pool_state(amm_pair) - .map_err(convert_node_err) - } - - async fn amm_mint( + async fn amm_burn( &self, asset0: AssetId, asset1: AssetId, - amount0: u64, - amount1: u64, + lp_token_amount: u64, ) -> RpcResult<()> { + let amm_pair = AmmPair::new(asset0, asset1); let amm_pool_state = self.get_amm_pool_state(asset0, asset1).await?; let next_amm_pool_state = amm_pool_state - .mint(amount0, amount1) + .burn(lp_token_amount) .map_err(|err| convert_node_err(err.into()))?; - let lp_token_mint = next_amm_pool_state.outstanding_lp_tokens - - amm_pool_state.outstanding_lp_tokens; + let amount0 = amm_pool_state.reserve0 - next_amm_pool_state.reserve0; + let amount1 = amm_pool_state.reserve1 - next_amm_pool_state.reserve1; let mut tx = Transaction::default(); let () = self .app .wallet - .amm_mint(&mut tx, asset0, asset1, amount0, amount1, lp_token_mint) + .amm_burn( + &mut tx, + amm_pair.asset0(), + amm_pair.asset1(), + amount0, + amount1, + lp_token_amount, + ) .map_err(convert_wallet_err)?; let authorized_tx = self.app.wallet.authorize(tx).map_err(convert_wallet_err)?; @@ -122,31 +80,24 @@ impl RpcServer for RpcServerImpl { .map_err(convert_node_err) } - async fn amm_burn( + async fn amm_mint( &self, asset0: AssetId, asset1: AssetId, - lp_token_amount: u64, + amount0: u64, + amount1: u64, ) -> RpcResult<()> { - let amm_pair = AmmPair::new(asset0, asset1); let amm_pool_state = self.get_amm_pool_state(asset0, asset1).await?; let next_amm_pool_state = amm_pool_state - .burn(lp_token_amount) + .mint(amount0, amount1) .map_err(|err| convert_node_err(err.into()))?; - let amount0 = amm_pool_state.reserve0 - next_amm_pool_state.reserve0; - let amount1 = amm_pool_state.reserve1 - next_amm_pool_state.reserve1; + let lp_token_mint = next_amm_pool_state.outstanding_lp_tokens + - amm_pool_state.outstanding_lp_tokens; let mut tx = Transaction::default(); let () = self .app .wallet - .amm_burn( - &mut tx, - amm_pair.asset0(), - amm_pair.asset1(), - amount0, - amount1, - lp_token_amount, - ) + .amm_mint(&mut tx, asset0, asset1, amount0, amount1, lp_token_mint) .map_err(convert_wallet_err)?; let authorized_tx = self.app.wallet.authorize(tx).map_err(convert_wallet_err)?; @@ -214,10 +165,19 @@ impl RpcServer for RpcServerImpl { self.app.node.bitassets().map_err(convert_node_err) } - async fn dutch_auctions( - &self, - ) -> RpcResult> { - self.app.node.dutch_auctions().map_err(convert_node_err) + async fn bitcoin_balance(&self) -> RpcResult { + self.app + .wallet + .get_bitcoin_balance() + .map_err(convert_wallet_err) + } + + async fn connect_peer(&self, addr: SocketAddr) -> RpcResult<()> { + self.app + .node + .connect_peer(addr) + .await + .map_err(convert_node_err) } async fn dutch_auction_bid( @@ -320,6 +280,63 @@ impl RpcServer for RpcServerImpl { Ok(()) } + async fn dutch_auctions( + &self, + ) -> RpcResult> { + self.app.node.dutch_auctions().map_err(convert_node_err) + } + + async fn format_deposit_address( + &self, + address: Address, + ) -> RpcResult { + let deposit_address = plain_bitassets::format_deposit_address( + node::THIS_SIDECHAIN, + &address.to_string(), + ); + Ok(deposit_address) + } + + async fn generate_mnemonic(&self) -> RpcResult { + let mnemonic = bip39::Mnemonic::new( + bip39::MnemonicType::Words12, + bip39::Language::English, + ); + Ok(mnemonic.to_string()) + } + + async fn get_amm_pool_state( + &self, + asset0: AssetId, + asset1: AssetId, + ) -> RpcResult { + let amm_pair = AmmPair::new(asset0, asset1); + self.app + .node + .get_amm_pool_state(amm_pair) + .map_err(convert_node_err) + } + + async fn get_amm_price( + &self, + base: AssetId, + quote: AssetId, + ) -> RpcResult> { + self.app + .node + .try_get_amm_price(base, quote) + .map_err(convert_node_err) + } + + async fn get_block(&self, block_hash: BlockHash) -> RpcResult { + let block = self + .app + .node + .get_block(block_hash) + .expect("This error should have been handled properly."); + Ok(block) + } + async fn get_block_hash(&self, height: u32) -> RpcResult { let block_hash = self .app @@ -331,13 +348,15 @@ impl RpcServer for RpcServerImpl { Ok(block_hash) } - async fn get_block(&self, block_hash: BlockHash) -> RpcResult { - let block = self - .app - .node - .get_block(block_hash) - .expect("This error should have been handled properly."); - Ok(block) + async fn get_new_address(&self) -> RpcResult
{ + self.app + .wallet + .get_new_address() + .map_err(convert_wallet_err) + } + + async fn getblockcount(&self) -> RpcResult { + self.app.node.get_height().map_err(convert_node_err) } async fn mine(&self, fee: Option) -> RpcResult<()> { @@ -370,21 +389,6 @@ impl RpcServer for RpcServerImpl { Ok(utxos) } - async fn get_new_address(&self) -> RpcResult
{ - self.app - .wallet - .get_new_address() - .map_err(convert_wallet_err) - } - - async fn generate_mnemonic(&self) -> RpcResult { - let mnemonic = bip39::Mnemonic::new( - bip39::MnemonicType::Words12, - bip39::Language::English, - ); - Ok(mnemonic.to_string()) - } - async fn set_seed_from_mnemonic(&self, mnemonic: String) -> RpcResult<()> { self.app .wallet @@ -399,6 +403,10 @@ impl RpcServer for RpcServerImpl { .map_err(convert_node_err) } + async fn stop(&self) { + std::process::exit(0); + } + async fn transfer( &self, dest: Address, diff --git a/lib/net.rs b/lib/net.rs index ebc6f43..d25ddc5 100644 --- a/lib/net.rs +++ b/lib/net.rs @@ -1,32 +1,62 @@ -use crate::types::{AuthorizedTransaction, Body, Header}; +use std::{collections::HashMap, net::SocketAddr, sync::Arc}; + use quinn::{ClientConfig, Connection, Endpoint, ServerConfig}; use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; -pub use quinn; -use std::collections::HashMap; -use std::{net::SocketAddr, sync::Arc}; +use crate::types::{AuthorizedTransaction, Body, Header}; pub const READ_LIMIT: usize = 1024; -// State. -// Archive. +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("address parse error")] + AddrParse(#[from] std::net::AddrParseError), + #[error("quinn error")] + Io(#[from] std::io::Error), + #[error("connect error")] + Connect(#[from] quinn::ConnectError), + #[error("connection error")] + Connection(#[from] quinn::ConnectionError), + #[error("rcgen")] + RcGen(#[from] rcgen::RcgenError), + #[error("accept error")] + AcceptError, + #[error("read to end error")] + ReadToEnd(#[from] quinn::ReadToEndError), + #[error("write error")] + Write(#[from] quinn::WriteError), + #[error("send datagram error")] + SendDatagram(#[from] quinn::SendDatagramError), + #[error("quinn rustls error")] + QuinnRustls(#[from] quinn::crypto::rustls::Error), + #[error("bincode error")] + Bincode(#[from] bincode::Error), + #[error("already connected to peer at {0}")] + AlreadyConnected(SocketAddr), +} -// Keep track of peer state -// Exchange metadata -// Bulk download -// Propagation -// -// Initial block download -// -// 1. Download headers -// 2. Download blocks -// 3. Update the state -#[derive(Clone)] -pub struct Net { - pub client: Endpoint, - pub server: Endpoint, - pub peers: Arc>>, +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct PeerState { + pub block_height: u32, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Request { + GetBlock { + height: u32, + }, + PushTransaction { + transaction: Box, + }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Response { + Block { header: Header, body: Body }, + NoBlock, + TransactionAccepted, + TransactionRejected, } #[derive(Clone)] @@ -53,27 +83,24 @@ impl Peer { } } -#[derive(Debug, Serialize, Deserialize)] -pub enum Request { - GetBlock { - height: u32, - }, - PushTransaction { - transaction: Box, - }, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum Response { - Block { header: Header, body: Body }, - NoBlock, - TransactionAccepted, - TransactionRejected, -} +// State. +// Archive. -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct PeerState { - pub block_height: u32, +// Keep track of peer state +// Exchange metadata +// Bulk download +// Propagation +// +// Initial block download +// +// 1. Download headers +// 2. Download blocks +// 3. Update the state +#[derive(Clone)] +pub struct Net { + pub client: Endpoint, + pub server: Endpoint, + pub peers: Arc>>, } impl Net { @@ -87,7 +114,8 @@ impl Net { peers, }) } - pub async fn connect(&self, addr: SocketAddr) -> Result { + + pub async fn connect_peer(&self, addr: SocketAddr) -> Result { for peer in self.peers.read().await.values() { if peer.connection.remote_address() == addr { return Err(Error::AlreadyConnected(addr)); @@ -186,31 +214,3 @@ fn configure_client() -> ClientConfig { ClientConfig::new(Arc::new(crypto)) } - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("address parse error")] - AddrParse(#[from] std::net::AddrParseError), - #[error("quinn error")] - Io(#[from] std::io::Error), - #[error("connect error")] - Connect(#[from] quinn::ConnectError), - #[error("connection error")] - Connection(#[from] quinn::ConnectionError), - #[error("rcgen")] - RcGen(#[from] rcgen::RcgenError), - #[error("accept error")] - AcceptError, - #[error("read to end error")] - ReadToEnd(#[from] quinn::ReadToEndError), - #[error("write error")] - Write(#[from] quinn::WriteError), - #[error("send datagram error")] - SendDatagram(#[from] quinn::SendDatagramError), - #[error("quinn rustls error")] - QuinnRustls(#[from] quinn::crypto::rustls::Error), - #[error("bincode error")] - Bincode(#[from] bincode::Error), - #[error("already connected to peer at {0}")] - AlreadyConnected(SocketAddr), -} diff --git a/lib/node.rs b/lib/node.rs index 7d6187d..89b5049 100644 --- a/lib/node.rs +++ b/lib/node.rs @@ -579,8 +579,8 @@ impl Node { Ok(()) } - pub async fn connect(&self, addr: SocketAddr) -> Result<(), Error> { - let peer = self.net.connect(addr).await?; + pub async fn connect_peer(&self, addr: SocketAddr) -> Result<(), Error> { + let peer = self.net.connect_peer(addr).await?; let peer0 = peer.clone(); let node0 = self.clone(); tokio::spawn(async move { @@ -732,7 +732,7 @@ impl Node { connection.remote_address() ); connection.close( - crate::net::quinn::VarInt::from_u32(1), + quinn::VarInt::from_u32(1), b"already connected", ); }