-
Notifications
You must be signed in to change notification settings - Fork 443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove wildcard selectors #1706
Conversation
I'm of the opinion that we don't need to have wildcard/fallback functions in ink!. We Upgradeable Contracts The only reason we introduced wildcard selectors was to enable upgradeable contracts This use case has been made obsolete with Accepting Native Token Transfers Unlike Solidity, we also don't use the fallback (or in their case Extensibility Lastly, using the fallback as a form of extensibility - like in the Diamond Pattern. Ignoring the fact that Substrate chains can configure a maximum contract size Instead of having to implicitly pass call data through the fallback function like we do For example, we can do something like this: /// Represents an ink! message.
#[derive(scale::Encode, scale::Decode)]
struct Message {
selector: Selector,
input: Input,
value: Value,
gas_limit: Gas,
}
/// A regular message which will forward the given `message` to the extension address.
#[ink(message)]
fn forward(&mut self, ext_address: AccountId, message: Message) {
let code_hash = self.env().code_hash(&ext_address).unwrap();
// Option 1: Use existing `CallBuilder` pattern
let Message {selector, input, value, gas_limit} = message;
build_call::<DefaultEnvironment>()
.delegate(code_hash)
.exec_input(
ExecutionInput::new(Selector::new(selector))
.push_arg(input)
)
.transferred_value(value)
.gas_limit(gas_limit)
.call_flags(
ink::env::CallFlags::default()
.set_tail_call(false),
)
.returns::<()>()
.invoke();
// Option 2: Add support for passing an encoded `Message` directly
//
// This would be similar to what how we forward input right now. We'd try and run
// the provided `Message` with the `code_hash`.
//
// Would trap if `Message` failed to decode correctly on dispatch.
build_call::<DefaultEnvironment>()
.delegate(code_hash)
.call_buffer(&message.encode())
.call_flags(
ink::env::CallFlags::default()
.set_tail_call(false),
)
.invoke();
} Pros:
Cons:
|
Codecov Report
@@ Coverage Diff @@
## master #1706 +/- ##
==========================================
+ Coverage 70.76% 70.98% +0.21%
==========================================
Files 206 204 -2
Lines 6455 6359 -96
==========================================
- Hits 4568 4514 -54
+ Misses 1887 1845 -42
... and 5 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
As you note in your cons list, this solution means it is no longer a "transparent" proxy, that is clients cannot simply take the metadata of a
That's true, but for larger contracts you need to pay the Another possible way of implementing extensibility without wildcards/fallbacks using #[ink(storage)]
struct Contract {
logic: Hash,
}
/// generates code to
#[ink(message(delegate_to = self.logic))]
pub fn transfer(&self, _to: AccountId, _value: Balance) {
// no body allowed
} Of course this pattern could introduce other unknown issues, and lacks some of the benefits such as auditability. In short I don't think we should easily dismiss the Diamond Pattern and similar, from what I understand in my research it is extremely popular on Ethereum and we want to attract those devs. I agree that it is probably an insecure pattern in general, but I don't think it is up to us to decide what type of contracts should be deployed. We should aim to provide as flexible as possible a language while guiding users to the pit of safety and success. |
Closing in favour of #1708 |
One of two possible approaches to solving the proxy selector clashing vulnerability
Motivation
The proxy selector clashing vulnerability depends on the usage of wildcard selectors/fallback functions in proxy contracts. By removing wildcard selectors this vulnerability is eliminated. Contract authors can still implement upgradeability using
set_code_hash
.Open questions
set_code_hash
, are there alternatives?Diamonds/Multi-Facet proxy
As described in https://eips.ethereum.org/EIPS/eip-2535, this pattern of delegating to many "facet" contracts routed by the selector would no longer be possible if we removed wildcard selectors.