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: define the turn for submitting attestation #191

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deployment/localup/localup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ function generate_genesis() {
sed -i -e "s/\"challenge_count_per_block\": \"1\"/\"challenge_count_per_block\": \"5\"/g" ${workspace}/.local/validator${i}/config/genesis.json
sed -i -e "s/\"challenge_keep_alive_period\": \"300\"/\"challenge_keep_alive_period\": \"50\"/g" ${workspace}/.local/validator${i}/config/genesis.json
sed -i -e "s/\"heartbeat_interval\": \"1000\"/\"heartbeat_interval\": \"100\"/g" ${workspace}/.local/validator${i}/config/genesis.json
sed -i -e "s/\"attestation_inturn_interval\": \"120\"/\"attestation_inturn_interval\": \"10\"/g" ${workspace}/.local/validator${i}/config/genesis.json
sed -i -e "s/\"time_iota_ms\": \"1000\"/\"time_iota_ms\": \"10\"/g" ${workspace}/.local/validator${i}/config/genesis.json
sed -i -e "s/\"discontinue_confirm_period\": \"604800\"/\"discontinue_confirm_period\": \"15\"/g" ${workspace}/.local/validator${i}/config/genesis.json
done
Expand Down
59 changes: 50 additions & 9 deletions e2e/tests/challenge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func (s *ChallengeTestSuite) TestNormalAttest() {

valBitset := s.calculateValidatorBitSet(height, s.ValidatorBLS.PubKey().String())

msgAttest := challengetypes.NewMsgAttest(user.GetAddr(), event.ChallengeId, event.ObjectId, primarySp.String(),
msgAttest := challengetypes.NewMsgAttest(s.Challenger.GetAddr(), event.ChallengeId, event.ObjectId, primarySp.String(),
challengetypes.CHALLENGE_SUCCEED, user.GetAddr().String(), valBitset.Bytes(), nil)
toSign := msgAttest.GetBlsSignBytes()

Expand All @@ -188,12 +188,33 @@ func (s *ChallengeTestSuite) TestNormalAttest() {
}
msgAttest.VoteAggSignature = voteAggSignature

txRes = s.SendTxBlock(msgAttest, user)
// wait to its turn
for {
queryRes, err := s.Client.ChallengeQueryClient.InturnAttestationSubmitter(context.Background(), &challengetypes.QueryInturnAttestationSubmitterRequest{})
s.Require().NoError(err)

s.T().Logf("current submitter %s, interval: %d - %d", queryRes.BlsPubKey,
queryRes.SubmitInterval.Start, queryRes.SubmitInterval.End)

if queryRes.BlsPubKey == hex.EncodeToString(s.ValidatorBLS.GetPrivKey().PubKey().Bytes()) {
break
}
}

// submit attest
txRes = s.SendTxBlock(msgAttest, s.Challenger)
s.Require().True(txRes.Code == 0)

queryRes, err := s.Client.ChallengeQueryClient.LatestAttestedChallenge(context.Background(), &challengetypes.QueryLatestAttestedChallengeRequest{})
queryRes, err := s.Client.ChallengeQueryClient.LatestAttestedChallenges(context.Background(), &challengetypes.QueryLatestAttestedChallengesRequest{})
s.Require().NoError(err)
s.Require().True(queryRes.ChallengeId == event.ChallengeId)
found := false
for _, challengeId := range queryRes.ChallengeIds {
if challengeId == event.ChallengeId {
found = true
break
}
}
s.Require().True(found)
}

func (s *ChallengeTestSuite) TestHeartbeatAttest() {
Expand All @@ -202,7 +223,6 @@ func (s *ChallengeTestSuite) TestHeartbeatAttest() {
}

heartbeatInterval := uint64(100)
user := s.GenAndChargeAccounts(1, 1000000)[0]

var event challengetypes.EventStartChallenge
found := false
Expand Down Expand Up @@ -236,7 +256,7 @@ func (s *ChallengeTestSuite) TestHeartbeatAttest() {

valBitset := s.calculateValidatorBitSet(height, s.ValidatorBLS.PubKey().String())

msgAttest := challengetypes.NewMsgAttest(user.GetAddr(), event.ChallengeId, event.ObjectId,
msgAttest := challengetypes.NewMsgAttest(s.Challenger.GetAddr(), event.ChallengeId, event.ObjectId,
event.SpOperatorAddress, challengetypes.CHALLENGE_FAILED, "", valBitset.Bytes(), nil)
toSign := msgAttest.GetBlsSignBytes()

Expand All @@ -246,12 +266,33 @@ func (s *ChallengeTestSuite) TestHeartbeatAttest() {
}
msgAttest.VoteAggSignature = voteAggSignature

txRes := s.SendTxBlock(msgAttest, user)
// wait to its turn
for {
queryRes, err := s.Client.ChallengeQueryClient.InturnAttestationSubmitter(context.Background(), &challengetypes.QueryInturnAttestationSubmitterRequest{})
s.Require().NoError(err)

s.T().Logf("current submitter %s, interval: %d - %d", queryRes.BlsPubKey,
queryRes.SubmitInterval.Start, queryRes.SubmitInterval.End)

if queryRes.BlsPubKey == hex.EncodeToString(s.ValidatorBLS.GetPrivKey().PubKey().Bytes()) {
break
}
}

// submit attest
txRes := s.SendTxBlock(msgAttest, s.Challenger)
s.Require().True(txRes.Code == 0)

queryRes, err := s.Client.ChallengeQueryClient.LatestAttestedChallenge(context.Background(), &challengetypes.QueryLatestAttestedChallengeRequest{})
queryRes, err := s.Client.ChallengeQueryClient.LatestAttestedChallenges(context.Background(), &challengetypes.QueryLatestAttestedChallengesRequest{})
s.Require().NoError(err)
s.Require().True(queryRes.ChallengeId == event.ChallengeId)
found = false
for _, challengeId := range queryRes.ChallengeIds {
if challengeId == event.ChallengeId {
found = true
break
}
}
s.Require().True(found)
}

func (s *ChallengeTestSuite) TestFailedAttest_ChallengeExpired() {
Expand Down
6 changes: 6 additions & 0 deletions proto/greenfield/challenge/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,10 @@ message Params {

// Heartbeat interval, based on challenge id, defines the frequency of heartbeat attestation.
uint64 heartbeat_interval = 10 [(gogoproto.moretags) = "yaml:\"heartbeat_interval\""];

// The time duration for each submitter to submit attestations in turn.
uint64 attestation_inturn_interval = 11 [(gogoproto.moretags) = "yaml:\"attestation_inturn_interval\""];

// The number of kept attested challenge ids, which can be queried by clients.
uint64 attestation_kept_count = 12 [(gogoproto.moretags) = "yaml:\"attestation_kept_count\""];
}
33 changes: 26 additions & 7 deletions proto/greenfield/challenge/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ service Query {
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/greenfield/challenge/params";
}
// Queries the latest attested challenge id.
rpc LatestAttestedChallenge(QueryLatestAttestedChallengeRequest) returns (QueryLatestAttestedChallengeResponse) {
// Queries the latest attested challenge ids.
rpc LatestAttestedChallenges(QueryLatestAttestedChallengesRequest) returns (QueryLatestAttestedChallengesResponse) {
option (google.api.http).get = "/greenfield/challenge/latest_attested_challenge";
}
// Queries the inturn challenger.
rpc InturnAttestationSubmitter(QueryInturnAttestationSubmitterRequest) returns (QueryInturnAttestationSubmitterResponse) {
option (google.api.http).get = "/greenfield/challenge/inturn_attestation_submitter";
}

// this line is used by starport scaffolding # 2
}
Expand All @@ -36,12 +40,27 @@ message QueryParamsResponse {
Params params = 1 [(gogoproto.nullable) = false];
}

// QueryParamsRequest is request type for the Query/LatestAttestedChallenge RPC method.
message QueryLatestAttestedChallengeRequest {}
// QueryLatestAttestedChallengesRequest is request type for the Query/LatestAttestedChallenges RPC method.
message QueryLatestAttestedChallengesRequest {}

// QueryLatestAttestedChallengesResponse is response type for the Query/LatestAttestedChallenges RPC method.
message QueryLatestAttestedChallengesResponse {
repeated uint64 challengeIds = 1;
}

// QueryInturnAttestationSubmitterRequest is request type for the Query/InturnAttestationSubmitter RPC method.
message QueryInturnAttestationSubmitterRequest {}

// QueryInturnAttestationSubmitterResponse is response type for the Query/InturnAttestationSubmitter RPC method.
message QueryInturnAttestationSubmitterResponse {
string bls_pub_key = 1;
SubmitInterval submit_interval = 2;
}

// QueryParamsResponse is response type for the Query/LatestAttestedChallenge RPC method.
message QueryLatestAttestedChallengeResponse {
uint64 challengeId = 1;
// SubmitInterval holds start and end (exclusive) (i.e., [start, end)) time of in turn attestation.
message SubmitInterval {
uint64 start = 1;
uint64 end = 2;
}

// this line is used by starport scaffolding # 3
13 changes: 13 additions & 0 deletions proto/greenfield/challenge/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,16 @@ message Challenge {
// The height at which the challenge will be expired.
uint64 expired_height = 2;
}

// AttestedChallengeIds stored fixed number of the latest attested challenge ids.
// To use the storage more efficiently, a circular queue will be constructed using these fields.
message AttestedChallengeIds {
// The fixed number of challenge ids to save.
uint64 size = 1;

// The latest attested challenge ids.
repeated uint64 ids = 2;

// The cursor to retrieve data from the ids field.
int64 cursor = 3;
}
60 changes: 59 additions & 1 deletion x/challenge/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"

"github.com/bnb-chain/greenfield/x/challenge/types"
Expand All @@ -21,9 +22,66 @@ func GetQueryCmd(queryRoute string) *cobra.Command {
}

cmd.AddCommand(CmdQueryParams())
cmd.AddCommand(CmdLatestAttestedChallenge())
cmd.AddCommand(CmdLatestAttestedChallenges())
cmd.AddCommand(CmdInturnChallenger())

// this line is used by starport scaffolding # 1

return cmd
}

func CmdLatestAttestedChallenges() *cobra.Command {
cmd := &cobra.Command{
Use: "latest-attested-challenges",
Short: "Query latest attested challenges",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) (err error) {

clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

params := &types.QueryLatestAttestedChallengesRequest{}

res, err := queryClient.LatestAttestedChallenges(cmd.Context(), params)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

func CmdInturnChallenger() *cobra.Command {
cmd := &cobra.Command{
Use: "inturn-attestation-submitter",
Short: "Query the inturn attestation submitter",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.InturnAttestationSubmitter(cmd.Context(), &types.QueryInturnAttestationSubmitterRequest{})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
43 changes: 0 additions & 43 deletions x/challenge/client/cli/query_latest_attested_challenge.go

This file was deleted.

10 changes: 2 additions & 8 deletions x/challenge/keeper/bls_signed_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"cosmossdk.io/errors"
"github.com/bits-and-blooms/bitset"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/prysmaticlabs/prysm/crypto/bls"

"github.com/bnb-chain/greenfield/x/challenge/types"
Expand All @@ -24,13 +24,7 @@ type BlsSignedMsg interface {
}

// verifySignature verifies whether the signature is valid or not.
func (k Keeper) verifySignature(ctx sdk.Context, signedMsg BlsSignedMsg) ([]string, error) {
historicalInfo, ok := k.stakingKeeper.GetHistoricalInfo(ctx, ctx.BlockHeight())
if !ok {
return nil, errors.Wrap(types.ErrInvalidVoteValidatorSet, "fail to get validators")
}
validators := historicalInfo.Valset

func (k Keeper) verifySignature(signedMsg BlsSignedMsg, validators []stakingtypes.Validator) ([]string, error) {
validatorsBitSet := bitset.From(signedMsg.GetVoteValidatorSet())
if validatorsBitSet.Count() > uint(len(validators)) {
return nil, errors.Wrap(types.ErrInvalidVoteValidatorSet, "number of validator set is larger than validators")
Expand Down
Loading