From a4cc68d9324486df441eba57c7bac88ce28a1c6f Mon Sep 17 00:00:00 2001 From: Sventimir Date: Tue, 26 Sep 2023 11:53:26 +0200 Subject: [PATCH 1/8] [RFC] Genesis ledger export --- rfcs/0050-genesis-ledger-export.md | 117 +++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 rfcs/0050-genesis-ledger-export.md diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md new file mode 100644 index 00000000000..de9fb253e7b --- /dev/null +++ b/rfcs/0050-genesis-ledger-export.md @@ -0,0 +1,117 @@ +## Summary + +This RFC describes the procedure to generate a genesis ledger from a +running network, using a node connected to that network. + +## Motivation + +The procedure described here is a part of the hard fork procedure, +which aims at spawning a new network, being a direct continuation of +the mainnet (or any other Mina network for that matter). To enable +this, the ledger of the old network must be exported in some form and +then fed into the newly created network. Because the new network's +initial state can be fed into nodes in a configuration file, it makes +sense to generate that file directly from the old node. Then necessary +updates can be made to it manually to update various protocol +constants, and then the new configuration file can be handed over to +node operators. + +## Detailed design + +The genesis ledger export is achieved using a GraphQL field named +`fork_config`. This field, if asked for, contains a new runtime +configuration, automatically updated with: + +* the dump of the current **staged ledger**, which will become the +genesis ledger for the new network +* updated values of `Fork_config`, i.e. previous state hash, previous +blockchain length and previous global slot. + +**IMPORTANT**: as of now the `genesis_ledger_timestamp` is **not** +being updated and must be manually set to the right value (which is at +the moment unknown). + +Thus generated configuration can be saved to a file, modified if +needed and fed directly into a new node, running a different protocol +version, using `--config-file` flag. As of the moment of writing this, +`compatible` and `berkeley` branches' configuration files are +compatible with each other (see: [PR #13768](https://github.com/MinaProtocol/mina/pull/13768)). + +The `fork_config` field has been added to GraphQL in [PR #13787](https://github.com/MinaProtocol/mina/pull/13787). + +## Drawbacks + +This RFC provides a simple enough procedure to generate the genesis +ledger for the new network. However, it's not without its problems. + +### File size + +At the moment the mainnet has more than 100 000 accounts created. +Each account takes at least 4 lines in the configuration, which adds +up to around 600kB of JSON data. The daemon can take considerable time +at startup to parse it and load its contents into memory. If we move +on with this approach, it might be desirable to make a dedicated +effort to improving the configuration parsing speed, as these files +will only grow larger in subsequent hard forks. Alternatively, we +might want to devise a better (less verbose) storage mechanism for the +genesis ledger. + +### Security concerns + +The generated genesis ledger is prone to malevolent manual +modifications. Beyond containing the hash of the previous ledger, it's +unprotected from tampering with. However, at the moment there is no +mechanism which could improve the situation. The system considers +genesis ledger the initial state of the blockchain, so there is no +previous state it could refer to. Also, because we dump the **staged +ledger**, it is never snarked. It can only be verified manually by end +users, which is cumbersome at best. + +Some protection against tampering with the ledger we gain from the +fact that all the nodes must use the same one, or they'll be kicked +out from the network. This protects the ledger from node operators, +but it doesn't exclude the possibility of tampering with it by the +party which will generate the configuration. + +## Rationale and alternatives + +The presented way of handling the ledger export is the simplest one +and the easiest to implement. The security concern indicated above +cannot be mitigated with any method currently available. In order to +overcome it, we would have to re-think the whole procedure and somehow +continue the existing network with the changed protocol instead of +creating a new one. + +It seems reasonable to export the ledger in binary form instead, but +currently the node does not persist the staged ledger in any way that +could survive the existing node and could be loaded by another one. +Even if we had such a process, the encoding of the ledger would have +to be compatible between `compatible` and `berkeley`, which could be +difficult to maintain in any binary format. + +Otherwise there's no reasonable alternative to the process described. + +## Prior art + +Some of the existing blockchains, like Tezos, deal with the protocol +upgrade problem, avoiding hard-forking entirely, and therefore +avoiding the ledger export in particular. They achieve it by careful +software design in which the protocol (containing in particular the +consensus mechanism and transaction logic) consists in a plugin to the +daemon, which can be loaded and unloaded at runtime. Thus the protocol +update is as simple as loading another plugin at runtime and does not +even require a node restart. + +It would certainly be beneficial to Mina to implement a similar +solution, but this is obviously a huge amount of work (involving +redesigning the whole code base), which makes it infeasible for the +moment. + +## Unresolved questions + +The genesis timestamp of the new network needs to be specified in the +runtime configuration, but it is as of now (and will probably remain +for some time still) unknown. This makes it hard to put it into the +configuration in any automated fashion. Relying on personnel +performing the hard fork to update it is far from ideal, but there +seems to be no better solution available at the moment. From 2f909c3adf8096fd639e964e4042ae818c9b1956 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Mon, 2 Oct 2023 14:13:18 +0200 Subject: [PATCH 2/8] [RFC] Add epoch data to the exported hard fork config. --- rfcs/0050-genesis-ledger-export.md | 1 + 1 file changed, 1 insertion(+) diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md index de9fb253e7b..a2085446f52 100644 --- a/rfcs/0050-genesis-ledger-export.md +++ b/rfcs/0050-genesis-ledger-export.md @@ -26,6 +26,7 @@ configuration, automatically updated with: genesis ledger for the new network * updated values of `Fork_config`, i.e. previous state hash, previous blockchain length and previous global slot. +* updated epoch data, in particular current and next epoch ledger and seed. **IMPORTANT**: as of now the `genesis_ledger_timestamp` is **not** being updated and must be manually set to the right value (which is at From ba12db3f0089a05ac7af7dc7fd16585e5c55bfe8 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Mon, 2 Oct 2023 14:22:44 +0200 Subject: [PATCH 3/8] [RFC] Mention compatibility issues between mainnet & berkeley. - Epoch seeds' encoding is incompatible - Some Runtime_config fields have been renamed --- rfcs/0050-genesis-ledger-export.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md index a2085446f52..311501bd752 100644 --- a/rfcs/0050-genesis-ledger-export.md +++ b/rfcs/0050-genesis-ledger-export.md @@ -37,6 +37,11 @@ needed and fed directly into a new node, running a different protocol version, using `--config-file` flag. As of the moment of writing this, `compatible` and `berkeley` branches' configuration files are compatible with each other (see: [PR #13768](https://github.com/MinaProtocol/mina/pull/13768)). +Sadly since then that compatibility has been broken by [PR #14014](https://github.com/MinaProtocol/mina/pull/14014). +We need to either port this change back to `compatible` or create a +migration script which will adapt a `mainnet` config file to the +format required by `berkeley`. The former solution would probably +be better. The `fork_config` field has been added to GraphQL in [PR #13787](https://github.com/MinaProtocol/mina/pull/13787). @@ -116,3 +121,10 @@ for some time still) unknown. This makes it hard to put it into the configuration in any automated fashion. Relying on personnel performing the hard fork to update it is far from ideal, but there seems to be no better solution available at the moment. + +Also epoch seeds from mainnet are incompatible with those on berkeley. +When epoch ledgers are being exported from a compatible node and +transferred into a berkeley node, the latter cannot load them, because +Base58check fails to decode them. This is a problem we need to overcome +or decide that we won't export the epoch ledgers and assume they're +the same as the genesis ledger for the purpose of hard fork. From dd4e371ec5d38a451bc2e7aedc44021ceb509b5a Mon Sep 17 00:00:00 2001 From: Sventimir Date: Thu, 26 Oct 2023 09:51:48 +0200 Subject: [PATCH 4/8] [RFC] Add reviewers' suggestions. --- rfcs/0050-genesis-ledger-export.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md index 311501bd752..4b87731d0e6 100644 --- a/rfcs/0050-genesis-ledger-export.md +++ b/rfcs/0050-genesis-ledger-export.md @@ -19,8 +19,10 @@ node operators. ## Detailed design The genesis ledger export is achieved using a GraphQL field named -`fork_config`. This field, if asked for, contains a new runtime -configuration, automatically updated with: +`fork_config`. Asking for this field requires providing a slot or a +state hash of the block that we want to base the exported ledger on. +This field, if asked for, contains a new runtime configuration, +automatically updated with: * the dump of the current **staged ledger**, which will become the genesis ledger for the new network @@ -43,7 +45,9 @@ migration script which will adapt a `mainnet` config file to the format required by `berkeley`. The former solution would probably be better. -The `fork_config` field has been added to GraphQL in [PR #13787](https://github.com/MinaProtocol/mina/pull/13787). +The `fork_config` field has been added to GraphQL in [PR #13787](https://github.com/MinaProtocol/mina/pull/13787). It needs to be extended to return the blockchain state for +a given block (height or state hash) so that we can export the +desired ledger after the blockchain has moved on. ## Drawbacks From b079a9cd282a7ac143dc46de34d5b0a860432d7e Mon Sep 17 00:00:00 2001 From: Sventimir Date: Fri, 27 Oct 2023 09:25:30 +0200 Subject: [PATCH 5/8] Note that the fork_config query should be parametrised by a block. --- rfcs/0050-genesis-ledger-export.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md index 4b87731d0e6..0af5fd8f9d2 100644 --- a/rfcs/0050-genesis-ledger-export.md +++ b/rfcs/0050-genesis-ledger-export.md @@ -24,8 +24,10 @@ state hash of the block that we want to base the exported ledger on. This field, if asked for, contains a new runtime configuration, automatically updated with: -* the dump of the current **staged ledger**, which will become the -genesis ledger for the new network +* the dump of the **staged ledger** as it was after the last block +before the slot where no more transactions were accepted +(transaction-stop slot). This ledger becomes the genesis ledger for +the new network * updated values of `Fork_config`, i.e. previous state hash, previous blockchain length and previous global slot. * updated epoch data, in particular current and next epoch ledger and seed. @@ -45,9 +47,11 @@ migration script which will adapt a `mainnet` config file to the format required by `berkeley`. The former solution would probably be better. -The `fork_config` field has been added to GraphQL in [PR #13787](https://github.com/MinaProtocol/mina/pull/13787). It needs to be extended to return the blockchain state for -a given block (height or state hash) so that we can export the -desired ledger after the blockchain has moved on. +The `fork_config` field has been added to GraphQL in [PR +#13787](https://github.com/MinaProtocol/mina/pull/13787). It needs to +be extended to return the blockchain state for a given block (height +or state hash) so that we can export the desired ledger after the +blockchain has moved on. ## Drawbacks From 6b1e8867e43f9e5b9999979682a11ecd998c5af4 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Fri, 27 Oct 2023 09:26:21 +0200 Subject: [PATCH 6/8] Describe a way to protect the exported ledger against dishonest update. --- rfcs/0050-genesis-ledger-export.md | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md index 0af5fd8f9d2..9f13f1be8ce 100644 --- a/rfcs/0050-genesis-ledger-export.md +++ b/rfcs/0050-genesis-ledger-export.md @@ -74,18 +74,26 @@ genesis ledger. The generated genesis ledger is prone to malevolent manual modifications. Beyond containing the hash of the previous ledger, it's -unprotected from tampering with. However, at the moment there is no -mechanism which could improve the situation. The system considers -genesis ledger the initial state of the blockchain, so there is no -previous state it could refer to. Also, because we dump the **staged -ledger**, it is never snarked. It can only be verified manually by end -users, which is cumbersome at best. - -Some protection against tampering with the ledger we gain from the +unprotected from tampering with. + +One way to improve this is to provide an external program, capable of +computing hash of the ledger as it will be after the config is loaded +into a node. Users will be able to obtain a raw fork config file from +their nodes. Later, given the official config for the new network, +they will be able to run the program against both files and compute +ledger hashes. The reason why this is needed is that the configuration +file will likely contain some manual updates. For instance the genesis +ledger timestamp will need to be updated manually when the start time +of the new network is known. Further changes may concern genesis +constants and other network configuration. All these changes should be +ignored during the hash computation and only the genesis ledger itself +should be taken into consideration. This way a user seeing that the +configuration file is not identical to the one they computed, still +does not contain any changes to the genesis ledger. + +Further protection against tampering with the ledger we gain from the fact that all the nodes must use the same one, or they'll be kicked -out from the network. This protects the ledger from node operators, -but it doesn't exclude the possibility of tampering with it by the -party which will generate the configuration. +out from the network. ## Rationale and alternatives From a69d1ff4ee6ac4ab6f44a4a302cbdad186d78ee1 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Tue, 31 Oct 2023 09:12:06 +0100 Subject: [PATCH 7/8] Extend the description of exported blockchain state. --- rfcs/0050-genesis-ledger-export.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md index 9f13f1be8ce..b6f23ccbcaa 100644 --- a/rfcs/0050-genesis-ledger-export.md +++ b/rfcs/0050-genesis-ledger-export.md @@ -24,18 +24,22 @@ state hash of the block that we want to base the exported ledger on. This field, if asked for, contains a new runtime configuration, automatically updated with: -* the dump of the **staged ledger** as it was after the last block -before the slot where no more transactions were accepted -(transaction-stop slot). This ledger becomes the genesis ledger for -the new network +* the dump of the **staged ledger** at the fork point * updated values of `Fork_config`, i.e. previous state hash, previous -blockchain length and previous global slot. -* updated epoch data, in particular current and next epoch ledger and seed. +blockchain length and previous global slot; +* Current epoch ledger; +* Current epoch data (total currency and seed); +* Next epoch ledger; +* Next epoch data (total currency and seed); +* Protocol state at the fork point; **IMPORTANT**: as of now the `genesis_ledger_timestamp` is **not** being updated and must be manually set to the right value (which is at the moment unknown). +By the fork point above we mean the last block before the slot where +no more transactions were accepted (transaction-stop slot). + Thus generated configuration can be saved to a file, modified if needed and fed directly into a new node, running a different protocol version, using `--config-file` flag. As of the moment of writing this, From 0dc837591e06c8d2301642bed7985d39db836dd8 Mon Sep 17 00:00:00 2001 From: Sventimir Date: Tue, 31 Oct 2023 09:12:29 +0100 Subject: [PATCH 8/8] Add a section on testing. --- rfcs/0050-genesis-ledger-export.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/rfcs/0050-genesis-ledger-export.md b/rfcs/0050-genesis-ledger-export.md index b6f23ccbcaa..5b784076353 100644 --- a/rfcs/0050-genesis-ledger-export.md +++ b/rfcs/0050-genesis-ledger-export.md @@ -148,3 +148,29 @@ transferred into a berkeley node, the latter cannot load them, because Base58check fails to decode them. This is a problem we need to overcome or decide that we won't export the epoch ledgers and assume they're the same as the genesis ledger for the purpose of hard fork. + +## Testing + +An automatic integration test will be written to check that the data is +being exported properly. The procedure is to start a fresh network and +generate a couple of transactions. Then the transactions are stopped. +Finally the ledger export is performed and the test compares the +exported state to the current state of the blockchain as obtained +through GraphQL. These checks must take into account the fact, that +it has changed slightly since the transaction stop (a couple additional +blocks might have been produced). However, all balances should definitely +be the same (after the transaction stop no transactions are allowed, there +are no fees of coinbase rewards anymore). + +The procedure can also be tested manually as follows: +* Sync up with the mainnet. +* Export the genesis ledger at any point in time. +* The program mentioned in a previous section can be +used to verify the exported ledger. +* Possibly add an account you control and change everyone's +delegation to point at that account so that you can produce +blocks. +* Start a new network with the exported state. +* The new network should be able to produce blocks. +* All the accounts should have the same balances and +delegates as on the mainnet at the moment of export.