Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Update ic.did #75

Closed
wants to merge 3 commits into from
Closed

Update ic.did #75

wants to merge 3 commits into from

Conversation

lwshang
Copy link
Contributor

@lwshang lwshang commented Aug 5, 2022

Some types of bitcoin and canister_http_request have different definition in the IC implementation.

Should we update the candid file in the spec or change the actual implementation?

Also delete user_id since it is not used by any methods.

@lwshang lwshang requested a review from a team as a code owner August 5, 2022 16:18
@netlify
Copy link

netlify bot commented Aug 5, 2022

Deploy Preview for ic-interface-spec ready!

Name Link
🔨 Latest commit 11cb6fb
🔍 Latest deploy log https://app.netlify.com/sites/ic-interface-spec/deploys/62ed4433ce9d300008eb20cc
😎 Deploy Preview https://deploy-preview-75--ic-interface-spec.netlify.app/
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@lwshang lwshang changed the title update ic.did Update ic.did Aug 5, 2022
@nomeata
Copy link
Contributor

nomeata commented Aug 5, 2022

It's hardly a spec if the implementation defines what's true; it becomes implementation then ;-)

Don't we have spec acceptance tests? Shouldn't they prevent such accidental difference? It seems somewhere some shortcuts were taken…

Looking at the diff it seems mostly artifacts of Rust specific naming conventions (e.g. upper case enum tags). Ideally that is not the guiding light for a language agnostic interface, and I'd say it's more important to be consistent within the interface. If all the other enums and variants have lowercase names, then these here better follow suit.

Copy link
Member

@Dfinity-Bjoern Dfinity-Bjoern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP API is not released, so changes there do not seem problematic. What concerns me a bit is that the changes appear to contradict our conventions.

testnet;
Mainnet;
Testnet;
Regtest;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does Regtest mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, https://developer.bitcoin.org/examples/testing.html#regtest-mode
For local bitcoin development, regtest is the chain being connected. The relevant PR here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regtest is a tool that we're choosing to add to facilitate local development, but it's not part of production, so IMO it does not belong to the interface spec.

@@ -52,8 +52,8 @@ type get_utxos_request = record {
address : bitcoin_address;
network: bitcoin_network;
filter: opt variant {
min_confirmations: nat32;
page: blob;
MinConfirmations: nat32;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems inconsistent with the naming conventions. Maybe we should actually fix the implementation instead? WDYT @ielashi @THLO

transform : opt variant {
function: func (http_response) -> (http_response) query
};
transform_method_name : opt text;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we changing this ? I will be on the side of using as much as type safety as possible .

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, this is not clear, could someone clarify?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to analyze whether both Motoko and Rust can support this. What constraints does this impose on the use of potential other languages like C?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nomeata : Can you help in clarifying whether and how one would implement in Rust against the current specification (lines 118-120)? Does it preclude other languages with a less expressive type system like C to be used for developing canisters?
I would really like to keep the spec as in 118-120. Thanks for any input!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Motoko has no problem supporting function references. On the Rust side, you can decode it to https://docs.rs/candid/0.7.16/candid/types/reference/struct.Func.html. But there is a problem in encoding the reference type. There are some workaround implemented in ic-proxy, but not ideal. See this issue: dfinity/candid#273

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I think we are debating exactly the same points as when we debated whether to use a virtual canister for management, or use system API. I had a hard time convincing Johan of the virtual canister approach, and only @ielashi managed to frame it in a way that convinced him. Maybe Islam can help coming to a conclusion here too :-)

Copy link
Contributor

@ielashi ielashi Aug 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am feeling the pressure now :-) I'm catching up here, so apologies in advance if I'm missing some major points.

I think we're all in agreement that we should keep the low level system API as minimal as possible, and the dilemma here is whether the transform method is a primitive that needs to be added to the system API, or whether it can be expressed using other primitives.

If I understand correctly, what makes the transform special, as Dimitris already mentioned, is the following:

  1. There's no sender (and hence it's somewhat different from a query).
  2. It should (ideally) not be invoked by any canister apart from the canister itself and the management canister.

IMHO, the first property isn't really necessary, and the second property can be enforced with other lower-level primitives.

Regarding "there's no sender", why is that the case? The canister is requesting from the management canister to do an HTTP request, and the management canister then calls the transform method, so it seems perfectly consistent to have the management canister as the sender. Are there any reasons we need this special casing?

As for access control, which is more of a nice-to-have than a hard requirement, I believe we're also all in agreement that we should charge for queries at some point, and with that we'll need some mechanism to allow canisters to accept/reject processing queries (i.e. some kind of equivalent to the canister_inspect_message we have for ingress messages). Once that primitive is available, then a canister can easily ensure that the transform method can only be called by itself and/or the management canister if it wishes.

With the above in mind, I'd be inclined to think the transform method is really no different than a query. What would we gain by special-casing this method and introducing a new system API?

As for the debate of whether to use a func or a text for the transform method, I don't have a strong opinion. I agree that func feels a bit too generic, but on the other hand I like the additional type safety that it can provide with the right support from a langauge's CDK, so I'd have a slight preference for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel there's still a misunderstanding here on what we mean when we say the management canister "calls" the transform function.

The design is that the replica calls the transform function and not really the management canister. If it was an actual call from the management canister, I'd expect it to be similar to an inter-canister call but the feature is designed in a way that the call does not resemble an inter-canister call. Perhaps it could have been designed and implemented in such a way but I simply don't see it in the current design and implementation.

That said, I feel we're just going in circles here. This discussion was brought up internally and a few people (tagged here and including myself) found the system method approach to be matching better. It seems there's another set of people that feel differently and we probably need to agree we disagree. Each side has presented their arguments, so I propose we leave it up to @Dfinity-Bjoern and other spec owners (and ultimately PR approvers) to set the direction.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The design is that the replica calls the transform function and not really the management canister.

That sentence doesn’t make sense to me. The management canister isn’t a think, it is an abstract concept, a facade for the replica (or the subnet, if you want). Just like if a canister calls the management canister to get some randomness, of course what’s happening really is the replica handles that.

But yes, I think the arguments are on the table. Poor @Dfinity-Bjoern will have to make a call :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit @nomeata swayed me to the let-it-be-a-query direction. The main reason reason is that, from a canister perspective, the API of calling aaaaa-aa and then getting a "callback" (in quotes since it's not a callback in the interface spec sense) from aaaaa-aa makes a lot of sense. It is, in a sense, upward-compatible to providing the functionality through an actual canister. So if I have to make a call, then we go with:

  • we leave it as a query that is invoked (with caller aaaaa-aa),
  • we also keep the type-safe variant.

@@ -19,7 +18,7 @@ type definite_canister_settings = record {
type http_header = record { name: text; value: text };

type http_response = record {
status: nat;
status: nat64;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The team thinks that this should be changed to nat64 in the spec as it does not make sense to have an arbitrary precision number for representing HTTP status codes.

Copy link
Contributor

@nomeata nomeata Aug 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not that important, but this goes against the general advice by @rossberg to not use fixed-width numbers unless you do bit-fiddling or need to be compatible with some crypto or it’s a fixed width hash or something like that.

Also note that nat is actually shorter on the wire than nat64 for small values.

And even if, why nat64 and not nat16 or nat32?

Copy link
Contributor

@nomeata nomeata Aug 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this push to use nat64 (here and elsewhere) is mostly an artifact of the Rust bindings being designed in a way that makes the use of nat more inconvenient than nat64.

This could probably be fixed by adding a newtype around i64 to the Rust library that encodes/decodes to nat, and errors out when the incoming number is too large. Then Rust code can interact with nat with very little extra work whenever it wants to reject very large values anyways. WDYT, @chenyan-dfinity?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i128/u128 already maps to int/nat in Candid. The question is whether we want to optimize space for messages or the Rust memory.

We could define a newtype for i64, but people may still choose to ignore it. Just like we already have candid::Int and candid::Nat defined. Maybe we need an option to map all Rust number types to nat/int on the wire?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nomeata : Thanks for your thoughts about this and the reference to Andreas Rossberg's opinion. So you would advise to keep it as a nat?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I guess just use i128 in rust and not worry any further :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nomeata, @chenyan-dfinity :Sounds good! Thanks for your helpful inputs here!

@@ -112,12 +112,10 @@ service ic : {
http_request : (record {
url : text;
max_response_bytes: opt nat64;
method : variant { get; head; post };
http_method : variant { GET; HEAD; POST };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will change the enumerations to lowercase in the implementation.
However, we wonder whether using "method" or "http_method" is better, considering that it is part of a record that has "http" in its name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a slight preference for just calling it "method" since it's in the context of an http_request and the HTTP spec refers to it as "request method" (not "HTTP method"). But I don't think it matters too much, I find it clear either way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, than let's go with

method : variant { get; head; post };

as it is currently in the spec and change the implementation.

@ielashi
Copy link
Contributor

ielashi commented Aug 19, 2022

Regarding the Bitcoin API, we discussed it internally and we agree that consistency of the interface is more important, and we'll be updating the implementation to comply with the spec.

@ielashi
Copy link
Contributor

ielashi commented Aug 31, 2022

Note that the bitcoin interface in the replica has been updated to be consistent with the current spec, so the changes proposed to the Bitcoin interface in this PR can be reverted.

@lwshang
Copy link
Contributor Author

lwshang commented Aug 31, 2022

In short, we all agree to keep the existing specification candid and let the teams fix the implementation to be consistent.
So I will just close this PR.

@lwshang lwshang closed this Aug 31, 2022
@lwshang lwshang deleted the lwshang/fix_candid_spec branch August 31, 2022 14:43
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants