In the context of dType, the Decentralized Type System described in EIP-1900, we are proposing to add support for registering functions (with a preference for pure and view) in the dType Registry.
Abstract
This proposal is part of a series of EIPs focused on expanding the concept of a Decentralized Type System, as explained in EIP-1900.
The current EIP specifies the data definitions and interfaces needed to support registering individual smart contract functions, as entries in the dType Registry.
Motivation
In order to evolve the EVM into a Singleton Operating System, we need a way to register, find and address contract functions that we want to run in an automated way.
This implies having access to all the data needed to run the function inside the EVM.
Aside from the above motivation, there are also near future benefits for this proposal. Having a globally available, non-custodial functions registry, will democratize the development of tools, such as those targeting: blockchain data analysis (e.g. block explorers), smart contract IDEs, security analysis of smart contracts.
Registering new smart contract functions can be done through the same consensus mechanism as EIP-1900 mentions, in order to avoid burdening the chain state with redundant or improper records.
Specification
This specification targets pure and view functions.
For each function, we can store:
name - type string unique function name, as defined in EIP-1900; required
types - the type data and label of each input, as defined in EIP-1900; required
outputs - the type data and label of each output; required
contractAddress - type address - smart contract where the function resides, as defined in EIP-1900; optional for interfaces
source - type bytes32 - reference to an external file containing the function source code, as defined in EIP-1900; optional
Therefore, this proposal adds outputs to the EIP-1900 type registration definition.
An example of a function registration object for the dType registry is:
{
"name": "setStaked",
"types": [
{"name": "TypeA", "label": "typeA", "relation":0, "dimensions":[]}
],
"typeChoice": 4,
"contractAddress": <address of the deployed smart contract where the function is defined>,
"source": <bytes32 hash for referencing source files>,
"outputs": [
{"name": "TypeB", "label": "typeB", "relation":0, "dimensions":[]}
]
}
The above object will be passed to <dType registry>.insert({...})
An additional setOutputs function is proposed for the dType registry:
function setOutputs(
bytes32 identifier,
dTypes[] memory outputs
)
public
identifier - type bytes32, the type’s identifier, as defined in EIP-1900
outputs - type dTypes, as defined in EIP-1900
Implementation Suggestions
In the dType registry implementation, outputs can be stored in a mapping:
mapping(bytes32 => dTypes[]) public outputs;
Rationale
The suggestion to treat each pure or view function as a separate entity instead of having a contract-based approach allows us to:
have a global context of readily available functions
scale designs through functional programming patterns rather than contract-encapsulated logic (which can be successfully used to scale development efforts independently)
bidirectionally connect functions with the types they use, making automation easier
cherry-pick functions from already deployed contracts if the other contract functions do not pass community consensus
have scope-restricted improvements - instead of redeploying entire contracts, we can just redeploy the new function versions that we want to be added to the registry
enable fine-grained auditing of individual functions, for the common good
enable testing directly on a production chain, without state side-effects
The proposal to store the minimum ABI information on-chain, for each function, allows us to:
enable on-chain automation (e.g. function chaining and composition)
be backward compatible in case the function signature format changes (e.g. from bytes4 to bytes32): multiple signature calculation functions can be registered with dType. Examples:
function getSignatureBytes4(bytes32 identifier)
view
public
returns (bytes4 signature)
function getSignatureBytes32(bytes32 identifier)
view
public
returns (bytes32 signature)
identifier - the type’s identifier, as defined in EIP-1900
signature - the function’s signature
Concerns about this design might be:
redundancy of storing contractAddress for each function that is part of the same contract
We think that state/storage cost will be compensated through DRYness across the chain, due to reusing types and functions that have already been registered and are now easy to find. Other state/storage cost calculations will be added once the specification and implementation are closer to be finalized.
Note that the input and output types are based on types that have already been registered. This lowers the amount of ABI information needed to be stored for each function and enables developers to aggregate and find functions that use the same types for their I/O. This can be a powerful tool for interoperability and smart contract composition.
Backwards Compatibility
This proposal does not affect extant Ethereum standards or implementations. Registering functions for existing contract deployments should be fully supported.
Test Cases
Will be added.
Implementation
In-work implementation examples can be found at https://github.com/pipeos-one/dType.
This proposal will be updated with an appropriate implementation when consensus is reached on the specifications.