Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add genesis state for checkpointing #101

Merged
merged 7 commits into from
Aug 25, 2022
Merged

Conversation

gitferry
Copy link
Contributor

This PR adds genesis state for the checkpointing module. In particular, it adds Bls keys and pop into GenesisState of the checkpointing module and implements InitGenesis.

@gitferry gitferry requested a review from aakoshh August 22, 2022 13:32
Copy link
Contributor

@aakoshh aakoshh left a comment

Choose a reason for hiding this comment

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

Cool, thanks for opening a different PR with tests for moving into the direction we discussed!

I sent some comments; to summarise I think that we should:

  • try to make the API symmetric and ask for both public keys during validation
  • not rely on the key included in the PoP for validation, but rather look it up in the system based on where we are
  • have dedicated type in the genesis config rather than have to validator fields during normal registrations that provide the same content

proto/babylon/checkpointing/bls_key.proto Outdated Show resolved Hide resolved
proto/babylon/checkpointing/bls_key.proto Outdated Show resolved Hide resolved
x/checkpointing/keeper/gen_bls.go Outdated Show resolved Hide resolved
x/checkpointing/keeper/msg_server.go Outdated Show resolved Hide resolved
x/checkpointing/types/msgs.go Outdated Show resolved Hide resolved
Comment on lines 19 to 20
}
ok := blskey.Pop.IsValid(*blskey.Pubkey)
ok := blskey.Pop.IsValid(*blskey.Pubkey, valPubkeys[i])
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it would be worth doing an explicit assertion that there are equal number of items in both arrays.

Comment on lines 43 to 50
valAddr, err := sdk.ValAddressFromBech32(msg.MsgCreateValidator.ValidatorAddress)
if err != nil {
return nil, err
}
valPubkey, found := m.k.GetValidatorPubkey(ctx, valAddr)
if !found {
return nil, errors.New("can not find validator by address")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't we just trying to create the validator after this, if the Proof-of-Possession is correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

Public key is in the message.

Copy link
Contributor

Choose a reason for hiding this comment

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

I keep getting confused by these keys.

We said we can remove the account key from the PoP because the validator key will be used to sign the MsgCreateValidator message, right?

So, if Eve sees Bob's MsgCreateValidator transaction, she can still snatch the PoP from it if she wants to - just as she could register the pubkey for herself, although she would not be able to use it for validation.

In the end I still got it wrong when I said in your earlier PR that it was safe as PoP only because the Ed25519 is used to sign the transaction, because it's not used like that. I guess we just have to make sure that nobody else can register the BLS key for themselves, unless we want to use the Secp256k1 key which is used to signed the transaction.

So the PoP proves not that the bearer possesses both BLS and Ed25519 keys, but rather that there is some person out there who wanted to use these keys together, but we don't know who they are and they can't prove it to Cosmos either, because Cosmos is not interested in signatures with these keys over any content that verifyable belongs to the sender 😵

@gitferry
Copy link
Contributor Author

Hi @aakoshh, thanks for your comments. Sorry for the early commit that caused some confusion as I was still revising the code. Now I think I have addressed all your comments. Regarding PoP, I think the current implementation is safe because each ed25519-bls binding is also bonded with an account address, the delegator. Therefore, the attacker can not register the same ed25519-bls binding with another account.

This PR failed the integration test but I cannot find the cause. @KonradStaniec Could you please take a look? It seems that the testnet cannot be started but my local make test seems OK.

@KonradStaniec
Copy link
Collaborator

Hey @gitferry , so you can start local testnet on your local machine by make localnet-start in repo root. Then the logs are produced to .testnets folder.

When i try to do it on this branch the testnet fails to start due to some panic:

�[90m4:13PM�[0m �[32mINF�[0m starting node with ABCI Tendermint in-process
�[90m4:13PM�[0m �[32mINF�[0m Starting multiAppConn service �[36mimpl=�[0mmultiAppConn �[36mmodule=�[0mproxy
�[90m4:13PM�[0m �[32mINF�[0m Starting localClient service �[36mconnection=�[0mquery �[36mimpl=�[0mlocalClient �[36mmodule=�[0mabci-client
�[90m4:13PM�[0m �[32mINF�[0m Starting localClient service �[36mconnection=�[0msnapshot �[36mimpl=�[0mlocalClient �[36mmodule=�[0mabci-client
�[90m4:13PM�[0m �[32mINF�[0m Starting localClient service �[36mconnection=�[0mmempool �[36mimpl=�[0mlocalClient �[36mmodule=�[0mabci-client
�[90m4:13PM�[0m �[32mINF�[0m Starting localClient service �[36mconnection=�[0mconsensus �[36mimpl=�[0mlocalClient �[36mmodule=�[0mabci-client
�[90m4:13PM�[0m �[32mINF�[0m Starting EventBus service �[36mimpl=�[0mEventBus �[36mmodule=�[0mevents
�[90m4:13PM�[0m �[32mINF�[0m Starting PubSub service �[36mimpl=�[0mPubSub �[36mmodule=�[0mpubsub
�[90m4:13PM�[0m �[32mINF�[0m Starting IndexerService service �[36mimpl=�[0mIndexerService �[36mmodule=�[0mtxindex
�[90m4:13PM�[0m �[32mINF�[0m ABCI Handshake App Info �[36mhash=�[0m �[36mheight=�[0m0 �[36mmodule=�[0mconsensus �[36mprotocol-version=�[0m0 �[36msoftware-version=�[0m67c2508
�[90m4:13PM�[0m �[32mINF�[0m ABCI Replay Blocks �[36mappHeight=�[0m0 �[36mmodule=�[0mconsensus �[36mstateHeight=�[0m0 �[36mstoreHeight=�[0m0
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m0/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mgov/module-account
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m1/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mdistribution/nonnegative-outstanding
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m2/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mdistribution/can-withdraw
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m3/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mdistribution/reference-count
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m4/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mdistribution/module-account
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m5/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mstaking/module-accounts
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m6/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mstaking/nonnegative-power
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m7/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mstaking/positive-delegation
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m8/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mstaking/delegator-shares
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m9/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mbank/nonnegative-outstanding
�[90m4:13PM�[0m �[32mINF�[0m asserting crisis invariants �[36minv=�[0m10/11 �[36mmodule=�[0mx/crisis �[36mname=�[0mbank/total-supply
�[90m4:13PM�[0m �[32mINF�[0m asserted all invariants �[36mduration=�[0m3.9139 �[36mheight=�[0m0 �[36mmodule=�[0mx/crisis
panic: encoding/hex: invalid byte: U+006E 'n'

goroutine 1 [running]:
github.com/babylonchain/babylon/x/checkpointing/keeper.Keeper.SetGenBlsKeys({{0x7f2f1c59d0d8, 0xc000dc99b0}, {0x2291718, 0xc000c82300}, {0x2291718, 0x0}, {0x22a4c80, 0xc0001593f0}, {0x0, 0x0}, ...}, ...)
	github.com/babylonchain/babylon/x/checkpointing/keeper/gen_bls.go:13 +0x3dc
github.com/babylonchain/babylon/x/checkpointing.InitGenesis({{0x22a2278, 0xc000042050}, {0x22ad540, 0xc001146900}, {{0x0, 0x0}, {0xc000bf84f0, 0xc}, 0x0, {0x1a9b5e28, ...}, ...}, ...}, ...)
	github.com/babylonchain/babylon/x/checkpointing/genesis.go:14 +0x1b0
github.com/babylonchain/babylon/x/checkpointing.AppModule.InitGenesis({{{0x7f2f1c59d0d8, 0xc000dc99b0}}, {{0x7f2f1c59d0d8, 0xc000dc99b0}, {0x2291718, 0xc000c82300}, {0x2291718, 0x0}, {0x22a4c80, 0xc0001593f0}, ...}, ...}, ...)
	github.com/babylonchain/babylon/x/checkpointing/module.go:158 +0x138
github.com/cosmos/cosmos-sdk/types/module.(*Manager).InitGenesis(_, {{0x22a2278, 0xc000042050}, {0x22ad540, 0xc001146900}, {{0x0, 0x0}, {0xc000bf84f0, 0xc}, 0x0, ...}, ...}, ...)
	github.com/cosmos/cosmos-sdk@v0.45.4/types/module/module.go:320 +0x29d
github.com/babylonchain/babylon/app.(*BabylonApp).InitChainer(_, {{0x22a2278, 0xc000042050}, {0x22ad540, 0xc001146900}, {{0x0, 0x0}, {0xc000bf84f0, 0xc}, 0x0, ...}, ...}, ...)
	github.com/babylonchain/babylon/app/app.go:559 +0x20e
github.com/cosmos/cosmos-sdk/baseapp.(*BaseApp).InitChain(0xc000eae340, {{0x1a9b5e28, 0xeda96f39d, 0x0}, {0xc000bf84f0, 0xc}, 0xc000d8c100, {0x2f75ed8, 0x0, 0x0}, ...})
	github.com/cosmos/cosmos-sdk@v0.45.4/baseapp/abci.go:62 +0x455
github.com/tendermint/tendermint/abci/client.(*localClient).InitChainSync(0xc0000bf980, {{0x1a9b5e28, 0xeda96f39d, 0x0}, {0xc000bf84f0, 0xc}, 0xc000d8c100, {0x2f75ed8, 0x0, 0x0}, ...})
	github.com/tendermint/tendermint@v0.34.19/abci/client/local_client.go:272 +0x118
github.com/tendermint/tendermint/proxy.(*appConnConsensus).InitChainSync(0xaf?, {{0x1a9b5e28, 0xeda96f39d, 0x0}, {0xc000bf84f0, 0xc}, 0xc000d8c100, {0x2f75ed8, 0x0, 0x0}, ...})
	github.com/tendermint/tendermint@v0.34.19/proxy/app_conn.go:77 +0x55
github.com/tendermint/tendermint/consensus.(*Handshaker).ReplayBlocks(_, {{{0xb, 0x0}, {0x19c9c49, 0x7}}, {0xc000bf84f0, 0xc}, 0x1, 0x0, {{0x0, ...}, ...}, ...}, ...)
	github.com/tendermint/tendermint@v0.34.19/consensus/replay.go:319 +0xd78
github.com/tendermint/tendermint/consensus.(*Handshaker).Handshake(0xc000fddfd0, {0x22adeb0, 0xc000ba4340})
	github.com/tendermint/tendermint@v0.34.19/consensus/replay.go:268 +0x3c8
github.com/tendermint/tendermint/node.doHandshake({_, _}, {{{0xb, 0x0}, {0x19c9c49, 0x7}}, {0xc000bf84f0, 0xc}, 0x1, 0x0, ...}, ...)
	github.com/tendermint/tendermint@v0.34.19/node/node.go:325 +0x1b8
github.com/tendermint/tendermint/node.NewNode(0xc000dd83c0, {0x229f1d0, 0xc000da8960}, 0xc000c83b00, {0x228cca0, 0xc00000fbc0}, 0x0?, 0x0?, 0xc000c83d50, {0x22a2f60, ...}, ...)
	github.com/tendermint/tendermint@v0.34.19/node/node.go:733 +0x577
github.com/cosmos/cosmos-sdk/server.startInProcess(_, {{0x0, 0x0, 0x0}, {0x22b43c0, 0xc000c19260}, {0x0, 0x0}, {0x22a5ec8, 0xc000dc99b0}, ...}, ...)
	github.com/cosmos/cosmos-sdk@v0.45.4/server/start.go:272 +0x7db
github.com/cosmos/cosmos-sdk/server.StartCmd.func2(0xc00022ca00?, {0xc000123200?, 0x0?, 0x4?})
	github.com/cosmos/cosmos-sdk@v0.45.4/server/start.go:126 +0x169
github.com/spf13/cobra.(*Command).execute(0xc00022ca00, {0xc000123100, 0x4, 0x4})
	github.com/spf13/cobra@v1.4.0/command.go:856 +0x67c
github.com/spf13/cobra.(*Command).ExecuteC(0xc000c8e500)
	github.com/spf13/cobra@v1.4.0/command.go:974 +0x3b4
github.com/spf13/cobra.(*Command).Execute(...)
	github.com/spf13/cobra@v1.4.0/command.go:902
github.com/spf13/cobra.(*Command).ExecuteContext(...)
	github.com/spf13/cobra@v1.4.0/command.go:895
github.com/cosmos/cosmos-sdk/server/cmd.Execute(0x0?, {0xc000119ea0, 0xf})
	github.com/cosmos/cosmos-sdk@v0.45.4/server/cmd/execute.go:36 +0x1eb
main.main()
	github.com/babylonchain/babylon/cmd/babylond/main.go:18 +0x31

My guess is that pr changes something with genesis handling which makes it impossible to start node.

@gitferry
Copy link
Contributor Author

Thanks @KonradStaniec! This is super helpful.

@aakoshh
Copy link
Contributor

aakoshh commented Aug 24, 2022

Regarding PoP, I think the current implementation is safe because each ed25519-bls binding is also bonded with an account address, the delegator. Therefore, the attacker can not register the same ed25519-bls binding with another account.

Right, so what we want to avoid is somebody registering a BLS public key that they don't own, which would allow them to mount an attack (although I forgot how). We do this by only allowing the first registration for the BLS key to go through.

What we are not doing is actually verifying that the person sending the registration has the BLS private key, because they could just copy someone else's PoP and use it for themselves. But if they do so, the system would make sure they are the only ones with this now useless BLS key.

So I agree that it's safe, it's just a bit confusing. But so was the basic idea of "PoP means you sign the BLS public key with the BLS private key" - anyone can steal that once they see it.

@@ -30,6 +31,18 @@ func (k Keeper) GetValidatorSet(ctx sdk.Context, epochNumber uint64) types.Valid
return types.NewSortedValidatorSet(vals)
}

func (k Keeper) GetValidatorPubkey(ctx sdk.Context, valAddr sdk.ValAddress) (cryptotypes.PubKey, bool) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this still used?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I'll remove it.

Copy link
Contributor

@aakoshh aakoshh left a comment

Choose a reason for hiding this comment

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

Looks good I think! 👍

@@ -216,7 +216,15 @@ func InitTestnet(
if err != nil {
return err
}
valPubkeys = append(valPubkeys, valPubkey)
genKey := &checkpointingtypes.GenesisKey{
ValidatorAddress: sdk.ValAddress(addr).String(),
Copy link
Collaborator

Choose a reason for hiding this comment

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

this will create bech32 encoded string , while in https://github.com/babylonchain/babylon/pull/101/files#diff-5e33f2573bcc600876bb7e96e8241263ea8790b62060ce20a43e2a0ff35e538fR11 you expect hex-encoded.

Maybe it is worth using betting typing in GenesisKey struct or at least at some comments what is expected format of address string. I would expect bech32, as it is standard across cosmos-sdk to use bech32 encoded strings.

Also question, why do we have address string and ValPubkey *ed25519.PubKey in GenesisKey struct, when you can derive address from public key ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also question, why do we have address string and ValPubkey *ed25519.PubKey

This is endlessly confusing, but based on the MsgCreateValidator my impression is that the address string is the account key (Secp256k1) and is not the same as the validator key. I thought that's what we have in genesis.proto as well: who is the account (validator_address) that paid to become a validator and what validator key (val_pubkey) and what BLS key they will use. We do this because genutil only accepts MsgCreateValidator which also has validator_address and delegator_address which have to be identical account keys, plus it has the pubkey to associate with them.

Copy link
Contributor Author

@gitferry gitferry Aug 25, 2022

Choose a reason for hiding this comment

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

Thanks @KonradStaniec, I have changed it to bech32.

Copy link
Contributor Author

@gitferry gitferry Aug 25, 2022

Choose a reason for hiding this comment

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

Also question, why do we have address string and ValPubkey *ed25519.PubKey in GenesisKey struct, when you can derive address from public key ?

The validator address actually is not from the validator's public key but from the account's public key. See here Yeah, it is confusing.
I think addresses from either the account public key or the ed25519 public key can both work.

Pubkey: &valKeys[i].BlsPubkey,
Pop: valKeys[i].PoP,
},
ValPubkey: nil,
Copy link
Collaborator

Choose a reason for hiding this comment

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

You are passing here nil so the BlsKey.Pop.IsValid(*key.BlsKey.Pubkey, key.ValPubkey) will fail in https://github.com/babylonchain/babylon/pull/101/files#diff-5e33f2573bcc600876bb7e96e8241263ea8790b62060ce20a43e2a0ff35e538fR19

Copy link
Contributor Author

@gitferry gitferry Aug 25, 2022

Choose a reason for hiding this comment

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

Thanks for pointing that out. I have fixed it but I still get nil err when I ran make localnet-start, it seems that valKey is still nil. I think the reason is because unmarshalling json to Pubkey does not succeed because Pubkey is Any type and the unmarshalling looses the cachedValue.

@gitferry gitferry force-pushed the checkpointing/add-genesis branch 2 times, most recently from f8452cf to d764ce5 Compare August 25, 2022 05:34
@gitferry gitferry merged commit c18ea46 into main Aug 25, 2022
@gitferry gitferry deleted the checkpointing/add-genesis branch August 25, 2022 11:13
vitsalis pushed a commit that referenced this pull request Jan 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants