mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 13:39:25 +00:00
doc rpc/mod.rs
This commit is contained in:
@@ -250,7 +250,7 @@ impl Protocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transparent structure representing a [https://web.getmonero.org/resources/moneropedia/pedersen-commitment.html]()'s contents.
|
/// Transparent structure representing a [Pedersen commitment](https://web.getmonero.org/resources/moneropedia/pedersen-commitment.html)'s contents.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
|
#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
|
||||||
pub struct Commitment {
|
pub struct Commitment {
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ impl Algorithm<Ed25519> for ClsagMultisig {
|
|||||||
let interim = self.interim.as_ref().unwrap();
|
let interim = self.interim.as_ref().unwrap();
|
||||||
let mut clsag = interim.clsag.clone();
|
let mut clsag = interim.clsag.clone();
|
||||||
// We produced shares as `r - p x`, yet the signature is `r - p x - c x`
|
// We produced shares as `r - p x`, yet the signature is `r - p x - c x`
|
||||||
// Substract `c x` (saved as `c`) now
|
// Subtract `c x` (saved as `c`) now
|
||||||
clsag.s[usize::from(self.input().decoys.i)] = sum.0 - interim.c;
|
clsag.s[usize::from(self.input().decoys.i)] = sum.0 - interim.c;
|
||||||
if clsag
|
if clsag
|
||||||
.verify(
|
.verify(
|
||||||
|
|||||||
@@ -34,8 +34,10 @@ pub use http::*;
|
|||||||
// src/wallet/wallet2.cpp#L121
|
// src/wallet/wallet2.cpp#L121
|
||||||
const GRACE_BLOCKS_FOR_FEE_ESTIMATE: u64 = 10;
|
const GRACE_BLOCKS_FOR_FEE_ESTIMATE: u64 = 10;
|
||||||
|
|
||||||
|
/// A empty marker struct representing an empty response.
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct EmptyResponse {}
|
pub struct EmptyResponse {}
|
||||||
|
/// A generic JSON-RPC response.
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct JsonRpcResponse<T> {
|
pub struct JsonRpcResponse<T> {
|
||||||
result: T,
|
result: T,
|
||||||
@@ -54,6 +56,7 @@ struct TransactionsResponse {
|
|||||||
txs: Vec<TransactionResponse>,
|
txs: Vec<TransactionResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The response data from an [`Rpc::get_outs`] call.
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct OutputResponse {
|
pub struct OutputResponse {
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
@@ -63,27 +66,41 @@ pub struct OutputResponse {
|
|||||||
txid: String,
|
txid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Possible errors that can occur from an RPC call.
|
||||||
|
///
|
||||||
|
/// This represents errors on the client side, as well
|
||||||
|
/// as valid error responses from the server.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "std", derive(thiserror::Error))]
|
#[cfg_attr(feature = "std", derive(thiserror::Error))]
|
||||||
pub enum RpcError {
|
pub enum RpcError {
|
||||||
|
/// There was an internal error.
|
||||||
#[cfg_attr(feature = "std", error("internal error ({0})"))]
|
#[cfg_attr(feature = "std", error("internal error ({0})"))]
|
||||||
InternalError(&'static str),
|
InternalError(&'static str),
|
||||||
|
/// There was a connection error.
|
||||||
#[cfg_attr(feature = "std", error("connection error ({0})"))]
|
#[cfg_attr(feature = "std", error("connection error ({0})"))]
|
||||||
ConnectionError(String),
|
ConnectionError(String),
|
||||||
|
/// The data response received from the node was invalid.
|
||||||
#[cfg_attr(feature = "std", error("invalid node ({0})"))]
|
#[cfg_attr(feature = "std", error("invalid node ({0})"))]
|
||||||
InvalidNode(String),
|
InvalidNode(String),
|
||||||
|
/// The Monero [`Protocol`] version was invalid.
|
||||||
#[cfg_attr(feature = "std", error("unsupported protocol version ({0})"))]
|
#[cfg_attr(feature = "std", error("unsupported protocol version ({0})"))]
|
||||||
UnsupportedProtocol(usize),
|
UnsupportedProtocol(usize),
|
||||||
|
/// Requested transaction hashes were not found.
|
||||||
#[cfg_attr(feature = "std", error("transactions not found"))]
|
#[cfg_attr(feature = "std", error("transactions not found"))]
|
||||||
TransactionsNotFound(Vec<[u8; 32]>),
|
TransactionsNotFound(Vec<[u8; 32]>),
|
||||||
|
/// A curve point received from the node was invalid.
|
||||||
#[cfg_attr(feature = "std", error("invalid point ({0})"))]
|
#[cfg_attr(feature = "std", error("invalid point ({0})"))]
|
||||||
InvalidPoint(String),
|
InvalidPoint(String),
|
||||||
|
/// The transaction(s) requested were pruned from the node.
|
||||||
#[cfg_attr(feature = "std", error("pruned transaction"))]
|
#[cfg_attr(feature = "std", error("pruned transaction"))]
|
||||||
PrunedTransaction,
|
PrunedTransaction,
|
||||||
|
/// An invalid transaction was either sent/received to/from the node.
|
||||||
#[cfg_attr(feature = "std", error("invalid transaction ({0:?})"))]
|
#[cfg_attr(feature = "std", error("invalid transaction ({0:?})"))]
|
||||||
InvalidTransaction([u8; 32]),
|
InvalidTransaction([u8; 32]),
|
||||||
|
/// The node failed to return a fee.
|
||||||
#[cfg_attr(feature = "std", error("unexpected fee response"))]
|
#[cfg_attr(feature = "std", error("unexpected fee response"))]
|
||||||
InvalidFee,
|
InvalidFee,
|
||||||
|
/// The transaction priority level given was invalid.
|
||||||
#[cfg_attr(feature = "std", error("invalid priority"))]
|
#[cfg_attr(feature = "std", error("invalid priority"))]
|
||||||
InvalidPriority,
|
InvalidPriority,
|
||||||
}
|
}
|
||||||
@@ -114,12 +131,15 @@ fn read_epee_vi<R: io::Read>(reader: &mut R) -> io::Result<u64> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let mut vi = u64::from(vi_start >> 2);
|
let mut vi = u64::from(vi_start >> 2);
|
||||||
for i in 1 .. len {
|
for i in 1..len {
|
||||||
vi |= u64::from(read_byte(reader)?) << (((i - 1) * 8) + 6);
|
vi |= u64::from(read_byte(reader)?) << (((i - 1) * 8) + 6);
|
||||||
}
|
}
|
||||||
Ok(vi)
|
Ok(vi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait representing an RPC connection.
|
||||||
|
///
|
||||||
|
/// Note that [`HttpRpc`] already implements this trait.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait RpcConnection: Clone + Debug {
|
pub trait RpcConnection: Clone + Debug {
|
||||||
/// Perform a POST request to the specified route with the specified body.
|
/// Perform a POST request to the specified route with the specified body.
|
||||||
@@ -128,6 +148,7 @@ pub trait RpcConnection: Clone + Debug {
|
|||||||
async fn post(&self, route: &str, body: Vec<u8>) -> Result<Vec<u8>, RpcError>;
|
async fn post(&self, route: &str, body: Vec<u8>) -> Result<Vec<u8>, RpcError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A generic RPC client.
|
||||||
// TODO: Make this provided methods for RpcConnection?
|
// TODO: Make this provided methods for RpcConnection?
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Rpc<R: RpcConnection>(R);
|
pub struct Rpc<R: RpcConnection>(R);
|
||||||
@@ -202,6 +223,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the node's current block height.
|
||||||
pub async fn get_height(&self) -> Result<usize, RpcError> {
|
pub async fn get_height(&self) -> Result<usize, RpcError> {
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct HeightResponse {
|
struct HeightResponse {
|
||||||
@@ -210,6 +232,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
Ok(self.rpc_call::<Option<()>, HeightResponse>("get_height", None).await?.height)
|
Ok(self.rpc_call::<Option<()>, HeightResponse>("get_height", None).await?.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get [`Transaction`]s by their `hashes`.
|
||||||
pub async fn get_transactions(&self, hashes: &[[u8; 32]]) -> Result<Vec<Transaction>, RpcError> {
|
pub async fn get_transactions(&self, hashes: &[[u8; 32]]) -> Result<Vec<Transaction>, RpcError> {
|
||||||
if hashes.is_empty() {
|
if hashes.is_empty() {
|
||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
@@ -274,6 +297,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a single [`Transaction`] by its hash.
|
||||||
pub async fn get_transaction(&self, tx: [u8; 32]) -> Result<Transaction, RpcError> {
|
pub async fn get_transaction(&self, tx: [u8; 32]) -> Result<Transaction, RpcError> {
|
||||||
self.get_transactions(&[tx]).await.map(|mut txs| txs.swap_remove(0))
|
self.get_transactions(&[tx]).await.map(|mut txs| txs.swap_remove(0))
|
||||||
}
|
}
|
||||||
@@ -314,6 +338,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
Ok(block)
|
Ok(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a [`Block`] by its height number.
|
||||||
pub async fn get_block_by_number(&self, number: usize) -> Result<Block, RpcError> {
|
pub async fn get_block_by_number(&self, number: usize) -> Result<Block, RpcError> {
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct BlockResponse {
|
struct BlockResponse {
|
||||||
@@ -341,6 +366,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get all the [`Transaction`]s belonging to the corresponding block `hash`.
|
||||||
pub async fn get_block_transactions(&self, hash: [u8; 32]) -> Result<Vec<Transaction>, RpcError> {
|
pub async fn get_block_transactions(&self, hash: [u8; 32]) -> Result<Vec<Transaction>, RpcError> {
|
||||||
let block = self.get_block(hash).await?;
|
let block = self.get_block(hash).await?;
|
||||||
let mut res = vec![block.miner_tx];
|
let mut res = vec![block.miner_tx];
|
||||||
@@ -405,7 +431,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
let read_object = |reader: &mut &[u8]| -> io::Result<Vec<u64>> {
|
let read_object = |reader: &mut &[u8]| -> io::Result<Vec<u64>> {
|
||||||
let fields = read_byte(reader)? >> 2;
|
let fields = read_byte(reader)? >> 2;
|
||||||
|
|
||||||
for _ in 0 .. fields {
|
for _ in 0..fields {
|
||||||
let name_len = read_byte(reader)?;
|
let name_len = read_byte(reader)?;
|
||||||
let name = read_raw_vec(read_byte, name_len.into(), reader)?;
|
let name = read_raw_vec(read_byte, name_len.into(), reader)?;
|
||||||
|
|
||||||
@@ -458,7 +484,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes_res = vec![];
|
let mut bytes_res = vec![];
|
||||||
for _ in 0 .. iters {
|
for _ in 0..iters {
|
||||||
bytes_res.push(f(reader)?);
|
bytes_res.push(f(reader)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,8 +504,8 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
if bytes_res
|
if bytes_res
|
||||||
.first()
|
.first()
|
||||||
.ok_or_else(|| io::Error::other("status wasn't a string"))?
|
.ok_or_else(|| io::Error::other("status wasn't a string"))?
|
||||||
.as_slice() !=
|
.as_slice()
|
||||||
b"OK"
|
!= b"OK"
|
||||||
{
|
{
|
||||||
// TODO: Better handle non-OK responses
|
// TODO: Better handle non-OK responses
|
||||||
Err(io::Error::other("response wasn't OK"))?;
|
Err(io::Error::other("response wasn't OK"))?;
|
||||||
@@ -623,6 +649,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a [`Fee`] based on [`Protocol::v14`] rules.
|
||||||
async fn get_fee_v14(&self, priority: FeePriority) -> Result<Fee, RpcError> {
|
async fn get_fee_v14(&self, priority: FeePriority) -> Result<Fee, RpcError> {
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct FeeResponseV14 {
|
struct FeeResponseV14 {
|
||||||
@@ -702,6 +729,7 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Broadcast a [`Transaction`] to the network.
|
||||||
pub async fn publish_transaction(&self, tx: &Transaction) -> Result<(), RpcError> {
|
pub async fn publish_transaction(&self, tx: &Transaction) -> Result<(), RpcError> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
@@ -730,6 +758,13 @@ impl<R: RpcConnection> Rpc<R> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate blocks.
|
||||||
|
///
|
||||||
|
/// - `address` is the address that will receive the coinbase reward
|
||||||
|
/// - `block_count` is the number of blocks that will be generated
|
||||||
|
///
|
||||||
|
/// Note this is only for testing with nodes started with `--regtest`, see:
|
||||||
|
/// <https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#generateblocks>.
|
||||||
// TODO: Take &Address, not &str?
|
// TODO: Take &Address, not &str?
|
||||||
pub async fn generate_blocks(
|
pub async fn generate_blocks(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
Reference in New Issue
Block a user