-
Notifications
You must be signed in to change notification settings - Fork 14
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
feat!: NNS-managed RPC providers #252
Conversation
…ic-eth-rpc into nns-providers
This PR updates the GitHub CI on the `evm-rpc-canister` branch to be equivalent to the original GitLab configuration. This is a temporary measure to unblock development, since we intend to migrate this branch into the [EVM RPC repository](internet-computer-protocol/evm-rpc-canister#252) (which contains the vast majority of the testing for the forked codebase).
This PR should be ready to merge! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot @rvanasa for this new version! I reviewed the whole MR in details and it looks very good! I left a few comments but most of them are minor, I don't see any blocker. Feel free to tell me if those comments are better addressed in a follow-up PR (in case you think there are meaningful to implement)
} | ||
|
||
#[test] | ||
fn should_insert_api_keys() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
additional test ideas:
- Set the key for a provider that uses Bearer Token.
- Updating a previously existing API key of some provider to
None
, removes it. - Panic if trying to specify an API key for a provider that uses
RpcAccess::Unauthenticated
- Panic if a provider is not found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I'll do this in a separate PR so we can get this one merged.
src/memory.rs
Outdated
pub static UNSTABLE_METRICS: RefCell<Metrics> = RefCell::new(Metrics::default()); | ||
static UNSTABLE_SUBNET_SIZE: RefCell<u32> = RefCell::new(NODES_IN_FIDUCIARY_SUBNET); | ||
static UNSTABLE_DEMO_STATUS: RefCell<bool> = RefCell::new(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
understanding question: why should this be unstable? For local development purposes, it would be I think a bit weird if one starts in demo mode, one does some local changes and upgrade, and the canister is back to non-demo mode. I would have a priori saved this flag in stable memory. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong preference either way, but we might as well keep this in stable memory since that seems more intuitive for how people might use the canister in local development.
It also turns out Storable
isn't implemented for bool
, at least in the version of ic-stable-structures
used in the project. 🙃 I added a BoolStorable
for now and will include tests in the PR mentioned in this comment.
cycles_per_message_byte: 0, | ||
pub const PROVIDERS: &[Provider] = &[ | ||
Provider { | ||
provider_id: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be maybe be a good thing to have a test ensuring that the provider_id
are stable (maybe in another PR). WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would you define "stable" in this context? As a starting point, I added a test to enforce the expected provider_id
sequence (starting at zero, increasing by one). This covers the cases of removing or skipping a provider, while other changes are unlikely to occur by accident because each ID is hard-coded.
.find(|(_, p)| p.primary && p.chain_id == id) | ||
.or_else(|| providers.iter().find(|(_, p)| p.chain_id == id)) | ||
RpcService::Chain(id) => ResolvedRpcService::Provider( | ||
find_provider(|p| p.chain_id == id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
understanding question: Before this was returning the first provider for which p.primary && p.chain_id == id
, while now this return the first provider for which p.chain_id == id
. Is-it clear that those are actually the same providers after this PR (do we need maybe a unit test for this?) or is-it somehow not that relevant here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic is equivalent because we never ended up changing the primary
flag on any provider in the production canister.
We could use this opportunity to remove the RpcService::Chain()
variant given the ambiguity. Because this update will make a few other breaking changes, we could include this in the migration steps for canisters to prepare for the new release.
fn from_bytes(bytes: Cow<[u8]>) -> Self { | ||
Decode!(&bytes, Self).unwrap() | ||
Self(String::from_bytes(bytes)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we should call here the try_from
from L.225 to ensure that the API key is valid (and panic otherwise).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A concern with doing this is that if we change the validation logic to exclude already registered API keys, this logic could potentially break the canister on upgrade and require a fresh reinstall in another NNS proposal. We could probably accept that risk, but it seems like a tradeoff. WDYT?
Co-authored-by: gregorydemay <[email protected]>
Thank you for the detailed review @gregorydemay! I'll merge this and then will make follow-up changes in separate PRs as mentioned. |
Follow-up testing and bugfixes for #252. This PR... * Adds state machine tests for the following scenarios: * Set the key for a provider that uses `RpcAuth::BearerToken`. * Update a previously existing API key of some provider to `None` removes it. * Panic if trying to specify an API key for a provider that uses `RpcAccess::Unauthenticated` * Panic if a provider is not found. * Sets up the following canister upgrade tests: * Keep previously inserted API keys. * Change or keep demo status based on upgrade args. * Change or keep principals allowed to manage API key providers based on upgrade args. * Includes unit tests for `BoolStorable` and `PrincipalStorable`. * Removes unused `StringStorable`. * Changes the `requestCost` canister method to return `0` when in demo mode. * Fixes the following bugs: * `BoolStorable` had an inverted condition in `from_bytes` * `getProviderCost()` returned `Nat` instead of `Result<Nat, RpcError>` in the state machine test logic Note that the canister upgrade tests use the same Wasm before and after upgrade. In the future (probably out of scope of this PR), we could extend this to test upgrading from the most recently deployed canister's Wasm file.
The management of providers was revamped in #252 and the provided commands in the README no longer apply.
This PR makes significant changes to the EVM RPC canister to enable using NNS proposals in place of a trusted principal to add, remove, and update RPC providers.
Progress:
Provider
struct for immutability{API_KEY}
placeholderProviderId
type aliasImplement post-upgrade actions to add, remove, and update one or more providersstableSize
andstableRead
canister methodsauthorize
,deauthorize
, andgetAuthorized
canister methodsFreeRpc
authPriorityRpc
auth as well asgetOpenRpcAccess
andsetOpenRpcAccess
PrincipalStorable
structAdd optionalpublic_url
to each providerdemo
flag to locally use EVM RPC canister without cycles payments, e.g. through Candid UIContent-Type
header