diff --git a/docs/architecture/ADR-002-QGB-ValSet.md b/docs/architecture/ADR-002-QGB-ValSet.md new file mode 100644 index 0000000000..ec7487c6c5 --- /dev/null +++ b/docs/architecture/ADR-002-QGB-ValSet.md @@ -0,0 +1,293 @@ +# ADR 002: Overview + +## Changelog + +- {date}: {changelog} + +## Context +To accommodate the requirements of the [Quantum Gravity Bridge](https://github.com/celestiaorg/quantum-gravity-bridge/blob/master/ethereum/solidity/src/QuantumGravityBridge.sol), We will need to add support for `ValSet`s, i.e. Validator Sets, which reflect the current state of the bridge validators. + +## Decision +Add the `ValSet` and `ValSetConfirm` type of messages in order to track the state of the validator set. + +## Detailed Design +Since the QGB is only a one way bridge and is not transferring assets, it doesn't require the portions of the gravity module that recreate state from the bridged chain. We only need to keep things relating to signing over the validator set (such as`MsgSetOrchestratorAddress` and `MsgValsetConfirm`) and relayer queries (such as `ValsetConfirm` and `GetDelegateKeyByOrchestrator`). + +It works by relying on a set of signers to attest to some event on Celestia: the Celestia validator set. + +The QGB contract keeps track of the Celestia validator set by updating its view of the validator set with `updateValidatorSet()`. More than 2/3 of the voting power of the current view of the validator set must sign off on new relayed events, submitted with +[`submitDataRootTupleRoot()`](https://github.com/celestiaorg/quantum-gravity-bridge/blob/980b9c68abc34b8d2e4d20ca644b8aa3025a239e/ethereum/solidity/src/QuantumGravityBridge.sol#L328). +Each event is a batch of `DataRootTuples`, with each tuple representing a single data root (i.e. block header). Relayed tuples are in the same order as Celestia block headers. +For more details, check the data commitment ADR. + +Finally, if there are no validator set updates for the unbonding window, the bridge must halt. + +### When are validator sets created +1. If there are no valSet requests, create a new one +2. If there is at least one validator who started unbonding in current block. (we persist last unbonded block height in `hooks.go`) + This will make sure the unbonding validator has to provide an attestation to a new ValSet + that excludes him before he completely unbonds. Otherwise, he will be slashed. +3. If power change between validators of CurrentValSet and latest valSet request is > 5% + +### Message types +We added the following messages types: + +#### Bridge Validator +The `BridgeValidator` represents a validator's ETH address and its power. +```protobuf +message BridgeValidator { + // Voting power of the validator. + uint64 power = 1; + // Ethereum address that will be used by the validator to sign messages. + string ethereum_address = 2; +} +``` + +#### ValSet +`Valset` is the Ethereum Bridge Multsig Set, each qgb validator also maintains an ETH key to sign messages, these are used to check signatures on ETH because of the significant gas savings. +```protobuf +message Valset { + // Unique number referencing the `ValSet`. + uint64 nonce = 1; + // List of BridgeValidator containing the current validator set. + repeated BridgeValidator members = 2 [ (gogoproto.nullable) = false ]; + // Current chain height + uint64 height = 3; +} +``` + +#### MsgSetOrchestratorAddress +`MsgSetOrchestratorAddress` allows validators to delegate their voting responsibilities to a given key. This key is then used as an optional authentication method for signing oracle claims. +```protobuf +message MsgSetOrchestratorAddress { + // The validator field is a celesvaloper1... string (i.e. sdk.ValAddress) + // that references a validator in the active set + string validator = 1; + // The orchestrator field is a celes1... string (i.e. sdk.AccAddress) that + // references the key that is being delegated to + string orchestrator = 2; + // This is a hex encoded 0x Ethereum public key that will be used by this + // validator on Ethereum + string eth_address = 3; +} +``` + +#### ValSetConfirm +`MsgValsetConfirm` is the message sent by the validators when they wish to submit their signatures over the validator set at a given block height. A validator must first call `SetOrchestratorAddress` to set their Ethereum's address to be used for signing. Then, using `EndBlocker()`, the protocol makes a `ValsetRequest`, the request is essentially a messaging mechanism to determine which block all validators should submit signatures over. Finally, validators sign the `validator set`, `powers`, and `Ethereum addresses` of the entire validator set at the height of a `Valset` and submit that signature with this message. + +If a sufficient number of validators (66% of voting power): +- have set Ethereum addresses and, +- submit `ValsetConfirm` messages with their signatures, +it is then possible for anyone to view these signatures in the chain store and submit them to Ethereum to update the validator set. +```protobuf +message MsgValsetConfirm { + // Unique number referencing the `ValSet`. + uint64 nonce = 1; + // Orchestrator `celes1` account address. + string orchestrator = 2; + // Ethereum address, associated to the orchestrator, used to sign the `ValSet` + // message. + string eth_address = 3; + // The `ValSet` message signature. + string signature = 4; +} + +``` + +### ValSetRequest Handling +`ValSetRequest`s are created at the `EndBlocker` function: +```go +func EndBlocker(ctx sdk.Context, k keeper.Keeper) { + ... +} +``` + +#### Get latest valset and unbonding height +We start by getting the latest valset, unbonding height and also initializing the power difference between valsets. +```go + latestValset := k.GetLatestValset(ctx) + lastUnbondingHeight := k.GetLastUnBondingBlockHeight(ctx) + + significantPowerDiff := false +``` + +#### Check if there was a signification power difference between valsets +If the previous valset is not null, then we had a previous set of validators defining a certain power. +We check if the current valset power is significantly different from the previous one. If so, we set the `significantPowerDiff` to true. + +The significance of power difference is calculated using a pre-defined constant. Currently, it is `0.05`. +For more information on the normalization of power, check: +https://github.com/celestiaorg/celestia-app/blob/df46d122da5f1fab1bd99bfb2bfcf9002f5bc154/x/qgb/types/validator.go#L101 + +#### Create a ValSet +Finally, if one of the following conditions hold: +- There was no valsets already committed to. +- The power difference between the previous valsets and the current one is significant. +- A validator started unbonding in the current block height. +We set a new valset request to be signed by the network and ultimately submitted to the QGB contracts. +```go + if (latestValset == nil) || (lastUnbondingHeight == uint64(ctx.BlockHeight())) || significantPowerDiff { + // if the conditions are true, put in a new validator set request to be signed and submitted to Ethereum + k.SetValsetRequest(ctx) + } +``` + +### ValSetConfirm Processing +Upon receiving a `MsgValSetConfirm`, we go for the following: + +#### ValSet check +We start off by checking if the `ValSet` referenced by the provided `nonce` exists. If so, we get it. If not, we return an error: +```go + valset := k.GetValset(ctx, msg.Nonce) + if valset == nil { + return nil, sdkerrors.Wrap(types.ErrInvalid, "couldn't find valset") + } +``` + +#### Check the address and signature +Next, we check the orchestrator address: +```go +orchaddr, err := sdk.AccAddressFromBech32(msg.Orchestrator) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalid, "acc address invalid") + } +``` + +Then, we verify if the signature is well-formed, and it is signed using a private key whose address is the one sent in the request: +```go + err = k.confirmHandlerCommon(ctx, msg.EthAddress, msg.Orchestrator, msg.Signature) + if err != nil { + return nil, err + } + // persist signature + if k.GetValsetConfirm(ctx, msg.Nonce, orchaddr) != nil { + return nil, sdkerrors.Wrap(types.ErrDuplicate, "signature duplicate") + } +``` + +The `confirmHandlerCommon` is an internal function that provides common code for processing signatures: +```go +func (k msgServer) confirmHandlerCommon(ctx sdk.Context, ethAddress string, orchestrator string, signature string) error { + _, err := hex.DecodeString(signature) + if err != nil { + return sdkerrors.Wrap(types.ErrInvalid, "signature decoding") + } + + submittedEthAddress, err := types.NewEthAddress(ethAddress) + if err != nil { + return sdkerrors.Wrap(types.ErrInvalid, "invalid eth address") + } + + orchaddr, err := sdk.AccAddressFromBech32(orchestrator) + if err != nil { + return sdkerrors.Wrap(types.ErrInvalid, "acc address invalid") + } + validator, found := k.GetOrchestratorValidator(ctx, orchaddr) + if !found { + return sdkerrors.Wrap(types.ErrUnknown, "validator") + } + if err := sdk.VerifyAddressFormat(validator.GetOperator()); err != nil { + return sdkerrors.Wrapf(err, "discovered invalid validator address for orchestrator %v", orchaddr) + } + + ethAddressFromStore, found := k.GetEthAddressByValidator(ctx, validator.GetOperator()) + if !found { + return sdkerrors.Wrap(types.ErrEmpty, "no eth address set for validator") + } + + if *ethAddressFromStore != *submittedEthAddress { + return sdkerrors.Wrap(types.ErrInvalid, "submitted eth address does not match delegate eth address") + } + return nil +} +``` +And, then check if the signature is a duplicate, i.e. whether another `ValSetConfirm` reflecting the same truth has already been committed to. + +#### Persist the ValSet confirm and emit an event +Lastly, we persist the `ValSetConfirm` message and broadcast an event: +```go + key := k.SetValsetConfirm(ctx, *msg) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, msg.Type()), + sdk.NewAttribute(types.AttributeKeyValsetConfirmKey, string(key)), + ), + ) +``` + +### SetOrchestratorAddress Processing +Upon receiving a `MsgSetOrchestratorAddress`, we go for the following: + +#### Basic validation +We start off by validating the parameters: +```go +// ensure that this passes validation, checks the key validity + err := msg.ValidateBasic() + if err != nil { + return nil, sdkerrors.Wrap(err, "Key not valid") + } + + ctx := sdk.UnwrapSDKContext(c) + + // check the following, all should be validated in validate basic + val, e1 := sdk.ValAddressFromBech32(msg.Validator) + orch, e2 := sdk.AccAddressFromBech32(msg.Orchestrator) + addr, e3 := types.NewEthAddress(msg.EthAddress) + if e1 != nil || e2 != nil || e3 != nil { + return nil, sdkerrors.Wrap(err, "Key not valid") + } + + // check that the validator does not have an existing key + _, foundExistingOrchestratorKey := k.GetOrchestratorValidator(ctx, orch) + _, foundExistingEthAddress := k.GetEthAddressByValidator(ctx, val) + + // ensure that the validator exists + if foundExistingOrchestratorKey || foundExistingEthAddress { + return nil, sdkerrors.Wrap(types.ErrResetDelegateKeys, val.String()) + } +``` + +Then, verify that neither keys is a duplicate: +```go + // check that neither key is a duplicate + delegateKeys := k.GetDelegateKeys(ctx) + for i := range delegateKeys { + if delegateKeys[i].EthAddress == addr.GetAddress() { + return nil, sdkerrors.Wrap(err, "Duplicate Ethereum Key") + } + if delegateKeys[i].Orchestrator == orch.String() { + return nil, sdkerrors.Wrap(err, "Duplicate Orchestrator Key") + } + } +``` + +#### Persist the Orchestrator and Ethereum address and emit an event +Lastly, we persist the orchestrator validator address: +```go + k.SetOrchestratorValidator(ctx, val, orch) +``` + +Then, we set the corresponding Ethereum address: +```go + k.SetEthAddressForValidator(ctx, val, *addr) +``` + +And finally, emit an event: +```go + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, msg.Type()), + sdk.NewAttribute(types.AttributeKeySetOperatorAddr, orch.String()), + ), + ) +``` + +## Status +Accepted + +## References + +- {reference link} diff --git a/docs/architecture/ADR-003-QGB-DataCommitment.md b/docs/architecture/ADR-003-QGB-DataCommitment.md new file mode 100644 index 0000000000..93a6259316 --- /dev/null +++ b/docs/architecture/ADR-003-QGB-DataCommitment.md @@ -0,0 +1,124 @@ +# ADR 002: Overview + +## Changelog + +- {date}: {changelog} + +## Context +To accommodate the requirements of the [Quantum Gravity Bridge](https://github.com/celestiaorg/quantum-gravity-bridge/blob/master/ethereum/solidity/src/QuantumGravityBridge.sol), We will need to add support for `DataCommitment`s messages, i.e. commitments generated over a set of blocks to attest their existence. + +## Decision +Add the `DataCommitmentConfirm` type of messages in order to attest that a set of blocks has been finalized. + +## Detailed Design +To accommodate the QGB, validators need a way to submit signatures for a data commitments so that relayers can easily find them and submit them to the bridged chain. To do this, we will introduce `MsgDataCommitmentConfirm` messages. This latter will be persisted for the sole reason of slashing. If not for that, a P2P network would do the job. + + +Data commitment messages attest that a certain set of blocks have been committed to in the Celestia chain. These commitments are used to update the data commitment checkpoint defined in the Ethereum smart contract of the QGB. + +Thus, they will contain the commitments along the signatures and will be used to check if an attestation has been signed by 2/3+ of the network validators and can be committed to the bridge contract. + +#### MsgDataCommitmentConfirm +`MsgDataCommitmentConfirm` describe a data commitment for a set of blocks signed by an orchestrator. +```protobuf +message MsgDataCommitmentConfirm { + // Signature over the commitment, the range of blocks, the validator address + // and the Ethereum address. + string signature = 1; + // Orchestrator account address who will be signing the message. + string validator_address = 2; + // Hex `0x` encoded Ethereum public key that will be used by this validator on + // Ethereum. + string eth_address = 3; + // Merkle root over a merkle tree containing the data roots of a set of + // blocks. + string commitment = 4; + // First block defining the ordered set of blocks used to create the + // commitment. + int64 begin_block = 5; + // Last block defining the ordered set of blocks used to create the + // commitment. + int64 end_block = 6; +} +``` + +### Data commitment message processing +When handling a `MsgDataCommitmentConfirm`, we go for the following: + +#### Verify the signature +We start off by verifying if the signature is well-formed, and return an error if not: +```go + sigBytes, err := hex.DecodeString(msg.Signature) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalid, "signature decoding") + } +``` +This is done first as the whole concept revolves around signing commitments. Thus, if a signature is mal-formed, there is no need to continue. + +#### Verify addresses +Then, we verify the provided address and check if an orchestrator exists for the provided address: +```go + validatorAddress, err := sdk.AccAddressFromBech32(msg.ValidatorAddress) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalid, "validator address invalid") + } + validator, found := k.GetOrchestratorValidator(ctx, validatorAddress) + if !found { + return nil, sdkerrors.Wrap(types.ErrUnknown, "validator") + } + if err := sdk.VerifyAddressFormat(validator.GetOperator()); err != nil { + return nil, sdkerrors.Wrapf(err, "discovered invalid validator address for validator %v", validatorAddress) + } +``` + +#### Verify Ethereum address and check signature +Next, we verify the Ethereum address and check if it was used to create the signature: +```go +ethAddress, err := types.NewEthAddress(msg.EthAddress) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalid, "invalid eth address") + } + err = types.ValidateEthereumSignature([]byte(msg.Commitment), sigBytes, *ethAddress) + if err != nil { + return nil, + sdkerrors.Wrap( + types.ErrInvalid, + fmt.Sprintf( + "signature verification failed expected sig by %s with checkpoint %s found %s", + ethAddress, + msg.Commitment, + msg.Signature, + ), + ) + } + ethAddressFromStore, found := k.GetEthAddressByValidator(ctx, validator.GetOperator()) + if !found { + return nil, sdkerrors.Wrap(types.ErrEmpty, "no eth address set for validator") + } + if *ethAddressFromStore != *ethAddress { + return nil, sdkerrors.Wrap(types.ErrInvalid, "submitted eth address does not match delegate eth address") + } +``` + +#### Set the data commitment confirm and send event +After checking that the message is valid, the addresses are correct and the signature is legit, we proceed to persist this data commitment confirm message: +```go + k.SetDataCommitmentConfirm(ctx, *msg) +``` +Then, we continue to broadcast an event containing the message: +```go + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, msg.Type()), + sdk.NewAttribute(types.AttributeKeyDataCommitmentConfirmKey, msg.String()), + ), + ) +``` + +## Status +Accepted + +## References + +- {reference link} diff --git a/proto/qgb/genesis.proto b/proto/qgb/genesis.proto index 1b294f3b27..84430acaed 100644 --- a/proto/qgb/genesis.proto +++ b/proto/qgb/genesis.proto @@ -11,15 +11,15 @@ option go_package = "github.com/celestiaorg/celestia-app/x/qgb/types"; message Params { option (gogoproto.stringer) = false; - uint64 data_commitment_window = 1; + uint64 data_commitment_window = 1; } -// GenesisState struct, containing all persistant data required by the Gravity module -message GenesisState { - Params params = 1; -} +// GenesisState struct, containing all persistant data required by the Gravity +// module +message GenesisState { Params params = 1; } -// GravityCounters contains the many noces and counters required to maintain the bridge state in the genesis +// GravityCounters contains the many noces and counters required to maintain the +// bridge state in the genesis message GravityNonces { // the nonce of the last generated validator set uint64 latest_valset_nonce = 1; diff --git a/proto/qgb/msgs.proto b/proto/qgb/msgs.proto index c57583879a..94033e196c 100644 --- a/proto/qgb/msgs.proto +++ b/proto/qgb/msgs.proto @@ -8,16 +8,20 @@ option go_package = "github.com/celestiaorg/celestia-app/x/qgb/types"; // Msg defines the state transitions possible for QGB service Msg { - // ValsetConfirm allows the validators to submit their signatures over the validator set. + // ValsetConfirm allows the validators to submit their signatures over the + // validator set. rpc ValsetConfirm(MsgValsetConfirm) returns (MsgValsetConfirmResponse) { option (google.api.http).post = "/qgb/valset_confirm"; } - // DataCommitmentConfirm allows the validators to submit a confirmation for a data commitment. - rpc DataCommitmentConfirm(MsgDataCommitmentConfirm) returns (MsgDataCommitmentConfirmResponse) { + // DataCommitmentConfirm allows the validators to submit a confirmation for a + // data commitment. + rpc DataCommitmentConfirm(MsgDataCommitmentConfirm) + returns (MsgDataCommitmentConfirmResponse) { option (google.api.http).post = "/qgb/data_commitment_confirm"; } // SetOrchestratorAddress allows to set the orchestrator address - rpc SetOrchestratorAddress(MsgSetOrchestratorAddress) returns (MsgSetOrchestratorAddressResponse) { + rpc SetOrchestratorAddress(MsgSetOrchestratorAddress) + returns (MsgSetOrchestratorAddressResponse) { option (google.api.http).post = "/qgb/set_orchestrator_address"; } } @@ -29,13 +33,13 @@ service Msg { message MsgSetOrchestratorAddress { // The validator field is a celesvaloper1... string (i.e. sdk.ValAddress) // that references a validator in the active set - string validator = 1; + string validator = 1; // The orchestrator field is a celes1... string (i.e. sdk.AccAddress) that // references the key that is being delegated to string orchestrator = 2; - // This is a hex encoded 0x Ethereum public key that will be used by this validator - // on Ethereum - string eth_address = 3; + // This is a hex encoded 0x Ethereum public key that will be used by this + // validator on Ethereum + string eth_address = 3; } // MsgSetOrchestratorAddressResponse @@ -57,10 +61,15 @@ message MsgSetOrchestratorAddressResponse {} // chain store and submit them to Ethereum to update the validator set // ------------- message MsgValsetConfirm { - uint64 nonce = 1; + // Unique number referencing the `ValSet`. + uint64 nonce = 1; + // Orchestrator `celes1` account address. string orchestrator = 2; - string eth_address = 3; - string signature = 4; + // Ethereum address, associated to the orchestrator, used to sign the `ValSet` + // message. + string eth_address = 3; + // The `ValSet` message signature. + string signature = 4; } // MsgValsetConfirmResponse describes the response returned after the submission @@ -69,11 +78,22 @@ message MsgValsetConfirmResponse {} // MsgDataCommitmentConfirm describes a data commitment for a set of blocks. message MsgDataCommitmentConfirm { + // Signature over the commitment, the range of blocks, the validator address + // and the Ethereum address. string signature = 1; + // Orchestrator account address who will be signing the message. string validator_address = 2; + // Hex `0x` encoded Ethereum public key that will be used by this validator on + // Ethereum. string eth_address = 3; + // Merkle root over a merkle tree containing the data roots of a set of + // blocks. string commitment = 4; + // First block defining the ordered set of blocks used to create the + // commitment. int64 begin_block = 5; + // Last block defining the ordered set of blocks used to create the + // commitment. int64 end_block = 6; } diff --git a/proto/qgb/query.proto b/proto/qgb/query.proto index 3c260044c5..90d976c6e1 100644 --- a/proto/qgb/query.proto +++ b/proto/qgb/query.proto @@ -11,109 +11,133 @@ option go_package = "github.com/celestiaorg/celestia-app/x/qgb/types"; // Query defines the gRPC querier service. service Query { - // DataCommitmentConfirm Queries the data commitment confirm by the commitment and the validator address - rpc DataCommitmentConfirm(QueryDataCommitmentConfirmRequest) returns (QueryDataCommitmentConfirmResponse) { - option (google.api.http).get = "/qgb/data_commitment/confirm/address/{address}/commitment/{commitment}"; + // DataCommitmentConfirm Queries the data commitment confirm by the commitment + // and the validator address + rpc DataCommitmentConfirm(QueryDataCommitmentConfirmRequest) + returns (QueryDataCommitmentConfirmResponse) { + option (google.api.http).get = "/qgb/data_commitment/confirm/address/" + "{address}/commitment/{commitment}"; } - // DataCommitmentConfirmsByValidator Queries data commitment confirms by validator address - rpc DataCommitmentConfirmsByValidator(QueryDataCommitmentConfirmsByValidatorRequest) returns (QueryDataCommitmentConfirmsByValidatorResponse) { - option (google.api.http).get = "/qgb/data_commitment/confirms/address/{address}"; + // DataCommitmentConfirmsByValidator Queries data commitment confirms by + // validator address + rpc DataCommitmentConfirmsByValidator( + QueryDataCommitmentConfirmsByValidatorRequest) + returns (QueryDataCommitmentConfirmsByValidatorResponse) { + option (google.api.http).get = + "/qgb/data_commitment/confirms/address/{address}"; } - // DataCommitmentConfirms Queries data commitment confirms by the actual commitment - rpc DataCommitmentConfirmsByCommitment(QueryDataCommitmentConfirmsByCommitmentRequest) returns (QueryDataCommitmentConfirmsByCommitmentResponse) { - option (google.api.http).get = "/qgb/data_commitment/confirms/commitment/{commitment}"; + // DataCommitmentConfirms Queries data commitment confirms by the actual + // commitment + rpc DataCommitmentConfirmsByCommitment( + QueryDataCommitmentConfirmsByCommitmentRequest) + returns (QueryDataCommitmentConfirmsByCommitmentResponse) { + option (google.api.http).get = + "/qgb/data_commitment/confirms/commitment/{commitment}"; } - // DataCommitmentConfirmsByRange Queries data commitment confirms by a block range - rpc DataCommitmentConfirmsByRange(QueryDataCommitmentConfirmsByRangeRequest) returns (QueryDataCommitmentConfirmsByRangeResponse) { - option (google.api.http).get = "/qgb/data_commitment/confirms/begin_block/{begin_block}/end_block/{end_block}"; + // DataCommitmentConfirmsByRange Queries data commitment confirms by a block + // range + rpc DataCommitmentConfirmsByRange(QueryDataCommitmentConfirmsByRangeRequest) + returns (QueryDataCommitmentConfirmsByRangeResponse) { + option (google.api.http).get = "/qgb/data_commitment/confirms/begin_block/" + "{begin_block}/end_block/{end_block}"; } // ValsetConfirm Queries ValSetConfirm - rpc ValsetConfirm(QueryValsetConfirmRequest) returns (QueryValsetConfirmResponse) { + rpc ValsetConfirm(QueryValsetConfirmRequest) + returns (QueryValsetConfirmResponse) { option (google.api.http).get = "/qgb/valset/confirm"; } // ValsetConfirmsByNonce - rpc ValsetConfirmsByNonce(QueryValsetConfirmsByNonceRequest) returns (QueryValsetConfirmsByNonceResponse) { + rpc ValsetConfirmsByNonce(QueryValsetConfirmsByNonceRequest) + returns (QueryValsetConfirmsByNonceResponse) { option (google.api.http).get = "/qgb/confirms/{nonce}"; } // GetDelegateKeyByOrchestrator Queries delegate key by orchestrator - rpc GetDelegateKeyByOrchestrator(QueryGetDelegateKeysByOrchestratorAddress) returns (QueryGetDelegateKeyByOrchestratorResponse) { + rpc GetDelegateKeyByOrchestrator(QueryGetDelegateKeysByOrchestratorAddress) + returns (QueryGetDelegateKeyByOrchestratorResponse) { option (google.api.http).get = "/qgb/query_delegate_keys_by_orchestrator"; } // this line is used by starport scaffolding # 2 } // QueryValsetConfirmsByNonceRequest -message QueryValsetConfirmsByNonceRequest { - uint64 nonce = 1; -} +message QueryValsetConfirmsByNonceRequest { uint64 nonce = 1; } // QueryValsetConfirmsByNonceResponse message QueryValsetConfirmsByNonceResponse { - repeated MsgValsetConfirm confirms = 1 [(gogoproto.nullable) = false]; + repeated MsgValsetConfirm confirms = 1 [ (gogoproto.nullable) = false ]; } // QueryValsetConfirmRequest ValSet confirm query request message QueryValsetConfirmRequest { - uint64 nonce = 1; + uint64 nonce = 1; string address = 2; } // QueryValsetConfirmResponse ValSet confirm query response -message QueryValsetConfirmResponse { - MsgValsetConfirm confirm = 1; -} +message QueryValsetConfirmResponse { MsgValsetConfirm confirm = 1; } -// QueryGetDelegateKeysByOrchestratorAddress Delegate keys by orchestrator address query request +// QueryGetDelegateKeysByOrchestratorAddress Delegate keys by orchestrator +// address query request message QueryGetDelegateKeysByOrchestratorAddress { string orchestrator_address = 1; } -// QueryGetDelegateKeyByOrchestratorResponse Delegate keys by orchestrator address query response +// QueryGetDelegateKeyByOrchestratorResponse Delegate keys by orchestrator +// address query response message QueryGetDelegateKeyByOrchestratorResponse { string validator_address = 1; - string eth_address = 2; + string eth_address = 2; } -// QueryDataCommitmentConfirmsRequest Data commitment confirm by commitment and validator address request +// QueryDataCommitmentConfirmsRequest Data commitment confirm by commitment and +// validator address request message QueryDataCommitmentConfirmRequest { string commitment = 1; string address = 2; } -// QueryDataCommitmentConfirmsResponse Data commitment confirm by commitment and validator address response +// QueryDataCommitmentConfirmsResponse Data commitment confirm by commitment and +// validator address response message QueryDataCommitmentConfirmResponse { MsgDataCommitmentConfirm confirm = 1; } -// QueryDataCommitmentConfirmsRequest Data commitment confirms by commitment request +// QueryDataCommitmentConfirmsRequest Data commitment confirms by commitment +// request message QueryDataCommitmentConfirmsByCommitmentRequest { string commitment = 1; } -// QueryDataCommitmentConfirmsResponse Data commitment confirms by commitment response +// QueryDataCommitmentConfirmsResponse Data commitment confirms by commitment +// response message QueryDataCommitmentConfirmsByCommitmentResponse { - repeated MsgDataCommitmentConfirm confirms = 1 [(gogoproto.nullable) = false]; + repeated MsgDataCommitmentConfirm confirms = 1 + [ (gogoproto.nullable) = false ]; } -// QueryDataCommitmentConfirmsByRangeRequest Data commitment confirms by range request +// QueryDataCommitmentConfirmsByRangeRequest Data commitment confirms by range +// request message QueryDataCommitmentConfirmsByRangeRequest { int64 begin_block = 1; int64 end_block = 2; } -// QueryDataCommitmentConfirmsByRangeResponse Data commitment confirms by range response +// QueryDataCommitmentConfirmsByRangeResponse Data commitment confirms by range +// response message QueryDataCommitmentConfirmsByRangeResponse { - repeated MsgDataCommitmentConfirm confirms = 1 [(gogoproto.nullable) = false]; + repeated MsgDataCommitmentConfirm confirms = 1 + [ (gogoproto.nullable) = false ]; } -// QueryDataCommitmentConfirmsByValidatorRequest Data commitment confirms by validator address request -message QueryDataCommitmentConfirmsByValidatorRequest { - string address = 1; -} +// QueryDataCommitmentConfirmsByValidatorRequest Data commitment confirms by +// validator address request +message QueryDataCommitmentConfirmsByValidatorRequest { string address = 1; } -// QueryDataCommitmentConfirmsByValidatorResponse Data commitment confirms by validator address response +// QueryDataCommitmentConfirmsByValidatorResponse Data commitment confirms by +// validator address response message QueryDataCommitmentConfirmsByValidatorResponse { - repeated MsgDataCommitmentConfirm confirms = 1 [(gogoproto.nullable) = false]; + repeated MsgDataCommitmentConfirm confirms = 1 + [ (gogoproto.nullable) = false ]; } // this line is used by starport scaffolding # 3 diff --git a/proto/qgb/types.proto b/proto/qgb/types.proto index 1e001cd6f2..15ec8e89f6 100644 --- a/proto/qgb/types.proto +++ b/proto/qgb/types.proto @@ -5,7 +5,9 @@ option go_package = "github.com/celestiaorg/celestia-app/x/qgb/types"; // BridgeValidator represents a validator's ETH address and its power message BridgeValidator { - uint64 power = 1; + // Voting power of the validator. + uint64 power = 1; + // Ethereum address that will be used by the validator to sign messages. string ethereum_address = 2; } @@ -13,7 +15,10 @@ message BridgeValidator { // maintains an ETH key to sign messages, these are used to check signatures on // ETH because of the significant gas savings message Valset { - uint64 nonce = 1; - repeated BridgeValidator members = 2 [(gogoproto.nullable) = false]; - uint64 height = 3; -} \ No newline at end of file + // Unique number referencing the `ValSet`. + uint64 nonce = 1; + // List of BridgeValidator containing the current validator set. + repeated BridgeValidator members = 2 [ (gogoproto.nullable) = false ]; + // Current chain height + uint64 height = 3; +} diff --git a/x/qgb/keeper/keeper_valset.go b/x/qgb/keeper/keeper_valset.go index e30aa499da..9e5d60cd65 100644 --- a/x/qgb/keeper/keeper_valset.go +++ b/x/qgb/keeper/keeper_valset.go @@ -135,7 +135,7 @@ func (k Keeper) GetValsets(ctx sdk.Context) (out []types.Valset) { } // GetLatestValset returns the latest validator set in store. This is different -// from the CurrrentValset because this one has been saved and is therefore *the* valset +// from the CurrentValset because this one has been saved and is therefore *the* valset // for this nonce. GetCurrentValset shows you what could be, if you chose to save it, this function // shows you what is the latest valset that was saved. func (k Keeper) GetLatestValset(ctx sdk.Context) (out *types.Valset) { @@ -152,7 +152,7 @@ func (k Keeper) SetLastUnBondingBlockHeight(ctx sdk.Context, unbondingBlockHeigh } // GetLastUnBondingBlockHeight returns the last unbonding block height, returns zero if not set, this is not -// saved or loaded ing enesis and is reset to zero on chain upgrade +// saved or loaded in genesis and is reset to zero on chain upgrade func (k Keeper) GetLastUnBondingBlockHeight(ctx sdk.Context) uint64 { store := ctx.KVStore(k.storeKey) bytes := store.Get([]byte(types.LastUnBondingBlockHeight))