diff --git a/abi/resolver/src/lib.rs b/abi/resolver/src/lib.rs index 0b18d347d4..65653bc657 100644 --- a/abi/resolver/src/lib.rs +++ b/abi/resolver/src/lib.rs @@ -165,6 +165,27 @@ impl<'a> ABIResolver<'a> { } }) } + + pub fn resolve_module_function_index( + &self, + module_id: &ModuleId, + function_idx: u16, + ) -> Result { + let module = self + .resolver + .get_module(module_id.address(), module_id.name())?; + if function_idx as usize >= module.function_defs.len() { + return Err(anyhow!( + "Function index {} out of range in {:?}", + function_idx, + module.self_id(), + )); + } + let function_def = module.function_def_at(FunctionDefinitionIndex::new(function_idx)); + let (func_name, func) = Function::new(&module, function_def); + self.function_to_abi(module_id, &func_name, &func) + } + pub fn resolve_function( &self, module_id: &ModuleId, @@ -398,6 +419,19 @@ mod tests { let func_abi = r.resolve_struct(&m, s.as_ident_str()).unwrap(); println!("{}", serde_json::to_string_pretty(&func_abi).unwrap()); } + + // test resolve module function index + { + let m = ModuleId::new(genesis_address(), Identifier::new("Dao").unwrap()); + let f = r.resolve_module_function_index(&m, 0).unwrap(); + assert_eq!(f.name(), "cast_vote"); + } + + // test resolve module function index overflow + { + let m = ModuleId::new(genesis_address(), Identifier::new("Dao").unwrap()); + assert!(r.resolve_module_function_index(&m, 31).is_err()) + } } #[test] @@ -417,7 +451,7 @@ mod tests { let test_source = r#" module {{sender}}::TestModule { struct A has copy, store{ - } + } struct B has key{ a: vector, } diff --git a/rpc/api/src/contract_api.rs b/rpc/api/src/contract_api.rs index b54229a17e..c0ecdb330b 100644 --- a/rpc/api/src/contract_api.rs +++ b/rpc/api/src/contract_api.rs @@ -46,6 +46,12 @@ pub trait ContractApi { #[rpc(name = "contract.resolve_function")] fn resolve_function(&self, function_id: FunctionIdView) -> FutureResult; + #[rpc(name = "contract.resolve_module_function_index")] + fn resolve_module_function_index( + &self, + module_id: ModuleIdView, + function_index: u16, + ) -> FutureResult; #[rpc(name = "contract.resolve_struct")] fn resolve_struct(&self, struct_tag: StructTagView) -> FutureResult; #[rpc(name = "contract.resolve_module")] diff --git a/rpc/generated_rpc_schema/contract_api.json b/rpc/generated_rpc_schema/contract_api.json index 4ade6dea9b..9ef0799b0f 100644 --- a/rpc/generated_rpc_schema/contract_api.json +++ b/rpc/generated_rpc_schema/contract_api.json @@ -3865,6 +3865,588 @@ } } }, + { + "name": "contract.resolve_module_function_index", + "params": [ + { + "name": "module_id", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "move_core_types::language_storage::ModuleId", + "type": "string" + } + }, + { + "name": "function_index", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "uint16", + "type": "integer", + "format": "uint16", + "minimum": 0.0 + } + } + ], + "result": { + "name": "FunctionABI", + "schema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "FunctionABI", + "type": "object", + "required": [ + "args", + "doc", + "module_name", + "name", + "returns", + "ty_args" + ], + "properties": { + "args": { + "description": "The description of regular arguments.", + "type": "array", + "items": { + "description": "The description of a (regular) argument in a script.", + "type": "object", + "required": [ + "doc", + "name", + "type_tag" + ], + "properties": { + "doc": { + "description": "The doc of the arg.", + "type": "string" + }, + "name": { + "description": "The name of the argument.", + "type": "string" + }, + "type_tag": { + "description": "The expected type. In Move scripts, this does contain generics type parameters.", + "oneOf": [ + { + "type": "string", + "enum": [ + "Bool", + "U8", + "U64", + "U128", + "Address", + "Signer" + ] + }, + { + "type": "object", + "required": [ + "Vector" + ], + "properties": { + "Vector": { + "$ref": "#/definitions/TypeInstantiation" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Struct" + ], + "properties": { + "Struct": { + "type": "object", + "required": [ + "abilities", + "doc", + "fields", + "module_name", + "name", + "ty_args" + ], + "properties": { + "abilities": { + "type": "string" + }, + "doc": { + "description": "The doc of the struct", + "type": "string" + }, + "fields": { + "description": "fields of the structs.", + "type": "array", + "items": { + "type": "object", + "required": [ + "doc", + "name", + "type_abi" + ], + "properties": { + "doc": { + "description": "doc of the field", + "type": "string" + }, + "name": { + "description": "field name", + "type": "string" + }, + "type_abi": { + "description": "type of the field", + "allOf": [ + { + "$ref": "#/definitions/TypeInstantiation" + } + ] + } + } + } + }, + "module_name": { + "description": "module contains the struct", + "type": "string" + }, + "name": { + "description": "name of the struct", + "type": "string" + }, + "ty_args": { + "type": "array", + "items": { + "description": "The description of a type argument in a script.", + "type": "object", + "required": [ + "abilities", + "name", + "phantom", + "ty" + ], + "properties": { + "abilities": { + "type": "string" + }, + "name": { + "description": "The name of the argument.", + "type": "string" + }, + "phantom": { + "type": "boolean" + }, + "ty": { + "$ref": "#/definitions/TypeInstantiation" + } + } + } + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "TypeParameter" + ], + "properties": { + "TypeParameter": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Reference" + ], + "properties": { + "Reference": { + "type": "array", + "items": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/TypeInstantiation" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "additionalProperties": false + } + ] + } + } + } + }, + "doc": { + "description": "Some text comment.", + "type": "string" + }, + "module_name": { + "description": "The module name where the script lives.", + "type": "string" + }, + "name": { + "description": "The public name of the script.", + "type": "string" + }, + "returns": { + "description": "return types", + "type": "array", + "items": { + "oneOf": [ + { + "type": "string", + "enum": [ + "Bool", + "U8", + "U64", + "U128", + "Address", + "Signer" + ] + }, + { + "type": "object", + "required": [ + "Vector" + ], + "properties": { + "Vector": { + "$ref": "#/definitions/TypeInstantiation" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Struct" + ], + "properties": { + "Struct": { + "type": "object", + "required": [ + "abilities", + "doc", + "fields", + "module_name", + "name", + "ty_args" + ], + "properties": { + "abilities": { + "type": "string" + }, + "doc": { + "description": "The doc of the struct", + "type": "string" + }, + "fields": { + "description": "fields of the structs.", + "type": "array", + "items": { + "type": "object", + "required": [ + "doc", + "name", + "type_abi" + ], + "properties": { + "doc": { + "description": "doc of the field", + "type": "string" + }, + "name": { + "description": "field name", + "type": "string" + }, + "type_abi": { + "description": "type of the field", + "allOf": [ + { + "$ref": "#/definitions/TypeInstantiation" + } + ] + } + } + } + }, + "module_name": { + "description": "module contains the struct", + "type": "string" + }, + "name": { + "description": "name of the struct", + "type": "string" + }, + "ty_args": { + "type": "array", + "items": { + "description": "The description of a type argument in a script.", + "type": "object", + "required": [ + "abilities", + "name", + "phantom", + "ty" + ], + "properties": { + "abilities": { + "type": "string" + }, + "name": { + "description": "The name of the argument.", + "type": "string" + }, + "phantom": { + "type": "boolean" + }, + "ty": { + "$ref": "#/definitions/TypeInstantiation" + } + } + } + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "TypeParameter" + ], + "properties": { + "TypeParameter": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Reference" + ], + "properties": { + "Reference": { + "type": "array", + "items": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/TypeInstantiation" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "additionalProperties": false + } + ] + } + }, + "ty_args": { + "description": "The names of the type arguments.", + "type": "array", + "items": { + "description": "The description of a type argument in a script.", + "type": "object", + "required": [ + "abilities", + "name", + "phantom" + ], + "properties": { + "abilities": { + "type": "string" + }, + "name": { + "description": "The name of the argument.", + "type": "string" + }, + "phantom": { + "type": "boolean" + } + } + } + } + }, + "definitions": { + "TypeInstantiation": { + "oneOf": [ + { + "type": "string", + "enum": [ + "Bool", + "U8", + "U64", + "U128", + "Address", + "Signer" + ] + }, + { + "type": "object", + "required": [ + "Vector" + ], + "properties": { + "Vector": { + "$ref": "#/definitions/TypeInstantiation" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Struct" + ], + "properties": { + "Struct": { + "type": "object", + "required": [ + "abilities", + "doc", + "fields", + "module_name", + "name", + "ty_args" + ], + "properties": { + "abilities": { + "type": "string" + }, + "doc": { + "description": "The doc of the struct", + "type": "string" + }, + "fields": { + "description": "fields of the structs.", + "type": "array", + "items": { + "type": "object", + "required": [ + "doc", + "name", + "type_abi" + ], + "properties": { + "doc": { + "description": "doc of the field", + "type": "string" + }, + "name": { + "description": "field name", + "type": "string" + }, + "type_abi": { + "description": "type of the field", + "allOf": [ + { + "$ref": "#/definitions/TypeInstantiation" + } + ] + } + } + } + }, + "module_name": { + "description": "module contains the struct", + "type": "string" + }, + "name": { + "description": "name of the struct", + "type": "string" + }, + "ty_args": { + "type": "array", + "items": { + "description": "The description of a type argument in a script.", + "type": "object", + "required": [ + "abilities", + "name", + "phantom", + "ty" + ], + "properties": { + "abilities": { + "type": "string" + }, + "name": { + "description": "The name of the argument.", + "type": "string" + }, + "phantom": { + "type": "boolean" + }, + "ty": { + "$ref": "#/definitions/TypeInstantiation" + } + } + } + } + } + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "TypeParameter" + ], + "properties": { + "TypeParameter": { + "type": "integer", + "format": "uint", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "Reference" + ], + "properties": { + "Reference": { + "type": "array", + "items": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/TypeInstantiation" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "additionalProperties": false + } + ] + } + } + } + } + }, { "name": "contract.resolve_struct", "params": [ diff --git a/rpc/server/src/module/contract_rpc.rs b/rpc/server/src/module/contract_rpc.rs index 8df3f7ef7e..9afaf82d5a 100644 --- a/rpc/server/src/module/contract_rpc.rs +++ b/rpc/server/src/module/contract_rpc.rs @@ -236,6 +236,21 @@ where Box::pin(fut.boxed()) } + fn resolve_module_function_index( + &self, + module_id: ModuleIdView, + function_idx: u16, + ) -> FutureResult { + let service = self.chain_state.clone(); + let storage = self.storage.clone(); + let fut = async move { + let state = ChainStateDB::new(storage, Some(service.state_root().await?)); + ABIResolver::new(&state).resolve_module_function_index(&module_id.0, function_idx) + } + .map_err(map_err); + Box::pin(fut.boxed()) + } + fn resolve_struct(&self, struct_tag: StructTagView) -> FutureResult { let service = self.chain_state.clone(); let storage = self.storage.clone();