Skip to content

Commit

Permalink
Implements abi spec changes. (#25)
Browse files Browse the repository at this point in the history
FuelLabs/fuel-specs#599

---------

Co-authored-by: hal3e <git@hal3e.io>
  • Loading branch information
esdrubal and hal3e authored Jul 24, 2024
1 parent 27df09e commit 7474403
Show file tree
Hide file tree
Showing 4 changed files with 542 additions and 75 deletions.
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

0 comments on commit 7474403

Please sign in to comment.