pub(crate) mod account;
pub(crate) mod block;
pub(crate) mod chunk;
pub(crate) mod gas_meter;
#[cfg(feature = "interop_sdk")]
mod sdk;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display};
use std::io;
use std::path::Path;
use std::str::FromStr;
pub use unc_account_id::AccountId;
use unc_primitives::borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};
use sha2::Digest;
use crate::error::{Error, ErrorKind};
use crate::result::Result;
pub use self::account::{AccountDetails, AccountDetailsPatch};
pub use self::chunk::{Chunk, ChunkHeader};
pub use self::gas_meter::GasMeter;
pub type Nonce = u64;
pub use unc_gas::UncGas as Gas;
pub use unc_token::UncToken;
pub type BlockHeight = u64;
pub type ShardId = u64;
fn from_base58(s: &str) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
bs58::decode(s).into_vec().map_err(|err| err.into())
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum KeyType {
ED25519 = 0,
SECP256K1 = 1,
RSA2048 = 2,
}
impl KeyType {
const fn into_unc_keytype(self) -> unc_crypto::KeyType {
match self {
Self::ED25519 => unc_crypto::KeyType::ED25519,
Self::SECP256K1 => unc_crypto::KeyType::SECP256K1,
Self::RSA2048 => unc_crypto::KeyType::RSA2048,
}
}
const fn from_unc_keytype(key_type: unc_crypto::KeyType) -> Self {
match key_type {
unc_crypto::KeyType::ED25519 => Self::ED25519,
unc_crypto::KeyType::SECP256K1 => Self::SECP256K1,
unc_crypto::KeyType::RSA2048 => Self::RSA2048,
}
}
pub const fn data_len(&self) -> usize {
match self {
Self::ED25519 => 32,
Self::SECP256K1 => 64,
Self::RSA2048 => 294,
}
}
}
impl Display for KeyType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.into_unc_keytype())
}
}
impl FromStr for KeyType {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let key_type = unc_crypto::KeyType::from_str(value)
.map_err(|e| ErrorKind::DataConversion.custom(e))?;
Ok(Self::from_unc_keytype(key_type))
}
}
impl TryFrom<u8> for KeyType {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::ED25519),
1 => Ok(Self::SECP256K1),
2 => Ok(Self::RSA2048),
unknown_key_type => Err(ErrorKind::DataConversion
.custom(format!("Unknown key type provided: {unknown_key_type}"))),
}
}
}
impl From<PublicKey> for unc_crypto::PublicKey {
fn from(pk: PublicKey) -> Self {
pk.0
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct PublicKey(pub(crate) unc_crypto::PublicKey);
#[allow(clippy::len_without_is_empty)] impl PublicKey {
pub fn empty(key_type: KeyType) -> Self {
Self(unc_crypto::PublicKey::empty(key_type.into_unc_keytype()))
}
pub fn try_from_parts(key_type: KeyType, bytes: &[u8]) -> Result<Self> {
let mut buf = Vec::new();
buf.push(key_type as u8);
buf.extend(bytes);
Ok(Self(unc_crypto::PublicKey::try_from_slice(&buf).map_err(
|e| {
ErrorKind::DataConversion
.full(format!("Invalid key data for key type: {key_type}"), e)
},
)?))
}
#[cfg(feature = "interop_sdk")]
fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
let key_type = KeyType::try_from(bytes[0])?;
Ok(Self(unc_crypto::PublicKey::try_from_slice(bytes).map_err(
|e| {
ErrorKind::DataConversion
.full(format!("Invalid key data for key type: {key_type}"), e)
},
)?))
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn key_type(&self) -> KeyType {
KeyType::from_unc_keytype(self.0.key_type())
}
pub fn key_data(&self) -> &[u8] {
self.0.key_data()
}
}
impl Display for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for PublicKey {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let pk = unc_crypto::PublicKey::from_str(value)
.map_err(|e| ErrorKind::DataConversion.custom(e))?;
Ok(Self(pk))
}
}
impl BorshSerialize for PublicKey {
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
BorshSerialize::serialize(&(self.len() as u32), writer)?;
BorshSerialize::serialize(&self.0, writer)
}
}
impl BorshDeserialize for PublicKey {
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let len: u32 = BorshDeserialize::deserialize_reader(reader)?;
let pk: unc_crypto::PublicKey = BorshDeserialize::deserialize_reader(reader)?;
if pk.len() != len as usize {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"Key length of {} does not match length of {} read from buffer",
pk.len(),
len
),
));
}
Ok(Self(pk))
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct SecretKey(pub(crate) unc_crypto::SecretKey);
impl SecretKey {
pub fn key_type(&self) -> KeyType {
KeyType::from_unc_keytype(self.0.key_type())
}
pub fn public_key(&self) -> PublicKey {
PublicKey(self.0.public_key())
}
pub fn from_seed(key_type: KeyType, seed: &str) -> Self {
let key_type = key_type.into_unc_keytype();
Self(unc_crypto::SecretKey::from_seed(key_type, seed))
}
pub fn from_random(key_type: KeyType) -> Self {
let key_type = key_type.into_unc_keytype();
Self(unc_crypto::SecretKey::from_random(key_type))
}
}
impl Display for SecretKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "{}", self.0)
}
}
impl FromStr for SecretKey {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let sk = unc_crypto::SecretKey::from_str(value)
.map_err(|e| ErrorKind::DataConversion.custom(e))?;
Ok(Self(sk))
}
}
#[derive(Clone)]
pub struct InMemorySigner {
pub(crate) account_id: AccountId,
pub(crate) secret_key: SecretKey,
}
impl InMemorySigner {
pub fn from_secret_key(account_id: AccountId, secret_key: SecretKey) -> Self {
Self {
account_id,
secret_key,
}
}
pub fn from_file(path: &Path) -> Result<Self> {
let signer =
unc_crypto::InMemorySigner::from_file(path).map_err(|err| ErrorKind::Io.custom(err))?;
Ok(Self::from_secret_key(
signer.account_id,
SecretKey(signer.secret_key),
))
}
pub(crate) fn inner(&self) -> unc_crypto::InMemorySigner {
unc_crypto::InMemorySigner::from_secret_key(
self.account_id.clone(),
self.secret_key.0.clone(),
)
}
}
#[derive(Copy, Clone, Default, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct CryptoHash(pub [u8; 32]);
impl CryptoHash {
pub(crate) fn hash_bytes(bytes: &[u8]) -> Self {
let hash = sha2::Sha256::digest(bytes).into();
Self(hash)
}
}
impl FromStr for CryptoHash {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let bytes = from_base58(s).map_err(|e| ErrorKind::DataConversion.custom(e))?;
Self::try_from(bytes)
}
}
impl TryFrom<&[u8]> for CryptoHash {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != 32 {
return Err(Error::message(
ErrorKind::DataConversion,
format!(
"incorrect hash length (expected 32, but {} was given)",
bytes.len()
),
));
}
let mut buf = [0; 32];
buf.copy_from_slice(bytes);
Ok(Self(buf))
}
}
impl TryFrom<Vec<u8>> for CryptoHash {
type Error = Error;
fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
<Self as TryFrom<&[u8]>>::try_from(v.as_ref())
}
}
impl Debug for CryptoHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self)
}
}
impl Display for CryptoHash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&bs58::encode(self.0).into_string(), f)
}
}
impl From<unc_primitives::hash::CryptoHash> for CryptoHash {
fn from(hash: unc_primitives::hash::CryptoHash) -> Self {
Self(hash.0)
}
}
#[derive(Clone, Debug)]
pub struct AccessKey {
pub nonce: Nonce,
pub permission: AccessKeyPermission,
}
impl AccessKey {
pub fn full_access() -> Self {
Self {
nonce: 0,
permission: AccessKeyPermission::FullAccess,
}
}
pub fn function_call_access(
receiver_id: &AccountId,
method_names: &[&str],
allowance: Option<UncToken>,
) -> Self {
Self {
nonce: 0,
permission: AccessKeyPermission::FunctionCall(FunctionCallPermission {
receiver_id: receiver_id.clone().into(),
method_names: method_names.iter().map(|s| s.to_string()).collect(),
allowance,
}),
}
}
}
#[derive(Clone, Debug)]
pub struct AccessKeyInfo {
pub public_key: PublicKey,
pub access_key: AccessKey,
}
impl From<unc_primitives::views::AccessKeyInfoView> for AccessKeyInfo {
fn from(view: unc_primitives::views::AccessKeyInfoView) -> Self {
Self {
public_key: PublicKey(view.public_key),
access_key: view.access_key.into(),
}
}
}
#[derive(Clone, Debug)]
pub enum AccessKeyPermission {
FunctionCall(FunctionCallPermission),
FullAccess,
}
#[derive(Clone, Debug)]
pub struct FunctionCallPermission {
pub allowance: Option<UncToken>,
pub receiver_id: String,
pub method_names: Vec<String>,
}
impl From<AccessKey> for unc_primitives::account::AccessKey {
fn from(access_key: AccessKey) -> Self {
Self {
nonce: access_key.nonce,
permission: match access_key.permission {
AccessKeyPermission::FunctionCall(function_call_permission) => {
unc_primitives::account::AccessKeyPermission::FunctionCall(
unc_primitives::account::FunctionCallPermission {
allowance: function_call_permission.allowance.map(|a| a.as_attounc()),
receiver_id: function_call_permission.receiver_id,
method_names: function_call_permission.method_names,
},
)
}
AccessKeyPermission::FullAccess => {
unc_primitives::account::AccessKeyPermission::FullAccess
}
},
}
}
}
impl From<unc_primitives::views::AccessKeyView> for AccessKey {
fn from(access_key: unc_primitives::views::AccessKeyView) -> Self {
Self {
nonce: access_key.nonce,
permission: match access_key.permission {
unc_primitives::views::AccessKeyPermissionView::FunctionCall {
allowance,
receiver_id,
method_names,
} => AccessKeyPermission::FunctionCall(FunctionCallPermission {
allowance: allowance.map(UncToken::from_attounc),
receiver_id,
method_names,
}),
unc_primitives::views::AccessKeyPermissionView::FullAccess => {
AccessKeyPermission::FullAccess
}
},
}
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Finality {
Optimistic,
DoomSlug,
Final,
}
impl From<Finality> for unc_primitives::types::BlockReference {
fn from(value: Finality) -> Self {
let value = match value {
Finality::Optimistic => unc_primitives::types::Finality::None,
Finality::DoomSlug => unc_primitives::types::Finality::DoomSlug,
Finality::Final => unc_primitives::types::Finality::Final,
};
value.into()
}
}