From 430e2b5d39dec513703f83110803aa5255186eab Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Mon, 11 Dec 2023 10:11:11 +0000 Subject: [PATCH 01/21] Add a sketch of branching policy --- BRANCHING.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 BRANCHING.md diff --git a/BRANCHING.md b/BRANCHING.md new file mode 100644 index 00000000000..0c8f1d61803 --- /dev/null +++ b/BRANCHING.md @@ -0,0 +1,66 @@ +# Mina Branching Policy + +- `master`: current stable release. + - It is frozen from the crypto side, does not depend on `proof-systems`. + - Never commit to it directly, except to introduce a hotfix. +- `compatible`: scheduled to be released. + - It contains all the changes which are literally backwards compatible with what people currently run on the mainnet. Any nodes running a version of mina based off of compatible should connect to the current mainnet. +- `develop`: next non-harmful release, but without cutting edge new protocol features enabled (that might go into the next release). + - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. + - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). + - **TODO** how is `develop` different from `berkeley` currently? +- `berkeley`/`izmir`: next hardfork branch. + - Contains all the new features that are scheduled for the release (berkeley or izmir). + - On releases. Current release is "mainnet", public. Next release is "berkeley", and the one after is "izmir". The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). +- Direction of merge: + - The back-merging direction is as follows. `master` merges back to `compatible`, `compatible` merges back to `runpub` (currently running in berkeley incentivized testnet) (ignored). `runpub` merges back into next hardfork (now, `berkeley`), which then merges back into `develop`. + - So `develop` contains all the changes from the more stable branches. + - Merging forward (when introducing features/fixes) is up this stack, but the place the change is introduced can be different (e.g. `compatible` for soft features, `develop` for more experimental/next release). +- Hard fork/Release: + - Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` + - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. + + + +### Diagram + +**TODO** fix diagram + +![git-flow_david-wong.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/09e92777-0232-401b-be44-9689d39ce22a/git-flow_david-wong.png) + +## Day to day: which branch should I use? + +When developing a feature, if it’s not something that breaks compatibility, then you should be developing a feature branch, called `foo_COMP` for example, based off of `compatible`. If you’re not sure whether or not your changes are breaking, they probably are not and should build upon compatible. + +### Directions for merging your branch `foo_COMP` + +- There is a CI job called `merges cleanly to develop` which runs whenever you have a PR off of `compatible`. If that CI job passes, then you can simply merge `foo_COMP` into `compatible` , and no further action is needed. +- If `merges cleanly to develop` does NOT pass, then when you’re done with your changes to `foo_COMP` and the PR is all approved, make a new branch+PR based off of `foo_COMP` called `foo_DEVELOP` (for example), and then merge `develop` into `foo_DEVELOP`. Fix any merge errors that result, then once `foo_DEVELOP` is approved, you can merge it into `develop`. +- Once `foo_DEVELOP` is fully landed into `develop`, then go and manually re-run the `merges cleanly to develop` CI job in the original `foo_COMP` PR. The CI job should now pass and go green. You can now merge `foo_COMP` +- If after making `foo_DEVELOP`, you need to make changes to `foo_COMP`, then make sure to merge the newly updated `foo_COMP` into `foo_DEVELOP`. In order for the git magic to work, `foo_DEVELOP` needs to be a superset of the commits from `foo`, and it also needs to merge first. You can make further changes post-merge in `foo_DEVELOP` as needed to ensure correctness + +### Releases + +(**TODO** is this outdated/needs to be removed?) + +`release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. + +`release/2.0.0`is the branch where Berkeley QA Net releases are being cut, between `compatible`and `develop` in the tree. So far nothing has been tagged there but there will be `2.0.0alphaX` tags once the code is more stable and we are closer to the Incentivized testnet. + +Unless it is an emergency, code should flow from feature branches into `compatible` then in batches into the release branch for tagging and testing + +# proof-systems Branching policy +Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important distinctions exist that are a result of proof-systems having been created after the mainnet release (**TODO** ?). + +- `compatible`: **TODO** ??? Apparently not used in `mina`, and does not have commits after February 2023. Abandoned? + - Mina's `compatible`, similarly to mina's `master`, does not have `proof-systems`. +- `develop`: matches mina's `develop`, soft fork-compatibility. + - small nuance: `proof-systems#develop` is used as a main branch for o1js. + - **TODO** clarify, this seems to not match with https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility? +- `berkley`: future release, will be going out to berkeley. This is where hotfixes go. +- `master`: future feature work development, containing breaking changes. Anything that does not need to be released alongside mina. + - Note that `mina`'s `master` does not depend on `proof-systems` at all, therefore current ``. +- `izmir`: next release after berkeley. +- In the future: `master`/`develop` will reverse roles and become something like gitflow. +- Currently `develop` should be back-merged into `master`. + From b238c7eb97e7ecaaea4e0faf65b8b76a84326a7a Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Tue, 12 Dec 2023 15:53:35 +0000 Subject: [PATCH 02/21] Details on develop/release, rampup --- BRANCHING.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/BRANCHING.md b/BRANCHING.md index 0c8f1d61803..8f9ade1f9a1 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -5,21 +5,26 @@ - Never commit to it directly, except to introduce a hotfix. - `compatible`: scheduled to be released. - It contains all the changes which are literally backwards compatible with what people currently run on the mainnet. Any nodes running a version of mina based off of compatible should connect to the current mainnet. +- `rampup`: what is deployed on the testnet + - Compatible with `mina#compatible`. + - Never make PRs to `rampup` unless you're explicitly fixing a testnet bug. +- `berkeley`/`izmir`: next hardfork branch / release candidate. + - Contains all the new features that are scheduled for the release (berkeley or izmir). + - On releases. Current release is "mainnet", public. Next release is "berkeley", and the one after is "izmir". The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). - `develop`: next non-harmful release, but without cutting edge new protocol features enabled (that might go into the next release). - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). - - **TODO** how is `develop` different from `berkeley` currently? -- `berkeley`/`izmir`: next hardfork branch. - - Contains all the new features that are scheduled for the release (berkeley or izmir). - - On releases. Current release is "mainnet", public. Next release is "berkeley", and the one after is "izmir". The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). + - How is `develop` different from `berkeley` currently? `berkeley` is like 2.0 will be the actual hardfork release, and `develop` is like 2.01 subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. - Direction of merge: - - The back-merging direction is as follows. `master` merges back to `compatible`, `compatible` merges back to `runpub` (currently running in berkeley incentivized testnet) (ignored). `runpub` merges back into next hardfork (now, `berkeley`), which then merges back into `develop`. + - The back-merging direction is as follows. `master` merges back to `compatible`, `compatible` merges back to `rampup` (currently running in berkeley incentivized testnet) (ignored). `rampup` merges back into next hardfork (now, `berkeley`), which then merges back into `develop`. - So `develop` contains all the changes from the more stable branches. - Merging forward (when introducing features/fixes) is up this stack, but the place the change is introduced can be different (e.g. `compatible` for soft features, `develop` for more experimental/next release). - Hard fork/Release: - Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. - +- `o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` + - mina changes from `rampup` + - but `proof-systems#develop` ### Diagram @@ -52,7 +57,10 @@ Unless it is an emergency, code should flow from feature branches into `compati # proof-systems Branching policy Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important distinctions exist that are a result of proof-systems having been created after the mainnet release (**TODO** ?). -- `compatible`: **TODO** ??? Apparently not used in `mina`, and does not have commits after February 2023. Abandoned? +- `compatible`: + - Compatible with `rampup` in `mina`. + - **TODO** ??? Apparently not used in `mina`, and does not have commits after February 2023. Abandoned? + - After berkeley `compatible` will become properly synced with `mina` compatible. - Mina's `compatible`, similarly to mina's `master`, does not have `proof-systems`. - `develop`: matches mina's `develop`, soft fork-compatibility. - small nuance: `proof-systems#develop` is used as a main branch for o1js. @@ -64,3 +72,4 @@ Generally, proof-systems intends to be synchronized with the mina repository, an - In the future: `master`/`develop` will reverse roles and become something like gitflow. - Currently `develop` should be back-merged into `master`. + From d94b59fcde7ea3d93e3e3d58700495a74f15df57 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Tue, 12 Dec 2023 17:02:28 +0000 Subject: [PATCH 03/21] Improve descriptions/writing --- BRANCHING.md | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/BRANCHING.md b/BRANCHING.md index 8f9ade1f9a1..a5de4c13321 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -6,25 +6,27 @@ - `compatible`: scheduled to be released. - It contains all the changes which are literally backwards compatible with what people currently run on the mainnet. Any nodes running a version of mina based off of compatible should connect to the current mainnet. - `rampup`: what is deployed on the testnet - - Compatible with `mina#compatible`. + - Compatible with `compatible`. - Never make PRs to `rampup` unless you're explicitly fixing a testnet bug. - `berkeley`/`izmir`: next hardfork branch / release candidate. - Contains all the new features that are scheduled for the release (berkeley or izmir). - On releases. Current release is "mainnet", public. Next release is "berkeley", and the one after is "izmir". The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). -- `develop`: next non-harmful release, but without cutting edge new protocol features enabled (that might go into the next release). +- `develop`: next non-harmful release (after `berkeley`). + - Does *not* contain cutting edge new protocol features enabled (that might go into the next release). - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). - - How is `develop` different from `berkeley` currently? `berkeley` is like 2.0 will be the actual hardfork release, and `develop` is like 2.01 subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. + - The difference between `develop` and `berkeley` is that `berkeley` will be the actual hardfork release, while `develop` is subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. So if `berkeley` can be thought of as 2.0, then `develop` is 2.01. - Direction of merge: - - The back-merging direction is as follows. `master` merges back to `compatible`, `compatible` merges back to `rampup` (currently running in berkeley incentivized testnet) (ignored). `rampup` merges back into next hardfork (now, `berkeley`), which then merges back into `develop`. + - The back-merging direction is `master` to `compatible` to `rampup` to the next hardfork (now, `berkeley`) to `develop`. - So `develop` contains all the changes from the more stable branches. - - Merging forward (when introducing features/fixes) is up this stack, but the place the change is introduced can be different (e.g. `compatible` for soft features, `develop` for more experimental/next release). + - Merging forward (when introducing features/fixes) is up this stack, but the place the change is introduced can be different (e.g. `compatible` for softfork features, `develop` for more experimental/next release). - Hard fork/Release: - Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. - `o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` - - mina changes from `rampup` - - but `proof-systems#develop` + - Contains mina changes from `rampup` + - But `proof-systems/develop` which by default is used by `mina/develop`. + - Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). ### Diagram @@ -59,17 +61,17 @@ Generally, proof-systems intends to be synchronized with the mina repository, an - `compatible`: - Compatible with `rampup` in `mina`. - - **TODO** ??? Apparently not used in `mina`, and does not have commits after February 2023. Abandoned? - - After berkeley `compatible` will become properly synced with `mina` compatible. - Mina's `compatible`, similarly to mina's `master`, does not have `proof-systems`. +- `berkley`: future hardfork release, will be going out to berkeley. + - This is where hotfixes go. - `develop`: matches mina's `develop`, soft fork-compatibility. - - small nuance: `proof-systems#develop` is used as a main branch for o1js. - - **TODO** clarify, this seems to not match with https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility? -- `berkley`: future release, will be going out to berkeley. This is where hotfixes go. + - Also used by `mina/o1js-main` and `o1js/main`. - `master`: future feature work development, containing breaking changes. Anything that does not need to be released alongside mina. - - Note that `mina`'s `master` does not depend on `proof-systems` at all, therefore current ``. -- `izmir`: next release after berkeley. -- In the future: `master`/`develop` will reverse roles and become something like gitflow. -- Currently `develop` should be back-merged into `master`. - - + - Note that `mina`'s `master` does not depend on `proof-systems` at all. +- `izmir`: next hardfork release after berkeley. +- In the future: + - `master`/`develop` will reverse roles and become something like gitflow. + - After Berkeley release `compatible` will become properly synced with `mina/compatible`. +- Direction of merge: + - Back-merging: `compatible` into `berkeley` into `develop` into `master`. + - Front-merging (introducing new features): other direction, but where you start depends on where the feature belongs. From 9964af5c9ac40701e94db6fc4a94e1a80cbe8f0e Mon Sep 17 00:00:00 2001 From: Misha Volkhov Date: Fri, 15 Dec 2023 16:53:04 +0100 Subject: [PATCH 04/21] Update BRANCHING.md --- BRANCHING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BRANCHING.md b/BRANCHING.md index a5de4c13321..b5804add99c 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -27,6 +27,7 @@ - Contains mina changes from `rampup` - But `proof-systems/develop` which by default is used by `mina/develop`. - Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). + - When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. ### Diagram From ed40cd67fca419e2af5659f84a467e2de3980adf Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Thu, 4 Jan 2024 16:06:40 +0000 Subject: [PATCH 05/21] Update the subsection on branching + diagram --- BRANCHING.md | 13 +++---------- git-flow_david-wong.png | Bin 0 -> 38814 bytes 2 files changed, 3 insertions(+), 10 deletions(-) create mode 100644 git-flow_david-wong.png diff --git a/BRANCHING.md b/BRANCHING.md index b5804add99c..2f527d9e623 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -22,6 +22,7 @@ - Merging forward (when introducing features/fixes) is up this stack, but the place the change is introduced can be different (e.g. `compatible` for softfork features, `develop` for more experimental/next release). - Hard fork/Release: - Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` + - `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. - `o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` - Contains mina changes from `rampup` @@ -32,9 +33,9 @@ ### Diagram -**TODO** fix diagram +**TODO** improve diagram -![git-flow_david-wong.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/09e92777-0232-401b-be44-9689d39ce22a/git-flow_david-wong.png) +![git-flow_david-wong.png](./git-flow_david-wong.png) ## Day to day: which branch should I use? @@ -47,15 +48,7 @@ When developing a feature, if it’s not something that breaks compatibility, th - Once `foo_DEVELOP` is fully landed into `develop`, then go and manually re-run the `merges cleanly to develop` CI job in the original `foo_COMP` PR. The CI job should now pass and go green. You can now merge `foo_COMP` - If after making `foo_DEVELOP`, you need to make changes to `foo_COMP`, then make sure to merge the newly updated `foo_COMP` into `foo_DEVELOP`. In order for the git magic to work, `foo_DEVELOP` needs to be a superset of the commits from `foo`, and it also needs to merge first. You can make further changes post-merge in `foo_DEVELOP` as needed to ensure correctness -### Releases -(**TODO** is this outdated/needs to be removed?) - -`release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. - -`release/2.0.0`is the branch where Berkeley QA Net releases are being cut, between `compatible`and `develop` in the tree. So far nothing has been tagged there but there will be `2.0.0alphaX` tags once the code is more stable and we are closer to the Incentivized testnet. - -Unless it is an emergency, code should flow from feature branches into `compatible` then in batches into the release branch for tagging and testing # proof-systems Branching policy Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important distinctions exist that are a result of proof-systems having been created after the mainnet release (**TODO** ?). diff --git a/git-flow_david-wong.png b/git-flow_david-wong.png new file mode 100644 index 0000000000000000000000000000000000000000..063d258e8dafdee0a4494ae44b1b4a7439901555 GIT binary patch literal 38814 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

8yNC$ht%RQmp1?`WTt7$rEDk%yX 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

PvRTO?=V*eA55Qh8p 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≧-H<;gnjaa%b)9ZM9=~SR~ z#)lkeEvy}itDfm4TFdUH+Hcco3s6_*Ca&ln&9hCGS%IPzlH>1n?fh~bFJbzCVMX7Q zNRfNF|LWWb8YmOe7?V!69LW4Fsl@?zWb<5Ki>#?=ZETe-v>CX#Am zM1X(xx;aVaF`T&|Y>qiST*b6uF1hgR6~a^G=O|9wbqI0A2V0Fo!9gZK~yyn067|ZKY&EF z*38Ks`dnN|+*sMlXT9Yg&)pg*b{6&DzDJ&#H}=NWm~uAzECB*7h{n4C8e@4;JI#y} zrFkBt9~vQbBZ&A-qneM8Lb$nf<;|uTt7V;9gvi{KN#@uOg6-SSWb)^*xF+g**$$FrFR3~DsKa=UCBmS{Kx4ADRst)au+BI*5}5LcJ0RU(25t z)A^*{|~fLN&K0$G#W5a5gEIPgADmZ0n;Oh%_l9XF~2F6%y3~W(%b`DnMH+ zD9Qym3-~_ckuVpb>f&Z!ChhZ(poxYjgt<#K!+v`N&=m2{q=A<-`QoI=jzhc;c9{n^ zwl#jS;~FWv>#H6FE~j8mu~3l*SsP$4Y6gHJDgEYd1~gA*rdGgW9t7VP;5{{VJ-|73 zLooS1#0{cg&$(yr!~i)b9qM<|U;i;AN1SY%RU5J{!R;ph4*M#z8K z?Ym>{IJceh3*J2kvea%BGo_FstKflfFyc!P)83XP4>r0}iwJ4+j{3)!ulFzL%!9m2 z7Eba3V2b>OA9P{w1HmrcfvI`!wyuW8`d=@*Q@ z!LPj*PD}%)~lU8c{uO+ZE@V-**!0Y8w2BSBr~Dujg#}EZ?raiM*SIZZHzSQ_=Ix*2>Z)I-*;GgaR4?&|RSxXjq`4b=}$ge2GQ!L;()FFyoGps71*QtvIzo27>@);cpiaO{z zl3$@ojjF+z($o9jGMEH7v&KFPM$+Sh=U=-yeiF2n9wfDAN-YM_JAVbC+Fv^%umH!G z@>Tj3rCot}G%%_OzVkYW0%$Z%xV+;K`Ru4E8g+s5tu>s)jE&&T4txioQ*q4am|!l9 zP!s66AFmRQ&hN#P_e4VYl`G|7QJ1<{yHG>Mjb?)y7=}{|56b7AUx&ubkAf9uoDqII zLo4jaOpWGQ2~qh(mO>^SJkbQ6Ub*qO54jyWq*5p3ue7Ma_B$jOiB{w!d{?zP6d7|v z*xg22YN$Q_*-2Q^s;dXY*O zvJ0vBFc*E9R5gYb`2rDwXfS6wT#q@d-MakN+_*r)eFQv7PF9jIbh%~Q=}8B1&H#ROZw;&CRN!(VB_ zsJ-5Czu@s)Fe*#?h$$L%0*&gmSNmMnu92RG3n!6CkR5KCED?q!PXtLZ&WgQ7tM>UQ zY$?+-i({8yQ8T_J3c{Q2va1xOLdOAbge6Q-1~pVn{DPr2%r|_jZDtVQ+^C40`64&i zDD$oJ4*vk*4k~mZ5UveUe!8E|E-LU&!NVnI;qmk*;JcKMtk8R$1fG-o7Z~7QwT_@A zO*`G#eW1pnWIeVA-eVgaz(f^3^8{$0Dy);=`u!MGkb1iB#}_GQ9ooz1VWO0xk!S|f z^srKU8I2$}xeTwbu7H7yH(*bKp4L^E3>1nu2K5)^L$T8M8VJhn7i$4*6MJ~6TO%!c zX!&$u^^vGA8N#5#ygShq9nvZK&`uas7Y*7yCA=7YOo0ejl>gna_V!qQAIYK!cXX(Mn_ z`iu-nBu%iRtyNkd!d&)%Mi<=3(7uIqDhIaIi24hmtFWkYD^%_XlWe#YE&{_)cL7eB zz%HguMsB1X9FgaK**E=ZtbZgdH2Zhw@=T7KK2g$i5fpAd{v5 z>$KR()CHEEUJV(^r!RGG(85HIgqC2Co;?Oh$-JwBl}H00slR?=7t9*=q)?6W{NVS( z=guYrm1(zNzsG=}Oo&67;{O0&d*-0!OGO3^M6LD_2L0pwnH@FPf+c+r5C=q9X$&yv z+xhhO@F*nxNJ4E;`}GqjW#S_pm_F9( z5nZ&+XkY@d0qQScBtv-rhjYd(k6;2%ete12ZhHn#*Pj)ihK;Mt2&zB&EzJSsi?iG<2T9;AKWLHn-6y`sEEe`6p$potsJKn7Nd6sW8Zo4W!g&~cDr7tFd2z6nmA zvB)8~|NAci0r1d0N8l70v!y}+?PG0%nb}R})RPS?88*Wm8 z@M?7|Z$)YjUPJ{&^~tpm5(g-@KzJIrbRgMVpQ45k{_r9)99WP)gjY9V$&gT7rl+v7CBN2h{ zA@!&R?7YhL2Yv8qB?2^*`De1hHiwYhJec+S$Y?M`a?BrGjnLySz;`kG>(P5C1L4`8 zho{iLE>MPy)Is3hmyH8zx@<4#ys_6@Jq=udmy#-mIuBU`M( zIn{f<31?}ThSIl6(ROH+>LK3NXbA%g4dql!-?O3Ge0qQ{35Jf&a^i?b@4Xw%^a}1j z?oOqLoJAiHqxDeHbD-hm;icvGUq^~e;0^6UUoWs&C~}NvE+X`Mb{z+Q3%uuqd%jnK zzz=P~;C)WD(MZ;gn6RCB54c&|@_j58&@|}O0?l$pn)NME7ii~n;9{!?K1n8IIbyil zCeh&H8RonNU=a%o4~PY-%xZv$3k@vBaa1G~>d8RV>ynx8-T4gFbw zBB+i(v1rl1VEV9Vi3ED;_hbu>6b8hrzl49*g0X448h_632Mz8dK&vZ0e(68B6_IdE8e-9%D zw`&n7esv}KT44QWb-Qx&b;gP~yrO%#082A(f7oJJ9g>YUB zN#*7RTC@ij&(QCv`P!_|?GWIMsociL13;>k<0uW?X}o(J)a@a4C7Ip@pWm2?05b7wdom96>fuWFuT34o~$M#Ri+ zgy~Me3J@C5FNCf{z#7oHzkoIQ#R2kp&QocT4T$h*p^EIML}+JLIvwv87UwWN^3y=$oy8-d{7{lvYV`5BuF=3eSN)_Ja-=ClR|0^okqE zz=iB;B0Jdt&KqFFaOY0|=L7u{u&s;~N}|X>SO)^zOC7ZF^R5$_RUvsg=>AOtSdno@ zu10eoErtg4F}U&~oLeJ8O!)?2p28pz87{szHdzBqofZz%_tv~`AE@67>JBr=zO=TY zO#m*lz3Lpma20%9S~OHYT@vcCFQ9fH+hwIW1MRK6@fb|QNkr7z3k!~JVsN_svdn#k z=is^JP$>GmdqYb4;X-W_s!6(L_v<}CC5u__pRHK#Xs$dmhCD(V3OHhN(qRsv0kHBI z`j@=lv&^?{+fXc_n!l*u=I>L_oa#m0CO#tq@o7IOS(IYEE^t7mp9TZGY=_szC9BQ| zL60#XVGf#vDI``|b9)aUSucDkWU;AAc% z3)az(>HElbK2gB_0xjiUHn&jFCh<2HCikB(GsuFX=$q@2K}VH_L7^g`d}9b0LV_-< z8<3+l0LyjQw0H?R{A=lg43+1M`T(cdjGW&7ZjV=R?^v)38dtq!4=NK`7ZOjN4|2g* zs2KYX2kvbEq+P$-p*a~(;PrY1pe!SO0GN8jx1zio@XtZMYK|;$7e<5-4%Ag3>6QHH zHpWLhZHy8p(#laZgZ2>+T|{$Ej#C2<@LOmi7JoV8+TL@dtv1A6iH@zx=r|x-ixJ_I zk!g$_avBfO!6kD(RRsLtUxq8hL@uxpfu7&doEbY>4783`z%Jf=WEi57u#^xPzD}7t zKYJLyf-(-8DH7inI6g_FurRX=-6^mAo2%ABKK{&Vi6CYWF(v7}q|WyRbL3d!Wu|)O z?c9lAGWRKFo2=D7ZTGx1e;`ws@6*#ZSG1o9eFT+!V7&~w93`Cet&^d7DA&BI3D?El zM^CGvjJC}@4~wls0DX5RqDMsc4P@dk?Lar5oS!n{!5M1{If|ZxR%veTtn`5END>&UI0VP$0^BsfT?m<2W#CmyP=RD8FAattV zj|UuefV&bfUu!V9K#&85%)!#%3T@_z)^W~{+~x;*6HL7bBw#nv8LOyl^X33Lp+K>P zWMShge82gqo58JUcV9o!8RLrR#fKZl&iG&DVKD^e7`5Xs! zMhc9-3ooALqH<3YX8!o$QQG)xz69|e!%tp-Q&1X< zQM|YWbgb^E<-T_F!hx~eoFORW$6b|QOLfU1e*plB!#OgDd&PQR`8Krre~(iABYQ&6 z+y|ICT*3U)OAV20FuY1*=pqhg3424{iqcs?l#)cw%lJE&t0WFm^1SOGkIG_y(Cn=M zHxPIfJviLR{jQeXXVhX~dLh|(b=_r!mVgqNeW&SHDw2KEoPqy>Q_G$r{^_T73gf;s>2`sj;eV2BZkgUl%Er0fKlxhnlp)25(z`_evcILW?3K6>j!zK7~ z)vvr_h2~iqga|GgFEG2>*>qNT0*nRqs}!ecnta=Lf_!(6xtnPk_*8_B=h+(D~P*eT%x>Ez|gXZ5QK=0P2=P4R#a039-tu(Ep^u*{N zB2s(v=Dywl`Z>KtJ9;haHoZvZiHg@56B~FSwNxOlwf4K45fF*mC_3G2Yn0_W1Qtp; z{G34U?ZVjl;Y}|uwsT8|S?vKONKvzE2QGJG|ESac-&LeV$lTK_4p&iTx8wXQPy5C} zjWyXW5uhoBAAbD#>DFXhk_DytB3y3LXf~t4)LFz<`luI*xcnSb>o$PrKjhT8dtvus zUWTR2WQ5_*KYKWlVKC|4`d1)@wOSml54SSYXfm%{4a`|fzqN)3V(}KUmrV&0H>!7u z;M4TO+z5sHgv#G7e)GA>E*-w$yWlh5hvP})HZXO57*%_#0?)4?R6KmY+S|#QWYbyj z75U%y0>xVdCtr=iAwM5aUw*Tznr3cvMbnm0eh)(e3A9?0ajCG4PQ*MWs z<6L*!u@g^R;Ko-92cEHGQ+>{&SD%3ozRkMAvh9z277-YE)#ZJY@Ln;^oRn+J$966_k!!N}6&{RG9hCderS|`irIwS4`JpB(8*KbQ0I+<)6>!Xte`cbvX3W%U-32?*cBxZW#wU$HQLUE>oLhZzV+SG;}Bs~7EZwzyqf0U zhByY_kZn3}2S706fKlb^9l`X8y|dk5D1-n)x8aT7PY7m>Tia`0wjMXDQ82mj|URcNP!=n`koz&aL_pftPUj8-0{48mp2Yrhk7_e<`r4o zC(rWt3*GiloCCt-{BbWp#>Zv)7iu1kfQ|!2aX+xRCXIlk^x#f#cp2z)Z-h0xb>*Q~ zzL;(cFby3yk|YovNL_H%#XB8G0GfV&dRU31*U0KvoTL*n_i+A~vBNglZrRXoMw?E> z7%w@=&{ndFB;lM2gIe}0MIfoJYuaMA8cJX)hTrXe7-lZxPjV1@5U zefd|gdP;$ezFqGKp9+^U71}(yv{fHAI4lSa9hCo_s1uK_#4$$j?b-46T6u?99(0>* zxajgj!uH&o1geR0t}Ae>)5}M2H*G(E&HB=5g|$nWgDk(7I0_Z}DfS*8Ze{Rx=&9Zp zo^?PwuDJ5cI>YgSdOJVu)r zP55&!J=0{rj=N-F zF;2#rtspDW#@R$>DSv2SNm_CsJ%5?bdh)I+Tv9}sH!F4f`RvK& zn?NBG-|N8q)*uZc10bl*+Q2UhU`^?9>8EY$Z8%9sadjB12j1PZx8@G9(~a@$UP@;S zvO+lFnon<(&yPzEW8AuhqS=??&)|t1ZP1d zxZ#CKO#<8Z+5X~iI-AGWn-;hNj66wlrxA&uf4`Sm7m-PcoKICRgow`&5$QJgEIhp4 zpDleF;jkk|x66m`@B3^&Os|G6W*q~h-TqX78XG4&WKOiX<`cZ5dfi0rzrJgm0!Fgj zC{4D3<)u~y^QQUaBspA0mm+HxHmdmyFtZ8LoQhSo+U;Nn{SjXFM1m9Xn*i)yj z4Mi3FP6cfA_NmpC9o*qBGjvM$PCHrL@iTlZX_XE;bM3OQY~$@abBu?g;BEvk^t?-b zG2~Bb5b!HlT|db8mk~wlro|8_)h@O8nMn$;oY~}qm1_^U@{lePxr6<@F0lro< z&q2K<9ht^=r4@Zt6-#wAwGUGOD4$!kW#bd!#se!JX>N zUPw}+KrI^IpV@3PZM)YCG7HG*q5nW~GgxBDz&5NF_y)OTX5Oqz0cz?NbO3bM&u?H` zq?B6ZmYUkEx0xLd%KZqqHz7MjGbTd8y*BSz#i~xi#GhD=9oppi(JR_`mP=+|_IjI< zBTtk;{BiFp;COEUWD<+I0yOW8;{7)*InAu6qF08kAi6%7>f>}d^zw27`IxBHlgVtw zbKjc))#}{A32I4O*?ga9~ z9x{N-ivT5k4zidcfsI-+G*BrNj*Tj|tnePU8CYU%CM7BD6~Vu20QgG3jdq;*$v|*} zSDJW4qYDfd>TxB1H07Wo(mzC^&Py+OQnm6fCE(;k+#|0nslIiEc;+#!7u+rv4=>fS zPX4`NosVu}4w-*u`^aWEVJ(H!Zl})yIPfL z_nHH?Z&_xBQ1p7lys=q!3c1*BrKK4aCW+k(a()0Bx1fDheOzO!; zvf8TyxZuud(dG{7@X{au>;~sDYF%;-?mR(=V}uSR1RV+ zvAaIyuWHM_K7`LXxLT0wE708NLby*Y2MMA)I6(!iDIC{vc=3(w9wEJxKHmwBc2U}* z^Y{Hi$9swA`LS8qNgY|c9az*v%kah=n!&C~3&1`8;sfV71wO^eZ~|WAwif?%TWy1w zVfu%FU&nF!ad4Fmd-yc~jV@#QQ?kPE1M=_uRXW9A^MkUXMEyj8(Dya0*jP=t1dN9z z6+p-|fsnYmB6in|E%QpUy$Lf*B1yH}6R6hvYg13qYgErF^5Kdm482~~rQ)R&0Hl{3 zJ8P(-?{wPK>v846dD=3*#1C? zt--;`19CsAwYu#C3jwJu2kJ^QtUrSr>}(HrBWmBb z#JT8w^GQ%9WTemJB0}7doQ?6Z=j(6m!sp;l=@6RVU#6-0y{(NsYD3rtSDL>cSzK%s zlEroYAu*Fa7Sl`B0!@6`Uuw)!nq`eVuXc-%Cij$QNr>WK$&`-Rb=@>cae#BFC#esR z^I45cRU|V_hnZq!vmiIj^ig3}&tkIKdaYSUZnKKOihj^0^+nn!qo|PH@{I8cV!KGT zU9|l6?~xbo!@K{svBcRz53}tpt)@G7r@3A|7KD3=$ZMRhW$0lHB-8p=^YU{^a;%EGF%I-~j+d!r#9C97% zJwSC@?N#tC7_Ln+bIO*%%hQ@vJg{|VC;PMa#hDM|F^WcDu76u+(GDIO{INJvRfP zy->;RvNzd5+;o^sJK2#I0o#3|zyLMq7Bf69rqn89h zX}}czZ7Hb5lpqO=)jdO`r!2tbA59JvOBSYNsq5*@l$luu?6j>xnVaOFFR#edn>~IH z9k+9Q4_?w|sw$H4``L(aIl=P*-!j6Yo5vz>8lp@49Bz%d{+lN0po$P6L2Q*l9)z!U zV>v|mJVNYiQy_1i=Ngu2Ea*wXOU4$^-hw;4+&wqDRaK-Rcp3(G%{FP&eH zTYtHed;81N29~4xhh3{yZWCmiZ++XN`wtKNS7ZX7Dgu&zJvxKRw>po&9j1@V0w0iL z3Y+OS6P9)k?f>!p2E;{B?t8VdpFRqXJT|Iw@neNhQ7Cfe*(v1xTi^;=BW9G~eowLm zz|+4O&A(5=-{H){a5_!#--Q0pDT%_Q`7LuhasTbZ&oC-CAjJOnm{2kW%$t7A^^E5K z_Tf`VVrf8y|6ftaKOPA6MTDvhuDBBW-#%nO1c6d#_MjB${~Y+0Hs~RF5zy9J)0pB6|OU40!tpDpnK&>d6d`~@s%JBah?ytYJR6uWT&ARs? zyw?BxFcj4z0cQz?*Z=uI#l&C`dBfM4e3X0mXC(IbUjV$LbO4+T=l>q_|1TuKSAY07 Zu9R@R<39QtcuIC%QoeFA=faKq{|C?F6@dT% literal 0 HcmV?d00001 From 16326b73debacfcb0e65c08d0225068f4c9e8feb Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Mon, 15 Jan 2024 13:21:24 +0000 Subject: [PATCH 06/21] Pass on BRANCHING, incorporate Deepthi's writeup --- BRANCHING.md | 69 ++++++++++++------ .../res/branching_flow_david_wong.png | Bin 2 files changed, 48 insertions(+), 21 deletions(-) rename git-flow_david-wong.png => docs/res/branching_flow_david_wong.png (100%) diff --git a/BRANCHING.md b/BRANCHING.md index 2f527d9e623..fa0899cd23a 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -1,41 +1,67 @@ # Mina Branching Policy + +The development branches in progress in `mina` are as follows: - `master`: current stable release. - It is frozen from the crypto side, does not depend on `proof-systems`. - Never commit to it directly, except to introduce a hotfix. - `compatible`: scheduled to be released. - - It contains all the changes which are literally backwards compatible with what people currently run on the mainnet. Any nodes running a version of mina based off of compatible should connect to the current mainnet. + - The staging branch for mainnet soft fork releases. + - It contains all the changes which are literally backwards compatible with the current mainnet deployment. Any nodes running a version of mina based off of compatible should connect to the current mainnet. + - It serves as the preparation ground for the next mainnet soft fork release. - `rampup`: what is deployed on the testnet - Compatible with `compatible`. + - The public incentivized network where an early version of the 2.0 hardfork is deployed for community testing. + - `rampup` is a temporary branch maintained until public testnets requiring compatibility are running. - Never make PRs to `rampup` unless you're explicitly fixing a testnet bug. - `berkeley`/`izmir`: next hardfork branch / release candidate. - Contains all the new features that are scheduled for the release (berkeley or izmir). - - On releases. Current release is "mainnet", public. Next release is "berkeley", and the one after is "izmir". The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). -- `develop`: next non-harmful release (after `berkeley`). - - Does *not* contain cutting edge new protocol features enabled (that might go into the next release). + - `berkeley` is a 2.0 temporary branch maintained until the hard fork after which compatible will include all berkeley changes. + - On releases. Current release is "mainnet" 1.0, public. Next release is "berkeley" 2.0, and the one after is "izmir" 3.0. + - The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). +- `develop`: 2.0 compatible changes not scoped for the 2.0 hard fork upgrade. + - In other words, `develop` is next non-harmful release (after `berkeley`). + - Is not *the most cutting edge: might not contain protocol features that scheduled for the subsequent (3.0) release. - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). - The difference between `develop` and `berkeley` is that `berkeley` will be the actual hardfork release, while `develop` is subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. So if `berkeley` can be thought of as 2.0, then `develop` is 2.01. -- Direction of merge: - - The back-merging direction is `master` to `compatible` to `rampup` to the next hardfork (now, `berkeley`) to `develop`. - - So `develop` contains all the changes from the more stable branches. - - Merging forward (when introducing features/fixes) is up this stack, but the place the change is introduced can be different (e.g. `compatible` for softfork features, `develop` for more experimental/next release). -- Hard fork/Release: - - Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` - - `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. - - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. -- `o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` - - Contains mina changes from `rampup` - - But `proof-systems/develop` which by default is used by `mina/develop`. - - Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). - - When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. -### Diagram +The relationship between the branches is `master ⊆ compatible ⊆ rampup ⊆ berkeley ⊆ develop`. +- This means `compatible` includes all the changes in `master`, `rampup` all the changes in `compatible` and so on. So `develop` contains all the changes from *all* the stable branches, but also contains features that do not exist in any of the "subsets". +- The back-merging direction is thus left-to-right: whenever a feature lands in this chain, it has to be periodically "back-merged" to the right. +- The branches are not merged in the other direction. When a new feature is introduced, it should aim at the exact target branch. This place depends on the feature (e.g. `compatible` for softfork features, `develop` for more experimental/next release). And then the feature is propagated to the right. + + +![Illustration of the branching strategy](docs/res/branching_flow_david_wong.png) + + +### On back-merging conflicts + +We have CI jobs named `check-merges-cleanly-into-*` that fail if a PR introduces changes conflicting with downstream branch changes. PR authors must create new PRs against those branches to resolve conflicts before merging the original PR. -**TODO** improve diagram +PRs resolving merge conflicts (merge-PRs) should only be merged after the original PR is approved, and all changes from the original PR are incorporated into the merge-PRs. For example: Consider a PR is made against `rampup` and causes conflicts in `berkeley` and `develop`. In this case the workflow is as follows: +- Review and approve the original PR against `rampup` (PR-rampup). CI passes except for `check-merges-cleanly-into-*` jobs. +- Incorporate all changes from PR-rampup into a new PR against `berkeley` (PR-berkeley) and resolve conflicts. +- Incorporate all changes from PR-rampup into a new PR against `develop` (PR-develop) and resolve conflicts. +- Review, approve, and merge PR-berkeley and PR-develop. They can be done in parallel. +- Rerun failing check-merges-cleanly-into-* jobs against PR-rampup and merge PR-rampup after CI is green. + + +The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches + + +### Hard forks / releases: + +Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` +- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. +- So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. +`o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` +- Contains mina changes from `rampup` +- But `proof-systems/develop` which by default is used by `mina/develop`. +- Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). +- When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. -![git-flow_david-wong.png](./git-flow_david-wong.png) ## Day to day: which branch should I use? @@ -51,7 +77,8 @@ When developing a feature, if it’s not something that breaks compatibility, th # proof-systems Branching policy -Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important distinctions exist that are a result of proof-systems having been created after the mainnet release (**TODO** ?). + +Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important (some, temporary) distinctions exist: - `compatible`: - Compatible with `rampup` in `mina`. diff --git a/git-flow_david-wong.png b/docs/res/branching_flow_david_wong.png similarity index 100% rename from git-flow_david-wong.png rename to docs/res/branching_flow_david_wong.png From d451bdbefab75103979f0d806e9759d6554a9212 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Mon, 15 Jan 2024 13:24:21 +0000 Subject: [PATCH 07/21] Rename BRANCHING.md into README-branching.md for uniformity --- BRANCHING.md => README-branching.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BRANCHING.md => README-branching.md (100%) diff --git a/BRANCHING.md b/README-branching.md similarity index 100% rename from BRANCHING.md rename to README-branching.md From 3f5042051eb9cd4eaea69e38158495a1b3f1b696 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Mon, 15 Jan 2024 13:49:40 +0000 Subject: [PATCH 08/21] Another pass on branching --- BRANCHING.md | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 BRANCHING.md diff --git a/BRANCHING.md b/BRANCHING.md new file mode 100644 index 00000000000..f44e73ef455 --- /dev/null +++ b/BRANCHING.md @@ -0,0 +1,95 @@ +# Mina Branching Policy + +Mina's current public release is "mainnet", version 1.X. The next hardfork release is "berkeley" 2.0, and the one planned after is "izmir" 3.0. + +The development branches in progress in `mina` are as follows: +- `master`: current stable release, currently mainnet 1.X. + - It is frozen from the crypto side, does not depend on `proof-systems`. + - Never commit to it directly, except to introduce a hotfix. +- `compatible`: scheduled to be softwork released. + - The staging branch for mainnet soft fork releases. + - It contains all the changes which are literally backwards compatible with the current mainnet deployment. Any nodes running a version of mina based off of compatible should connect to the current mainnet. + - It serves as the preparation ground for the next mainnet soft fork release. +- `rampup`: what is deployed on the testnet + - Compatible with `compatible`. + - The public incentivized network where an early version of the 2.0 hardfork is deployed for community testing. + - `rampup` is a temporary branch maintained until public testnets requiring compatibility are running. + - Never make PRs to `rampup` unless you're explicitly fixing a testnet bug. +- `berkeley`/`izmir`: next hardfork branch / release candidate. + - Contains all the new features that are scheduled for the release (berkeley or izmir). + - `berkeley` is a 2.0 temporary branch maintained until the hard fork after which compatible will include all berkeley changes. + - + - The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). +- `develop`: 2.0 compatible changes not scoped for the 2.0 hard fork upgrade. + - In other words, `develop` is next non-harmful release (after `berkeley`). + - Is not *the most cutting edge: might not contain protocol features that scheduled for the subsequent (3.0) release. + - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. + - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). + - The difference between `develop` and `berkeley` is that `berkeley` will be the actual hardfork release, while `develop` is subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. So if `berkeley` can be thought of as 2.0, then `develop` is 2.01. + + +The relationship between the branches is as presented: `master ⊆ compatible ⊆ rampup ⊆ berkeley ⊆ develop`. +- This means `compatible` includes all the changes in `master`, `rampup` all the changes in `compatible` and so on. So `develop` contains all the changes from *all* the stable branches, but also contains features that do not exist in any of the "subsets". +- The back-merging direction is thus left-to-right: whenever a feature lands in this chain, it has to be periodically "back-merged" to the right. +- The branches are merged in the other direction (upstream) only when released. +- When merely a new feature is introduced, it should aim at the exact target branch. This place depends on the feature, e.g. `compatible` for softfork features, `develop` for more experimental/next release, etc. And then the merged feature is back-propagated downstream (to the right). + + +![Illustration of the branching strategy](docs/res/branching_flow_david_wong.png) + + + +### Hard forks / releases: + +Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` +- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. +- So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. +`o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` +- Contains mina changes from `rampup` +- But `proof-systems/develop` which by default is used by `mina/develop`. +- Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). +- When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. + + +## Day to day: which branch should I use? + +When developing a feature, if it’s not something that breaks compatibility, then you should be developing a feature branch, called `foo_COMP` for example, based off of `compatible`. If you’re not sure whether or not your changes are breaking, they probably are not and should build upon compatible. + +### Handling back-merging conflicts + +We have CI jobs named `check-merges-cleanly-into-BRANCH` that fail if a PR introduces changes conflicting with changes in a downstream branch `BRANCH`. E.g. `check-merges-cleanly-into-develop` will check that a PR aimed at `compatible` is easily back-mergable downstream up to `develop`. PR authors must create new PRs against those branches to resolve conflicts before merging the original PR. + +If that CI job passes, then you can proceed and no further action is needed. + +PRs resolving merge conflicts (merge-PRs) should only be merged after the original PR is approved, and all changes from the original PR are incorporated into the merge-PRs. Consider a PR with is made from `mybranch` branch against `rampup`, and causes conflicts in `berkeley` and `develop`. In this case the workflow is as follows: +- Review and approve the original PR against `rampup` (PR-rampup). CI passes except for `check-merges-cleanly-into-*` jobs. +- Incorporate all changes from PR-rampup into a new PR against `berkeley` (PR-berkeley) and resolve conflicts. Concretely, make a new branch+PR based off of `mybranch` called `mybranch-berkeley` (for example), and then merge `berkeley` into `mybranch-berkeley`. Fix any merge errors that result. + - Keeping branches in sync: If after making e.g. `mybranch-berkeley`, you need to make changes to `mybranch`, then do so, but make sure to merge the newly updated `mybranch` into `mybranch-berkeley`. In order for the git magic to work, `mybranch-berkeley` needs to be a superset of the commits from `mybranch`, and it also needs to be merged first. +- Similarly, incorporate all changes from PR-rampup into a new PR against `develop` (PR-develop) and resolve conflicts. +- Review, approve, and merge PR-berkeley and PR-develop. They can be done in parallel. +- Rerun failing `check-merges-cleanly-into-*` jobs against the original PR-rampup and merge PR-rampup after CI is green. + + +The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches + + +# proof-systems Branching policy + +Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important (some, temporary) distinctions exist: + +- `compatible`: + - Compatible with `rampup` in `mina`. + - Mina's `compatible`, similarly to mina's `master`, does not have `proof-systems`. +- `berkley`: future hardfork release, will be going out to berkeley. + - This is where hotfixes go. +- `develop`: matches mina's `develop`, soft fork-compatibility. + - Also used by `mina/o1js-main` and `o1js/main`. +- `master`: future feature work development, containing breaking changes. Anything that does not need to be released alongside mina. + - Note that `mina`'s `master` does not depend on `proof-systems` at all. +- `izmir`: next hardfork release after berkeley. +- In the future: + - `master`/`develop` will reverse roles and become something like gitflow. + - After Berkeley release `compatible` will become properly synced with `mina/compatible`. +- Direction of merge: + - Back-merging: `compatible` into `berkeley` into `develop` into `master`. + - Front-merging (introducing new features): other direction, but where you start depends on where the feature belongs. From 5778bae652714d497ac1dd27161e9436f9a021d7 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Mon, 15 Jan 2024 13:54:12 +0000 Subject: [PATCH 09/21] Small pass on branching --- BRANCHING.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/BRANCHING.md b/BRANCHING.md index f44e73ef455..43cba88425f 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -11,14 +11,12 @@ The development branches in progress in `mina` are as follows: - It contains all the changes which are literally backwards compatible with the current mainnet deployment. Any nodes running a version of mina based off of compatible should connect to the current mainnet. - It serves as the preparation ground for the next mainnet soft fork release. - `rampup`: what is deployed on the testnet - - Compatible with `compatible`. - The public incentivized network where an early version of the 2.0 hardfork is deployed for community testing. - `rampup` is a temporary branch maintained until public testnets requiring compatibility are running. - Never make PRs to `rampup` unless you're explicitly fixing a testnet bug. - `berkeley`/`izmir`: next hardfork branch / release candidate. - Contains all the new features that are scheduled for the release (berkeley or izmir). - `berkeley` is a 2.0 temporary branch maintained until the hard fork after which compatible will include all berkeley changes. - - - The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). - `develop`: 2.0 compatible changes not scoped for the 2.0 hard fork upgrade. - In other words, `develop` is next non-harmful release (after `berkeley`). @@ -53,7 +51,10 @@ Whenever a hard fork happens, the code in `develop` is released. When this hap ## Day to day: which branch should I use? -When developing a feature, if it’s not something that breaks compatibility, then you should be developing a feature branch, called `foo_COMP` for example, based off of `compatible`. If you’re not sure whether or not your changes are breaking, they probably are not and should build upon compatible. +When developing a feature, use the general description of the branches above to decide. Here's a quick rule: +- If a feature/enhancement/bug fix is not feature breaking, and scoped for a mainnet then base it off of `compatible`. If you’re not sure whether or not your changes are breaking, they probably are not and should build upon `compatible`. +- If the feature is scoped for hardfork and is not compatible against a running public testnet, then base it off of the hardfork branch (for example, `berkeley`). +- If it is a bug fix required for a public testnet testing upcoming hardfork then base it off of `rampup`. ### Handling back-merging conflicts From 8251ec4b5d3af72d42d2cc1f7f812c638aefe3ac Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Mon, 15 Jan 2024 13:56:03 +0000 Subject: [PATCH 10/21] Clarify releases --- BRANCHING.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/BRANCHING.md b/BRANCHING.md index 43cba88425f..a656f6e9480 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -24,6 +24,11 @@ The development branches in progress in `mina` are as follows: - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). - The difference between `develop` and `berkeley` is that `berkeley` will be the actual hardfork release, while `develop` is subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. So if `berkeley` can be thought of as 2.0, then `develop` is 2.01. +- `o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` + - Contains mina changes from `rampup` + - But `proof-systems/develop` which by default is used by `mina/develop`. + - Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). + - When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. The relationship between the branches is as presented: `master ⊆ compatible ⊆ rampup ⊆ berkeley ⊆ develop`. @@ -39,14 +44,9 @@ The relationship between the branches is as presented: `master ⊆ compatible ### Hard forks / releases: -Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` -- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. +Whenever a hard fork happens, the code in the corresponding release branch, e.g. `berkeley`, is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop`: +- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. -`o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` -- Contains mina changes from `rampup` -- But `proof-systems/develop` which by default is used by `mina/develop`. -- Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). -- When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. ## Day to day: which branch should I use? From e3d814209223e7ba698139587334af3edc6cf8ba Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Mon, 15 Jan 2024 13:57:11 +0000 Subject: [PATCH 11/21] A few typos --- BRANCHING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BRANCHING.md b/BRANCHING.md index a656f6e9480..25a0ac7eaf3 100644 --- a/BRANCHING.md +++ b/BRANCHING.md @@ -45,7 +45,7 @@ The relationship between the branches is as presented: `master ⊆ compatible ### Hard forks / releases: Whenever a hard fork happens, the code in the corresponding release branch, e.g. `berkeley`, is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop`: -- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. +- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the downstream branches (compatible, develop) then the tagged branch is also merged back for consistency. - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. @@ -71,7 +71,7 @@ PRs resolving merge conflicts (merge-PRs) should only be merged after the origin - Rerun failing `check-merges-cleanly-into-*` jobs against the original PR-rampup and merge PR-rampup after CI is green. -The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches +The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches. # proof-systems Branching policy From dc2d8293b9c606404f017e524c678b6a880a81a3 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 17 Jan 2024 10:20:13 +0000 Subject: [PATCH 12/21] Move BRANCHING.md into README-branching.md for good --- BRANCHING.md | 96 --------------------------------------------- README-branching.md | 64 +++++++++++++++--------------- 2 files changed, 31 insertions(+), 129 deletions(-) delete mode 100644 BRANCHING.md diff --git a/BRANCHING.md b/BRANCHING.md deleted file mode 100644 index 25a0ac7eaf3..00000000000 --- a/BRANCHING.md +++ /dev/null @@ -1,96 +0,0 @@ -# Mina Branching Policy - -Mina's current public release is "mainnet", version 1.X. The next hardfork release is "berkeley" 2.0, and the one planned after is "izmir" 3.0. - -The development branches in progress in `mina` are as follows: -- `master`: current stable release, currently mainnet 1.X. - - It is frozen from the crypto side, does not depend on `proof-systems`. - - Never commit to it directly, except to introduce a hotfix. -- `compatible`: scheduled to be softwork released. - - The staging branch for mainnet soft fork releases. - - It contains all the changes which are literally backwards compatible with the current mainnet deployment. Any nodes running a version of mina based off of compatible should connect to the current mainnet. - - It serves as the preparation ground for the next mainnet soft fork release. -- `rampup`: what is deployed on the testnet - - The public incentivized network where an early version of the 2.0 hardfork is deployed for community testing. - - `rampup` is a temporary branch maintained until public testnets requiring compatibility are running. - - Never make PRs to `rampup` unless you're explicitly fixing a testnet bug. -- `berkeley`/`izmir`: next hardfork branch / release candidate. - - Contains all the new features that are scheduled for the release (berkeley or izmir). - - `berkeley` is a 2.0 temporary branch maintained until the hard fork after which compatible will include all berkeley changes. - - The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). -- `develop`: 2.0 compatible changes not scoped for the 2.0 hard fork upgrade. - - In other words, `develop` is next non-harmful release (after `berkeley`). - - Is not *the most cutting edge: might not contain protocol features that scheduled for the subsequent (3.0) release. - - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. - - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). - - The difference between `develop` and `berkeley` is that `berkeley` will be the actual hardfork release, while `develop` is subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. So if `berkeley` can be thought of as 2.0, then `develop` is 2.01. -- `o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` - - Contains mina changes from `rampup` - - But `proof-systems/develop` which by default is used by `mina/develop`. - - Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). - - When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. - - -The relationship between the branches is as presented: `master ⊆ compatible ⊆ rampup ⊆ berkeley ⊆ develop`. -- This means `compatible` includes all the changes in `master`, `rampup` all the changes in `compatible` and so on. So `develop` contains all the changes from *all* the stable branches, but also contains features that do not exist in any of the "subsets". -- The back-merging direction is thus left-to-right: whenever a feature lands in this chain, it has to be periodically "back-merged" to the right. -- The branches are merged in the other direction (upstream) only when released. -- When merely a new feature is introduced, it should aim at the exact target branch. This place depends on the feature, e.g. `compatible` for softfork features, `develop` for more experimental/next release, etc. And then the merged feature is back-propagated downstream (to the right). - - -![Illustration of the branching strategy](docs/res/branching_flow_david_wong.png) - - - -### Hard forks / releases: - -Whenever a hard fork happens, the code in the corresponding release branch, e.g. `berkeley`, is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop`: -- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the downstream branches (compatible, develop) then the tagged branch is also merged back for consistency. -- So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. - - -## Day to day: which branch should I use? - -When developing a feature, use the general description of the branches above to decide. Here's a quick rule: -- If a feature/enhancement/bug fix is not feature breaking, and scoped for a mainnet then base it off of `compatible`. If you’re not sure whether or not your changes are breaking, they probably are not and should build upon `compatible`. -- If the feature is scoped for hardfork and is not compatible against a running public testnet, then base it off of the hardfork branch (for example, `berkeley`). -- If it is a bug fix required for a public testnet testing upcoming hardfork then base it off of `rampup`. - -### Handling back-merging conflicts - -We have CI jobs named `check-merges-cleanly-into-BRANCH` that fail if a PR introduces changes conflicting with changes in a downstream branch `BRANCH`. E.g. `check-merges-cleanly-into-develop` will check that a PR aimed at `compatible` is easily back-mergable downstream up to `develop`. PR authors must create new PRs against those branches to resolve conflicts before merging the original PR. - -If that CI job passes, then you can proceed and no further action is needed. - -PRs resolving merge conflicts (merge-PRs) should only be merged after the original PR is approved, and all changes from the original PR are incorporated into the merge-PRs. Consider a PR with is made from `mybranch` branch against `rampup`, and causes conflicts in `berkeley` and `develop`. In this case the workflow is as follows: -- Review and approve the original PR against `rampup` (PR-rampup). CI passes except for `check-merges-cleanly-into-*` jobs. -- Incorporate all changes from PR-rampup into a new PR against `berkeley` (PR-berkeley) and resolve conflicts. Concretely, make a new branch+PR based off of `mybranch` called `mybranch-berkeley` (for example), and then merge `berkeley` into `mybranch-berkeley`. Fix any merge errors that result. - - Keeping branches in sync: If after making e.g. `mybranch-berkeley`, you need to make changes to `mybranch`, then do so, but make sure to merge the newly updated `mybranch` into `mybranch-berkeley`. In order for the git magic to work, `mybranch-berkeley` needs to be a superset of the commits from `mybranch`, and it also needs to be merged first. -- Similarly, incorporate all changes from PR-rampup into a new PR against `develop` (PR-develop) and resolve conflicts. -- Review, approve, and merge PR-berkeley and PR-develop. They can be done in parallel. -- Rerun failing `check-merges-cleanly-into-*` jobs against the original PR-rampup and merge PR-rampup after CI is green. - - -The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches. - - -# proof-systems Branching policy - -Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important (some, temporary) distinctions exist: - -- `compatible`: - - Compatible with `rampup` in `mina`. - - Mina's `compatible`, similarly to mina's `master`, does not have `proof-systems`. -- `berkley`: future hardfork release, will be going out to berkeley. - - This is where hotfixes go. -- `develop`: matches mina's `develop`, soft fork-compatibility. - - Also used by `mina/o1js-main` and `o1js/main`. -- `master`: future feature work development, containing breaking changes. Anything that does not need to be released alongside mina. - - Note that `mina`'s `master` does not depend on `proof-systems` at all. -- `izmir`: next hardfork release after berkeley. -- In the future: - - `master`/`develop` will reverse roles and become something like gitflow. - - After Berkeley release `compatible` will become properly synced with `mina/compatible`. -- Direction of merge: - - Back-merging: `compatible` into `berkeley` into `develop` into `master`. - - Front-merging (introducing new features): other direction, but where you start depends on where the feature belongs. diff --git a/README-branching.md b/README-branching.md index fa0899cd23a..25a0ac7eaf3 100644 --- a/README-branching.md +++ b/README-branching.md @@ -1,23 +1,22 @@ # Mina Branching Policy +Mina's current public release is "mainnet", version 1.X. The next hardfork release is "berkeley" 2.0, and the one planned after is "izmir" 3.0. The development branches in progress in `mina` are as follows: -- `master`: current stable release. +- `master`: current stable release, currently mainnet 1.X. - It is frozen from the crypto side, does not depend on `proof-systems`. - Never commit to it directly, except to introduce a hotfix. -- `compatible`: scheduled to be released. +- `compatible`: scheduled to be softwork released. - The staging branch for mainnet soft fork releases. - It contains all the changes which are literally backwards compatible with the current mainnet deployment. Any nodes running a version of mina based off of compatible should connect to the current mainnet. - It serves as the preparation ground for the next mainnet soft fork release. - `rampup`: what is deployed on the testnet - - Compatible with `compatible`. - The public incentivized network where an early version of the 2.0 hardfork is deployed for community testing. - `rampup` is a temporary branch maintained until public testnets requiring compatibility are running. - Never make PRs to `rampup` unless you're explicitly fixing a testnet bug. - `berkeley`/`izmir`: next hardfork branch / release candidate. - Contains all the new features that are scheduled for the release (berkeley or izmir). - `berkeley` is a 2.0 temporary branch maintained until the hard fork after which compatible will include all berkeley changes. - - On releases. Current release is "mainnet" 1.0, public. Next release is "berkeley" 2.0, and the one after is "izmir" 3.0. - The "devnet" testnet is running from `master`, sometimes `compatible`, and features only the current release (not cutting edge/berkeley). - `develop`: 2.0 compatible changes not scoped for the 2.0 hard fork upgrade. - In other words, `develop` is next non-harmful release (after `berkeley`). @@ -25,55 +24,54 @@ The development branches in progress in `mina` are as follows: - Contains changes which break backwards compatibility, or changes that depend on past compatibility-breaking changes. “Not backwards compatible” means that a daemon running this version of mina will not connect to mainnet. - Major changes to the daemon, protocol, or crypto will sometimes cause backwards-compatibility breaking changes, and of course such changes need to be done with deliberation and are not to be taken lightly. Changes to infrastructure, auxiliary develop scripts, tests, CI, are usually not be backwards compatibility breaking, and thereby should go into compatible (unless you are doing something very special and you know what you’re doing). - The difference between `develop` and `berkeley` is that `berkeley` will be the actual hardfork release, while `develop` is subsequent softfork release candidate, softfork after `berkeley`. `develop` is just not tested as rigorously, but it's softfork compatible with `berkeley`. So if `berkeley` can be thought of as 2.0, then `develop` is 2.01. +- `o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` + - Contains mina changes from `rampup` + - But `proof-systems/develop` which by default is used by `mina/develop`. + - Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). + - When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. -The relationship between the branches is `master ⊆ compatible ⊆ rampup ⊆ berkeley ⊆ develop`. +The relationship between the branches is as presented: `master ⊆ compatible ⊆ rampup ⊆ berkeley ⊆ develop`. - This means `compatible` includes all the changes in `master`, `rampup` all the changes in `compatible` and so on. So `develop` contains all the changes from *all* the stable branches, but also contains features that do not exist in any of the "subsets". - The back-merging direction is thus left-to-right: whenever a feature lands in this chain, it has to be periodically "back-merged" to the right. -- The branches are not merged in the other direction. When a new feature is introduced, it should aim at the exact target branch. This place depends on the feature (e.g. `compatible` for softfork features, `develop` for more experimental/next release). And then the feature is propagated to the right. +- The branches are merged in the other direction (upstream) only when released. +- When merely a new feature is introduced, it should aim at the exact target branch. This place depends on the feature, e.g. `compatible` for softfork features, `develop` for more experimental/next release, etc. And then the merged feature is back-propagated downstream (to the right). ![Illustration of the branching strategy](docs/res/branching_flow_david_wong.png) -### On back-merging conflicts - -We have CI jobs named `check-merges-cleanly-into-*` that fail if a PR introduces changes conflicting with downstream branch changes. PR authors must create new PRs against those branches to resolve conflicts before merging the original PR. - -PRs resolving merge conflicts (merge-PRs) should only be merged after the original PR is approved, and all changes from the original PR are incorporated into the merge-PRs. For example: Consider a PR is made against `rampup` and causes conflicts in `berkeley` and `develop`. In this case the workflow is as follows: -- Review and approve the original PR against `rampup` (PR-rampup). CI passes except for `check-merges-cleanly-into-*` jobs. -- Incorporate all changes from PR-rampup into a new PR against `berkeley` (PR-berkeley) and resolve conflicts. -- Incorporate all changes from PR-rampup into a new PR against `develop` (PR-develop) and resolve conflicts. -- Review, approve, and merge PR-berkeley and PR-develop. They can be done in parallel. -- Rerun failing check-merges-cleanly-into-* jobs against PR-rampup and merge PR-rampup after CI is green. - - -The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches - ### Hard forks / releases: -Whenever a hard fork happens, the code in `develop` is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop` -- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the upstream branches (compatible, develop) then the tagged branch is also merged back for consistency. +Whenever a hard fork happens, the code in the corresponding release branch, e.g. `berkeley`, is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop`: +- `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the downstream branches (compatible, develop) then the tagged branch is also merged back for consistency. - So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. -`o1js-main`: compatible with testnet, but has latest `proof-systems` features so that they can be used in `o1js` -- Contains mina changes from `rampup` -- But `proof-systems/develop` which by default is used by `mina/develop`. -- Uses `o1js/main` and `o1js-bindings/main` as explained [here](https://github.com/o1-labs/o1js/blob/main/README-dev.md#branch-compatibility?). -- When `proof-systems/develop` is too cutting-edge and the adaptations of its changes haven't been landed in mina, `o1js` will use the `proof-systems/o1js-main` branch which is lagging behind `proof-systems/develop` a bit. ## Day to day: which branch should I use? -When developing a feature, if it’s not something that breaks compatibility, then you should be developing a feature branch, called `foo_COMP` for example, based off of `compatible`. If you’re not sure whether or not your changes are breaking, they probably are not and should build upon compatible. +When developing a feature, use the general description of the branches above to decide. Here's a quick rule: +- If a feature/enhancement/bug fix is not feature breaking, and scoped for a mainnet then base it off of `compatible`. If you’re not sure whether or not your changes are breaking, they probably are not and should build upon `compatible`. +- If the feature is scoped for hardfork and is not compatible against a running public testnet, then base it off of the hardfork branch (for example, `berkeley`). +- If it is a bug fix required for a public testnet testing upcoming hardfork then base it off of `rampup`. + +### Handling back-merging conflicts + +We have CI jobs named `check-merges-cleanly-into-BRANCH` that fail if a PR introduces changes conflicting with changes in a downstream branch `BRANCH`. E.g. `check-merges-cleanly-into-develop` will check that a PR aimed at `compatible` is easily back-mergable downstream up to `develop`. PR authors must create new PRs against those branches to resolve conflicts before merging the original PR. -### Directions for merging your branch `foo_COMP` +If that CI job passes, then you can proceed and no further action is needed. + +PRs resolving merge conflicts (merge-PRs) should only be merged after the original PR is approved, and all changes from the original PR are incorporated into the merge-PRs. Consider a PR with is made from `mybranch` branch against `rampup`, and causes conflicts in `berkeley` and `develop`. In this case the workflow is as follows: +- Review and approve the original PR against `rampup` (PR-rampup). CI passes except for `check-merges-cleanly-into-*` jobs. +- Incorporate all changes from PR-rampup into a new PR against `berkeley` (PR-berkeley) and resolve conflicts. Concretely, make a new branch+PR based off of `mybranch` called `mybranch-berkeley` (for example), and then merge `berkeley` into `mybranch-berkeley`. Fix any merge errors that result. + - Keeping branches in sync: If after making e.g. `mybranch-berkeley`, you need to make changes to `mybranch`, then do so, but make sure to merge the newly updated `mybranch` into `mybranch-berkeley`. In order for the git magic to work, `mybranch-berkeley` needs to be a superset of the commits from `mybranch`, and it also needs to be merged first. +- Similarly, incorporate all changes from PR-rampup into a new PR against `develop` (PR-develop) and resolve conflicts. +- Review, approve, and merge PR-berkeley and PR-develop. They can be done in parallel. +- Rerun failing `check-merges-cleanly-into-*` jobs against the original PR-rampup and merge PR-rampup after CI is green. -- There is a CI job called `merges cleanly to develop` which runs whenever you have a PR off of `compatible`. If that CI job passes, then you can simply merge `foo_COMP` into `compatible` , and no further action is needed. -- If `merges cleanly to develop` does NOT pass, then when you’re done with your changes to `foo_COMP` and the PR is all approved, make a new branch+PR based off of `foo_COMP` called `foo_DEVELOP` (for example), and then merge `develop` into `foo_DEVELOP`. Fix any merge errors that result, then once `foo_DEVELOP` is approved, you can merge it into `develop`. -- Once `foo_DEVELOP` is fully landed into `develop`, then go and manually re-run the `merges cleanly to develop` CI job in the original `foo_COMP` PR. The CI job should now pass and go green. You can now merge `foo_COMP` -- If after making `foo_DEVELOP`, you need to make changes to `foo_COMP`, then make sure to merge the newly updated `foo_COMP` into `foo_DEVELOP`. In order for the git magic to work, `foo_DEVELOP` needs to be a superset of the commits from `foo`, and it also needs to merge first. You can make further changes post-merge in `foo_DEVELOP` as needed to ensure correctness +The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches. # proof-systems Branching policy From 85e7c04dc5ad744f2b29840749832d6f68ef71e1 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Mon, 15 Jan 2024 16:14:22 +0100 Subject: [PATCH 13/21] Add genesis constants to the fork config generated by GraphQL. --- src/lib/mina_graphql/mina_graphql.ml | 5 +---- src/lib/runtime_config/dune | 3 +++ src/lib/runtime_config/runtime_config.ml | 22 +++++++++++++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/lib/mina_graphql/mina_graphql.ml b/src/lib/mina_graphql/mina_graphql.ml index ed7153779c3..e2e3aafc6ab 100644 --- a/src/lib/mina_graphql/mina_graphql.ml +++ b/src/lib/mina_graphql/mina_graphql.ml @@ -4356,9 +4356,6 @@ module Queries = struct | Some (`Finalized (Ledger_db l)) -> return (Some (Ledger.Any_ledger.cast (module Ledger.Db) l)) in - let protocol_state_hash = - Transition_frontier.Breadcrumb.state_hash best_tip - in Option.iter next_epoch_ledger ~f:(fun ledger -> assert ( Mina_base.Ledger_hash.equal @@ -4367,7 +4364,7 @@ module Queries = struct let%map new_config = Runtime_config.make_fork_config ~staged_ledger ~global_slot ~staking_ledger ~staking_epoch_seed ~next_epoch_ledger - ~next_epoch_seed ~blockchain_length ~protocol_state_hash + ~next_epoch_seed ~blockchain_length ~protocol_state runtime_config in Runtime_config.to_yojson new_config |> Yojson.Safe.to_basic ) diff --git a/src/lib/runtime_config/dune b/src/lib/runtime_config/dune index 04953a3626c..d8338a380b2 100644 --- a/src/lib/runtime_config/dune +++ b/src/lib/runtime_config/dune @@ -14,12 +14,15 @@ result sexplib0 ;; local libraries + block_time currency + genesis_constants data_hash_lib merkle_ledger mina_base mina_numbers ppx_dhall_type + mina_state snark_params unsigned_extended pasta diff --git a/src/lib/runtime_config/runtime_config.ml b/src/lib/runtime_config/runtime_config.ml index 866b58257d4..80fb05774e8 100644 --- a/src/lib/runtime_config/runtime_config.ml +++ b/src/lib/runtime_config/runtime_config.ml @@ -1267,7 +1267,7 @@ let ledger_of_accounts accounts = } let make_fork_config ~staged_ledger ~global_slot ~blockchain_length - ~protocol_state_hash ~staking_ledger ~staking_epoch_seed ~next_epoch_ledger + ~protocol_state ~staking_ledger ~staking_epoch_seed ~next_epoch_ledger ~next_epoch_seed (runtime_config : t) = let open Async.Deferred.Result.Let_syntax in let global_slot = Mina_numbers.Global_slot.to_int global_slot in @@ -1283,10 +1283,26 @@ let make_fork_config ~staged_ledger ~global_slot ~blockchain_length let%map fork = proof.fork in fork.previous_length + blockchain_length in + let protocol_constants = Mina_state.Protocol_state.constants protocol_state in + let genesis = + { Genesis.k = + Some + (Unsigned.UInt32.to_int + protocol_constants.Genesis_constants.Protocol.Poly.k ) + ; delta = Some (Unsigned.UInt32.to_int protocol_constants.delta) + ; slots_per_epoch = + Some (Unsigned.UInt32.to_int protocol_constants.slots_per_epoch) + ; slots_per_sub_window = + Some (Unsigned.UInt32.to_int protocol_constants.slots_per_sub_window) + ; genesis_state_timestamp = + Some (Block_time.to_string protocol_constants.genesis_state_timestamp) + } + in let fork = Fork_config. { previous_state_hash = - Mina_base.State_hash.to_base58_check protocol_state_hash + Mina_base.State_hash.to_base58_check + protocol_state.Mina_state.Protocol_state.Poly.previous_state_hash ; previous_length = Option.value ~default:blockchain_length previous_length ; previous_global_slot = global_slot @@ -1321,7 +1337,7 @@ let make_fork_config ~staged_ledger ~global_slot ~blockchain_length artificially add it. In fact, it wouldn't work at all, because the new node would try to create this account at startup, even though it already exists, leading to an error.*) - ~epoch_data + ~epoch_data ~genesis ~ledger: { ledger with base = Accounts accounts From 9a940b1bba336a147b22a690c125973c31fb5fa8 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Tue, 16 Jan 2024 09:24:05 +0100 Subject: [PATCH 14/21] Insert explicit yields into ledger export procedure. --- src/lib/mina_graphql/mina_graphql.ml | 5 +++- src/lib/runtime_config/dune | 1 + src/lib/runtime_config/runtime_config.ml | 38 +++++++++++++++++------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/lib/mina_graphql/mina_graphql.ml b/src/lib/mina_graphql/mina_graphql.ml index e2e3aafc6ab..484f3def7a2 100644 --- a/src/lib/mina_graphql/mina_graphql.ml +++ b/src/lib/mina_graphql/mina_graphql.ml @@ -4361,12 +4361,15 @@ module Queries = struct Mina_base.Ledger_hash.equal (Ledger.Any_ledger.M.merkle_root ledger) next_epoch.ledger.hash ) ) ; - let%map new_config = + let%bind new_config = Runtime_config.make_fork_config ~staged_ledger ~global_slot ~staking_ledger ~staking_epoch_seed ~next_epoch_ledger ~next_epoch_seed ~blockchain_length ~protocol_state runtime_config in + let%map () = + Async_unix.Scheduler.yield () |> Deferred.map ~f:Result.return + in Runtime_config.to_yojson new_config |> Yojson.Safe.to_basic ) let thread_graph = diff --git a/src/lib/runtime_config/dune b/src/lib/runtime_config/dune index d8338a380b2..019b5915c8f 100644 --- a/src/lib/runtime_config/dune +++ b/src/lib/runtime_config/dune @@ -5,6 +5,7 @@ ;; opam libraries async async_kernel + async_unix core_kernel bin_prot.shape base.caml diff --git a/src/lib/runtime_config/runtime_config.ml b/src/lib/runtime_config/runtime_config.ml index 80fb05774e8..fad959208d6 100644 --- a/src/lib/runtime_config/runtime_config.ml +++ b/src/lib/runtime_config/runtime_config.ml @@ -58,14 +58,13 @@ let of_yojson_generic ~fields of_yojson json = dump_on_error json @@ of_yojson @@ yojson_strip_fields ~keep_fields:fields json -let map_results ls ~f = - let open Result.Let_syntax in - let%map r = - List.fold_result ls ~init:[] ~f:(fun t el -> - let%map h = f el in - h :: t ) - in - List.rev r +let rec deferred_list_fold ~init ~f = function + | [] -> + Async.Deferred.Result.return init + | h :: t -> + let open Async.Deferred.Result.Let_syntax in + let%bind init = f init h in + deferred_list_fold ~init ~f t module Json_layout = struct module Accounts = struct @@ -1253,8 +1252,21 @@ let gen = } let ledger_accounts (ledger : Mina_base.Ledger.Any_ledger.witness) = - Mina_base.Ledger.Any_ledger.M.to_list ledger - |> Async.Deferred.map ~f:(map_results ~f:Accounts.Single.of_account) + let open Async.Deferred.Result.Let_syntax in + let yield = Async_unix.Scheduler.yield_every ~n:100 |> Staged.unstage in + let%bind accounts = + Mina_base.Ledger.Any_ledger.M.to_list ledger + |> Async.Deferred.map ~f:Result.return + in + let%map accounts = + deferred_list_fold ~init:[] + ~f:(fun acc el -> + let%bind () = yield () |> Async.Deferred.map ~f:Result.return in + let%map elt = Accounts.Single.of_account el |> Async.Deferred.return in + elt :: acc ) + accounts + in + List.rev accounts let ledger_of_accounts accounts = Ledger. @@ -1272,6 +1284,10 @@ let make_fork_config ~staged_ledger ~global_slot ~blockchain_length let open Async.Deferred.Result.Let_syntax in let global_slot = Mina_numbers.Global_slot.to_int global_slot in let blockchain_length = Unsigned.UInt32.to_int blockchain_length in + let yield () = + Async_unix.Scheduler.yield () |> Async.Deferred.map ~f:Result.return + in + let%bind () = yield () in let%bind accounts = Mina_base.Ledger.Any_ledger.cast (module Mina_base.Ledger) staged_ledger |> ledger_accounts @@ -1308,7 +1324,9 @@ let make_fork_config ~staged_ledger ~global_slot ~blockchain_length ; previous_global_slot = global_slot } in + let%bind () = yield () in let%bind staking_ledger_accounts = ledger_accounts staking_ledger in + let%bind () = yield () in let%map next_epoch_ledger_accounts = match next_epoch_ledger with | None -> From 3ccd2b1ad1027ca3bbf1f79ea023e0988007eeb3 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Tue, 16 Jan 2024 13:50:39 +0100 Subject: [PATCH 15/21] Extract functions for searching chains for a particular breadcrumb. --- src/lib/mina_graphql/mina_graphql.ml | 39 +++------------------------- src/lib/mina_lib/mina_lib.ml | 32 +++++++++++++++++++++++ src/lib/mina_lib/mina_lib.mli | 6 +++++ 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/lib/mina_graphql/mina_graphql.ml b/src/lib/mina_graphql/mina_graphql.ml index 484f3def7a2..352e748bbb8 100644 --- a/src/lib/mina_graphql/mina_graphql.ml +++ b/src/lib/mina_graphql/mina_graphql.ml @@ -4076,25 +4076,13 @@ module Queries = struct ~resolve:(fun { ctx = coda; _ } () (state_hash_base58_opt : string option) (height_opt : int option) -> let open Result.Let_syntax in - let get_transition_frontier () = - let transition_frontier_pipe = Mina_lib.transition_frontier coda in - Pipe_lib.Broadcast_pipe.Reader.peek transition_frontier_pipe - |> Result.of_option ~error:"Could not obtain transition frontier" - in let block_from_state_hash state_hash_base58 = let%bind state_hash = State_hash.of_base58_check state_hash_base58 |> Result.map_error ~f:Error.to_string_hum in - let%bind transition_frontier = get_transition_frontier () in let%map breadcrumb = - Transition_frontier.find transition_frontier state_hash - |> Result.of_option - ~error: - (sprintf - "Block with state hash %s not found in transition \ - frontier" - state_hash_base58 ) + Mina_lib.best_chain_block_by_state_hash coda state_hash in block_of_breadcrumb coda breadcrumb in @@ -4107,29 +4095,10 @@ module Queries = struct *) Unsigned.UInt32.of_int height in - let%bind transition_frontier = get_transition_frontier () in - let best_chain_breadcrumbs = - Transition_frontier.best_tip_path transition_frontier - in - let%map desired_breadcrumb = - List.find best_chain_breadcrumbs ~f:(fun bc -> - let validated_transition = - Transition_frontier.Breadcrumb.validated_transition bc - in - let block_height = - Mina_block.( - blockchain_length @@ With_hash.data - @@ Validated.forget validated_transition) - in - Unsigned.UInt32.equal block_height height_uint32 ) - |> Result.of_option - ~error: - (sprintf - "Could not find block in transition frontier with height \ - %d" - height ) + let%map breadcrumb = + Mina_lib.best_chain_block_by_height coda height_uint32 in - block_of_breadcrumb coda desired_breadcrumb + block_of_breadcrumb coda breadcrumb in match (state_hash_base58_opt, height_opt) with | Some state_hash_base58, None -> diff --git a/src/lib/mina_lib/mina_lib.ml b/src/lib/mina_lib/mina_lib.ml index ddddaa71d44..c760df6b736 100644 --- a/src/lib/mina_lib/mina_lib.ml +++ b/src/lib/mina_lib/mina_lib.ml @@ -2083,3 +2083,35 @@ let get_filtered_log_entries !in_memory_reverse_structured_log_messages_for_integration_test in (get_from_idx curr_idx messages [], is_started) + +let get_transition_frontier (t : t) = + transition_frontier t |> Pipe_lib.Broadcast_pipe.Reader.peek + |> Result.of_option ~error:"Could not obtain transition frontier" + +let best_chain_block_by_height (t : t) height = + let open Result.Let_syntax in + let%bind transition_frontier = get_transition_frontier t in + Transition_frontier.best_tip_path transition_frontier + |> List.find ~f:(fun bc -> + let validated_transition = + Transition_frontier.Breadcrumb.validated_transition bc + in + let block_height = + Mina_block.( + blockchain_length @@ With_hash.data + @@ Validated.forget validated_transition) + in + Unsigned.UInt32.equal block_height height ) + |> Result.of_option + ~error: + (sprintf "Could not find block in transition frontier with height %s" + (Unsigned.UInt32.to_string height) ) + +let best_chain_block_by_state_hash (t : t) hash = + let open Result.Let_syntax in + let%bind transition_frontier = get_transition_frontier t in + Transition_frontier.find transition_frontier hash + |> Result.of_option + ~error: + (sprintf "Block with state hash %s not found in transition frontier" + (State_hash.to_base58_check hash) ) diff --git a/src/lib/mina_lib/mina_lib.mli b/src/lib/mina_lib/mina_lib.mli index f76041ec3b1..96d18820592 100644 --- a/src/lib/mina_lib/mina_lib.mli +++ b/src/lib/mina_lib/mina_lib.mli @@ -200,3 +200,9 @@ val runtime_config : t -> Runtime_config.t val start_filtered_log : t -> string list -> unit Or_error.t val get_filtered_log_entries : t -> int -> string list * bool + +val best_chain_block_by_height : + t -> Unsigned.UInt32.t -> (Transition_frontier.Breadcrumb.t, string) Result.t + +val best_chain_block_by_state_hash : + t -> State_hash.t -> (Transition_frontier.Breadcrumb.t, string) Result.t From edce5bbe1b460ab89b9cfdf49d99f187b59fa7b1 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Wed, 17 Jan 2024 11:57:10 +0100 Subject: [PATCH 16/21] Allow for choice of block to base ledger export on. --- graphql_schema.json | 20 ++- src/lib/mina_graphql/mina_graphql.ml | 178 +++++++++++++++------------ 2 files changed, 120 insertions(+), 78 deletions(-) diff --git a/graphql_schema.json b/graphql_schema.json index e2d6e4915a1..37635c141b9 100644 --- a/graphql_schema.json +++ b/graphql_schema.json @@ -10067,7 +10067,25 @@ "name": "fork_config", "description": "The runtime configuration for a blockchain fork intended to be a continuation of the current one.", - "args": [], + "args": [ + { + "name": "height", + "description": + "The height of the desired block in the best chain", + "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, + "defaultValue": null + }, + { + "name": "stateHash", + "description": "The state hash of the desired block", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], "type": { "kind": "NON_NULL", "name": null, diff --git a/src/lib/mina_graphql/mina_graphql.ml b/src/lib/mina_graphql/mina_graphql.ml index 352e748bbb8..eca6dddac85 100644 --- a/src/lib/mina_graphql/mina_graphql.ml +++ b/src/lib/mina_graphql/mina_graphql.ml @@ -4261,85 +4261,109 @@ module Queries = struct "The runtime configuration for a blockchain fork intended to be a \ continuation of the current one." ~typ:(non_null Types.json) - ~args:Arg.[] - ~resolve:(fun { ctx = mina; _ } () -> - match Mina_lib.best_tip mina with - | `Bootstrapping -> - Deferred.Result.fail "Daemon is bootstrapping" - | `Active best_tip -> - let open Deferred.Result.Let_syntax in - let block = Transition_frontier.Breadcrumb.(block best_tip) in - let blockchain_length = Mina_block.blockchain_length block in - let global_slot = - Mina_block.consensus_state block - |> Consensus.Data.Consensus_state.curr_global_slot - in - let staged_ledger = - Transition_frontier.Breadcrumb.staged_ledger best_tip - |> Staged_ledger.ledger - in - let protocol_state = - Transition_frontier.Breadcrumb.protocol_state best_tip - in - let consensus = - Mina_state.Protocol_state.consensus_state protocol_state - in - let staking_epoch = - Consensus.Proof_of_stake.Data.Consensus_state.staking_epoch_data - consensus - in - let next_epoch = - Consensus.Proof_of_stake.Data.Consensus_state.next_epoch_data - consensus - in - let staking_epoch_seed = - Mina_base.Epoch_seed.to_base58_check - staking_epoch.Mina_base.Epoch_data.Poly.seed - in - let next_epoch_seed = - Mina_base.Epoch_seed.to_base58_check - next_epoch.Mina_base.Epoch_data.Poly.seed - in - let runtime_config = Mina_lib.runtime_config mina in - let%bind staking_ledger = - match Mina_lib.staking_ledger mina with - | None -> - Deferred.Result.fail "Staking ledger is not initialized." - | Some (Genesis_epoch_ledger l) -> - return (Ledger.Any_ledger.cast (module Ledger) l) - | Some (Ledger_db l) -> - return (Ledger.Any_ledger.cast (module Ledger.Db) l) - in + ~args: + Arg. + [ arg "stateHash" ~doc:"The state hash of the desired block" + ~typ:string + ; arg "height" + ~doc:"The height of the desired block in the best chain" ~typ:int + ] + ~resolve:(fun { ctx = mina; _ } () state_hash_opt block_height_opt -> + let open Deferred.Result.Let_syntax in + let%bind breadcrumb = + match (state_hash_opt, block_height_opt) with + | None, None -> ( + match Mina_lib.best_tip mina with + | `Bootstrapping -> + Deferred.Result.fail "Daemon is bootstrapping" + | `Active breadcrumb -> + return breadcrumb ) + | Some state_hash_base58, None -> + let%bind state_hash = + State_hash.of_base58_check state_hash_base58 + |> Result.map_error ~f:Error.to_string_hum + |> Deferred.return + in + Mina_lib.best_chain_block_by_state_hash mina state_hash + |> Deferred.return + | None, Some block_height -> + Mina_lib.best_chain_block_by_height mina + (Unsigned.UInt32.of_int block_height) + |> Deferred.return + | Some _, Some _ -> + Deferred.Result.fail "Cannot specify both state hash and height" + in + let block = Transition_frontier.Breadcrumb.(block breadcrumb) in + let blockchain_length = Mina_block.blockchain_length block in + let global_slot = + Mina_block.consensus_state block + |> Consensus.Data.Consensus_state.curr_global_slot + in + let staged_ledger = + Transition_frontier.Breadcrumb.staged_ledger breadcrumb + |> Staged_ledger.ledger + in + let protocol_state = + Transition_frontier.Breadcrumb.protocol_state breadcrumb + in + let consensus = + Mina_state.Protocol_state.consensus_state protocol_state + in + let staking_epoch = + Consensus.Proof_of_stake.Data.Consensus_state.staking_epoch_data + consensus + in + let next_epoch = + Consensus.Proof_of_stake.Data.Consensus_state.next_epoch_data + consensus + in + let staking_epoch_seed = + Mina_base.Epoch_seed.to_base58_check + staking_epoch.Mina_base.Epoch_data.Poly.seed + in + let next_epoch_seed = + Mina_base.Epoch_seed.to_base58_check + next_epoch.Mina_base.Epoch_data.Poly.seed + in + let runtime_config = Mina_lib.runtime_config mina in + let%bind staking_ledger = + match Mina_lib.staking_ledger mina with + | None -> + Deferred.Result.fail "Staking ledger is not initialized." + | Some (Genesis_epoch_ledger l) -> + return (Ledger.Any_ledger.cast (module Ledger) l) + | Some (Ledger_db l) -> + return (Ledger.Any_ledger.cast (module Ledger.Db) l) + in + assert ( + Mina_base.Ledger_hash.equal + (Ledger.Any_ledger.M.merkle_root staking_ledger) + staking_epoch.ledger.hash ) ; + let%bind next_epoch_ledger = + match Mina_lib.next_epoch_ledger mina with + | None -> + Deferred.Result.fail "Next epoch ledger is not initialized." + | Some `Notfinalized -> + return None + | Some (`Finalized (Genesis_epoch_ledger l)) -> + return (Some (Ledger.Any_ledger.cast (module Ledger) l)) + | Some (`Finalized (Ledger_db l)) -> + return (Some (Ledger.Any_ledger.cast (module Ledger.Db) l)) + in + Option.iter next_epoch_ledger ~f:(fun ledger -> assert ( Mina_base.Ledger_hash.equal - (Ledger.Any_ledger.M.merkle_root staking_ledger) - staking_epoch.ledger.hash ) ; - let%bind next_epoch_ledger = - match Mina_lib.next_epoch_ledger mina with - | None -> - Deferred.Result.fail "Next epoch ledger is not initialized." - | Some `Notfinalized -> - return None - | Some (`Finalized (Genesis_epoch_ledger l)) -> - return (Some (Ledger.Any_ledger.cast (module Ledger) l)) - | Some (`Finalized (Ledger_db l)) -> - return (Some (Ledger.Any_ledger.cast (module Ledger.Db) l)) - in - Option.iter next_epoch_ledger ~f:(fun ledger -> - assert ( - Mina_base.Ledger_hash.equal - (Ledger.Any_ledger.M.merkle_root ledger) - next_epoch.ledger.hash ) ) ; - let%bind new_config = - Runtime_config.make_fork_config ~staged_ledger ~global_slot - ~staking_ledger ~staking_epoch_seed ~next_epoch_ledger - ~next_epoch_seed ~blockchain_length ~protocol_state - runtime_config - in - let%map () = - Async_unix.Scheduler.yield () |> Deferred.map ~f:Result.return - in - Runtime_config.to_yojson new_config |> Yojson.Safe.to_basic ) + (Ledger.Any_ledger.M.merkle_root ledger) + next_epoch.ledger.hash ) ) ; + let%bind new_config = + Runtime_config.make_fork_config ~staged_ledger ~global_slot + ~staking_ledger ~staking_epoch_seed ~next_epoch_ledger + ~next_epoch_seed ~blockchain_length ~protocol_state runtime_config + in + let%map () = + Async_unix.Scheduler.yield () |> Deferred.map ~f:Result.return + in + Runtime_config.to_yojson new_config |> Yojson.Safe.to_basic ) let thread_graph = field "threadGraph" From c87e4b5380b955cd1bf9d4d8acb1fdea3fc4a2dc Mon Sep 17 00:00:00 2001 From: Sventimir Date: Wed, 17 Jan 2024 12:55:45 +0100 Subject: [PATCH 17/21] Fix broken benchmarks. --- src/app/ledger_export_bench/ledger_export_benchmark.ml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/ledger_export_bench/ledger_export_benchmark.ml b/src/app/ledger_export_bench/ledger_export_benchmark.ml index ba2102d8578..cd5846345a2 100644 --- a/src/app/ledger_export_bench/ledger_export_benchmark.ml +++ b/src/app/ledger_export_bench/ledger_export_benchmark.ml @@ -11,8 +11,15 @@ let load_daemon_cfg filename () = let serialize cfg () = Runtime_config.to_yojson cfg |> Yojson.Safe.to_string +let map_results ~f = + List.fold ~init:(Ok []) ~f:(fun acc x -> + let open Result.Let_syntax in + let%bind accum = acc in + let%map y = f x in + y :: accum ) + let convert accounts () = - Runtime_config.(map_results ~f:Accounts.Single.of_account accounts) + map_results ~f:Runtime_config.Accounts.Single.of_account accounts let () = let runtime_config = Sys.getenv_exn "RUNTIME_CONFIG" in From 29131a603048b1f96e55205eeab45cd738d97bdd Mon Sep 17 00:00:00 2001 From: Sventimir Date: Wed, 17 Jan 2024 16:05:38 +0100 Subject: [PATCH 18/21] Improve code readability. --- src/lib/mina_graphql/mina_graphql.ml | 3 ++- src/lib/runtime_config/runtime_config.ml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/mina_graphql/mina_graphql.ml b/src/lib/mina_graphql/mina_graphql.ml index eca6dddac85..518c4df9b4a 100644 --- a/src/lib/mina_graphql/mina_graphql.ml +++ b/src/lib/mina_graphql/mina_graphql.ml @@ -4361,7 +4361,8 @@ module Queries = struct ~next_epoch_seed ~blockchain_length ~protocol_state runtime_config in let%map () = - Async_unix.Scheduler.yield () |> Deferred.map ~f:Result.return + let open Async.Deferred.Infix in + Async_unix.Scheduler.yield () >>| Result.return in Runtime_config.to_yojson new_config |> Yojson.Safe.to_basic ) diff --git a/src/lib/runtime_config/runtime_config.ml b/src/lib/runtime_config/runtime_config.ml index fad959208d6..50192908891 100644 --- a/src/lib/runtime_config/runtime_config.ml +++ b/src/lib/runtime_config/runtime_config.ml @@ -1285,7 +1285,8 @@ let make_fork_config ~staged_ledger ~global_slot ~blockchain_length let global_slot = Mina_numbers.Global_slot.to_int global_slot in let blockchain_length = Unsigned.UInt32.to_int blockchain_length in let yield () = - Async_unix.Scheduler.yield () |> Async.Deferred.map ~f:Result.return + let open Async.Deferred.Infix in + Async_unix.Scheduler.yield () >>| Result.return in let%bind () = yield () in let%bind accounts = From 6f44a34e98e5cf4b13b27f0fa089c5bc109e6f4f Mon Sep 17 00:00:00 2001 From: Sventimir Date: Thu, 18 Jan 2024 09:29:57 +0100 Subject: [PATCH 19/21] Apply style improvements. --- src/lib/mina_graphql/mina_graphql.ml | 12 +++++------- src/lib/runtime_config/runtime_config.ml | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/lib/mina_graphql/mina_graphql.ml b/src/lib/mina_graphql/mina_graphql.ml index 518c4df9b4a..4d19a9278ab 100644 --- a/src/lib/mina_graphql/mina_graphql.ml +++ b/src/lib/mina_graphql/mina_graphql.ml @@ -4279,12 +4279,10 @@ module Queries = struct | `Active breadcrumb -> return breadcrumb ) | Some state_hash_base58, None -> - let%bind state_hash = - State_hash.of_base58_check state_hash_base58 - |> Result.map_error ~f:Error.to_string_hum - |> Deferred.return - in - Mina_lib.best_chain_block_by_state_hash mina state_hash + let open Result.Monad_infix in + State_hash.of_base58_check state_hash_base58 + |> Result.map_error ~f:Error.to_string_hum + >>= Mina_lib.best_chain_block_by_state_hash mina |> Deferred.return | None, Some block_height -> Mina_lib.best_chain_block_by_height mina @@ -4293,7 +4291,7 @@ module Queries = struct | Some _, Some _ -> Deferred.Result.fail "Cannot specify both state hash and height" in - let block = Transition_frontier.Breadcrumb.(block breadcrumb) in + let block = Transition_frontier.Breadcrumb.block breadcrumb in let blockchain_length = Mina_block.blockchain_length block in let global_slot = Mina_block.consensus_state block diff --git a/src/lib/runtime_config/runtime_config.ml b/src/lib/runtime_config/runtime_config.ml index 50192908891..42106f438e3 100644 --- a/src/lib/runtime_config/runtime_config.ml +++ b/src/lib/runtime_config/runtime_config.ml @@ -1261,7 +1261,8 @@ let ledger_accounts (ledger : Mina_base.Ledger.Any_ledger.witness) = let%map accounts = deferred_list_fold ~init:[] ~f:(fun acc el -> - let%bind () = yield () |> Async.Deferred.map ~f:Result.return in + let open Async.Deferred.Infix in + let%bind () = yield () >>| Result.return in let%map elt = Accounts.Single.of_account el |> Async.Deferred.return in elt :: acc ) accounts From fa90e55e7f513cf717b0758f1924c078b421653d Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Thu, 18 Jan 2024 10:29:23 +0000 Subject: [PATCH 20/21] Address Deepthi's comments regarding branching --- README-branching.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README-branching.md b/README-branching.md index 25a0ac7eaf3..8fad29a1daa 100644 --- a/README-branching.md +++ b/README-branching.md @@ -44,10 +44,11 @@ The relationship between the branches is as presented: `master ⊆ compatible ### Hard forks / releases: -Whenever a hard fork happens, the code in the corresponding release branch, e.g. `berkeley`, is released. When this happens, the current `compatible` is entirely discarded and a new `compatible` gets created based off of `develop`: +Whenever a hard fork happens, the code in the corresponding release branch, e.g. `berkeley`, is released to become the new `master`. +- The intention is then to again have `compatible` as a next soft-fork branch. + - The transition will be gradual: right after HF, `berkeley` will be copied into both `master` *and* `compatible`, and `develop` will remain as is for a while. PRs from `develop` will be gradually picked based on release scope and included in `compatible` for subsequent soft-fork releases. + - The pre-Berkeley `compatible` is entirely discarded. The pre-Berkeley branch `berkeley` is completely removed from both `mina` and `proof-systems`. - `release/1.X.X` branches are made off of `compatible` and tagged with alpha and beta tags until the code is deemed stable, then the `release/1.X.X` branch is merged into `master` and given a stable tag. Whenever code is tagged, if anything is missing in in the downstream branches (compatible, develop) then the tagged branch is also merged back for consistency. -- So after Berkeley release: `berkeley` branch will become the new `master`. `berkeley` will be removed from `proof-systems`. `develop` will be renamed into `compatible`. - ## Day to day: which branch should I use? @@ -62,7 +63,7 @@ We have CI jobs named `check-merges-cleanly-into-BRANCH` that fail if a PR intro If that CI job passes, then you can proceed and no further action is needed. -PRs resolving merge conflicts (merge-PRs) should only be merged after the original PR is approved, and all changes from the original PR are incorporated into the merge-PRs. Consider a PR with is made from `mybranch` branch against `rampup`, and causes conflicts in `berkeley` and `develop`. In this case the workflow is as follows: +PRs resolving merge conflicts (merge-PRs) should only be merged after the original PR is approved, and all changes from the original PR are incorporated into the merge-PRs. Consider a PR which is made from `mybranch` branch against `rampup`, and causes conflicts in `berkeley` and `develop`. In this case the workflow is as follows: - Review and approve the original PR against `rampup` (PR-rampup). CI passes except for `check-merges-cleanly-into-*` jobs. - Incorporate all changes from PR-rampup into a new PR against `berkeley` (PR-berkeley) and resolve conflicts. Concretely, make a new branch+PR based off of `mybranch` called `mybranch-berkeley` (for example), and then merge `berkeley` into `mybranch-berkeley`. Fix any merge errors that result. - Keeping branches in sync: If after making e.g. `mybranch-berkeley`, you need to make changes to `mybranch`, then do so, but make sure to merge the newly updated `mybranch` into `mybranch-berkeley`. In order for the git magic to work, `mybranch-berkeley` needs to be a superset of the commits from `mybranch`, and it also needs to be merged first. From cb1ce0f7bbe42d580531a0cf409b09b90fe0e0ba Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Thu, 18 Jan 2024 10:32:59 +0000 Subject: [PATCH 21/21] Remove branching policy for proof-systems --- README-branching.md | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/README-branching.md b/README-branching.md index 8fad29a1daa..d8dee224e7f 100644 --- a/README-branching.md +++ b/README-branching.md @@ -73,25 +73,3 @@ PRs resolving merge conflicts (merge-PRs) should only be merged after the origin The protocol team at o1labs will conduct weekly synchronization of all branches for all non-conflicting changes to ensure a smooth experience for everyone involved in the Mina repository. The protocol team will reach out to respective teams if there are any conflicting changes (due to force-merges performed mistakenly) and/or failing tests caused by code changes in the upstream branches. - - -# proof-systems Branching policy - -Generally, proof-systems intends to be synchronized with the mina repository, and so its branching policy is quite similar. However several important (some, temporary) distinctions exist: - -- `compatible`: - - Compatible with `rampup` in `mina`. - - Mina's `compatible`, similarly to mina's `master`, does not have `proof-systems`. -- `berkley`: future hardfork release, will be going out to berkeley. - - This is where hotfixes go. -- `develop`: matches mina's `develop`, soft fork-compatibility. - - Also used by `mina/o1js-main` and `o1js/main`. -- `master`: future feature work development, containing breaking changes. Anything that does not need to be released alongside mina. - - Note that `mina`'s `master` does not depend on `proof-systems` at all. -- `izmir`: next hardfork release after berkeley. -- In the future: - - `master`/`develop` will reverse roles and become something like gitflow. - - After Berkeley release `compatible` will become properly synced with `mina/compatible`. -- Direction of merge: - - Back-merging: `compatible` into `berkeley` into `develop` into `master`. - - Front-merging (introducing new features): other direction, but where you start depends on where the feature belongs.