From b0b1cda8999bf3833068e4f126dfa4a0a9018bb4 Mon Sep 17 00:00:00 2001 From: Miraculous Owonubi Date: Sun, 21 Aug 2022 22:53:21 +0400 Subject: [PATCH 1/3] refactor primitives for abi embedding --- Cargo.toml | 2 +- src/lib.rs | 127 ++++----------------------------------------- src/private.rs | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 119 deletions(-) create mode 100644 src/private.rs diff --git a/Cargo.toml b/Cargo.toml index d89106a..f25c7a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,4 @@ schemars = "0.8.8" serde_json = "1" [features] -versioned-entries = [] +chunked-entries = [] diff --git a/src/lib.rs b/src/lib.rs index 8d2400a..7fb1120 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,16 @@ -use std::collections::{HashMap, HashSet}; -use std::fmt; +use std::collections::HashMap; + +#[cfg(feature = "chunked-entries")] +mod private; +#[cfg(feature = "chunked-entries")] +pub use private::{AbiCombineError, AbiCombineErrorKind, ChunkedAbiEntry}; use borsh::schema::{BorshSchemaContainer, Declaration, Definition, Fields, VariantName}; use schemars::schema::{RootSchema, Schema}; use serde::{Deserialize, Serialize}; /// Current version of the ABI schema format. -const ABI_SCHEMA_SEMVER: &str = env!("CARGO_PKG_VERSION"); +pub const SCHEMA_VERSION: &str = env!("CARGO_PKG_VERSION"); /// Contract ABI. #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] @@ -20,8 +24,8 @@ pub struct AbiRoot { } impl AbiRoot { - #[cfg(feature = "versioned-entries")] - pub fn new(metadata: AbiMetadata, versioned_abi: VersionedAbiEntry) -> AbiRoot { + #[cfg(feature = "chunked-entries")] + pub fn new(metadata: AbiMetadata, versioned_abi: ChunkedAbiEntry) -> AbiRoot { AbiRoot { abi_schema_version: versioned_abi.abi_schema_version, metadata, @@ -59,119 +63,6 @@ pub struct AbiEntry { pub root_schema: RootSchema, } -/// Core ABI information, with schema version. -#[cfg(feature = "versioned-entries")] -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct VersionedAbiEntry { - /// Semver of the ABI schema format. - abi_schema_version: String, - #[serde(flatten)] - pub abi: AbiEntry, -} - -#[cfg(feature = "versioned-entries")] -impl VersionedAbiEntry { - pub fn new(functions: Vec, root_schema: RootSchema) -> VersionedAbiEntry { - Self { - abi_schema_version: ABI_SCHEMA_SEMVER.to_string(), - abi: AbiEntry { - functions, - root_schema, - }, - } - } - - pub fn combine>( - entries: I, - ) -> Result { - let mut abi_schema_version = None; - let mut functions = Vec::::new(); - let mut gen = schemars::gen::SchemaGenerator::default(); - let definitions = gen.definitions_mut(); - - let mut unexpected_versions = HashSet::new(); - - for entry in entries { - if let Some(ref abi_schema_version) = abi_schema_version { - // should probably only disallow major version mismatch - if abi_schema_version != &entry.abi_schema_version { - unexpected_versions.insert(entry.abi_schema_version.clone()); - continue; - } - } else { - abi_schema_version = Some(entry.abi_schema_version); - } - - // Update resulting JSON Schema - definitions.extend(entry.abi.root_schema.definitions.to_owned()); - - // Update resulting function list - functions.extend(entry.abi.functions); - } - - if !unexpected_versions.is_empty() { - return Err(AbiCombineError { - kind: AbiCombineErrorKind::SchemaVersionConflict { - expected: abi_schema_version.unwrap(), - found: unexpected_versions.into_iter().collect(), - }, - }); - } - - // Sort the function list for readability - functions.sort_by(|x, y| x.name.cmp(&y.name)); - - Ok(VersionedAbiEntry { - abi_schema_version: abi_schema_version.unwrap(), - abi: AbiEntry { - functions, - root_schema: gen.into_root_schema_for::(), - }, - }) - } -} - -#[derive(Eq, Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct AbiCombineError { - #[serde(flatten)] - kind: AbiCombineErrorKind, -} - -impl AbiCombineError { - pub fn kind(&self) -> &AbiCombineErrorKind { - &self.kind - } -} - -impl std::error::Error for AbiCombineError {} -impl fmt::Display for AbiCombineError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.kind.fmt(f) - } -} - -#[derive(Eq, Clone, Debug, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "SCREAMING_SNAKE_CASE")] -pub enum AbiCombineErrorKind { - SchemaVersionConflict { - expected: String, - found: Vec, - }, -} - -impl fmt::Display for AbiCombineErrorKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - AbiCombineErrorKind::SchemaVersionConflict { expected, found } => format!( - "ABI schema version conflict: expected {}, found {}", - expected, - found.join(", ") - ) - .fmt(f), - } - } -} - /// ABI of a single function. #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct AbiFunction { diff --git a/src/private.rs b/src/private.rs new file mode 100644 index 0000000..f185405 --- /dev/null +++ b/src/private.rs @@ -0,0 +1,136 @@ +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use super::{AbiEntry, AbiFunction, RootSchema, SCHEMA_VERSION}; + +/// Core ABI information, with schema version and identity hash. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct ChunkedAbiEntry { + /// Semver of the ABI schema format. + pub(crate) abi_schema_version: String, + pub source_hash: u64, + #[serde(flatten)] + pub abi: AbiEntry, +} + +impl ChunkedAbiEntry { + pub fn new( + source_hash: u64, + functions: Vec, + root_schema: RootSchema, + ) -> ChunkedAbiEntry { + Self { + abi_schema_version: SCHEMA_VERSION.to_string(), + source_hash, + abi: AbiEntry { + functions, + root_schema, + }, + } + } + + pub fn combine>( + entries: I, + ) -> Result { + let mut abi_schema_version = None; + let mut functions = Vec::::new(); + let mut source_hash = None; + + let mut gen = schemars::gen::SchemaGenerator::default(); + let definitions = gen.definitions_mut(); + + let mut unexpected_versions = std::collections::HashSet::new(); + + for entry in entries { + if let Some(ref abi_schema_version) = abi_schema_version { + // should probably only disallow major version mismatch + if abi_schema_version != &entry.abi_schema_version { + unexpected_versions.insert(entry.abi_schema_version.clone()); + continue; + } + } else { + abi_schema_version = Some(entry.abi_schema_version); + } + if let Some(ref source_hash) = source_hash { + if source_hash != &entry.source_hash { + return Err(AbiCombineError { + kind: AbiCombineErrorKind::SourceConflict, + }); + } + } else { + source_hash = Some(entry.source_hash); + } + + // Update resulting JSON Schema + definitions.extend(entry.abi.root_schema.definitions.to_owned()); + + // Update resulting function list + functions.extend(entry.abi.functions); + } + + if !unexpected_versions.is_empty() { + return Err(AbiCombineError { + kind: AbiCombineErrorKind::SchemaVersionConflict { + expected: abi_schema_version.unwrap(), + found: unexpected_versions.into_iter().collect(), + }, + }); + } + + // Sort the function list for readability + functions.sort_by(|x, y| x.name.cmp(&y.name)); + + Ok(ChunkedAbiEntry { + abi_schema_version: abi_schema_version.unwrap(), + source_hash: source_hash.unwrap(), + abi: AbiEntry { + functions, + root_schema: gen.into_root_schema_for::(), + }, + }) + } +} + +#[derive(Eq, Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct AbiCombineError { + #[serde(flatten)] + kind: AbiCombineErrorKind, +} + +impl AbiCombineError { + pub fn kind(&self) -> &AbiCombineErrorKind { + &self.kind + } +} + +impl std::error::Error for AbiCombineError {} +impl fmt::Display for AbiCombineError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.kind.fmt(f) + } +} + +#[derive(Eq, Clone, Debug, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum AbiCombineErrorKind { + SchemaVersionConflict { + expected: String, + found: Vec, + }, + SourceConflict, +} + +impl fmt::Display for AbiCombineErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::SchemaVersionConflict { expected, found } => format!( + "ABI schema version conflict: expected {}, found {}", + expected, + found.join(", ") + ) + .fmt(f), + Self::SourceConflict => "ABI entry source conflict".fmt(f), + } + } +} From bed9b5253971870643567dca79f2abc95a8be17a Mon Sep 17 00:00:00 2001 From: Miraculous Owonubi Date: Mon, 22 Aug 2022 00:28:37 +0400 Subject: [PATCH 2/3] keep clippy happy --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7fb1120..2fbdbf5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,7 +167,7 @@ mod borsh_clone { pub fn clone_definition(definition: &Definition) -> Definition { match definition { Definition::Array { length, elements } => Definition::Array { - length: length.clone(), + length: *length, elements: elements.clone(), }, Definition::Sequence { elements } => Definition::Sequence { From 5c7f78051f900d4dd92a1071d42bbca59b42a178 Mon Sep 17 00:00:00 2001 From: Miraculous Owonubi Date: Mon, 22 Aug 2022 13:14:17 +0400 Subject: [PATCH 3/3] drop source hash --- src/private.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/private.rs b/src/private.rs index f185405..2b40d01 100644 --- a/src/private.rs +++ b/src/private.rs @@ -9,20 +9,14 @@ use super::{AbiEntry, AbiFunction, RootSchema, SCHEMA_VERSION}; pub struct ChunkedAbiEntry { /// Semver of the ABI schema format. pub(crate) abi_schema_version: String, - pub source_hash: u64, #[serde(flatten)] pub abi: AbiEntry, } impl ChunkedAbiEntry { - pub fn new( - source_hash: u64, - functions: Vec, - root_schema: RootSchema, - ) -> ChunkedAbiEntry { + pub fn new(functions: Vec, root_schema: RootSchema) -> ChunkedAbiEntry { Self { abi_schema_version: SCHEMA_VERSION.to_string(), - source_hash, abi: AbiEntry { functions, root_schema, @@ -35,7 +29,6 @@ impl ChunkedAbiEntry { ) -> Result { let mut abi_schema_version = None; let mut functions = Vec::::new(); - let mut source_hash = None; let mut gen = schemars::gen::SchemaGenerator::default(); let definitions = gen.definitions_mut(); @@ -52,15 +45,6 @@ impl ChunkedAbiEntry { } else { abi_schema_version = Some(entry.abi_schema_version); } - if let Some(ref source_hash) = source_hash { - if source_hash != &entry.source_hash { - return Err(AbiCombineError { - kind: AbiCombineErrorKind::SourceConflict, - }); - } - } else { - source_hash = Some(entry.source_hash); - } // Update resulting JSON Schema definitions.extend(entry.abi.root_schema.definitions.to_owned()); @@ -83,7 +67,6 @@ impl ChunkedAbiEntry { Ok(ChunkedAbiEntry { abi_schema_version: abi_schema_version.unwrap(), - source_hash: source_hash.unwrap(), abi: AbiEntry { functions, root_schema: gen.into_root_schema_for::(), @@ -118,7 +101,6 @@ pub enum AbiCombineErrorKind { expected: String, found: Vec, }, - SourceConflict, } impl fmt::Display for AbiCombineErrorKind { @@ -130,7 +112,6 @@ impl fmt::Display for AbiCombineErrorKind { found.join(", ") ) .fmt(f), - Self::SourceConflict => "ABI entry source conflict".fmt(f), } } }