Skip to content

Commit

Permalink
feat(batching): add double batch signing evidence submission
Browse files Browse the repository at this point in the history
Closes: #459
  • Loading branch information
Thomasvdam committed Jan 14, 2025
1 parent 59dca71 commit 5d457f6
Show file tree
Hide file tree
Showing 18 changed files with 1,929 additions and 20 deletions.
9 changes: 8 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ func NewApp(
app.AccountKeeper.AddressCodec(),
runtime.ProvideCometInfoService(),
)
// If evidence needs to be handled for the app, set routes in router here and seal
// Evidence routes and router are set after instantiating SEDA keepers.
app.EvidenceKeeper = *evidenceKeeper

wasmDir := filepath.Join(homePath, wasmDirectory)
Expand Down Expand Up @@ -672,6 +672,7 @@ func NewApp(
appCodec,
runtime.NewKVStoreService(keys[batchingtypes.StoreKey]),
app.StakingKeeper,
app.SlashingKeeper,
app.WasmStorageKeeper,
app.PubKeyKeeper,
contractKeeper,
Expand All @@ -689,6 +690,12 @@ func NewApp(
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

// Create evidence router, add batching evidence route, seal it, and set it in the keeper.
evidenceRouter := evidencetypes.NewRouter()
evidenceRouter.AddRoute(batchingtypes.RouteBatchDoubleSign, batchingkeeper.NewBatchDoubleSignHandler(app.BatchingKeeper))
evidenceRouter.Seal()
app.EvidenceKeeper.SetRouter(evidenceRouter)

/* =================================================== */
/* TRANSFER STACK */
/* =================================================== */
Expand Down
40 changes: 40 additions & 0 deletions proto/sedachain/batching/v1/evidence.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
syntax = "proto3";
package sedachain.batching.v1;

import "amino/amino.proto";
import "cosmos_proto/cosmos.proto";

option go_package = "github.com/sedaprotocol/seda-chain/x/batching/types";

// BatchDoubleSign implements the Evidence interface and defines evidence of
// double signing a batch for a given proving scheme.
message BatchDoubleSign {
option (amino.name) = "sedachain/DoubleSign";

// batch_number is the number of the batch that the validator double signed.
uint64 batch_number = 1;

// block_height is the height of the block which includes the batch that the
// validator double signed.
int64 block_height = 2;

// operator_address is the operator address of the validator committing the
// double signing.
string operator_address = 3
[ (cosmos_proto.scalar) = "cosmos.AddressString" ];

// validator_root is the hex-encoded root of the validator merkle tree.
string validator_root = 4;

// data_result_root is the hex-encoded root of the data result merkle tree.
string data_result_root = 5;

// proving_metadata_hash is the hex-encoded hash of the proving metadata.
string proving_metadata_hash = 6;

// signature is the hex-encoded signature of the validator.
string signature = 7;

// proving_scheme_index is the SEDA key index of the proving scheme.
uint32 proving_scheme_index = 8;
}
132 changes: 132 additions & 0 deletions x/batching/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package cli

import (
"fmt"
"strconv"

"github.com/spf13/cobra"

evidencetypes "cosmossdk.io/x/evidence/types"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/sedaprotocol/seda-chain/app/utils"
"github.com/sedaprotocol/seda-chain/x/batching/types"
)

const (
// FlagProvingScheme defines a flag to specify the proving scheme.
FlagProvingScheme = "proving-scheme"
)

// GetTxCmd returns the CLI transaction commands for this module
func GetTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: types.ModuleName,
Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName),
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
cmd.AddCommand(
SubmitBatchDoubleSign(),
)
return cmd
}

func SubmitBatchDoubleSign() *cobra.Command {
cmd := &cobra.Command{
Use: "submit-double-sign [batch_height] [block_height] [operator_address] [validator_root] [data_result_root] [proving_metadata_hash] [signature]",
Short: "Submit evidence of a validator double signing a batch",
Args: cobra.ExactArgs(7),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

submitter := clientCtx.GetFromAddress().String()
if submitter == "" {
return fmt.Errorf("set the from address using --from flag")
}

batchNumber, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("invalid batch number: %s", args[0])
}

blockHeight, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return fmt.Errorf("invalid block height: %s", args[1])
}

operatorAddr := args[2]
valAddr := sdk.ValAddress(operatorAddr)
if valAddr.Empty() {
return fmt.Errorf("invalid operator address: %s", args[2])
}

validatorRoot := args[3]
if validatorRoot == "" {
return fmt.Errorf("invalid validator root: %s", args[3])
}

dataResultRoot := args[4]
if dataResultRoot == "" {
return fmt.Errorf("invalid data result root: %s", args[4])
}

provingMetadataHash := args[5]
if provingMetadataHash == "" {
return fmt.Errorf("invalid proving metadata hash: %s", args[5])
}

signature := args[6]
if signature == "" {
return fmt.Errorf("invalid signature: %s", args[6])
}

// It's easier to use a uint64 as it's the return type of the strconv.ParseUint function
var provingSchemeIndex uint64
provingSchemeInput, _ := cmd.Flags().GetString(FlagProvingScheme)
if provingSchemeInput != "" {
provingSchemeIndex, err = strconv.ParseUint(provingSchemeInput, 10, 32)
if err != nil || provingSchemeIndex != uint64(utils.SEDAKeyIndexSecp256k1) {
return fmt.Errorf("invalid proving scheme index: %s", provingSchemeInput)
}
} else {
provingSchemeIndex = uint64(utils.SEDAKeyIndexSecp256k1)
}

evidence := &types.BatchDoubleSign{
BatchNumber: batchNumber,
BlockHeight: blockHeight,
OperatorAddress: operatorAddr,
ValidatorRoot: validatorRoot,
DataResultRoot: dataResultRoot,
ProvingMetadataHash: provingMetadataHash,
Signature: signature,
ProvingSchemeIndex: uint32(provingSchemeIndex),
}

evidencePacked, err := codectypes.NewAnyWithValue(evidence)
if err != nil {
return err
}

msg := &evidencetypes.MsgSubmitEvidence{
Submitter: submitter,
Evidence: evidencePacked,
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

cmd.Flags().String(FlagProvingScheme, "0", fmt.Sprintf("proving scheme index [%d]", utils.SEDAKeyIndexSecp256k1))
flags.AddTxFlagsToCmd(cmd)
return cmd
}
14 changes: 1 addition & 13 deletions x/batching/keeper/endblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,7 @@ func (k Keeper) ConstructBatch(ctx sdk.Context) (types.Batch, types.DataResultTr
provingMetaDataHash = hasher.Sum(nil)
}

// Compute the batch ID, which is defined as
// keccak256(batch_number, block_height, validator_root, results_root, proving_metadata_hash)
var hashContent []byte
hashContent = binary.BigEndian.AppendUint64(hashContent, newBatchNum)
//nolint:gosec // G115: We shouldn't get negative block heights anyway.
hashContent = binary.BigEndian.AppendUint64(hashContent, uint64(ctx.BlockHeight()))
hashContent = append(hashContent, valRoot...)
hashContent = append(hashContent, superRoot...)
hashContent = append(hashContent, provingMetaDataHash...)

hasher := sha3.NewLegacyKeccak256()
hasher.Write(hashContent)
batchID := hasher.Sum(nil)
batchID := types.ComputeBatchID(newBatchNum, ctx.BlockHeight(), valRoot, superRoot, provingMetaDataHash)

return types.Batch{
BatchNumber: newBatchNum,
Expand Down
Loading

0 comments on commit 5d457f6

Please sign in to comment.