How can we trust the code of an on-chain contract?
We can fetch the code off-chain and compare it to a trusted version.
We can ask another contract on-chain whether we can trust it,
but we’ll still need to fetch contract code off-chain to trust that
contract or any code signatures it gives us.
Solution
Define a new type and instruction that allows validating the code version of a contract on-chain:
contract_code
Must be comparable
Not storable or pushable because the code representation can change
CONTRACT_CODE : address -> contract_code
It could be typed, since contracts with different types can’t be equal: CONTRACT_CODE : contract A -> contract_code A
If no method is provided that exposes the contents of the code, it could be called contract_code_id
This would ensure that contract_code values remain consistent across protocol upgrades
Possible Implementations
contract_code could be fetched as the raw bytes stored for the contract, on-demand
This requires fetching the code for both compared contracts, which could be expensive
contract_code could be a hash of the code, computed at origination
This allows for more efficient fetching and caching than (1), but lacks uniqueness guarantees
contract_code could be represented by a unique-ID assigned to each contract at origination
The contract’s storage and code could be stored separately, where the code of all contracts
is deduplicated with unique-ID’s assigned to each one (internally). This would allow
many copies of a contract to share one copy of code and reduce the origination fees for sufficiently
large/many contracts.
Sorry but I am not sure I understand the problem you are solving. Contract scripts are extremely hard to change – the only time it is possible to modify a script is during a protocol activation – so checking at runtime that the script at a given address has not changed seems overkill. The contract that you are querying to know who to trust could simply store a whitelist of trusted contract addresses or a whitelist of trusted script hashes (of type bytes).
Moreover, the script is only part of what needs to be trusted because the storage can hold important information too, typically the address of the contract administrator or even peices of the contract logic inside a lambda.
@Blindripper hash-consing is a way to deduplicate AST’s.
It could be used to calculate unique ID’s for contract code, but it doesn’t imply this feature.
@rafoo Right, you’d only need to check at runtime when adding a contract to a list of trusted addresses:
otherwise you’d store “code ID’s” (e.g. trusted script hashes).
If we trust the code, we can trust entrypoints that allow us to audit the storage.
Example
Suppose we have a DAO contract where:
A token represents your voting power
There’s a voting cycle on proposals
Proposals can fund projects, represented as contracts
Question
We want to propose a project with its own sub-DAO:
The sub-DAO has its own voting token and cycle
Proposals on the top-level DAO can be used to administrate the project
How do we trust that the sub-DAO contract respects users’
voting power on the top-level DAO and synchronizes with its voting process?
Existing solution: factories
A factory contract consists of a contract template and address registry with two entrypoints:
Originate a contract using the template and add its address to the registry
Query whether an address is in the registry
The top-level DAO stores trusted factory addresses
Users vote to add/remove factory addresses
Origination proposals consist of factory contract parameters
Cons:
Both the template and the implementation of each factory must be trusted
The maximum-size contract cannot directly fit in a factory
The code of contracts too large to fit in a factory must be added piecewise,
e.g. by storing it as lambdas/bytes or by originating multiple contracts
The contract must be originated by the factory to be trusted as an instance of it
Applying Contract Versioning
The top-level DAO stores trusted contract code ID’s (e.g. code hashes) and addresses
Users vote to add/remove contract code ID’s
Proposals to add an address include its code ID
The code ID is validated on submission
Once the code is validated, we know how the entrypoints will behave
This allows some storage can be validated on-chain
Trusted entrypoints make it easier for voters to audit the contract