-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Experimental features should be deprecated #817
Comments
I think this would make it easier to develop large features, e.g.. Schnorr signatures. Currently our model (and that of Bitcoin Core) is to have large atomic changes in a single PR developed by a single party who addresses review comments over and over. And reviewers keep reviewing the same stuff because people don't want to commit and the PR takes forever to be merged. I believe it's easier to develop large changes in a separate feature branch (or fork), but then create small PRs against this feature branch to avoid that PRs become huge, and later create a single large PR against master. Some things are simply too large to be handled in a single PR. This is what Bitcoin Core is effectively doing with secp256k1. (Sorry, this is somewhat off-topic.) |
I think there are a few somewhat related issues here. "experimental" used to not mean very muchThis library wasn't well maintained for a long time, and that led to a few things remaining marked experimental for far longer than they should have been. This has improved lately, and ECDH (which was effectively stable for years) is about to be marked non-experimental (see #809). I think the ARM assembly will in the near future become non-experimental as well, but I'd like to see CI support for it. Beyond those two, the only remaining experimental feature is the recently-merged BIP340 support. It is experimental for two reasons:
This is all to say: I think our recent notion of what "experimental" is narrower now than what it has been for a long time, and for what is left, there are specific criteria for letting them graduate - not an open-ended noncommitment. If you can't commit to an API, you can't include it.I disagree here. There are certainly packaging/compatibility complexities (see next point), but there shouldn't be a reason why software that uses a pinned version of their dependencies (through subtrees, submodules, commit hashes in dependency systems, ...) cannot use an experimental API. It works, it's tested and reviewed, and it's included in the library so that things can be developed against it - they just have to be prepared to, for now, adapt to API changes when updating. As for leaving things in a branch... perhaps that is an approach, but may make it harder to start developing software that builds on it. I think experimental feature just means you can only use it in a controlled environment. Linking issues when dependencies need overlapping featuresThis is a hard problem, though it's not restricted to experimental-ness - any kind of optionality in features can cause this problem. It's even worse when there are downstream projects that add extra functionality (e.g. secp256k1-zkp; what if you need the rangeproofs from there, but also BIP340 support from the current upstream master, while -zkp isn't rebased on top of that?). I feel that perhaps at some point it will be needed to support a compile-time option to add some prefix to all exported symbol names. (Non-experimental) features should be default-on when possibleIgnoring experimental features - whether you agree with them or not - perhaps this is the main point you're trying to convey? When there are stable features in a library that are optional, they will be enabled in generic builds, and even when pinned within projects due to the need to provide for multiple indirect dependencies (e.g. libwally as you point out). So that's an argument to make them default-on, or even non-optional, to minimize the potential configuration combinations that end users may end up with. Perhaps ECDH is a good candidate to make default to on now because of that. I'm less certain about recovery, as it's something that (I personally think) should be discouraged from being relied on in new systems (potential patent concerns, and aggregation schemes being more powerful in general). |
Yes. All optional features will get turned on for the vast majority of users. If that's not safe, we need to seriously consider whether the feature should be included at all. If we simply don't like the feature, then we should state those reasons clearly in documentation to discourage new users. And of course we can have a multitude of cut-down flags to eliminate parts of the library for specialized envs.
If experimental means "API unstable", then I'm afraid it hasn't met the bar for inclusion in a mature library. Which is totally fine: make it a separate library. When the result has matured sufficiently, include it in libsecp256k1. Otherwise you're not a mature library: this is part of the commitment which is reasonably expected from libraries, and it's not arbitrary. Breaking an API means pain and suffering for downstream projects; please don't call a library version 1.0 and then try to change the API. |
That seems very reasonable.
What do you mean by separate library?
It's far from ideal, but I think having a feature that's just temporarily in an experimental state is a good middle road. It gets the code changes in mainline, lets testing happen on interactions between the feature and other things being developed, signifies the code is reviewed and tested, lets downstream extensions rebase on it, make it easy for projects that pin the version to start developing on top of without conflicts, ... but also means some changes can still happen, and users will be aware of this.
libsecp256k1 hasn't released a version 1.0. |
We can't have both "we want people to start using this feature" and "sorry, there's no API stability"; they are opposed in practice.
Well, in the BIP340 case there's a clear path (since it will presumably become non-experimental once BIP340 is merged into bitcoin-core?). I still prefer it as a separate library, which would not have been as bad if it had started that way (note: we can share non-ABI-stable internals between two dependent libraries, which lets us do most things sanely). Not worth it now, but I don't know what other changes we'll see in future. I'm arguing for weaning off the existing ones, and never adding another. For example, it seems (from rough reading) recovery could be moved out to a separate library if there are patent concerns which means it should never be a "core" thing.
Yes. But I hope to see it one day! |
@sipa Having experimental modules is hard, I'm concerned that it becomes even harder after we release a 1.0. We have two kinds of users: 1) projects that pin a commit (primarily Bitcoin Core but also others) and 2) projects that want a general library. Now what will happen for the latter? Distributions tend to enable all features because it makes sense to do so, (related: #675) and I'm not sure if we can convince them from not enabling experimental features. Somebody will need the experimental feature, so distros will enable it. Assume we have something like semver. What kind of release is an API break in an experimental module? Major release? Then there is no difference to normal modules. Minor release? Then users of experimental modules will need to pin version numbers, which creates all kinds of issues in dependency managers etc. The only way I see is to exclude experimental features from the versioning, discourage distros from enabling experimental features, and recommend that users who need experimental modules should vendor the library/pin a commit. (And put all the blame on them if they don't stick to the policy.)
Would a single experimental branch be more difficult to work with? You can test interactions, downstream extensions can rebase on it, and projects can pin commits of the experimental branch. You sadi that a separate branch will make things unnecessarily difficult for developing things on top. Can you explain how?
Recovery is not an experimental module. And it's actually used within Bitcoin Core, so we need this. (But I get what you're saying.) |
Experimental features just don't have any promises. Breaking the interface for one isn't any kind of API break because no API commitment was made at all. It may not be possible to design a really good and safe API for something without actually also attempting to implement the something in an application and getting feedback from how it integrates. While that is going on there needs to be a mechanism to coordinate with the new application(s). They could, for sure, be in a separately forked copy of the library-- but this software exists as a freestanding library rather than a directory in bitcoin-core in part because it was believed it would be easier maintained this way. I think this choice has, for whatever reason, panned out somewhat poorly, resulting in a outright dangerous lack of attention and-- at times-- a near total inability to move things forward (although lately it's been better). It has also not resulted in a particularly large amount of of adoption by other users (with a few exceptions, e.g. libwally/c-lightning)-- instead obviously provably less secure alternatives are ubiquitous in hardware wallets, as an example. If the library was further split into more separately maintained things I don't believe an outcome other than abandonment is likely. Similarly, there have been features such as ECDH where holding them to the safety and integrity standard used in the library would have simply precluded their development as before they existed had zero usage to justify the hundreds of man hours of review and testing needed to mature them. Without the ability to have unsupported/test components the response to attempt to develop such things would be "don't bother". Again, it could be developed somewhere else, but I suspect that would just end up forgotten and abandoned (or else, all development would move to that, leaving this side abandoned and just renaming the library you're taking issue with). I don't follow this separate library discussion. This library is a single compilation unit, it would be a single file library except its nicer to maintain split into modules. The overall design depends pretty heavily on inlining, and none of the internal symbols are exported at all. Exposing the internals directly would be contrary to the design principle of only providing safe, supported, "complete cryptosystem" interfaces as much as possible. Having a configurable prefix-- as is pretty common other crypto libraries that are mostly copied rather than linked-- would probably be pretty useful. The symbol naming is already pretty well set up for it because everything is already prefixed "secp256k1_", so that could just be the default prefix. Some thought would need to be given on how to handle the typedefs. As far as "supported but you probably shouldn't use it in new things", perhaps: Rename the relevant functions something with deprecated in them, keep the original name as a wrapper but with __attribute((deprecated)) set on it. Existing callers will change the name of their call to silence the warnings, thus getting notified.
It's used only by "signmessage" -- nowhere by the bitcoin protocol. And signmessage is increasingly useless because it doesn't work with the address types mostly being used by users today, and without using the same addresses there is almost no justification for using signmessage over, say, PGP or signify... I think it's likely that bitcoin would (eventually) drop signmessage if any of the several efforts to make an alternative that worked more generally were finished. |
(oops I mentioned the wrong issue in my PR, please ignore the mention above this comment.) |
Maybe libsecp256k1 can/should install a libsecp256k1.so and libsecp256k1_experimental.so, and pkg-config files for each module to autoselect which library to include? |
@luke-jr That's an interesting idea but I wonder if this really helps. I don't think we would want to ship a pkg-config for experimental features. (What's the point in checking for some version of an unstable API?) |
@gmaxwell Actually, libsecp is becoming widely used; every lightning implementation uses it, for example. And the schnorr stuff is likely to complete this dominance, since it's just Damn Nice for any new uses.
That... doesn't help me. I'm using it. I do not treat it any differently from the rest of libsecp256k1. If it had, at least, been a separate library I might have (for example, auditing the code). You're certainly implying that I should have!
But another library could share most of this inlining, and I disagree that exposing (say) secp256k1_internal* symbols would break the design, if it came to that. WRT deprecating things, it generally implies a pending removal (and timeline here should probably be >= 24 months). I wouldn't start a deprecation unless there's a clear, documented path to removal. Sometimes it's better to simply label "/* THIS IS A NASTY FUNCTION, HERE FOR LEGACY USE CASES. Please use xxx instead and make all of our lives better */". |
To make sure the user has that correct version and get the CFLAGS/etc correct for it... Same as with a stable API. |
Speaking of which, we need to do some benchmarking of it. At the time of writing GCC was generating quite horrible code for ARM with a plenty of stack spilling. Back then it was an impressive improvement. But it's very possible that in the meantime, GCC has grown "good enough" to get close to, or even beat the manually implemented code. I do still have ARM32 hardware in use (i.MX6) so might give it at try. |
I was recently benchmarking gcc 9.2 on i.MX6 and the code you wrote was still a massssiiiivvvveee speedup. :) (if you dig through the safegcd thread you can see some numbers w/o asm on 32-bit arm) |
3ed0d02 doc: add CHANGELOG template (Jonas Nick) 6f42dc1 doc: add release_process.md (Jonas Nick) 0bd3e42 build: set library version to 0.0.0 explicitly (Jonas Nick) b4b02fd build: change libsecp version from 0.1 to 0.1.0-pre (Jonas Nick) Pull request description: This is an attempt at a simple release process. Fixes #856. To keep it simple, there is no concept of release candidates for now. The release version is determined by semantic versioning of the API. Since it does not seem to be a lot of work, it is proper to also version the ABI with the libtool versioning system. This versioning scheme (semver API, libtool versioning ABI) follows the suggestion in the [autotools mythbusters](https://autotools.io/libtool/version.html). Experimental modules are a bit of a headache, as expected. This release process suggests to treat any change in experimental modules as backwards compatible. That way, users of stable modules are not bothered by frequent non-backwards compatible releases. But a downside is that one must not use experimental modules in shared libraries (which should be mentioned in the README?). It would be nice if we could make the schnorrsig module stable in the not too distant future (see also #817). ACKs for top commit: apoelstra: utACK 3ed0d02 elichai: ACK 3ed0d02 sipa: ACK 3ed0d02 real-or-random: ACK 3ed0d02 Tree-SHA512: 25a04335a9579e16de48d378b93a9c6a248529f67f7c436680fa2d495192132743ce016c547aa9718cdcc7fe932de31dd7594f49052e8bd85572a84264f2dbee
41e8704 build: Enable some modules by default (Tim Ruffing) Pull request description: This has been discussed in #817 (comment) and I agree with the arguments brought up there. Alternatively, we could not enable them and add a discussion to the readme why we discourage people from using the modules. I believe enabling ECDH is not very controversial. But what about recovery? Do we want to leave it off and instead give a reason? ACKs for top commit: sipa: ACK 41e8704 jonasnick: ACK 41e8704 Tree-SHA512: 1dd21037043f2b2c94a92cd2f31e69b505ba5b43119897bc0934966d9ccd84fc4fc20e7509af634f1c3a096710db1a2253090f5f1f107b9d258945a5546e9ba4
If a feature is genuinely experimental, keep it in a separate branch.
Otherwise, it will be compiled in, as there may be a user. This becomes inevitable in larger systems: in particular, c-lightning uses both libsecp and libwally. The latter includes libsecp, and you can't have two libraries with the same symbols, so c-lightning needs to use the libwally one. Packaging systems fix this, but they have the same problem: they must configure in everything.
You can have boutique builds that omit features for embedded use, sure. But the default will be kitchen sink.
I know it's hard: labelling something experimental is a good way of avoiding commitment. But it is a mere fig leaf which doesn't work, and mature libraries don't get that luxury.
If you're not prepared to commit to an API (ideally an ABI too), you simply cannot include something. In that case, it needs to be a separate library (and if it gets folded in later, all the names have to change!).
The text was updated successfully, but these errors were encountered: