Skip to content

Commit

Permalink
add private network to network enum (#7)
Browse files Browse the repository at this point in the history
* add private network to network enum

* remove utils::NetworkType and replace it with types::Network

* added test for network
  • Loading branch information
error2215 committed Aug 28, 2023
1 parent 7ee774a commit 9d15431
Show file tree
Hide file tree
Showing 20 changed files with 193 additions and 168 deletions.
12 changes: 6 additions & 6 deletions corebc-blockindex/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,21 @@ impl Client {
let mut res: Transaction = serde_json::from_value(response.clone())?;
res.from = response["vin"][0]["addresses"][0].to_string().replace('\"', "");
res.to = response["vout"][0]["addresses"][0].to_string().replace('\"', "");
res.status = response["ethereumSpecific"]["status"]
res.status = response["corecoinSpecific"]["status"]
.as_u64()
.ok_or_else(|| BlockindexError::Builder("status".to_string()))?;
res.nonce = response["ethereumSpecific"]["nonce"]
res.nonce = response["corecoinSpecific"]["nonce"]
.as_u64()
.ok_or_else(|| BlockindexError::Builder("nonce".to_string()))?;
res.energy_limit = response["ethereumSpecific"]["energyLimit"]
res.energy_limit = response["corecoinSpecific"]["energyLimit"]
.as_u64()
.ok_or_else(|| BlockindexError::Builder("energyLimit".to_string()))?;
res.energy_used = response["ethereumSpecific"]["energyUsed"]
res.energy_used = response["corecoinSpecific"]["energyUsed"]
.as_u64()
.ok_or_else(|| BlockindexError::Builder("energyUsed".to_string()))?;
res.energy_price =
response["ethereumSpecific"]["energyPrice"].to_string().replace('\"', "");
res.data = response["ethereumSpecific"]["data"].to_string().replace('\"', "");
response["corecoinSpecific"]["energyPrice"].to_string().replace('\"', "");
res.data = response["corecoinSpecific"]["data"].to_string().replace('\"', "");

Ok(res)
}
Expand Down
4 changes: 2 additions & 2 deletions corebc-blockindex/tests/it/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ async fn get_balance_history_success() {
let account = &"ab30f0091ce7386584b85eecf92f75157582179887ce".parse().unwrap();
run_with_client(Network::Devin, |client| async move {
let history = client.get_balance_history(account, None).await;
assert_eq!(history.unwrap().len(), 2);
assert_eq!(history.unwrap().len(), 4);
})
.await
}
Expand All @@ -92,7 +92,7 @@ async fn get_balance_history_empty() {
run_with_client(Network::Devin, |client| async move {
let history = client
.get_balance_history(
&"ae57dde1a47041fc3c570c0318a713128ced55fd2ada".parse().unwrap(),
&"ab720000000000000000000000000000000000000000".parse().unwrap(),
None,
)
.await;
Expand Down
4 changes: 2 additions & 2 deletions corebc-contract/src/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,15 +320,15 @@ where
/// # Example
///
/// ```no_run
/// use corebc_ylem::Solc;
/// use corebc_ylem::Ylem;
/// use corebc_contract::ContractFactory;
/// use corebc_providers::{Provider, Http};
/// use std::convert::TryFrom;
///
/// # async fn foo() -> Result<(), Box<dyn std::error::Error>> {
/// // first we'll compile the contract (you can alternatively compile it yourself
/// // and pass the ABI/Bytecode
/// let compiled = Solc::default().compile_source("./tests/contract.sol").unwrap();
/// let compiled = Ylem::default().compile_source("./tests/contract.sol").unwrap();
/// let contract = compiled
/// .get("./tests/contract.sol", "SimpleStorage")
/// .expect("could not find contract");
Expand Down
4 changes: 2 additions & 2 deletions corebc-contract/tests/it/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use corebc_core::{
utils::AnvilInstance,
};
use corebc_providers::{Http, Middleware, Provider};
use corebc_ylem::Solc;
use corebc_ylem::Ylem;
use std::{convert::TryFrom, sync::Arc, time::Duration};

// Note: The `EthEvent` derive macro implements the necessary conversion between `Tokens` and
Expand All @@ -25,7 +25,7 @@ pub struct ValueChanged {
#[track_caller]
pub fn compile_contract(name: &str, filename: &str) -> (Abi, Bytes) {
let path = format!("./tests/solidity-contracts/{filename}");
let compiled = Solc::default().compile_source(&path).unwrap();
let compiled = Ylem::default().compile_source(&path).unwrap();
let contract = compiled.get(&path, name).expect("could not find contract");
let (abi, bin, _) = contract.into_parts_or_default();
(abi, bin)
Expand Down
177 changes: 106 additions & 71 deletions corebc-core/src/types/network.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,18 @@
use super::{U128, U256, U512, U64};
use serde::{Deserialize, Serialize, Serializer};
use std::{
convert::{TryFrom, TryInto},
fmt,
time::Duration,
};
use strum::{AsRefStr, EnumCount, EnumIter, EnumString, EnumVariantNames};

// compatibility re-export
#[doc(hidden)]
pub use num_enum::{TryFromPrimitive, TryFromPrimitiveError};
#[doc(hidden)]
pub type ParseNetworkError = TryFromPrimitiveError<Network>;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{convert::TryFrom, fmt, str::FromStr, time::Duration};
use strum::{EnumCount, EnumIter, EnumVariantNames};

#[derive(Debug)]
pub struct ParseNetworkError {
pub number: u64,
}

// When adding a new network:
// 1. add new variant to the Network enum;
// 2. add extra information in the last `impl` block (explorer URLs, block time) when applicable;
// 3. (optional) add aliases:
// - Strum (in kebab-case): `#[strum(to_string = "<main>", serialize = "<aliasX>", ...)]`
// `to_string = "<main>"` must be present and will be used in `Display`, `Serialize`
// and `FromStr`, while `serialize = "<aliasX>"` will be appended to `FromStr`.
// More info: <https://docs.rs/strum/latest/strum/additional_attributes/index.html#attributes-on-variants>
// - Serde (in snake_case): `#[serde(alias = "<aliasX>", ...)]`
// Aliases are appended to the `Deserialize` implementation.
// More info: <https://serde.rs/variant-attrs.html>
// - Add a test at the bottom of the file

// We don't derive Serialize because it is manually implemented using AsRef<str> and it would
// break a lot of things since Serialize is `kebab-case` vs Deserialize `snake_case`.
// This means that the Network type is not "round-trippable", because the Serialize and Deserialize
// implementations do not use the same case style.

/// An Ethereum EIP-155 Network.
#[derive(
Clone,
Expand All @@ -41,30 +23,19 @@ pub type ParseNetworkError = TryFromPrimitiveError<Network>;
PartialOrd,
Ord,
Hash,
AsRefStr, // AsRef<str>, fmt::Display and serde::Serialize
EnumVariantNames, // Network::VARIANTS
EnumString, // FromStr, TryFrom<&str>
EnumIter, // Network::iter
EnumCount, // Network::COUNT
TryFromPrimitive, // TryFrom<u64>
Deserialize,
EnumCount, /* Network::COUNT */
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "kebab-case")]
#[repr(u64)]
pub enum Network {
#[strum(to_string = "mainnet", serialize = "xcblive")]
#[serde(alias = "xcblive")]
Mainnet = 1,
#[strum(to_string = "devin", serialize = "xablive")]
#[serde(alias = "xablive")]
Devin = 3,
Private(u64),
}

// === impl Network ===

// This must be implemented manually so we avoid a conflict with `TryFromPrimitive` where it treats
// the `#[default]` attribute as its own `#[num_enum(default)]`
impl Default for Network {
fn default() -> Self {
Self::Mainnet
Expand All @@ -75,7 +46,11 @@ macro_rules! impl_into_numeric {
($($ty:ty)+) => {$(
impl From<Network> for $ty {
fn from(network: Network) -> Self {
u64::from(network).into()
match network {
Network::Mainnet => (1 as u64).into(),
Network::Devin =>(3 as u64).into(),
Network::Private(n) => (n as u64).into(),
}
}
}
)+};
Expand All @@ -88,7 +63,11 @@ macro_rules! impl_try_from_numeric {
type Error = ParseNetworkError;

fn try_from(value: $native) -> Result<Self, Self::Error> {
(value as u64).try_into()
match value as u64 {
1 => Ok(Network::Mainnet),
3 => Ok(Network::Devin),
n => Ok(Network::Private(n)),
}
}
}
)+
Expand All @@ -99,11 +78,13 @@ macro_rules! impl_try_from_numeric {

fn try_from(value: $primitive) -> Result<Self, Self::Error> {
if value.bits() > 64 {
// `TryFromPrimitiveError` only has a `number` field which has the same type
// as the `#[repr(_)]` attribute on the enum.
return Err(ParseNetworkError { number: value.low_u64() })
}
value.low_u64().try_into()
match value.low_u64() {
1 => Ok(Network::Mainnet),
3 => Ok(Network::Devin),
n => Ok(Network::Private(n)),
}
}
}
)*
Expand All @@ -112,7 +93,11 @@ macro_rules! impl_try_from_numeric {

impl From<Network> for u64 {
fn from(network: Network) -> Self {
network as u64
match network {
Network::Mainnet => 1,
Network::Devin => 3,
Network::Private(n) => n,
}
}
}

Expand All @@ -122,15 +107,31 @@ impl TryFrom<U64> for Network {
type Error = ParseNetworkError;

fn try_from(value: U64) -> Result<Self, Self::Error> {
value.low_u64().try_into()
match value.low_u64() {
1 => Ok(Network::Mainnet),
3 => Ok(Network::Devin),
n => Ok(Network::Private(n)),
}
}
}

impl_try_from_numeric!(u8 u16 u32 usize; U128 U256 U512);
impl TryFrom<&str> for Network {
type Error = ParseNetworkError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(Network::from(value.to_string()))
}
}

impl_try_from_numeric!(u8 u16 u32 u64 usize; U128 U256 U512);

impl fmt::Display for Network {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(self.as_ref())
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Network::Mainnet => write!(f, "mainnet"),
Network::Devin => write!(f, "devin"),
Network::Private(id) => write!(f, "private-{}", id),
}
}
}

Expand All @@ -139,7 +140,42 @@ impl Serialize for Network {
where
S: Serializer,
{
s.serialize_str(self.as_ref())
s.serialize_str(format!("{}", self).as_str())
}
}

impl<'de> Deserialize<'de> for Network {
fn deserialize<D>(deserializer: D) -> Result<Network, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(Network::from(s))
}
}

impl From<String> for Network {
fn from(s: String) -> Network {
match s.as_str() {
"mainnet" => Network::Mainnet,
"devin" => Network::Devin,
unknown => {
if let ["private", id_str] = unknown.split('-').collect::<Vec<_>>().as_slice() {
if let Ok(id) = id_str.parse::<u64>() {
return Network::Private(id)
}
}
panic!("Unknown network: {}", unknown);
}
}
}
}

impl FromStr for Network {
type Err = ParseNetworkError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Network::from(s.to_string()))
}
}

Expand Down Expand Up @@ -171,7 +207,7 @@ impl Network {
use Network::*;

let ms = match self {
Mainnet | Devin => 7_000,
Mainnet | Devin | Private(_) => 7_000,
};

Some(Duration::from_millis(ms))
Expand All @@ -192,7 +228,7 @@ impl Network {

match self {
// Known EIP-1559 networks
Mainnet | Devin => false,
Mainnet | Devin | Private(_) => false,
}
}

Expand Down Expand Up @@ -220,6 +256,7 @@ impl Network {
let urls = match self {
Mainnet => ("https://blockindex.net/api/v2", "https://blockindex.net"),
Devin => ("https://devin.blockindex.net/api/v2", "https://devin.blockindex.net"),
Private(_) => ("", ""),
};

Some(urls)
Expand All @@ -246,7 +283,6 @@ mod tests {
for network in Network::iter() {
let network_string = network.to_string();
assert_eq!(network_string, format!("{network}"));
assert_eq!(network_string.as_str(), network.as_ref());
assert_eq!(serde_json::to_string(&network).unwrap(), format!("\"{network_string}\""));

assert_eq!(network_string.parse::<Network>().unwrap(), network);
Expand All @@ -257,28 +293,10 @@ mod tests {
fn roundtrip_serde() {
for network in Network::iter() {
let network_string = serde_json::to_string(&network).unwrap();
let network_string = network_string.replace('-', "_");
assert_eq!(serde_json::from_str::<'_, Network>(&network_string).unwrap(), network);
}
}

#[test]
// CORETODO: Needs anvil
fn aliases() {
use Network::*;

// kebab-case
const ALIASES: &[(Network, &[&str])] = &[(Mainnet, &["xcblive"]), (Devin, &["xablive"])];

for &(network, aliases) in ALIASES {
for &alias in aliases {
assert_eq!(alias.parse::<Network>().unwrap(), network);
let s = alias.to_string().replace('-', "_");
assert_eq!(serde_json::from_str::<Network>(&format!("\"{s}\"")).unwrap(), network);
}
}
}

#[test]
fn serde_to_string_match() {
for network in Network::iter() {
Expand All @@ -287,4 +305,21 @@ mod tests {
assert_eq!(network_serde, network_string);
}
}

#[test]
fn u64_to_network() {
let mainnet = Network::try_from(1u64).expect("cannot parse mainnet network_id");
assert_eq!(mainnet, Network::Mainnet);

let devin = Network::try_from(3u64).expect("cannot parse devin network_id");
assert_eq!(devin, Network::Devin);

let private = Network::try_from(6u64).expect("cannot parse private network_id 6");
assert_eq!(private, Network::Private(6));

for network_id in 1..10u64 {
let network = Network::try_from(network_id).expect("cannot parse u64 as network_id");
assert_eq!(u64::from(network), network_id);
}
}
}
6 changes: 3 additions & 3 deletions corebc-core/src/types/signature.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Code adapted from: https://github.com/tomusdrw/rust-web3/blob/master/src/api/accounts.rs
use crate::{
types::{Address, H256, U256},
utils::{hash_message, to_ican, NetworkType},
types::{Address, Network, H256, U256},
utils::{hash_message, to_ican},
};
use elliptic_curve::{consts::U32, sec1::ToEncodedPoint};
use ethabi::ethereum_types::H160;
Expand Down Expand Up @@ -133,7 +133,7 @@ impl Signature {
bytes.copy_from_slice(&hash[12..]);
let addr = H160::from(bytes);
// CORETODO: Change the networktype logic
Ok(to_ican(&addr, &NetworkType::Mainnet))
Ok(to_ican(&addr, &Network::Mainnet))
}

/// Retrieves the recovery signature.
Expand Down

0 comments on commit 9d15431

Please sign in to comment.