Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ keywords = ["core blockchain", "xcb", "cli"]
license = "MIT OR Apache-2.0"
homepage = "https://github.com/core-coin/core-cli"
repository = "https://github.com/core-coin/core-cli"
version = "0.0.4"
version = "0.0.5"

[workspace.dependencies]
# Workspace members
Expand Down
7 changes: 6 additions & 1 deletion crates/console/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ fn list() {

println!("'xcb' - XCB module commands:");
println!(" 'get_block_height()' - get the current block height");
println!(" 'get_block(<hash>|<number>|'latest')' - get block information by hash or number. Use 'latest' to get the latest block");
println!(" 'get_energy_price()' - get the current energy price to allow a timely execution of a transaction");
println!(" 'get_network_id()' - get the nework ID of the current network");
println!(" 'syncing()' - get the syncing status of the node");
println!(" 'get_block(<hash>|<number>|'latest')' - get block information by hash or number. Use 'latest' to get the latest block");
println!(" 'get_balance(<address>, <block> | 'latest')' - get the balance of an account at a specific block. Use 'latest' to get the latest balance");
println!(" 'get_tx_count(<address>, <block> | 'latest')' - get the transaction count of an account at a specific block. Use 'latest' to get the latest transaction count");
println!(" 'get_code(<address>, <block> | 'latest')' - get the code of an account at a specific block. Use 'latest' to get the latest code");
println!(" 'get_storage_at(<address>, <key>, <block> | 'latest')' - get the storage at a specific key of an account at a specific block. Use 'latest' to get the latest storage");
println!(" 'send_raw_transaction(<transaction>)' - send a raw transaction to the network");

println!("'xcbkey' - XCB Key module commands:");
println!(" 'list()' - list all accounts");
Expand Down
131 changes: 130 additions & 1 deletion crates/modules/src/xcb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,127 @@ impl XcbModule {
}
}

async fn get_balance(&self, args: Vec<String>) -> Result<Response, CliError> {
if args.len() != 2 {
return Err(CliError::InvalidNumberOfArguments("1".to_string()));
}
let address = &args[0];
let block = if args[1] == "latest" {
None
} else {
Some(args[1].parse::<u64>().map_err(|_| {
CliError::InvalidArgument(args[1].clone(), "number or `latest`".to_string())
})?)
};
let balance = self
.client()
.await
.lock()
.await
.get_balance(address.to_string(), block)
.await;
match balance {
Ok(balance) => Ok(Response::U256(balance)),
Err(e) => Err(e),
}
}

async fn get_tx_count(&self, args: Vec<String>) -> Result<Response, CliError> {
if args.len() != 2 {
return Err(CliError::InvalidNumberOfArguments("1".to_string()));
}
let address = &args[0];
let block = if args[1] == "latest" {
None
} else {
Some(args[1].parse::<u64>().map_err(|_| {
CliError::InvalidArgument(args[1].clone(), "number or `latest`".to_string())
})?)
};
let tx_count = self
.client()
.await
.lock()
.await
.get_tx_count(address.to_string(), block)
.await;
match tx_count {
Ok(tx_count) => Ok(Response::U64(tx_count)),
Err(e) => Err(e),
}
}

async fn get_code(&self, args: Vec<String>) -> Result<Response, CliError> {
if args.len() != 2 {
return Err(CliError::InvalidNumberOfArguments("1".to_string()));
}
let address = &args[0];
let block = if args[1] == "latest" {
None
} else {
Some(args[1].parse::<u64>().map_err(|_| {
CliError::InvalidArgument(args[1].clone(), "number or `latest`".to_string())
})?)
};
let code = self
.client()
.await
.lock()
.await
.get_code(address.to_string(), block)
.await;
match code {
Ok(code) => Ok(Response::String(code)),
Err(e) => Err(e),
}
}

async fn send_raw_transaction(&self, args: Vec<String>) -> Result<Response, CliError> {
if args.len() != 1 {
return Err(CliError::InvalidNumberOfArguments("1".to_string()));
}
let tx = &args[0];
let tx_hash = self
.client()
.await
.lock()
.await
.send_raw_transaction(tx.to_string())
.await;
match tx_hash {
Ok(tx_hash) => Ok(Response::String(tx_hash)),
Err(e) => Err(e),
}
}

async fn get_storage_at(&self, args: Vec<String>) -> Result<Response, CliError> {
if args.len() != 3 {
return Err(CliError::InvalidNumberOfArguments("1".to_string()));
}
let address = &args[0];
let key = args[1].parse::<u128>().map_err(|_| {
CliError::InvalidArgument(args[1].clone(), "hex string".to_string())
})?;
let block = if args[2] == "latest" {
None
} else {
Some(args[2].parse::<u64>().map_err(|_| {
CliError::InvalidArgument(args[2].clone(), "number or `latest`".to_string())
})?)
};
let storage = self
.client()
.await
.lock()
.await
.get_storage_at(address.to_string(), key, block)
.await;
match storage {
Ok(storage) => Ok(Response::String(storage)),
Err(e) => Err(e),
}
}

async fn syncing(&self) -> Result<Response, CliError> {
let syncing = self.client().await.lock().await.syncing().await;
match syncing {
Expand All @@ -101,9 +222,17 @@ impl Module for XcbModule {
async fn execute(&mut self, command: String, args: Vec<String>) -> Result<Response, CliError> {
match command.as_str() {
"get_block_height" => self.block_height().await,
"get_block" => self.block(args).await,
"get_energy_price" => self.get_energy_price().await,
"get_network_id" => self.get_network_id().await,

"get_block" => self.block(args).await,
"get_balance" => self.get_balance(args).await,
"get_tx_count" => self.get_tx_count(args).await,
"get_code" => self.get_code(args).await,
"get_storage_at" => self.get_storage_at(args).await,

"send_raw_transaction" => self.send_raw_transaction(args).await,

"syncing" => self.syncing().await,
_ => Err(CliError::UnknownCommand),
}
Expand Down
80 changes: 79 additions & 1 deletion crates/rpc/src/go_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use atoms_provider::{network::Ethereum, Provider, RootProvider};
use atoms_rpc_client::RpcClient as AtomsRpcClient;
use atoms_rpc_types::{Block, BlockId, BlockNumberOrTag, RpcBlockHash, SyncStatus};
use atoms_transport_http::{Client, Http};
use base_primitives::{hex::FromHex, FixedBytes};
use base_primitives::{hex::FromHex, FixedBytes, IcanAddress, U256};
use cli_error::CliError;

pub struct GoCoreClient {
Expand Down Expand Up @@ -99,4 +99,82 @@ impl RpcClient for GoCoreClient {
.map_err(|e| CliError::RpcError(e.to_string()))?;
Ok(response)
}

async fn get_balance(&self, account: String, block: Option<u64>) -> Result<U256, CliError> {
let id = if let Some(number) = block {
BlockId::Number(BlockNumberOrTag::Number(number))
} else {
BlockId::Number(BlockNumberOrTag::Latest)
};
let hex = IcanAddress::from_hex(account)
.map_err(|e| CliError::InvalidHexArgument(e.to_string()))?;
let response = self
.provider
.get_balance(hex, id)
.await
.map_err(|e| CliError::RpcError(e.to_string()))?;
Ok(response)
}

async fn get_tx_count(&self, account: String, block: Option<u64>) -> Result<u64, CliError> {
let id = if let Some(number) = block {
BlockId::Number(BlockNumberOrTag::Number(number))
} else {
BlockId::Number(BlockNumberOrTag::Latest)
};
let hex = IcanAddress::from_hex(account)
.map_err(|e| CliError::InvalidHexArgument(e.to_string()))?;
let response = self
.provider
.get_transaction_count(hex, id)
.await
.map_err(|e| CliError::RpcError(e.to_string()))?;
Ok(response)
}

async fn get_code(&self, account: String, block: Option<u64>) -> Result<String, CliError> {
let id = if let Some(number) = block {
BlockId::Number(BlockNumberOrTag::Number(number))
} else {
BlockId::Number(BlockNumberOrTag::Latest)
};
let hex = IcanAddress::from_hex(account)
.map_err(|e| CliError::InvalidHexArgument(e.to_string()))?;
let response = self
.provider
.get_code_at(hex, id)
.await
.map_err(|e| CliError::RpcError(e.to_string()))?;
Ok(response.to_string())
}

async fn send_raw_transaction(&self, tx: String) -> Result<String, CliError> {
let response = self
.provider
.send_raw_transaction(tx.as_bytes())
.await
.map_err(|e| CliError::RpcError(e.to_string()))?;
Ok(response.tx_hash().to_string())
}

async fn get_storage_at(
&self,
address: String,
key: u128,
block: Option<u64>,
) -> Result<String, CliError> {
let id = if let Some(number) = block {
BlockId::Number(BlockNumberOrTag::Number(number))
} else {
BlockId::Number(BlockNumberOrTag::Latest)
};
let hex = IcanAddress::from_hex(address)
.map_err(|e| CliError::InvalidHexArgument(e.to_string()))?;
let response = self
.provider
.get_storage_at(hex, U256::from(key), id)
.await
.map_err(|e| CliError::RpcError(e.to_string()))?;
Ok(response.to_string())
}
}
14 changes: 14 additions & 0 deletions crates/rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use async_trait::async_trait;
use atoms_rpc_types::{Block, SyncStatus};
use base_primitives::U256;
use cli_error::CliError;

pub mod go_core;
Expand All @@ -19,4 +20,17 @@ pub trait RpcClient {
async fn get_network_id(&self) -> Result<u64, CliError>;

async fn syncing(&self) -> Result<SyncStatus, CliError>;

async fn get_balance(&self, account: String, block: Option<u64>) -> Result<U256, CliError>;
async fn get_tx_count(&self, account: String, block: Option<u64>) -> Result<u64, CliError>;
async fn get_code(&self, account: String, block: Option<u64>) -> Result<String, CliError>;

async fn get_storage_at(
&self,
account: String,
key: u128,
block: Option<u64>,
) -> Result<String, CliError>;

async fn send_raw_transaction(&self, tx: String) -> Result<String, CliError>;
}
21 changes: 21 additions & 0 deletions crates/rpc/src/mock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{CliError, RpcClient};
use async_trait::async_trait;
use atoms_rpc_types::Block;
use base_primitives::U256;

pub struct MockRpcClient {
pub block_height: u64,
Expand Down Expand Up @@ -96,4 +97,24 @@ impl RpcClient for MockRpcClient {
async fn syncing(&self) -> Result<atoms_rpc_types::SyncStatus, CliError> {
Ok(self.syncing)
}

async fn get_balance(&self, _account: String, _block: Option<u64>) -> Result<U256, CliError> {
Ok(U256::from(0))
}

async fn get_tx_count(&self, _account: String, _block: Option<u64>) -> Result<u64, CliError> {
Ok(0)
}

async fn get_code(&self, _account: String, _block: Option<u64>) -> Result<String, CliError> {
Ok("".to_string())
}

async fn send_raw_transaction(&self, _tx: String) -> Result<String, CliError> {
Ok("".to_string())
}

async fn get_storage_at(&self, _account: String, _key: u128, _block: Option<u64>) -> Result<String, CliError> {
Ok("".to_string())
}
}
3 changes: 2 additions & 1 deletion crates/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ chrono.workspace = true
hex.workspace = true

atoms-rpc-types.workspace = true
atoms-signer-wallet.workspace = true
atoms-signer-wallet.workspace = true
base-primitives.workspace = true
4 changes: 4 additions & 0 deletions crates/types/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::Serialize;

use crate::{account::KeyFile, Account};
use atoms_rpc_types::SyncStatus;
use base_primitives::U256;
use std::str::FromStr;

/// ResponseView decided if response of call will be returned as a string, json object or human readable format
Expand Down Expand Up @@ -34,6 +35,7 @@ impl FromStr for ResponseView {
pub enum Response {
U64(u64),
U128(u128),
U256(U256),

Bool(bool),
String(String),
Expand All @@ -51,6 +53,7 @@ impl std::fmt::Display for Response {
match self {
Response::U64(val) => write!(f, "{}", val),
Response::U128(val) => write!(f, "{}", val),
Response::U256(val) => write!(f, "{}", val),
Response::Bool(val) => write!(f, "{}", val),
Response::String(val) => write!(f, "{}", val),
Response::Block(val) => write!(
Expand Down Expand Up @@ -101,6 +104,7 @@ impl Response {
match self {
Response::U64(val) => format!("u64 value: {:#?}", val),
Response::U128(val) => format!("U128 value: {:#?}", val),
Response::U256(val) => format!("U256 value: {:#?}", val),
Response::Bool(val) => format!("Boolean value: {:#?}", val),
Response::String(val) => format!("String value: {:#?}", val),
Response::Block(val) => format!("{:#?}", val),
Expand Down
Loading