diff --git a/src/context/mod.rs b/src/context/mod.rs index cdbccbf..42b0cd3 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -5,7 +5,6 @@ use anyhow::{anyhow, Context}; use graph::{ blockchain::Blockchain, data::{ - graphql::ext::DirectiveFinder, store::{Attribute, Value}, value::Word, }, @@ -13,13 +12,15 @@ use graph::{ ethabi::{Address, Token}, DataSourceContext, }, - runtime::{asc_get, asc_new, gas::GasCounter, AscPtr, HostExportError}, + runtime::{ + asc_get, asc_new, gas::GasCounter, AscIndexId, AscPtr, AscType, FromAscObj, + HostExportError, ToAscObj, + }, semver::Version, }; use graph_chain_ethereum::runtime::{ abi::AscUnresolvedContractCall_0_0_4, runtime_adapter::UnresolvedContractCall, }; -use graph_graphql::graphql_parser::schema; use graph_runtime_wasm::{ asc_abi::class::{ Array, AscEntity, AscEnum, AscEnumArray, AscString, EnumPayload, EthereumValueKind, @@ -33,40 +34,18 @@ use serde::Serialize; use serde_json::to_string_pretty; use crate::logging; -use crate::SCHEMA_LOCATION; mod conversion; -mod derived_schema; +mod schema; mod template; use conversion::{collect_types, get_kind, get_token_value}; -use derived_schema::derive_schema; +use schema::{get_entity_required_fields, populate_derived_fields, populate_schema_definitions}; use template::{data_source_create, populate_templates}; lazy_static! { /// Special tokens... pub(crate) static ref REVERTS_IDENTIFIER: Vec = vec![Token::Bytes(vec![255, 255, 255, 255, 255, 255, 255])]; - - /// The global GraphQL Schema from `schema.graphql`. - static ref SCHEMA: schema::Document<'static, String> = { - let mut s = "".to_owned(); - SCHEMA_LOCATION.with(|path| { - s = std::fs::read_to_string(&*path.borrow()).unwrap_or_else(|err| { - logging::critical!( - "Something went wrong when trying to read `{:?}`: {}", - &*path.borrow(), - err, - ) - }); - }); - - schema::parse_schema::(&s).unwrap_or_else(|err| { - logging::critical!( - "Something went wrong when trying to parse `schema.graphql`: {}", - err - ) - }).into_static() - }; } type Store = HashMap>; @@ -174,18 +153,8 @@ impl MatchstickInstanceContext { template_kinds: HashMap::new(), }; - // reads the graphql schema file and extracts all entities and their object types - SCHEMA.definitions.iter().for_each(|def| { - if let schema::Definition::TypeDefinition(schema::TypeDefinition::Object(entity_def)) = - def - { - context - .schema - .insert(entity_def.name.clone(), entity_def.clone()); - } - }); - - derive_schema(&mut context); + populate_schema_definitions(&mut context); + populate_derived_fields(&mut context); populate_templates(&mut context); context } @@ -207,14 +176,30 @@ impl MatchstickInstanceContext { /// Implementation of external functions (used in AssemblyScript sources). impl MatchstickInstanceContext { + fn resolve_asc_pointer(&mut self, pointer: AscPtr) -> T + where + R: AscType + AscIndexId, + T: FromAscObj, + { + asc_get(&self.wasm_ctx, pointer, &GasCounter::new(), 0).unwrap() + } + + fn create_asc_pointer(&mut self, rust_obj: &T) -> AscPtr + where + E: AscType + AscIndexId, + T: ToAscObj, + { + asc_new(&mut self.wasm_ctx, rust_obj, &GasCounter::new()).unwrap() + } + /// function log(level: enum Level (u32), msg: string): void pub fn log( &mut self, _gas: &GasCounter, level: u32, - msg: AscPtr, + msg_ptr: AscPtr, ) -> Result<(), HostExportError> { - let msg: String = asc_get(&self.wasm_ctx, msg, &GasCounter::new(), 0)?; + let msg: String = self.resolve_asc_pointer(msg_ptr); match level { 0 => logging::critical!(msg), @@ -239,7 +224,8 @@ impl MatchstickInstanceContext { _gas: &GasCounter, template_ptr: AscPtr, ) -> Result<(), HostExportError> { - let template: String = asc_get(&self.wasm_ctx, template_ptr, &GasCounter::new(), 0)?; + let template: String = self.resolve_asc_pointer(template_ptr); + let data_sources = self.templates.get(&template).unwrap_or_else(|| { logging::critical!( "(logDataSources) No template with name '{}' found.", @@ -267,8 +253,8 @@ impl MatchstickInstanceContext { entity_id_ptr: AscPtr, show_related_ptr: AscPtr, ) -> Result<(), HostExportError> { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let entity_id: String = asc_get(&self.wasm_ctx, entity_id_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let entity_id: String = self.resolve_asc_pointer(entity_id_ptr); let show_related: bool = bool::from(EnumPayload(show_related_ptr.to_payload())); let mut log: HashMap = HashMap::new(); @@ -314,10 +300,9 @@ impl MatchstickInstanceContext { } } - logging::debug!( - "{}", - to_string_pretty(&log).unwrap_or_else(|err| logging::critical!(err)), - ); + let pretty_log = to_string_pretty(&log).unwrap_or_else(|err| logging::critical!(err)); + + logging::debug!("{}", pretty_log); Ok(()) } @@ -339,12 +324,12 @@ impl MatchstickInstanceContext { pub fn register_test( &mut self, _gas: &GasCounter, - name: AscPtr, - should_fail: AscPtr, + name_ptr: AscPtr, + should_fail_ptr: AscPtr, func_idx: u32, ) -> Result<(), HostExportError> { - let name: String = asc_get(&self.wasm_ctx, name, &GasCounter::new(), 0)?; - let should_fail = bool::from(EnumPayload(should_fail.to_payload())); + let name: String = self.resolve_asc_pointer(name_ptr); + let should_fail = bool::from(EnumPayload(should_fail_ptr.to_payload())); self.meta_tests .push((name, should_fail, func_idx, "test".to_owned())); Ok(()) @@ -354,10 +339,10 @@ impl MatchstickInstanceContext { pub fn register_describe( &mut self, _gas: &GasCounter, - name: AscPtr, + name_ptr: AscPtr, func_idx: u32, ) -> Result<(), HostExportError> { - let name: String = asc_get(&self.wasm_ctx, name, &GasCounter::new(), 0)?; + let name: String = self.resolve_asc_pointer(name_ptr); self.meta_tests .push((name, false, func_idx, "describe".to_owned())); @@ -369,9 +354,9 @@ impl MatchstickInstanceContext { &mut self, _gas: &GasCounter, func_idx: u32, - role: AscPtr, + role_ptr: AscPtr, ) -> Result<(), HostExportError> { - let role: String = asc_get(&self.wasm_ctx, role, &GasCounter::new(), 0)?; + let role: String = self.resolve_asc_pointer(role_ptr); self.meta_tests .push((String::from(""), false, func_idx, role)); Ok(()) @@ -389,11 +374,10 @@ impl MatchstickInstanceContext { field_name_ptr: AscPtr, expected_val_ptr: AscPtr, ) -> Result { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let id: String = asc_get(&self.wasm_ctx, id_ptr, &GasCounter::new(), 0)?; - let field_name: String = asc_get(&self.wasm_ctx, field_name_ptr, &GasCounter::new(), 0)?; - let expected_val: String = - asc_get(&self.wasm_ctx, expected_val_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let id: String = self.resolve_asc_pointer(id_ptr); + let field_name: String = self.resolve_asc_pointer(field_name_ptr); + let expected_val: String = self.resolve_asc_pointer(expected_val_ptr); if !self.store.contains_key(&entity_type) { logging::error!( @@ -448,18 +432,8 @@ impl MatchstickInstanceContext { expected_ptr: u32, actual_ptr: u32, ) -> Result { - let expected: Token = asc_get::<_, AscEnum, _>( - &self.wasm_ctx, - expected_ptr.into(), - &GasCounter::new(), - 0, - )?; - let actual: Token = asc_get::<_, AscEnum, _>( - &self.wasm_ctx, - actual_ptr.into(), - &GasCounter::new(), - 0, - )?; + let expected: Token = self.resolve_asc_pointer(expected_ptr.into()); + let actual: Token = self.resolve_asc_pointer(actual_ptr.into()); let exp_val = get_token_value(expected); let act_val = get_token_value(actual); @@ -483,8 +457,8 @@ impl MatchstickInstanceContext { entity_type_ptr: AscPtr, id_ptr: AscPtr, ) -> Result { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let id: String = asc_get(&self.wasm_ctx, id_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let id: String = self.resolve_asc_pointer(id_ptr); if self.store.contains_key(&entity_type) && self.store.get(&entity_type).unwrap().contains_key(&id) @@ -506,8 +480,7 @@ impl MatchstickInstanceContext { template_name_ptr: AscPtr, expected_count: u32, ) -> Result { - let template_name: String = - asc_get(&self.wasm_ctx, template_name_ptr, &GasCounter::new(), 0)?; + let template_name: String = self.resolve_asc_pointer(template_name_ptr); if let Some(template) = self.templates.get(&template_name) { let actual_count = template.len() as u32; @@ -539,9 +512,8 @@ impl MatchstickInstanceContext { template_name_ptr: AscPtr, address_ptr: AscPtr, ) -> Result { - let template_name: String = - asc_get(&self.wasm_ctx, template_name_ptr, &GasCounter::new(), 0)?; - let address: String = asc_get(&self.wasm_ctx, address_ptr, &GasCounter::new(), 0)?; + let template_name: String = self.resolve_asc_pointer(template_name_ptr); + let address: String = self.resolve_asc_pointer(address_ptr); if let Some(template) = self.templates.get(&template_name) { if !template.contains_key(&address) { @@ -579,12 +551,11 @@ impl MatchstickInstanceContext { expected_val_ptr: AscPtr, message_ptr: AscPtr, ) -> Result { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let id: String = asc_get(&self.wasm_ctx, id_ptr, &GasCounter::new(), 0)?; - let field_name: String = asc_get(&self.wasm_ctx, field_name_ptr, &GasCounter::new(), 0)?; - let expected_val: String = - asc_get(&self.wasm_ctx, expected_val_ptr, &GasCounter::new(), 0)?; - let message: String = asc_get(&self.wasm_ctx, message_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let id: String = self.resolve_asc_pointer(id_ptr); + let field_name: String = self.resolve_asc_pointer(field_name_ptr); + let expected_val: String = self.resolve_asc_pointer(expected_val_ptr); + let message: String = self.resolve_asc_pointer(message_ptr); if !self.store.contains_key(&entity_type) { logging::error!( @@ -636,19 +607,9 @@ impl MatchstickInstanceContext { actual_ptr: u32, message_ptr: AscPtr, ) -> Result { - let expected: Token = asc_get::<_, AscEnum, _>( - &self.wasm_ctx, - expected_ptr.into(), - &GasCounter::new(), - 0, - )?; - let actual: Token = asc_get::<_, AscEnum, _>( - &self.wasm_ctx, - actual_ptr.into(), - &GasCounter::new(), - 0, - )?; - let message: String = asc_get(&self.wasm_ctx, message_ptr, &GasCounter::new(), 0)?; + let expected: Token = self.resolve_asc_pointer(expected_ptr.into()); + let actual: Token = self.resolve_asc_pointer(actual_ptr.into()); + let message: String = self.resolve_asc_pointer(message_ptr); let exp_val = get_token_value(expected); let act_val = get_token_value(actual); @@ -670,9 +631,9 @@ impl MatchstickInstanceContext { id_ptr: AscPtr, message_ptr: AscPtr, ) -> Result { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let id: String = asc_get(&self.wasm_ctx, id_ptr, &GasCounter::new(), 0)?; - let message: String = asc_get(&self.wasm_ctx, message_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let id: String = self.resolve_asc_pointer(id_ptr); + let message: String = self.resolve_asc_pointer(message_ptr); if self.store.contains_key(&entity_type) && self.store.get(&entity_type).unwrap().contains_key(&id) @@ -692,10 +653,8 @@ impl MatchstickInstanceContext { expected_count: u32, message_ptr: AscPtr, ) -> Result { - let template_name: String = - asc_get(&self.wasm_ctx, template_name_ptr, &GasCounter::new(), 0)?; - - let message: String = asc_get(&self.wasm_ctx, message_ptr, &GasCounter::new(), 0)?; + let template_name: String = self.resolve_asc_pointer(template_name_ptr); + let message: String = self.resolve_asc_pointer(message_ptr); if let Some(template) = self.templates.get(&template_name) { let actual_count = template.len() as u32; @@ -723,10 +682,9 @@ impl MatchstickInstanceContext { address_ptr: AscPtr, message_ptr: AscPtr, ) -> Result { - let template_name: String = - asc_get(&self.wasm_ctx, template_name_ptr, &GasCounter::new(), 0)?; - let address: String = asc_get(&self.wasm_ctx, address_ptr, &GasCounter::new(), 0)?; - let message: String = asc_get(&self.wasm_ctx, message_ptr, &GasCounter::new(), 0)?; + let template_name: String = self.resolve_asc_pointer(template_name_ptr); + let address: String = self.resolve_asc_pointer(address_ptr); + let message: String = self.resolve_asc_pointer(message_ptr); if let Some(template) = self.templates.get(&template_name) { if !template.contains_key(&address) { @@ -751,8 +709,8 @@ impl MatchstickInstanceContext { id_ptr: AscPtr, _gas: &GasCounter, ) -> Result, HostExportError> { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let id: String = asc_get(&self.wasm_ctx, id_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let id: String = self.resolve_asc_pointer(id_ptr); let store = match scope { StoreScope::Global => &self.store, @@ -763,12 +721,9 @@ impl MatchstickInstanceContext { .get(&entity_type) .and_then(|entities| entities.get(&id)); - if entity.is_some() { - let res = asc_new( - &mut self.wasm_ctx, - &entity.unwrap().clone().to_entity(), - &GasCounter::new(), - )?; + if let Some(entity) = entity { + let res = self.create_asc_pointer(&entity.clone().to_entity()); + return Ok(res); } @@ -838,14 +793,9 @@ impl MatchstickInstanceContext { entity_id_ptr: AscPtr, entity_virtual_field_ptr: AscPtr, ) -> Result>>, HostExportError> { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let entity_id: String = asc_get(&self.wasm_ctx, entity_id_ptr, &GasCounter::new(), 0)?; - let entity_virtual_field: String = asc_get( - &self.wasm_ctx, - entity_virtual_field_ptr, - &GasCounter::new(), - 0, - )?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let entity_id: String = self.resolve_asc_pointer(entity_id_ptr); + let entity_virtual_field: String = self.resolve_asc_pointer(entity_virtual_field_ptr); let related_entities: Vec = self .load_related_entities(&entity_type, &entity_id, &entity_virtual_field) @@ -855,7 +805,7 @@ impl MatchstickInstanceContext { .collect(); let related_entities_ptr: AscPtr>> = - asc_new(&mut self.wasm_ctx, &related_entities, &GasCounter::new())?; + self.create_asc_pointer(&related_entities); Ok(related_entities_ptr) } @@ -888,17 +838,11 @@ impl MatchstickInstanceContext { data_ptr: AscPtr, _gas: &GasCounter, ) -> Result<(), HostExportError> { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let id: String = asc_get(&self.wasm_ctx, id_ptr, &GasCounter::new(), 0)?; - let data: StoreEntity = asc_get(&self.wasm_ctx, data_ptr, &GasCounter::new(), 0)?; - - let required_fields = self.schema.get(&entity_type).unwrap_or_else(|| { - logging::critical!("Something went wrong! Could not find the entity defined in the GraphQL schema.") - }) - .fields - .iter() - .clone() - .filter(|&f| matches!(f.field_type, schema::Type::NonNullType(..)) && !f.is_derived()); + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let id: String = self.resolve_asc_pointer(id_ptr); + let data: StoreEntity = self.resolve_asc_pointer(data_ptr); + + let required_fields = get_entity_required_fields(self, entity_type.clone()); for f in required_fields { if !data.contains_key(&f.name) { @@ -971,8 +915,8 @@ impl MatchstickInstanceContext { entity_type_ptr: AscPtr, id_ptr: AscPtr, ) -> Result<(), HostExportError> { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; - let id: String = asc_get(&self.wasm_ctx, id_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); + let id: String = self.resolve_asc_pointer(id_ptr); if self.store.contains_key(&entity_type) && self.store.get(&entity_type).unwrap().contains_key(&id) @@ -1000,12 +944,8 @@ impl MatchstickInstanceContext { _gas: &GasCounter, contract_call_ptr: u32, ) -> Result, HostExportError> { - let call: UnresolvedContractCall = asc_get::<_, AscUnresolvedContractCall_0_0_4, _>( - &self.wasm_ctx, - contract_call_ptr.into(), - &GasCounter::new(), - 0, - )?; + let call: UnresolvedContractCall = self + .resolve_asc_pointer::<_, AscUnresolvedContractCall_0_0_4>(contract_call_ptr.into()); let contract_address = call.contract_address.to_string(); let fn_name = call.function_name.to_string(); @@ -1023,18 +963,12 @@ impl MatchstickInstanceContext { let return_val; if self.fn_ret_map.contains_key(&fn_id) { - if *self.fn_ret_map.get(&fn_id).unwrap() == REVERTS_IDENTIFIER.clone() { + let func: Vec = self.fn_ret_map.get(&fn_id).unwrap().clone(); + if *func == REVERTS_IDENTIFIER.clone() { return Ok(AscPtr::null()); } - return_val = asc_new( - &mut self.wasm_ctx, - self.fn_ret_map - .get(&fn_id) - .unwrap_or_else(|| logging::critical!("Could not get value from function map.")) - .as_slice(), - &GasCounter::new(), - )?; + return_val = self.create_asc_pointer(func.as_slice()); Ok(return_val) } else { @@ -1063,27 +997,11 @@ impl MatchstickInstanceContext { return_value_ptr: u32, reverts_ptr: AscPtr, ) -> Result<(), HostExportError> { - let contract_address: Address = asc_get( - &self.wasm_ctx, - contract_address_ptr.into(), - &GasCounter::new(), - 0, - )?; - let fn_name: String = asc_get(&self.wasm_ctx, fn_name_ptr, &GasCounter::new(), 0)?; - let fn_signature: String = - asc_get(&self.wasm_ctx, fn_signature_ptr, &GasCounter::new(), 0)?; - let fn_args: Vec = asc_get::<_, Array>>, _>( - &self.wasm_ctx, - fn_args_ptr.into(), - &GasCounter::new(), - 0, - )?; - let return_value: Vec = asc_get::<_, Array>>, _>( - &self.wasm_ctx, - return_value_ptr.into(), - &GasCounter::new(), - 0, - )?; + let contract_address: Address = self.resolve_asc_pointer(contract_address_ptr.into()); + let fn_name: String = self.resolve_asc_pointer(fn_name_ptr); + let fn_signature: String = self.resolve_asc_pointer(fn_signature_ptr); + let fn_args: Vec = self.resolve_asc_pointer(fn_args_ptr.into()); + let return_value: Vec = self.resolve_asc_pointer(return_value_ptr.into()); let reverts = bool::from(EnumPayload(reverts_ptr.to_payload())); // Extracts the arguments part from the function signature @@ -1151,11 +1069,11 @@ impl MatchstickInstanceContext { pub fn mock_data_source_create( &mut self, _gas: &GasCounter, - _name_ptr: AscPtr, - _params_ptr: AscPtr>>, + name_ptr: AscPtr, + params_ptr: AscPtr>>, ) -> Result<(), HostExportError> { - let name: String = asc_get(&self.wasm_ctx, _name_ptr, &GasCounter::new(), 0)?; - let params: Vec = asc_get(&self.wasm_ctx, _params_ptr, &GasCounter::new(), 0)?; + let name: String = self.resolve_asc_pointer(name_ptr); + let params: Vec = self.resolve_asc_pointer(params_ptr); data_source_create(name, params, None, self) } @@ -1167,14 +1085,14 @@ impl MatchstickInstanceContext { pub fn mock_data_source_create_with_context( &mut self, _gas: &GasCounter, - _name_ptr: AscPtr, - _params_ptr: AscPtr>>, - _context_ptr: AscPtr, + name_ptr: AscPtr, + params_ptr: AscPtr>>, + context_ptr: AscPtr, ) -> Result<(), HostExportError> { - let name: String = asc_get(&self.wasm_ctx, _name_ptr, &GasCounter::new(), 0)?; - let params: Vec = asc_get(&self.wasm_ctx, _params_ptr, &GasCounter::new(), 0)?; - let context: HashMap = - asc_get(&self.wasm_ctx, _context_ptr, &GasCounter::new(), 0)?; + let name: String = self.resolve_asc_pointer(name_ptr); + let params: Vec = self.resolve_asc_pointer(params_ptr); + let context: HashMap = self.resolve_asc_pointer(context_ptr); + let context = DataSourceContext::from(context); data_source_create(name, params, Some(context), self) @@ -1187,31 +1105,25 @@ impl MatchstickInstanceContext { ) -> Result, HostExportError> { let default_address_val = "0x0000000000000000000000000000000000000000"; - let result = match &self.data_source_return_value.0 { + let result = match self.data_source_return_value.0.clone() { Some(value) => { - let address = Address::from_str(value).unwrap_or_default(); + let eth_address = Address::from_str(&value).unwrap_or_default(); // checks whether the value is a valid ethereum address and parses it // otherwise it is considered as ipfs cid // Zero address is considered as valid only if matches the mocked value - if !address.is_zero() || value.eq(default_address_val) { - asc_new(&mut self.wasm_ctx, &address, &GasCounter::new()) - .expect("Couldn't create pointer.") + if !eth_address.is_zero() || value.eq(default_address_val) { + self.create_asc_pointer(ð_address) } else { - asc_new(&mut self.wasm_ctx, value.as_bytes(), &GasCounter::new()) - .expect("Couldn't create pointer.") + self.create_asc_pointer(value.as_bytes()) } } None => { logging::error!( "No mocked Eth address or Ipfs CID found, so fallback to Eth Zero address" ); - - asc_new( - &mut self.wasm_ctx, + self.create_asc_pointer( &Address::from_str(default_address_val).expect("Couldn't create address"), - &GasCounter::new(), ) - .expect("Couldn't create pointer.") } }; @@ -1252,9 +1164,9 @@ impl MatchstickInstanceContext { Some(value) => { let entity: Entity = value.clone().to_entity(); - asc_new(&mut self.wasm_ctx, &entity, &GasCounter::new()).unwrap() + self.create_asc_pointer(&entity) } - None => asc_new(&mut self.wasm_ctx, &default_context_val, &GasCounter::new()).unwrap(), + None => self.create_asc_pointer(&default_context_val), }; Ok(result) @@ -1268,10 +1180,9 @@ impl MatchstickInstanceContext { network_ptr: AscPtr, context_ptr: AscPtr, ) -> Result<(), HostExportError> { - let address: String = asc_get(&self.wasm_ctx, address_ptr, &GasCounter::new(), 0)?; - let network: String = asc_get(&self.wasm_ctx, network_ptr, &GasCounter::new(), 0)?; - let context: HashMap = - asc_get(&self.wasm_ctx, context_ptr, &GasCounter::new(), 0)?; + let address: String = self.resolve_asc_pointer(address_ptr); + let network: String = self.resolve_asc_pointer(network_ptr); + let context: HashMap = self.resolve_asc_pointer(context_ptr); self.data_source_return_value = (Some(address), Some(network), Some(context)); Ok(()) @@ -1283,7 +1194,7 @@ impl MatchstickInstanceContext { _gas: &GasCounter, entity_type_ptr: AscPtr, ) -> Result { - let entity_type: String = asc_get(&self.wasm_ctx, entity_type_ptr, &GasCounter::new(), 0)?; + let entity_type: String = self.resolve_asc_pointer(entity_type_ptr); match self.store.get(&entity_type) { Some(inner_map) => Ok(inner_map.len().try_into().unwrap_or_else(|err| { @@ -1303,12 +1214,12 @@ impl MatchstickInstanceContext { _gas: &GasCounter, file_path_ptr: AscPtr, ) -> Result, HostExportError> { - let file_path: String = asc_get(&self.wasm_ctx, file_path_ptr, &GasCounter::new(), 0)?; + let file_path: String = self.resolve_asc_pointer(file_path_ptr); let string = std::fs::read_to_string(&file_path).unwrap_or_else(|err| { logging::critical!("Failed to read file `{}` with error: {}", &file_path, err) }); - let result = asc_new(&mut self.wasm_ctx, string.as_bytes(), &GasCounter::new())?; + let result = self.create_asc_pointer(string.as_bytes()); Ok(result) } @@ -1320,8 +1231,8 @@ impl MatchstickInstanceContext { hash_ptr: AscPtr, file_path_ptr: AscPtr, ) -> Result<(), HostExportError> { - let hash: String = asc_get(&self.wasm_ctx, hash_ptr, &GasCounter::new(), 0)?; - let file_path: String = asc_get(&self.wasm_ctx, file_path_ptr, &GasCounter::new(), 0)?; + let hash: String = self.resolve_asc_pointer(hash_ptr); + let file_path: String = self.resolve_asc_pointer(file_path_ptr); self.ipfs.insert(hash, file_path); Ok(()) @@ -1333,7 +1244,7 @@ impl MatchstickInstanceContext { _gas: &GasCounter, hash_ptr: AscPtr, ) -> Result, HostExportError> { - let hash: String = asc_get(&self.wasm_ctx, hash_ptr, &GasCounter::new(), 0)?; + let hash: String = self.resolve_asc_pointer(hash_ptr); let file_path = &self .ipfs .get(&hash) @@ -1341,7 +1252,7 @@ impl MatchstickInstanceContext { let string = std::fs::read_to_string(file_path).unwrap_or_else(|err| { logging::critical!("Failed to read file `{}` with error: {}", &file_path, err) }); - let result = asc_new(&mut self.wasm_ctx, string.as_bytes(), &GasCounter::new())?; + let result = self.create_asc_pointer(string.as_bytes()); Ok(result) } @@ -1355,9 +1266,9 @@ impl MatchstickInstanceContext { user_data_ptr: AscPtr>, _flags_ptr: AscPtr>>, ) -> Result<(), HostExportError> { - let link: String = asc_get(&self.wasm_ctx, link_ptr, &GasCounter::new(), 0)?; - let callback: String = asc_get(&self.wasm_ctx, callback_ptr, &GasCounter::new(), 0)?; - let user_data: Value = asc_get(&self.wasm_ctx, user_data_ptr, &GasCounter::new(), 0)?; + let link: String = self.resolve_asc_pointer(link_ptr); + let callback: String = self.resolve_asc_pointer(callback_ptr); + let user_data: Value = self.resolve_asc_pointer(user_data_ptr); let file_path = &self .ipfs @@ -1384,18 +1295,10 @@ impl MatchstickInstanceContext { ) .unwrap(); - let data_ptr = asc_new( - &mut instance.instance_ctx_mut().wasm_ctx, - &user_data, - &GasCounter::new(), - )?; + let data_ptr = instance.instance_ctx_mut().create_asc_pointer(&user_data); for value in json_values { - let value_ptr = asc_new( - &mut instance.instance_ctx_mut().wasm_ctx, - &value, - &GasCounter::new(), - )?; + let value_ptr = instance.instance_ctx_mut().create_asc_pointer(&value); instance.instance_ctx_mut().store = self.store.clone(); instance.instance_ctx_mut().fn_ret_map = self.fn_ret_map.clone(); diff --git a/src/context/derived_schema.rs b/src/context/schema.rs similarity index 51% rename from src/context/derived_schema.rs rename to src/context/schema.rs index 9bbd99b..461712b 100644 --- a/src/context/derived_schema.rs +++ b/src/context/schema.rs @@ -1,10 +1,50 @@ -use std::collections::HashMap; - use graph::data::graphql::ext::DirectiveFinder; +use graph_graphql::graphql_parser::schema; +use std::collections::HashMap; use crate::context::MatchstickInstanceContext; +use crate::logging; +use crate::SCHEMA_LOCATION; + +// reads the graphql schema file and parses it +fn load_schema_document() -> schema::Document<'static, String> { + let mut schema_file = "".to_owned(); + SCHEMA_LOCATION.with(|path| { + schema_file = std::fs::read_to_string(&*path.borrow()).unwrap_or_else(|err| { + logging::critical!( + "Something went wrong when trying to read `{:?}`: {}", + &*path.borrow(), + err, + ) + }); + }); + + schema::parse_schema::(&schema_file) + .unwrap_or_else(|err| { + logging::critical!( + "Something went wrong when trying to parse `schema.graphql`: {}", + err + ) + }) + .into_static() +} + +pub(crate) fn populate_schema_definitions( + context: &mut MatchstickInstanceContext, +) { + let schema_document = load_schema_document(); + + schema_document.definitions.iter().for_each(|def| { + if let schema::Definition::TypeDefinition(schema::TypeDefinition::Object(entity_def)) = def + { + context + .schema + .insert(entity_def.name.clone(), entity_def.clone()); + } + }); +} -pub(crate) fn derive_schema( +pub(crate) fn populate_derived_fields( context: &mut MatchstickInstanceContext, ) { context @@ -51,3 +91,22 @@ pub(crate) fn derive_schema( } }); } + +pub(crate) fn get_entity_required_fields( + context: &mut MatchstickInstanceContext, + entity_type: String, +) -> Vec<&schema::Field<'static, String>> { + context + .schema + .get(&entity_type) + .unwrap_or_else(|| { + logging::critical!( + "Something went wrong! Could not find the entity defined in the GraphQL schema." + ) + }) + .fields + .iter() + .clone() + .filter(|&f| matches!(f.field_type, schema::Type::NonNullType(..)) && !f.is_derived()) + .collect() +} diff --git a/src/context/template.rs b/src/context/template.rs index 765e5d3..9ca2aa8 100644 --- a/src/context/template.rs +++ b/src/context/template.rs @@ -16,6 +16,7 @@ pub(crate) fn populate_templates( ); templates.iter().for_each(|(name, kind)| { + context.templates.insert(name.to_string(), HashMap::new()); context .template_kinds .insert(name.to_string(), kind.to_string()); @@ -59,14 +60,8 @@ pub(crate) fn data_source_create( context, }; - if instance_ctx.templates.contains_key(&name) { - let template = instance_ctx.templates.get_mut(&name).unwrap(); - template.insert(params[0].clone(), template_info); - } else { - let mut template: HashMap = HashMap::new(); - template.insert(params[0].clone(), template_info); - instance_ctx.templates.insert(name.clone(), template); - } + let template = instance_ctx.templates.get_mut(&name).unwrap(); + template.insert(params[0].clone(), template_info); Ok(()) }