Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements abi spec changes. #25

Merged
merged 9 commits into from
Jul 24, 2024
113 changes: 56 additions & 57 deletions src/abi/full_program.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
use std::collections::HashMap;

use crate::{
abi::program::{
ABIFunction, Attribute, Configurable, LoggedType, ProgramABI, TypeApplication,
TypeDeclaration,
},
utils::extract_custom_type_name,
};
use crate::{abi::program::Attribute, utils::extract_custom_type_name};

use crate::{
error::{error, Error, Result},
utils::TypePath,
};

use super::program::Version;
use super::{
program::Version,
unified_program::{
UnifiedABIFunction, UnifiedConfigurable, UnifiedLoggedType, UnifiedProgramABI,
UnifiedTypeApplication, UnifiedTypeDeclaration,
},
};

/// 'Full' versions of the ABI structures are needed to simplify duplicate
/// detection later on. The original ones([`ProgramABI`], [`TypeApplication`],
/// [`TypeDeclaration`] and others) are not suited for this due to their use of
/// detection later on. The original ones([`UnifiedProgramABI`], [`UnifiedTypeApplication`],
/// [`UnifiedTypeDeclaration`] and others) are not suited for this due to their use of
/// ids, which might differ between contracts even though the type they
/// represent is virtually the same.
#[derive(Debug, Clone)]
pub struct FullProgramABI {
pub encoding: Option<Version>,
pub program_type: String,
pub spec_version: Version,
pub encoding_version: Version,
pub types: Vec<FullTypeDeclaration>,
pub functions: Vec<FullABIFunction>,
pub logged_types: Vec<FullLoggedType>,
Expand All @@ -31,45 +33,47 @@ pub struct FullProgramABI {

impl FullProgramABI {
pub fn from_json_abi(abi: &str) -> Result<Self> {
let parsed_abi: ProgramABI = serde_json::from_str(abi)?;
FullProgramABI::from_counterpart(&parsed_abi)
let unified_program_abi = UnifiedProgramABI::from_json_abi(abi)?;
FullProgramABI::from_counterpart(&unified_program_abi)
}

fn from_counterpart(program_abi: &ProgramABI) -> Result<FullProgramABI> {
let lookup: HashMap<_, _> = program_abi
fn from_counterpart(unified_program_abi: &UnifiedProgramABI) -> Result<FullProgramABI> {
let lookup: HashMap<_, _> = unified_program_abi
.types
.iter()
.map(|ttype| (ttype.type_id.clone(), ttype.clone()))
.map(|ttype| (ttype.type_id, ttype.clone()))
.collect();

let types = program_abi
let types = unified_program_abi
.types
.iter()
.map(|ttype| FullTypeDeclaration::from_counterpart(ttype, &lookup))
.collect();

let functions = program_abi
let functions = unified_program_abi
.functions
.iter()
.map(|fun| FullABIFunction::from_counterpart(fun, &lookup))
.collect::<Result<Vec<_>>>()?;

let logged_types = program_abi
let logged_types = unified_program_abi
.logged_types
.iter()
.flatten()
.map(|logged_type| FullLoggedType::from_counterpart(logged_type, &lookup))
.collect();

let configurables = program_abi
let configurables = unified_program_abi
.configurables
.iter()
.flatten()
.map(|configurable| FullConfigurable::from_counterpart(configurable, &lookup))
.collect();

Ok(Self {
encoding: program_abi.encoding.clone(),
program_type: unified_program_abi.program_type.clone(),
spec_version: unified_program_abi.spec_version.clone(),
encoding_version: unified_program_abi.encoding_version.clone(),
types,
functions,
logged_types,
Expand Down Expand Up @@ -136,8 +140,8 @@ impl FullABIFunction {
}

pub fn from_counterpart(
abi_function: &ABIFunction,
types: &HashMap<String, TypeDeclaration>,
abi_function: &UnifiedABIFunction,
types: &HashMap<usize, UnifiedTypeDeclaration>,
) -> Result<FullABIFunction> {
let inputs = abi_function
.inputs
Expand Down Expand Up @@ -167,8 +171,8 @@ pub struct FullTypeDeclaration {

impl FullTypeDeclaration {
pub fn from_counterpart(
type_decl: &TypeDeclaration,
types: &HashMap<String, TypeDeclaration>,
type_decl: &UnifiedTypeDeclaration,
types: &HashMap<usize, UnifiedTypeDeclaration>,
) -> FullTypeDeclaration {
let components = type_decl
.components
Expand Down Expand Up @@ -209,8 +213,8 @@ pub struct FullTypeApplication {

impl FullTypeApplication {
pub fn from_counterpart(
type_application: &TypeApplication,
types: &HashMap<String, TypeDeclaration>,
type_application: &UnifiedTypeApplication,
types: &HashMap<usize, UnifiedTypeDeclaration>,
) -> FullTypeApplication {
let type_arguments = type_application
.type_arguments
Expand Down Expand Up @@ -241,8 +245,8 @@ pub struct FullLoggedType {

impl FullLoggedType {
fn from_counterpart(
logged_type: &LoggedType,
types: &HashMap<String, TypeDeclaration>,
logged_type: &UnifiedLoggedType,
types: &HashMap<usize, UnifiedTypeDeclaration>,
) -> FullLoggedType {
FullLoggedType {
log_id: logged_type.log_id.clone(),
Expand All @@ -260,8 +264,8 @@ pub struct FullConfigurable {

impl FullConfigurable {
pub fn from_counterpart(
configurable: &Configurable,
types: &HashMap<String, TypeDeclaration>,
configurable: &UnifiedConfigurable,
types: &HashMap<usize, UnifiedTypeDeclaration>,
) -> FullConfigurable {
FullConfigurable {
name: configurable.name.clone(),
Expand Down Expand Up @@ -311,42 +315,38 @@ mod tests {
#[test]
fn can_convert_into_full_type_decl() {
// given
let type_0 = TypeDeclaration {
type_id: "9da470e78078ef5bf7aabdd59e465abbd0b288fb01443a5777c8bcf6488a747b".to_string(),
let type_0 = UnifiedTypeDeclaration {
type_id: 0,
type_field: "type_0".to_string(),
components: Some(vec![TypeApplication {
components: Some(vec![UnifiedTypeApplication {
name: "type_0_component_a".to_string(),
type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0"
.to_string(),
type_arguments: Some(vec![TypeApplication {
type_id: 1,
type_arguments: Some(vec![UnifiedTypeApplication {
name: "type_0_type_arg_0".to_string(),
type_id: "00b4c853d51a6da239f08800898a6513eaa6950018fb89def110627830eb323f"
.to_string(),
type_id: 2,
type_arguments: None,
}]),
}]),
type_parameters: Some(vec![
"00b4c853d51a6da239f08800898a6513eaa6950018fb89def110627830eb323f".to_string(),
]),
type_parameters: Some(vec![2]),
};

let type_1 = TypeDeclaration {
type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0".to_string(),
let type_1 = UnifiedTypeDeclaration {
type_id: 1,
type_field: "type_1".to_string(),
components: None,
type_parameters: None,
};

let type_2 = TypeDeclaration {
type_id: "00b4c853d51a6da239f08800898a6513eaa6950018fb89def110627830eb323f".to_string(),
let type_2 = UnifiedTypeDeclaration {
type_id: 2,
type_field: "type_2".to_string(),
components: None,
type_parameters: None,
};

let types = [&type_0, &type_1, &type_2]
.iter()
.map(|&ttype| (ttype.type_id.clone(), ttype.clone()))
.map(|&ttype| (ttype.type_id, ttype.clone()))
.collect::<HashMap<_, _>>();

// when
Expand Down Expand Up @@ -382,34 +382,33 @@ mod tests {

#[test]
fn can_convert_into_full_type_appl() {
let application = TypeApplication {
let application = UnifiedTypeApplication {
name: "ta_0".to_string(),
type_id: "9da470e78078ef5bf7aabdd59e465abbd0b288fb01443a5777c8bcf6488a747b".to_string(),
type_arguments: Some(vec![TypeApplication {
type_id: 0,
type_arguments: Some(vec![UnifiedTypeApplication {
name: "ta_1".to_string(),
type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0"
.to_string(),
type_id: 1,
type_arguments: None,
}]),
};

let type_0 = TypeDeclaration {
type_id: "9da470e78078ef5bf7aabdd59e465abbd0b288fb01443a5777c8bcf6488a747b".to_string(),
let type_0 = UnifiedTypeDeclaration {
type_id: 0,
type_field: "type_0".to_string(),
components: None,
type_parameters: None,
};

let type_1 = TypeDeclaration {
type_id: "0bb3a6b090834070f46e91d3e25184ec5d701976dc5cebe3d1fc121948231fb0".to_string(),
let type_1 = UnifiedTypeDeclaration {
type_id: 1,
type_field: "type_1".to_string(),
components: None,
type_parameters: None,
};

let types = [&type_0, &type_1]
.into_iter()
.map(|ttype| (ttype.type_id.clone(), ttype.clone()))
.map(|ttype| (ttype.type_id, ttype.clone()))
.collect::<HashMap<_, _>>();

// given
Expand Down
1 change: 1 addition & 0 deletions src/abi/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod full_program;
pub mod program;
pub mod unified_program;
78 changes: 60 additions & 18 deletions src/abi/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ use serde::{Deserialize, Serialize};
pub struct ProgramABI {
pub program_type: String,
pub spec_version: Version,
pub abi_version: Version,
#[serde(skip_serializing_if = "Option::is_none")]
pub encoding: Option<Version>,
pub types: Vec<TypeDeclaration>,
pub encoding_version: Version,
pub concrete_types: Vec<TypeConcreteDeclaration>,
pub metadata_types: Vec<TypeMetadataDeclaration>,
pub functions: Vec<ABIFunction>,
pub logged_types: Option<Vec<LoggedType>>,
pub messages_types: Option<Vec<MessageType>>,
Expand Down Expand Up @@ -49,12 +48,37 @@ impl Version {
}
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct ConcreteTypeId(pub String);

impl From<&str> for ConcreteTypeId {
fn from(value: &str) -> Self {
ConcreteTypeId(value.into())
}
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct MetadataTypeId(pub usize);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(untagged)]
pub enum TypeId {
Concrete(ConcreteTypeId),
Metadata(MetadataTypeId),
}

impl Default for TypeId {
fn default() -> Self {
TypeId::Metadata(MetadataTypeId(usize::MAX))
}
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ABIFunction {
pub inputs: Vec<TypeApplication>,
pub inputs: Vec<TypeConcreteParameter>,
pub name: String,
pub output: TypeApplication,
pub output: ConcreteTypeId,
pub attributes: Option<Vec<Attribute>>,
}

Expand All @@ -69,45 +93,63 @@ impl ABIFunction {

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TypeDeclaration {
pub type_id: String,
pub struct TypeMetadataDeclaration {
#[serde(rename = "type")]
pub type_field: String,
pub metadata_type_id: MetadataTypeId,
#[serde(skip_serializing_if = "Option::is_none")]
pub components: Option<Vec<TypeApplication>>, // Used for custom types
pub type_parameters: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub type_parameters: Option<Vec<MetadataTypeId>>,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TypeConcreteDeclaration {
#[serde(rename = "type")]
pub type_field: String,
pub concrete_type_id: ConcreteTypeId,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata_type_id: Option<MetadataTypeId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub type_arguments: Option<Vec<ConcreteTypeId>>,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TypeConcreteParameter {
pub name: String,
pub concrete_type_id: ConcreteTypeId,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TypeApplication {
pub name: String,
#[serde(rename = "type")]
pub type_id: String,
pub type_id: TypeId,
#[serde(skip_serializing_if = "Option::is_none")]
pub type_arguments: Option<Vec<TypeApplication>>,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LoggedType {
pub log_id: String,
#[serde(rename = "loggedType")]
pub application: TypeApplication,
pub concrete_type_id: ConcreteTypeId,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MessageType {
pub message_id: u64,
#[serde(rename = "messageType")]
pub application: TypeApplication,
pub message_id: String,
pub concrete_type_id: ConcreteTypeId,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Configurable {
pub name: String,
#[serde(rename = "configurableType")]
pub application: TypeApplication,
pub concrete_type_id: ConcreteTypeId,
pub offset: u64,
}

Expand Down
Loading
Loading