diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e6d4f478..3fea0b34 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,6 @@ # [Choice] Debian OS version (use bullseye on local arm64/Apple Silicon): buster, bullseye ARG VARIANT="bullseye" -FROM golang:1.20.4 +FROM golang:1.21 ARG DEBIAN_FRONTEND=noninteractive @@ -14,10 +14,6 @@ RUN apt-get -y install --no-install-recommends vim # WASM dependencies + Rustup RUN apt-get -y install --no-install-recommends binaryen -# Cosmos dependencies -# Sadly Ignite + Cosmos SDK v0.47.x is broken atm -# RUN curl https://get.ignite.com/cli@nightly! | bash - # Go language extension dependencies RUN go install github.com/cweill/gotests/gotests@v1.6.0 RUN go install github.com/fatih/gomodifytags@v1.16.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a5f11908..67828f1d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,8 @@ on: permissions: contents: read + repository-projects: read + packages: read concurrency: group: ci-${{ github.ref }}-tests @@ -18,6 +20,9 @@ concurrency: jobs: build: runs-on: ubuntu-latest + env: + GOPRIVATE: github.com/sedaprotocol/vrf-go + PAT: ${{ secrets.PAT }} strategy: matrix: arch: [amd64, arm64] @@ -46,6 +51,9 @@ jobs: env: GOOS: ${{ matrix.targetos }} GOARCH: ${{ matrix.arch }} + - name: Configure private token + run: | + git config --global url."https://${PAT}@github.com/".insteadOf "https://github.com/" - name: Compile if: steps.cache-binaries.outputs.cache-hit != 'true' && env.GIT_DIFF run: | @@ -54,6 +62,9 @@ jobs: tests: runs-on: ubuntu-latest + env: + GOPRIVATE: github.com/sedaprotocol/vrf-go + PAT: ${{ secrets.PAT }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v4 @@ -62,6 +73,7 @@ jobs: check-latest: true cache: true cache-dependency-path: go.sum + - run: git config --global url.https://${PAT}@github.com/.insteadOf https://github.com/ - uses: technote-space/get-diff-action@v6.1.2 id: git_diff with: @@ -84,20 +96,29 @@ jobs: test-e2e: runs-on: ubuntu-latest + env: + GOPRIVATE: github.com/sedaprotocol/vrf-go + USERNAME: hacheigriega + PAT: ${{ secrets.PAT }} timeout-minutes: 10 steps: - uses: actions/setup-go@v4 with: go-version: "1.21" - uses: actions/checkout@v4 + - run: git config --global url.https://${GITHUB_TOKEN}@github.com/.insteadOf https://github.com/ - uses: technote-space/get-diff-action@v6.0.1 with: PATTERNS: | **/**.go go.mod go.sum - - name: Build e2e Docker Image - run: make docker-build-e2e - - name: Test E2E - run: make test-e2e - + - name: Create .netrc file + run: | + echo "machine github.com" > ${GITHUB_WORKSPACE}/.netrc + echo " login ${USERNAME}" >> ${GITHUB_WORKSPACE}/.netrc + echo " password ${PAT}" >> ${GITHUB_WORKSPACE}/.netrc + chmod 600 ${GITHUB_WORKSPACE}/.netrc + - name: Test e2e + run: | + make test-e2e diff --git a/DEVELOPING.md b/DEVELOPING.md index 916bbc70..a7d191db 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -160,7 +160,15 @@ To see test coverage: make cover-html ``` -To run end-to-end tests: +To run end-to-end tests, you first need to create a file `.netrc` containing GitHub credentials in the project root. This enables an access to the private repositories during the Docker build process. The `.netrc` file should look as follows: ```bash +machine github.com + login + password +``` + +Change the permissions of `.netrc` and run e2e with the following commands: +```bash +chmod 600 .netrc make test-e2e ``` diff --git a/Makefile b/Makefile index a0ebcdba..ba398822 100644 --- a/Makefile +++ b/Makefile @@ -212,7 +212,9 @@ cover-html: test-unit-cover @go tool cover -html=$(TEST_COVERAGE_PROFILE) docker-build-e2e: - @docker build -t sedaprotocol/seda-chaind-e2e -f dockerfiles/Dockerfile.e2e . + @docker build \ + -t sedaprotocol/seda-chaind-e2e \ + -f dockerfiles/Dockerfile.e2e . .PHONY: cover-html run-tests $(TEST_TARGETS) test test-race docker-build-e2e diff --git a/app/app.go b/app/app.go index e30ae833..7bd10845 100644 --- a/app/app.go +++ b/app/app.go @@ -51,6 +51,7 @@ import ( servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/std" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/mempool" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" @@ -97,7 +98,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" - "github.com/cosmos/cosmos-sdk/x/staking" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/gogoproto/proto" @@ -128,6 +128,7 @@ import ( "github.com/sedaprotocol/seda-chain/x/randomness/keeper" randomnesskeeper "github.com/sedaprotocol/seda-chain/x/randomness/keeper" randomnesstypes "github.com/sedaprotocol/seda-chain/x/randomness/types" + customstaking "github.com/sedaprotocol/seda-chain/x/staking" wasmstorage "github.com/sedaprotocol/seda-chain/x/wasm-storage" wasmstoragekeeper "github.com/sedaprotocol/seda-chain/x/wasm-storage/keeper" wasmstoragetypes "github.com/sedaprotocol/seda-chain/x/wasm-storage/types" @@ -264,7 +265,6 @@ type App struct { mm *module.Manager bmm module.BasicManager - // sm is the simulation manager sm *module.SimulationManager configurator module.Configurator } @@ -303,7 +303,12 @@ func NewApp( std.RegisterLegacyAminoCodec(legacyAmino) std.RegisterInterfaces(interfaceRegistry) + // TO-DO // building BaseApp + nonceMempool := mempool.NewSenderNonceMempool() + mempoolOpt := baseapp.SetMempool(nonceMempool) + baseAppOptions = append(baseAppOptions, mempoolOpt) + bApp := baseapp.NewBaseApp(Name, logger, db, txConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) bApp.SetVersion(version.Version) @@ -313,12 +318,14 @@ func NewApp( keys := storetypes.NewKVStoreKeys( authtypes.StoreKey, authz.ModuleName, banktypes.StoreKey, stakingtypes.StoreKey, crisistypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, ibcexported.StoreKey, upgradetypes.StoreKey, - feegrant.StoreKey, evidencetypes.StoreKey, circuittypes.StoreKey, - ibctransfertypes.StoreKey, icahosttypes.StoreKey, capabilitytypes.StoreKey, group.StoreKey, - icacontrollertypes.StoreKey, consensusparamtypes.StoreKey, wasmstoragetypes.StoreKey, - wasmtypes.StoreKey, randomnesstypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, + feegrant.StoreKey, evidencetypes.StoreKey, circuittypes.StoreKey, group.StoreKey, + capabilitytypes.StoreKey, ibcexported.StoreKey, ibctransfertypes.StoreKey, ibcfeetypes.StoreKey, + wasmtypes.StoreKey, icahosttypes.StoreKey, + icacontrollertypes.StoreKey, + wasmstoragetypes.StoreKey, randomnesstypes.StoreKey, ) + tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -561,13 +568,11 @@ func NewApp( panic(fmt.Sprintf("error while reading wasm config: %s", err)) } - var wasmOpts []wasmkeeper.Option - randomnessQueryPlugin := keeper.NewQuerierImpl(app.RandomnessKeeper) queryPluginOpt := wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{ Custom: keeper.SeedQueryPlugin(randomnessQueryPlugin), }) - wasmOpts = append([]wasm.Option{queryPluginOpt}, wasmOpts...) + wasmOpts := []wasmkeeper.Option{queryPluginOpt} // The last arguments can contain custom message handlers, and custom query handlers, // if we want to allow any custom callbacks @@ -670,7 +675,7 @@ func NewApp( mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, nil), slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil, app.interfaceRegistry), distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil), - staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, nil), + customstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, nil), upgrade.NewAppModule(app.UpgradeKeeper, app.AccountKeeper.AddressCodec()), evidence.NewAppModule(app.EvidenceKeeper), consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), @@ -687,10 +692,10 @@ func NewApp( crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, nil), // always be last to make sure that it checks for all invariants and not only part of them ) - // // bmm defines the module BasicManager is in charge of setting up basic, - // // non-dependant module elements, such as codec registration and genesis verification. - // // By default it is composed of all the module from the module manager. - // // Additionally, app module basics can be overwritten by passing them as argument. + // BasicModuleManager defines the module BasicManager is in charge of setting up basic, + // non-dependant module elements, such as codec registration and genesis verification. + // By default it is composed of all the module from the module manager. + // Additionally, app module basics can be overwritten by passing them as argument. app.bmm = module.NewBasicManagerFromManager( app.mm, map[string]module.AppModuleBasic{ @@ -794,7 +799,6 @@ func NewApp( vestingtypes.ModuleName, consensusparamtypes.ModuleName, circuittypes.ModuleName, - wasmstoragetypes.ModuleName, // ibc modules capabilitytypes.ModuleName, ibctransfertypes.ModuleName, @@ -861,6 +865,27 @@ func NewApp( app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) + // Pseudorandomness beacon + app.SetPrepareProposal( + randomnesskeeper.PrepareProposalHandler( + txConfig, + homePath, + cast.ToString(appOpts.Get("priv_validator_key_file")), + app.RandomnessKeeper, + app.AccountKeeper, + app.StakingKeeper, + nonceMempool, + ), + ) + + app.SetProcessProposal( + randomnesskeeper.ProcessProposalHandler( + txConfig, + app.RandomnessKeeper, + app.StakingKeeper, + ), + ) + if loadLatest { if err := app.LoadLatestVersion(); err != nil { tmos.Exit(err.Error()) diff --git a/app/params/encoding.go b/app/params/encoding.go new file mode 100644 index 00000000..0ebeb8a8 --- /dev/null +++ b/app/params/encoding.go @@ -0,0 +1,17 @@ +package params + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" +) + +// EncodingConfig specifies the concrete encoding types to use for a given app. +// This is provided for compatibility between protobuf and amino implementations. +type EncodingConfig struct { + InterfaceRegistry types.InterfaceRegistry + Codec codec.Codec + Marshaler codec.Codec + TxConfig client.TxConfig + Amino *codec.LegacyAmino +} diff --git a/cmd/seda-chaind/cmd/init.go b/cmd/seda-chaind/cmd/init.go index cd4e356c..e3aca466 100644 --- a/cmd/seda-chaind/cmd/init.go +++ b/cmd/seda-chaind/cmd/init.go @@ -12,6 +12,7 @@ import ( "github.com/spf13/cobra" cfg "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/crypto/secp256k1" cmtos "github.com/cometbft/cometbft/libs/os" "github.com/cometbft/cometbft/privval" "github.com/cometbft/cometbft/types" @@ -64,7 +65,21 @@ func readInMnemonic(cmd *cobra.Command) (string, error) { return mnemonic, nil } -// If validator key file exists, create and save an empty validator state file. +func generateValidatorWithSecp256k1Key(config *cfg.Config) error { + pvKeyFile := config.PrivValidatorKeyFile() + if err := os.MkdirAll(filepath.Dir(pvKeyFile), 0o777); err != nil { + return fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvKeyFile), err) + } + pvStateFile := config.PrivValidatorStateFile() + if err := os.MkdirAll(filepath.Dir(pvStateFile), 0o777); err != nil { + return fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvStateFile), err) + } + + pv := privval.NewFilePV(secp256k1.GenPrivKey(), config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()) + pv.Save() + return nil +} + func configureValidatorFiles(config *cfg.Config) error { keyFilePath := config.PrivValidatorKeyFile() if err := os.MkdirAll(filepath.Dir(keyFilePath), 0o777); err != nil { diff --git a/cmd/seda-chaind/cmd/init_cmds.go b/cmd/seda-chaind/cmd/init_cmds.go index 48512216..a386f11e 100644 --- a/cmd/seda-chaind/cmd/init_cmds.go +++ b/cmd/seda-chaind/cmd/init_cmds.go @@ -12,6 +12,7 @@ import ( cfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/libs/cli" + cmtos "github.com/cometbft/cometbft/libs/os" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -81,6 +82,16 @@ func newNetworkCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Comma initHeight = 1 } + // Before initializing the node, if a mnemonic is not given and + // the private validator key file does not exist, create a validator + // using a key generated on secp256k1. + if len(mnemonic) == 0 && !cmtos.FileExists(config.PrivValidatorKeyFile()) { + err = generateValidatorWithSecp256k1Key(config) + if err != nil { + return err + } + } + // initialize node nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic) if err != nil { @@ -179,12 +190,23 @@ $ %s init join moniker --network devnet return fmt.Errorf("unsupported network type: %s", network) } - // configure validator files + // TO-DO remove (See: https://github.com/sedaprotocol/seda-chain/pull/76#issuecomment-1762303200) + // If validator key file exists, create and save an empty validator state file. err = configureValidatorFiles(config) if err != nil { return err } + // Before initializing the node, if a mnemonic is not given and + // the private validator key file does not exist, create a validator + // using a key generated on secp256k1. + if len(mnemonic) == 0 && !cmtos.FileExists(config.PrivValidatorKeyFile()) { + err = generateValidatorWithSecp256k1Key(config) + if err != nil { + return err + } + } + // initialize the node nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic) if err != nil { diff --git a/dockerfiles/Dockerfile.e2e b/dockerfiles/Dockerfile.e2e index f4c34fd0..7dcacd80 100644 --- a/dockerfiles/Dockerfile.e2e +++ b/dockerfiles/Dockerfile.e2e @@ -15,9 +15,13 @@ ARG GIT_COMMIT RUN apk add --no-cache \ ca-certificates \ build-base \ - linux-headers + linux-headers \ + git # Download go dependencies +COPY .netrc /root/ +RUN chmod 600 /root/.netrc + WORKDIR /seda-chain COPY go.mod go.sum ./ RUN --mount=type=cache,target=/root/.cache/go-build \ diff --git a/docs/static/openapi.yml b/docs/static/openapi.yml index cbc6528a..51b4c9ab 100644 --- a/docs/static/openapi.yml +++ b/docs/static/openapi.yml @@ -34685,7 +34685,7 @@ paths: This rpc is deprecated now that IBC has its own replacement - (https://github.com/cosmos/ibc-go/blob/2c880a22e9f9cc75f62b527ca94aa75ce1106001/proto/ibc/core/client/v1/query.proto#L54) + (https://github.com/cosmos/ibc-go/v8/blob/2c880a22e9f9cc75f62b527ca94aa75ce1106001/proto/ibc/core/client/v1/query.proto#L54) operationId: CosmosUpgradeV1Beta1UpgradedConsensusState responses: '200': diff --git a/e2e/e2e_gov_test.go b/e2e/e2e_gov_test.go index 5d6b4216..f0afe23d 100644 --- a/e2e/e2e_gov_test.go +++ b/e2e/e2e_gov_test.go @@ -4,12 +4,14 @@ import ( "bytes" "context" "encoding/hex" + "encoding/json" "fmt" "os" "path/filepath" "strconv" "time" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" @@ -75,7 +77,7 @@ func (s *IntegrationTestSuite) execWasmStorageStoreOverlay( opt = append(opt, withKeyValue(flagSummary, summary)) opt = append(opt, withKeyValue(flagDeposit, "10000000aseda")) opt = append(opt, withKeyValue(flagAuthority, authtypes.NewModuleAddress("gov").String())) - opts := applyOptions(c.id, opt) + opts := applyTxOptions(c.id, opt) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -122,7 +124,7 @@ func (s *IntegrationTestSuite) execGovVoteYes( ) { opt = append(opt, withKeyValue(flagFees, fees)) opt = append(opt, withKeyValue(flagFrom, from)) - opts := applyOptions(c.id, opt) + opts := applyTxOptions(c.id, opt) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -155,3 +157,54 @@ func (s *IntegrationTestSuite) execGovVoteYes( 5*time.Second, ) } + +func (s *IntegrationTestSuite) execGetSeedQuery( + c *chain, + valIdx int, + proxyContractAddr string, + expectErr bool, + opt ...flagOption, +) { + opts := applyQueryOptions(c.id, opt) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // seda-chaind query wasm contract-state smart $PROXY_CONTRACT_ADDRESS '{"query_seed_request":{}}' --node $RPC_URL --output json + command := []string{ + binary, + queryCommand, + wasmtypes.ModuleName, + "contract-state", + "smart", + proxyContractAddr, + `{"query_seed_request":{}}`, + } + for flag, value := range opts { + command = append(command, fmt.Sprintf("--%s=%v", flag, value)) + } + + s.T().Logf("getting seed from contract %s on chain %s", proxyContractAddr, c.id) + + s.executeQuery(ctx, c, command, valIdx, s.validateGetSeedResponse(false)) +} + +func (s *IntegrationTestSuite) validateGetSeedResponse(expectEmpty bool) func([]byte, []byte) bool { + return func(stdOut []byte, stdErr []byte) bool { + var getSeedResponse struct { + Data struct { + BlockHeight int `json:"block_height"` + Seed string `json:"seed"` + } `json:"data"` + } + + err := json.Unmarshal(stdOut, &getSeedResponse) + s.Require().NoError(err) + if expectEmpty { + s.Require().Empty(getSeedResponse.Data.Seed) + } else { + s.Require().NotEmpty(getSeedResponse.Data.Seed) // TO-DO better seed check + } + return true + } +} diff --git a/e2e/e2e_register_proxy_contract_test.go b/e2e/e2e_register_proxy_contract_test.go index 6798bf55..ac394ea5 100644 --- a/e2e/e2e_register_proxy_contract_test.go +++ b/e2e/e2e_register_proxy_contract_test.go @@ -37,8 +37,12 @@ func (s *IntegrationTestSuite) testInstantiateAndRegisterProxyContract() { _, err = sdktypes.AccAddressFromBech32(res.Address) s.Require().NoError(err) + s.Require().NotEmpty(res.Address) - return res.Address != "" + s.execGetSeedQuery(s.chain, 0, res.Address, false) + s.Require().NoError(err) + + return true }, 30*time.Second, 5*time.Second, @@ -70,7 +74,7 @@ func (s *IntegrationTestSuite) execInstantiateAndRegisterProxyContract( opt = append(opt, withKeyValue(flagAuthority, authtypes.NewModuleAddress("gov").String())) - opts := applyOptions(c.id, opt) + opts := applyTxOptions(c.id, opt) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -118,7 +122,7 @@ func (s *IntegrationTestSuite) execWasmStore( ) { opt = append(opt, withKeyValue(flagFees, fees)) opt = append(opt, withKeyValue(flagFrom, from)) - opts := applyOptions(c.id, opt) + opts := applyTxOptions(c.id, opt) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() diff --git a/e2e/e2e_setup_test.go b/e2e/e2e_setup_test.go index 26d86604..5454b87d 100644 --- a/e2e/e2e_setup_test.go +++ b/e2e/e2e_setup_test.go @@ -12,14 +12,14 @@ import ( "testing" "time" - tmconfig "github.com/cometbft/cometbft/config" - tmjson "github.com/cometbft/cometbft/libs/json" - rpchttp "github.com/cometbft/cometbft/rpc/client/http" "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" "github.com/spf13/viper" "github.com/stretchr/testify/suite" + tmconfig "github.com/cometbft/cometbft/config" + rpchttp "github.com/cometbft/cometbft/rpc/client/http" + "cosmossdk.io/math" evidencetypes "cosmossdk.io/x/evidence/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -27,6 +27,7 @@ import ( "github.com/cosmos/cosmos-sdk/server" srvconfig "github.com/cosmos/cosmos-sdk/server/config" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) @@ -73,6 +74,7 @@ type IntegrationTestSuite struct { dkrNet *dockertest.Network valResources map[string][]*dockertest.Resource endpoint string + grpcEndpoint string } func TestIntegrationTestSuite(t *testing.T) { @@ -174,7 +176,7 @@ func (s *IntegrationTestSuite) initGenesis(c *chain) { config.Moniker = validator.moniker genFilePath := config.GenesisFile() - appGenState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFilePath) + appGenState, appGenesis, err := genutiltypes.GenesisStateFromGenFile(genFilePath) s.Require().NoError(err) var evidenceGenState evidencetypes.GenesisState @@ -222,10 +224,15 @@ func (s *IntegrationTestSuite) initGenesis(c *chain) { appGenState[genutiltypes.ModuleName], err = cdc.MarshalJSON(&genUtilGenState) s.Require().NoError(err) - genDoc.AppState, err = json.MarshalIndent(appGenState, "", " ") + appGenesis.AppState, err = json.MarshalIndent(appGenState, "", " ") + s.Require().NoError(err) + + genutil.ExportGenesisFile(appGenesis, genFilePath) + + err = appGenesis.ValidateAndComplete() s.Require().NoError(err) - bz, err := tmjson.MarshalIndent(genDoc, "", " ") + bz, err := json.MarshalIndent(appGenesis, "", " ") s.Require().NoError(err) // write the updated genesis file to each validator. diff --git a/e2e/e2e_wasm_storage_test.go b/e2e/e2e_wasm_storage_test.go index 41b0ba7b..acc8cea5 100644 --- a/e2e/e2e_wasm_storage_test.go +++ b/e2e/e2e_wasm_storage_test.go @@ -91,7 +91,7 @@ func (s *IntegrationTestSuite) execWasmStorageStoreDataRequest( opt = append(opt, withKeyValue(flagFrom, from)) opt = append(opt, withKeyValue(flagWasmType, wasmType)) - opts := applyOptions(c.id, opt) + opts := applyTxOptions(c.id, opt) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() diff --git a/e2e/e2e_exec_test.go b/e2e/exec_commands_test.go similarity index 75% rename from e2e/e2e_exec_test.go rename to e2e/exec_commands_test.go index 024950dc..1023f8a4 100644 --- a/e2e/e2e_exec_test.go +++ b/e2e/exec_commands_test.go @@ -47,7 +47,7 @@ func withKeyValue(key string, value interface{}) flagOption { } } -func applyOptions(chainID string, options []flagOption) map[string]interface{} { +func applyTxOptions(chainID string, options []flagOption) map[string]interface{} { opts := map[string]interface{}{ flagKeyringBackend: "test", flagOutput: "json", @@ -65,6 +65,53 @@ func applyOptions(chainID string, options []flagOption) map[string]interface{} { return opts } +func applyQueryOptions(chainID string, options []flagOption) map[string]interface{} { + opts := map[string]interface{}{ + flagOutput: "json", + } + for _, apply := range options { + apply(opts) + } + return opts +} + +func (s *IntegrationTestSuite) executeQuery(ctx context.Context, c *chain, command []string, valIdx int, validation func([]byte, []byte) bool) { + s.T().Logf("executing command %s", command) + + if validation == nil { + validation = s.defaultExecValidation(s.chain, 0) + } + var ( + outBuf bytes.Buffer + errBuf bytes.Buffer + ) + exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{ + Context: ctx, + AttachStdout: true, + AttachStderr: true, + Container: s.valResources[c.id][valIdx].Container.ID, + User: "root", + Cmd: command, + }) + s.Require().NoError(err) + + err = s.dkrPool.Client.StartExec(exec.ID, docker.StartExecOptions{ + Context: ctx, + Detach: false, + OutputStream: &outBuf, + ErrorStream: &errBuf, + }) + s.Require().NoError(err) + + stdOut := outBuf.Bytes() + stdErr := errBuf.Bytes() + + if !validation(stdOut, stdErr) { + s.Require().FailNowf("Query execution validation failed", "stdout: %s, stderr: %s", + string(stdOut), string(stdErr)) + } +} + func (s *IntegrationTestSuite) executeTx(ctx context.Context, c *chain, command []string, valIdx int, validation func([]byte, []byte) bool) { s.T().Logf("executing command %s", command) @@ -102,7 +149,6 @@ func (s *IntegrationTestSuite) executeTx(ctx context.Context, c *chain, command } } -// TO-DO refactor func (s *IntegrationTestSuite) expectErrExecValidation(chain *chain, valIdx int, expectErr bool) func([]byte, []byte) bool { return func(stdOut []byte, stdErr []byte) bool { var txResp sdk.TxResponse diff --git a/e2e/genesis.go b/e2e/genesis.go index bf8f05d2..c3965ca9 100644 --- a/e2e/genesis.go +++ b/e2e/genesis.go @@ -7,14 +7,15 @@ import ( "cosmossdk.io/math" + cmttypes "github.com/cometbft/cometbft/types" + "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - - crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -46,6 +47,7 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, gl return fmt.Errorf("failed to unmarshal genesis state: %w", err) } + // modify AppState authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState) accs, err := authtypes.UnpackAccounts(authGenState.Accounts) if err != nil { @@ -106,6 +108,8 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, gl govparams := govv1.DefaultParams() votingPeriod := time.Duration(15) * time.Second govparams.VotingPeriod = &votingPeriod + expeditedVotingPeriod := time.Duration(10) * time.Second + govparams.ExpeditedVotingPeriod = &expeditedVotingPeriod govparams.MinDeposit = sdk.NewCoins(sdk.NewCoin(denom, math.NewInt(10000000))) govState := govv1.NewGenesisState(1, govparams) @@ -119,7 +123,21 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, gl if err != nil { return fmt.Errorf("failed to marshal application genesis state: %w", err) } - genDoc.AppState = appStateJSON - return genutil.ExportGenesisFile(genDoc, genFile) + // modify CometBFT consensus genesis + consensusParams := cmttypes.DefaultConsensusParams() + consensusParams.Validator.PubKeyTypes = []string{"secp256k1"} + + // collect modified data and overwrite genesis file + appGenesis := &genutiltypes.AppGenesis{ + ChainID: genDoc.ChainID, + AppState: appStateJSON, + Consensus: &genutiltypes.ConsensusGenesis{ + Validators: nil, + Params: consensusParams, + }, + InitialHeight: int64(1), + } + + return genutil.ExportGenesisFile(appGenesis, genFile) } diff --git a/e2e/validator.go b/e2e/validator.go index d23bcb58..1175500f 100644 --- a/e2e/validator.go +++ b/e2e/validator.go @@ -9,6 +9,7 @@ import ( "path/filepath" tmcfg "github.com/cometbft/cometbft/config" + "github.com/cometbft/cometbft/crypto/secp256k1" tmos "github.com/cometbft/cometbft/libs/os" "github.com/cometbft/cometbft/p2p" "github.com/cometbft/cometbft/privval" @@ -73,7 +74,6 @@ func (v *validator) init() error { config.SetRoot(v.configDir()) config.Moniker = v.moniker - // TO-DO use existing genesis, if exists? appState, err := json.MarshalIndent(app.ModuleBasics.DefaultGenesis(cdc), "", " ") if err != nil { return fmt.Errorf("failed to JSON encode app genesis state: %w", err) @@ -123,7 +123,9 @@ func (v *validator) createConsensusKey() error { return err } - filePV := privval.LoadOrGenFilePV(pvKeyFile, pvStateFile) + filePV := privval.NewFilePV(secp256k1.GenPrivKey(), config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()) + filePV.Save() + v.consensusKey = filePV.Key return nil diff --git a/go.mod b/go.mod index 81acdc61..1d8d52da 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/hyperledger/burrow v0.34.4 github.com/ory/dockertest/v3 v3.10.0 github.com/pkg/errors v0.9.1 + github.com/sedaprotocol/vrf-go v0.0.0-20231211075603-e5a17bb0b87c github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 @@ -57,7 +58,7 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/CosmWasm/wasmvm v1.5.0 // indirect github.com/DataDog/zstd v1.5.5 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/aws/aws-sdk-go v1.44.224 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -94,12 +95,13 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/cli v23.0.1+incompatible // indirect - github.com/docker/docker v23.0.1+incompatible // indirect + github.com/docker/docker v24.0.5+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/emicklei/dot v1.6.0 // indirect + github.com/ethereum/go-ethereum v1.13.5 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect @@ -114,7 +116,7 @@ require ( github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect diff --git a/go.sum b/go.sum index dc3b3b11..7f6fa938 100644 --- a/go.sum +++ b/go.sum @@ -241,8 +241,8 @@ github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -458,8 +458,8 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY= -github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= +github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -491,6 +491,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/ethereum/go-ethereum v1.13.5 h1:U6TCRciCqZRe4FPXmy1sMGxTfuk8P7u2UoinF3VbaFk= +github.com/ethereum/go-ethereum v1.13.5/go.mod h1:yMTu38GSuyxaYzQMViqNmQ1s3cE84abZexQmTgenWk0= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= @@ -564,8 +566,8 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -624,8 +626,9 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= +github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= @@ -1091,6 +1094,12 @@ github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71e github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/sedaprotocol/vrf-go v0.0.0-20231202231847-9ca3f58655e6 h1:GqAxxdvT0bteI0b0Sq3iPDMP6BGlymYjPHCOveK9KH4= +github.com/sedaprotocol/vrf-go v0.0.0-20231202231847-9ca3f58655e6/go.mod h1:cub/hpbOATCymOnKPJVOhuExFhhspWaOJW2nr/yzWUs= +github.com/sedaprotocol/vrf-go v0.0.0-20231211032335-c4a11d69429d h1:K3ttV/oBQlaO4grPIK9cy477HgiVHysMbsj94k4BQZc= +github.com/sedaprotocol/vrf-go v0.0.0-20231211032335-c4a11d69429d/go.mod h1:DEIXHk41VUzOMVbZnIApssPXtZ+2zrETDP7kJjGc1RM= +github.com/sedaprotocol/vrf-go v0.0.0-20231211075603-e5a17bb0b87c h1:PbSn7HpWeox6lqBu6Ba6YZS3On3euwn1BPz/egsnEgA= +github.com/sedaprotocol/vrf-go v0.0.0-20231211075603-e5a17bb0b87c/go.mod h1:DEIXHk41VUzOMVbZnIApssPXtZ+2zrETDP7kJjGc1RM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= diff --git a/proto/sedachain/randomness/v1/genesis.proto b/proto/sedachain/randomness/v1/genesis.proto new file mode 100644 index 00000000..06393829 --- /dev/null +++ b/proto/sedachain/randomness/v1/genesis.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package sedachain.randomness.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/sedaprotocol/seda-chain/x/randomness/types"; + +message GenesisState { + string seed = 1; +} diff --git a/proto/sedachain/randomness/v1/tx.proto b/proto/sedachain/randomness/v1/tx.proto new file mode 100644 index 00000000..643789e2 --- /dev/null +++ b/proto/sedachain/randomness/v1/tx.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; +package sedachain.randomness.v1; + +import "cosmos/msg/v1/msg.proto"; + +option go_package = "github.com/sedaprotocol/seda-chain/x/randomness/types"; + +service Msg { + rpc NewSeed(MsgNewSeed) + returns (MsgNewSeedResponse); +} + +message MsgNewSeed { + option (cosmos.msg.v1.signer) = "proposer"; + + string proposer = 1; + string pi = 2; // VRF proof + string beta = 3; // VRF hash +} + +message MsgNewSeedResponse {} diff --git a/scripts/local_setup.sh b/scripts/local_setup.sh index 3a0de02a..611fbecb 100755 --- a/scripts/local_setup.sh +++ b/scripts/local_setup.sh @@ -2,30 +2,49 @@ set -e set -x +BIN=./build/seda-chaind +CONFIG_PATH=$HOME/.seda-chain/config + +function add_key_and_account() { + local name=$1 + local amount=$2 + $BIN keys add $name --keyring-backend test + $BIN add-genesis-account $name $amount --keyring-backend test +} + # # Local Single-node Setup # # NOTE: Run this script from project root. # + +# build the binary make build -BIN=./build/seda-chaind +# reset the chain $BIN tendermint unsafe-reset-all -rm -rf ~/.seda-chain +rm -rf ~/.seda-chain || true + +# configure seda-chaind +$BIN config set client chain-id sedachain + +# initialize the chain $BIN init new node0 cat $HOME/.seda-chain/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="30s"' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json -cat $HOME/.seda-chain/config/genesis.json | jq '.app_state["gov"]["params"]["voting_period"]="30s"' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json +# cat $HOME/.seda-chain/config/genesis.json | jq '.app_state["gov"]["params"]["voting_period"]="30s"' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json cat $HOME/.seda-chain/config/genesis.json | jq '.app_state["gov"]["params"]["expedited_voting_period"]="15s"' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json +cat $HOME/.seda-chain/config/genesis.json | jq '.consensus["params"]["validator"]["pub_key_types"]=["secp256k1"]' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json -$BIN keys add satoshi --keyring-backend test -ADDR=$($BIN keys show satoshi --keyring-backend test -a) -$BIN add-genesis-account $ADDR 100000000000000000seda --keyring-backend test -$BIN gentx satoshi 10000000000000000seda --keyring-backend test +# update genesis +add_key_and_account "satoshi" "100000000000000000seda" +add_key_and_account "acc1" "100000000000000000seda" -$BIN keys add acc1 --keyring-backend test -ADDR=$($BIN keys show acc1 --keyring-backend test -a) -$BIN add-genesis-account $ADDR 100000000000000000seda --keyring-backend test +# create a default validator +$BIN gentx satoshi 10000000000000000seda --keyring-backend test +# collect genesis txns $BIN collect-gentxs -$BIN start + +# start the chain +$BIN start --log_level debug || echo "Failed to start the chain" diff --git a/scripts/testnet/README.md b/scripts/testnet/README.md new file mode 100644 index 00000000..730f15df --- /dev/null +++ b/scripts/testnet/README.md @@ -0,0 +1,11 @@ +## Testnet Deployment SCripts + +These scripts generate a genesis file and deploy chain across the nodes specified in the parameters. + +Make sure to first create a configuration file named config.sh using the template config_example.sh and populate it with the values reflecting your environment and desired deployment settings. + +Run in the following order, one by one: + +1. `create_genesis.sh` - Validates validator files for each node and creates a genesis file. +2. `add_wasm_state_to_genesis.sh` - Runs a chain, deploys Wasm contracts on it, and dumps the Wasm state, which is then added to a given genesis file. +3. `upload_and_start.sh` - Uploads and runs setup_node.sh on the nodes to process necessary setups. Then uploads the validator files and genesis and restarts the nodes. diff --git a/scripts/testnet/add_wasm_state_to_genesis.sh b/scripts/testnet/add_wasm_state_to_genesis.sh index 2235b5cc..59e66142 100755 --- a/scripts/testnet/add_wasm_state_to_genesis.sh +++ b/scripts/testnet/add_wasm_state_to_genesis.sh @@ -17,9 +17,11 @@ function download_contract_release() { mkdir -p $WASM_DIR function gh_curl() { + set +x curl -H "Authorization: token $GITHUB_TOKEN" \ -H "Accept: application/vnd.github.v3.raw" \ $@ + set -x } if [ "$CONTRACTS_VERSION" = "latest" ]; then @@ -35,10 +37,12 @@ function download_contract_release() { exit 1 fi; + set +x curl -sL --header "Authorization: token $GITHUB_TOKEN" \ --header 'Accept: application/octet-stream' \ https://$GITHUB_TOKEN:@api.github.com/repos/$repo/releases/assets/$asset_id \ --output-dir $WASM_DIR --output ${1} + set -x } # store_and_instantiate() stores and instantiates a contract and returns its address @@ -46,7 +50,7 @@ function download_contract_release() { # $1: Contract file name # $2: Initial state function store_and_instantiate() { - local TX_OUTPUT=$($BIN tx wasm store $WASM_DIR/$1 --from $ADDR --keyring-backend test --gas auto --gas-adjustment 1.2 --home $TMP_HOME -y --output json) + local TX_OUTPUT=$($BIN tx wasm store $WASM_DIR/$1 --from $ADDR --keyring-backend test --gas auto --gas-adjustment 1.2 --home $TMP_HOME --chain-id $TEMP_CHAIN_ID -y --output json) [[ -z "$TX_OUTPUT" ]] && { echo "failed to get tx output" ; exit 1; } local TX_HASH=$(echo $TX_OUTPUT | jq -r .txhash) sleep 10; @@ -55,12 +59,12 @@ function store_and_instantiate() { local CODE_ID=$(echo $STORE_TX_OUTPUT | jq -r '.events[] | select(.type | contains("store_code")).attributes[] | select(.key | contains("code_id")).value') [[ -z "$CODE_ID" ]] && { echo "failed to get code ID" ; exit 1; } - local INSTANTIATE_OUTPUT=$($BIN tx wasm instantiate $CODE_ID "$2" --no-admin --from $ADDR --keyring-backend test --label $CODE_ID --gas auto --gas-adjustment 1.2 --home $TMP_HOME -y --output json) + local INSTANTIATE_OUTPUT=$($BIN tx wasm instantiate $CODE_ID "$2" --no-admin --from $ADDR --keyring-backend test --label $CODE_ID --gas auto --gas-adjustment 1.2 --home $TMP_HOME --chain-id $TEMP_CHAIN_ID -y --output json) TX_HASH=$(echo "$INSTANTIATE_OUTPUT" | jq -r '.txhash') sleep 10; local INSTANTIATE_TX_OUTPUT=$($BIN query tx $TX_HASH --home $TMP_HOME --output json) - local CONTRACT_ADDRESS=$(echo $INSTANTIATE_TX_OUTPUT | jq -r '.logs[].events[] | select(.type=="instantiate") | .attributes[] | select(.key=="_contract_address") | .value') + local CONTRACT_ADDRESS=$(echo $INSTANTIATE_TX_OUTPUT | jq -r '.events[] | select(.type == "instantiate") | .attributes[] | select(.key == "_contract_address") | .value') [[ -z "$CONTRACT_ADDRESS" ]] && { echo "failed to get contract address for ${1}" ; exit 1; } echo $CONTRACT_ADDRESS @@ -86,16 +90,19 @@ download_contract_release proxy_contract.wasm download_contract_release staking.wasm download_contract_release data_requests.wasm +TEMP_CHAIN_ID=temp-seda-chain # # SCRIPT BEGINS - START CHAIN # -$BIN init new node0 --home $TMP_HOME +$BIN init new node0 --home $TMP_HOME --chain-id $TEMP_CHAIN_ID + +cat $TMP_HOME/config/genesis.json | jq '.consensus["params"]["validator"]["pub_key_types"]=["secp256k1"]' > $TMP_HOME/config/tmp_genesis.json && mv $TMP_HOME/config/tmp_genesis.json $TMP_HOME/config/genesis.json $BIN keys add deployer --home $TMP_HOME --keyring-backend test ADDR=$($BIN keys show deployer --home $TMP_HOME --keyring-backend test -a) $BIN add-genesis-account $ADDR 100000000000000000seda --home $TMP_HOME --keyring-backend test -$BIN gentx deployer 10000000000000000seda --home $TMP_HOME --keyring-backend test +$BIN gentx deployer 10000000000000000seda --home $TMP_HOME --keyring-backend test --chain-id $TEMP_CHAIN_ID $BIN collect-gentxs --home $TMP_HOME @@ -117,9 +124,9 @@ DR_ADDR=$(store_and_instantiate data_requests.wasm "$ARG") # Call SetStaking and SetDataRequests on Proxy contract to set circular dependency -$BIN tx wasm execute $PROXY_ADDR '{"set_staking":{"contract":"'$STAKING_ADDR'"}}' --from $ADDR --gas auto --gas-adjustment 1.2 --keyring-backend test --home $TMP_HOME -y +$BIN tx wasm execute $PROXY_ADDR '{"set_staking":{"contract":"'$STAKING_ADDR'"}}' --from $ADDR --gas auto --gas-adjustment 1.2 --keyring-backend test --home $TMP_HOME --chain-id $TEMP_CHAIN_ID -y sleep 10 -$BIN tx wasm execute $PROXY_ADDR '{"set_data_requests":{"contract":"'$DR_ADDR'"}}' --from $ADDR --gas auto --gas-adjustment 1.2 --keyring-backend test --home $TMP_HOME -y +$BIN tx wasm execute $PROXY_ADDR '{"set_data_requests":{"contract":"'$DR_ADDR'"}}' --from $ADDR --gas auto --gas-adjustment 1.2 --keyring-backend test --home $TMP_HOME --chain-id $TEMP_CHAIN_ID -y sleep 10 diff --git a/scripts/testnet/create_genesis.sh b/scripts/testnet/create_genesis.sh index 0a7bd422..90c89554 100755 --- a/scripts/testnet/create_genesis.sh +++ b/scripts/testnet/create_genesis.sh @@ -25,6 +25,7 @@ $BIN init new node0 --chain-id $CHAIN_ID cat $HOME/.seda-chain/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="180s"' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json cat $HOME/.seda-chain/config/genesis.json | jq '.app_state["gov"]["params"]["voting_period"]="180s"' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json cat $HOME/.seda-chain/config/genesis.json | jq '.app_state["gov"]["params"]["max_deposit_period"]="180s"' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json +cat $HOME/.seda-chain/config/genesis.json | jq '.consensus["params"]["validator"]["pub_key_types"]=["secp256k1"]' > $HOME/.seda-chain/config/tmp_genesis.json && mv $HOME/.seda-chain/config/tmp_genesis.json $HOME/.seda-chain/config/genesis.json # TO-DO? # - chain id @@ -66,7 +67,7 @@ for i in ${!MONIKERS[@]}; do # to output geneis file $BIN add-genesis-account $VALIDATOR_ADDRESS 500000000000000000seda - $BIN gentx ${MONIKERS[$i]} ${SELF_DELEGATION_AMOUNTS[$i]} --moniker=${MONIKERS[$i]} --keyring-backend=test --home $INDIVIDUAL_VAL_HOME_DIR --ip=${IPS[$i]} + $BIN gentx ${MONIKERS[$i]} ${SELF_DELEGATION_AMOUNTS[$i]} --moniker=${MONIKERS[$i]} --keyring-backend=test --home $INDIVIDUAL_VAL_HOME_DIR --ip=${IPS[$i]} --chain-id $CHAIN_ID cp -a $INDIVIDUAL_VAL_CONFIG_DIR/gentx/. $GENTX_DIR done diff --git a/testutil/testwasms/data_requests.wasm b/testutil/testwasms/data_requests.wasm new file mode 100644 index 00000000..eb8dada3 Binary files /dev/null and b/testutil/testwasms/data_requests.wasm differ diff --git a/testutil/testwasms/integration_tests.wasm b/testutil/testwasms/integration_tests.wasm new file mode 100644 index 00000000..4d484947 Binary files /dev/null and b/testutil/testwasms/integration_tests.wasm differ diff --git a/testutil/testwasms/proxy_contract.wasm b/testutil/testwasms/proxy_contract.wasm index 8cd4e255..5cd58d76 100644 Binary files a/testutil/testwasms/proxy_contract.wasm and b/testutil/testwasms/proxy_contract.wasm differ diff --git a/testutil/testwasms/staking.wasm b/testutil/testwasms/staking.wasm index 635b04ec..f0e60c18 100644 Binary files a/testutil/testwasms/staking.wasm and b/testutil/testwasms/staking.wasm differ diff --git a/x/randomness/genesis.go b/x/randomness/genesis.go new file mode 100644 index 00000000..dd8b2236 --- /dev/null +++ b/x/randomness/genesis.go @@ -0,0 +1,21 @@ +package randomness + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/sedaprotocol/seda-chain/x/randomness/keeper" + "github.com/sedaprotocol/seda-chain/x/randomness/types" +) + +// InitGenesis puts data from genesis state into store. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, data types.GenesisState) { + k.SetSeed(ctx, data.Seed) + +} + +// ExportGenesis extracts data from store to genesis state. +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) types.GenesisState { + return types.GenesisState{ + Seed: k.GetSeed(ctx), + } +} diff --git a/x/randomness/keeper/abci.go b/x/randomness/keeper/abci.go index ef809673..6ea6f11c 100644 --- a/x/randomness/keeper/abci.go +++ b/x/randomness/keeper/abci.go @@ -1,20 +1,275 @@ package keeper import ( + "bytes" + "context" "encoding/hex" - "strings" - "time" + "fmt" + "os" + "path/filepath" + + vrf "github.com/sedaprotocol/vrf-go" abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto" + cmtjson "github.com/cometbft/cometbft/libs/json" + "github.com/cometbft/cometbft/privval" - "github.com/cosmos/cosmos-sdk/telemetry" + "github.com/cosmos/cosmos-sdk/client" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/mempool" + txsigning "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/sedaprotocol/seda-chain/x/randomness/types" ) -func (k *Keeper) EndBlocker(ctx sdk.Context) []abci.ValidatorUpdate { - defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker) - k.SetSeed(ctx, strings.ToUpper(hex.EncodeToString(ctx.BlockHeader().AppHash))) - return nil +func PrepareProposalHandler( + txConfig client.TxConfig, + homePath string, + pvFile string, + keeper Keeper, + authKeeper types.AccountKeeper, + stakingKeeper types.StakingKeeper, + mempool mempool.Mempool, +) sdk.PrepareProposalHandler { + return func(ctx sdk.Context, req *abci.RequestPrepareProposal) (*abci.ResponsePrepareProposal, error) { + // TO-DO run DefaultProposalHandler.PrepareProposalHandler first? + + // alpha = (seed_{i-1} || timestamp) + prevSeed := keeper.GetSeed(ctx) + if prevSeed == "" { + panic("seed should never be empty") + } + timestamp, err := req.Time.MarshalBinary() + if err != nil { + return nil, err + } + alpha := append([]byte(prevSeed), timestamp...) + + // prepare secret key + secretKey, err := readPrivKey(filepath.Join(homePath, pvFile)) + if err != nil { + return nil, err + } + + // produce VRF proof + k256vrf := vrf.NewK256VRF() + pi, err := k256vrf.Prove(secretKey.Bytes(), alpha) + if err != nil { + return nil, err + } + + beta, err := k256vrf.ProofToHash(pi) + if err != nil { + return nil, err + } + + validator, err := stakingKeeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(req.ProposerAddress)) + if err != nil { + return nil, err + } + publicKey, err := validator.ConsPubKey() + if err != nil { + return nil, err + } + account := authKeeper.GetAccount(ctx, sdk.AccAddress(publicKey.Address().Bytes())) + + newSeedTx, _, err := encodeNewSeedTx(ctx, txConfig, secretKey, publicKey, account, &types.MsgNewSeed{ + Proposer: sdk.AccAddress(req.ProposerAddress).String(), + Pi: hex.EncodeToString(pi), + Beta: hex.EncodeToString(beta), + }) + if err != nil { + return nil, err + } + + // TO-DO mempool + // err = mempool.Insert(ctx, tx) + // if err != nil { + // return nil, err + // } + + // prepend to list of txs and return + res := new(abci.ResponsePrepareProposal) + res.Txs = append([][]byte{newSeedTx}, req.Txs...) + return res, nil + } +} + +func ProcessProposalHandler( + txConfig client.TxConfig, + keeper Keeper, + stakingKeeper types.StakingKeeper, +) sdk.ProcessProposalHandler { + return func(ctx sdk.Context, req *abci.RequestProcessProposal) (*abci.ResponseProcessProposal, error) { + msg, err := decodeNewSeedTx(txConfig, req.Txs[0]) + if err != nil { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err + } + + if msg.Proposer != string(sdk.AccAddress(req.ProposerAddress).String()) { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, + fmt.Errorf("the NewSeed transaction must be from the block proposer") + } + + // TO-DO run DefaultProposalHandler.ProcessProposalHandler first? + // TO-DO Validate()? + + // get block proposer's validator public key + validator, err := stakingKeeper.GetValidatorByConsAddr(ctx, sdk.ConsAddress(req.ProposerAddress)) + if err != nil { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err + } + publicKey, err := validator.ConsPubKey() + if err != nil { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err + } + + prevSeed := keeper.GetSeed(ctx) + if prevSeed == "" { + panic("seed should never be empty") + } + timestamp, err := req.Time.MarshalBinary() + if err != nil { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err + } + alpha := append([]byte(prevSeed), timestamp...) + + pi, err := hex.DecodeString(msg.Pi) + if err != nil { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err + } + + // verify VRF proof + k256vrf := vrf.NewK256VRF() + beta, err := k256vrf.Verify(publicKey.Bytes(), pi, alpha) + if err != nil { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err + } + + // sanity check + msgBeta, err := hex.DecodeString(msg.Beta) + if err != nil { + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err + } + if !bytes.Equal(beta, msgBeta) { + panic(err) + } + + return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil + } +} + +func encodeNewSeedTx(ctx sdk.Context, txConfig client.TxConfig, privKey crypto.PrivKey, pubKey cryptotypes.PubKey, account sdk.AccountI, msg *types.MsgNewSeed) ([]byte, sdk.Tx, error) { + txBuilder := txConfig.NewTxBuilder() + err := txBuilder.SetMsgs(msg) + if err != nil { + return nil, nil, err + } + + txBuilder.SetFeePayer(account.GetAddress()) + txBuilder.SetFeeAmount(sdk.NewCoins()) + txBuilder.SetGasLimit(200000) // TO-DO what number to put here? + + signerData := authsigning.SignerData{ + ChainID: ctx.ChainID(), + AccountNumber: account.GetAccountNumber(), + Sequence: account.GetSequence(), + PubKey: pubKey, + Address: account.GetAddress().String(), + } + + // TO-DO re-examine signing logic + + // For SIGN_MODE_DIRECT, calling SetSignatures calls setSignerInfos on + // TxBuilder under the hood, and SignerInfos is needed to generate the sign + // bytes. This is the reason for setting SetSignatures here, with a nil + // signature. + // + // Note: This line is not needed for SIGN_MODE_LEGACY_AMINO, but putting it + // also doesn't affect its generated sign bytes, so for code's simplicity + // sake, we put it here. + sig := txsigning.SignatureV2{ + PubKey: pubKey, + Data: &txsigning.SingleSignatureData{ + SignMode: txsigning.SignMode_SIGN_MODE_DIRECT, + Signature: nil, + }, + Sequence: account.GetSequence(), + } + + if err := txBuilder.SetSignatures(sig); err != nil { + return nil, nil, err + } + + bytesToSign, err := authsigning.GetSignBytesAdapter( + context.Background(), + txConfig.SignModeHandler(), + txsigning.SignMode_SIGN_MODE_DIRECT, + signerData, + txBuilder.GetTx(), + ) + if err != nil { + return nil, nil, err + } + + sigBytes, err := privKey.Sign(bytesToSign) + if err != nil { + return nil, nil, err + } + + sig = txsigning.SignatureV2{ + PubKey: pubKey, + Data: &txsigning.SingleSignatureData{ + SignMode: txsigning.SignMode_SIGN_MODE_DIRECT, + Signature: sigBytes, + }, + Sequence: account.GetSequence(), + } + if err := txBuilder.SetSignatures(sig); err != nil { + return nil, nil, err + } + + signedTx := txBuilder.GetTx() + txBytes, err := txConfig.TxEncoder()(signedTx) + if err != nil { + return nil, nil, err + } + + tx, err := txConfig.TxDecoder()(txBytes) + if err != nil { + return nil, nil, err + } + return txBytes, tx, nil +} + +func decodeNewSeedTx(txConfig client.TxConfig, txBytes []byte) (*types.MsgNewSeed, error) { + tx, err := txConfig.TxDecoder()(txBytes) + if err != nil { + return nil, err + } + msgs := tx.GetMsgs() + if len(msgs) != 1 { + return nil, err + } + msgNewSeed, ok := msgs[0].(*types.MsgNewSeed) + if !ok { + return nil, err + } + return msgNewSeed, nil +} + +func readPrivKey(keyFilePath string) (crypto.PrivKey, error) { + keyJSONBytes, err := os.ReadFile(keyFilePath) + if err != nil { + return nil, err + } + pvKey := privval.FilePVKey{} + err = cmtjson.Unmarshal(keyJSONBytes, &pvKey) + if err != nil { + return nil, fmt.Errorf("error reading PrivValidator key from %v: %w", keyFilePath, err) + } + return pvKey.PrivKey, nil } diff --git a/x/randomness/keeper/msg_server.go b/x/randomness/keeper/msg_server.go new file mode 100644 index 00000000..24fc07a0 --- /dev/null +++ b/x/randomness/keeper/msg_server.go @@ -0,0 +1,42 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/sedaprotocol/seda-chain/x/randomness/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +func (k msgServer) NewSeed(goCtx context.Context, msg *types.MsgNewSeed) (*types.MsgNewSeedResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // TO-DO spam prevention? + + k.Keeper.SetSeed(ctx, msg.Beta) + + // TO-DO event? + // err = ctx.EventManager().EmitTypedEvent( + // &types.EventNewSeed{ + // Hash: hashString, + // WasmType: msg.WasmType, + // Bytecode: msg.Wasm, + // }) + // if err != nil { + // return nil, err + // } + + return &types.MsgNewSeedResponse{}, nil +} diff --git a/x/randomness/module.go b/x/randomness/module.go index 6a6b7953..1da8666f 100644 --- a/x/randomness/module.go +++ b/x/randomness/module.go @@ -3,6 +3,7 @@ package randomness import ( "context" "encoding/json" + "fmt" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -50,20 +51,27 @@ func (AppModuleBasic) Name() string { } // RegisterLegacyAminoCodec registers the amino codec for the module, which is used to marshal and unmarshal structs to/from []byte in order to persist them in the module's KVStore -func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} // RegisterInterfaces registers a module's interface types and their concrete implementations as proto.Message -func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) {} +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} // DefaultGenesis returns a default GenesisState for the module, marshaled to json.RawMessage. The default GenesisState need to be defined by the module developer and is primarily used for testing func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - // return cdc.MustMarshalJSON(&types.GenesisState{}) - return nil + return cdc.MustMarshalJSON(types.DefaultGenesisState()) } // ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { - return nil + var data types.GenesisState + if err := cdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %v", types.ModuleName, err) + } + return types.ValidateGenesis(data) } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module @@ -103,6 +111,7 @@ func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { // RegisterServices registers a gRPC query service to respond to the module-specific gRPC queries func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), keeper.Querier{Keeper: am.keeper}) } @@ -111,17 +120,16 @@ func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} // InitGenesis performs the module's genesis initialization. It returns no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { - // var genesisState types.GenesisState - // cdc.MustUnmarshalJSON(gs, &genesisState) - // InitGenesis(ctx, am.keeper, genesisState) + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(gs, &genesisState) + InitGenesis(ctx, am.keeper, genesisState) return []abci.ValidatorUpdate{} } // ExportGenesis returns the module's exported genesis state as raw JSON bytes. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - // gs := ExportGenesis(ctx, am.keeper) - // return cdc.MustMarshalJSON(&gs) - return nil + gs := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(&gs) } // ConsensusVersion is a sequence number for state-breaking change of the module. It should be incremented on each consensus-breaking change introduced by the module. To avoid wrong/empty versions, the initial version should be set to 1 @@ -132,5 +140,5 @@ func (am AppModule) BeginBlock(_ sdk.Context) {} // EndBlock contains the logic that is automatically triggered at the end of each block func (am AppModule) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { - return am.keeper.EndBlocker(ctx) + return []abci.ValidatorUpdate{} } diff --git a/x/randomness/types/codec.go b/x/randomness/types/codec.go new file mode 100644 index 00000000..b70e2a44 --- /dev/null +++ b/x/randomness/types/codec.go @@ -0,0 +1,19 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) diff --git a/x/randomness/types/expected_keepers.go b/x/randomness/types/expected_keepers.go new file mode 100644 index 00000000..0629defa --- /dev/null +++ b/x/randomness/types/expected_keepers.go @@ -0,0 +1,17 @@ +package types + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +type StakingKeeper interface { + GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (validator types.Validator, err error) +} + +type AccountKeeper interface { + GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI + SetAccount(ctx context.Context, acc sdk.AccountI) +} diff --git a/x/randomness/types/genesis.go b/x/randomness/types/genesis.go new file mode 100644 index 00000000..bf1b6330 --- /dev/null +++ b/x/randomness/types/genesis.go @@ -0,0 +1,22 @@ +package types + +import ( + "fmt" +) + +const DefaultSeed = "sedouards" + +// ValidateGenesis ensures validity of given randomness genesis state. +func ValidateGenesis(data GenesisState) error { + if data.Seed == "" { + return fmt.Errorf("randomness seed cannot be empty") + } + return nil +} + +// DefaultGenesisState returns default state for randomness module. +func DefaultGenesisState() *GenesisState { + return &GenesisState{ + Seed: DefaultSeed, + } +} diff --git a/x/randomness/types/genesis.pb.go b/x/randomness/types/genesis.pb.go new file mode 100644 index 00000000..88a0cb70 --- /dev/null +++ b/x/randomness/types/genesis.pb.go @@ -0,0 +1,319 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: sedachain/randomness/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type GenesisState struct { + Seed string `protobuf:"bytes,1,opt,name=seed,proto3" json:"seed,omitempty"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_7099e3dee686bc86, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetSeed() string { + if m != nil { + return m.Seed + } + return "" +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "sedachain.randomness.v1.GenesisState") +} + +func init() { + proto.RegisterFile("sedachain/randomness/v1/genesis.proto", fileDescriptor_7099e3dee686bc86) +} + +var fileDescriptor_7099e3dee686bc86 = []byte{ + // 181 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2d, 0x4e, 0x4d, 0x49, + 0x4c, 0xce, 0x48, 0xcc, 0xcc, 0xd3, 0x2f, 0x4a, 0xcc, 0x4b, 0xc9, 0xcf, 0xcd, 0x4b, 0x2d, 0x2e, + 0xd6, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, + 0xc9, 0x17, 0x12, 0x87, 0x2b, 0xd3, 0x43, 0x28, 0xd3, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, + 0xcf, 0x07, 0xab, 0xd1, 0x07, 0xb1, 0x20, 0xca, 0x95, 0x94, 0xb8, 0x78, 0xdc, 0x21, 0xfa, 0x83, + 0x4b, 0x12, 0x4b, 0x52, 0x85, 0x84, 0xb8, 0x58, 0x8a, 0x53, 0x53, 0x53, 0x24, 0x18, 0x15, 0x18, + 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x27, 0xff, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, + 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, + 0x88, 0x32, 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x07, 0xd9, 0x0b, + 0x36, 0x33, 0x39, 0x3f, 0x07, 0xcc, 0xd1, 0x85, 0x38, 0xb6, 0x02, 0xd9, 0xb9, 0x25, 0x95, 0x05, + 0xa9, 0xc5, 0x49, 0x6c, 0x60, 0x75, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x48, 0xd8, + 0x0b, 0xd3, 0x00, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Seed) > 0 { + i -= len(m.Seed) + copy(dAtA[i:], m.Seed) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Seed))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Seed) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Seed", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Seed = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/randomness/types/tx.go b/x/randomness/types/tx.go new file mode 100644 index 00000000..b8b0a9ec --- /dev/null +++ b/x/randomness/types/tx.go @@ -0,0 +1,20 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (msg MsgNewSeed) Route() string { + return RouterKey +} + +func (msg MsgNewSeed) Type() string { + return "new-seed" +} + +func (msg MsgNewSeed) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Proposer); err != nil { + return err + } + return nil +} diff --git a/x/randomness/types/tx.pb.go b/x/randomness/types/tx.pb.go new file mode 100644 index 00000000..55cd39ed --- /dev/null +++ b/x/randomness/types/tx.pb.go @@ -0,0 +1,628 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: sedachain/randomness/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type MsgNewSeed struct { + Proposer string `protobuf:"bytes,1,opt,name=proposer,proto3" json:"proposer,omitempty"` + Pi string `protobuf:"bytes,2,opt,name=pi,proto3" json:"pi,omitempty"` + Beta string `protobuf:"bytes,3,opt,name=beta,proto3" json:"beta,omitempty"` +} + +func (m *MsgNewSeed) Reset() { *m = MsgNewSeed{} } +func (m *MsgNewSeed) String() string { return proto.CompactTextString(m) } +func (*MsgNewSeed) ProtoMessage() {} +func (*MsgNewSeed) Descriptor() ([]byte, []int) { + return fileDescriptor_9575b460ec9dfc32, []int{0} +} +func (m *MsgNewSeed) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgNewSeed) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgNewSeed.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgNewSeed) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgNewSeed.Merge(m, src) +} +func (m *MsgNewSeed) XXX_Size() int { + return m.Size() +} +func (m *MsgNewSeed) XXX_DiscardUnknown() { + xxx_messageInfo_MsgNewSeed.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgNewSeed proto.InternalMessageInfo + +func (m *MsgNewSeed) GetProposer() string { + if m != nil { + return m.Proposer + } + return "" +} + +func (m *MsgNewSeed) GetPi() string { + if m != nil { + return m.Pi + } + return "" +} + +func (m *MsgNewSeed) GetBeta() string { + if m != nil { + return m.Beta + } + return "" +} + +type MsgNewSeedResponse struct { +} + +func (m *MsgNewSeedResponse) Reset() { *m = MsgNewSeedResponse{} } +func (m *MsgNewSeedResponse) String() string { return proto.CompactTextString(m) } +func (*MsgNewSeedResponse) ProtoMessage() {} +func (*MsgNewSeedResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9575b460ec9dfc32, []int{1} +} +func (m *MsgNewSeedResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgNewSeedResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgNewSeedResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgNewSeedResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgNewSeedResponse.Merge(m, src) +} +func (m *MsgNewSeedResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgNewSeedResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgNewSeedResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgNewSeedResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgNewSeed)(nil), "sedachain.randomness.v1.MsgNewSeed") + proto.RegisterType((*MsgNewSeedResponse)(nil), "sedachain.randomness.v1.MsgNewSeedResponse") +} + +func init() { proto.RegisterFile("sedachain/randomness/v1/tx.proto", fileDescriptor_9575b460ec9dfc32) } + +var fileDescriptor_9575b460ec9dfc32 = []byte{ + // 264 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x28, 0x4e, 0x4d, 0x49, + 0x4c, 0xce, 0x48, 0xcc, 0xcc, 0xd3, 0x2f, 0x4a, 0xcc, 0x4b, 0xc9, 0xcf, 0xcd, 0x4b, 0x2d, 0x2e, + 0xd6, 0x2f, 0x33, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x87, 0xab, + 0xd0, 0x43, 0xa8, 0xd0, 0x2b, 0x33, 0x94, 0x12, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0xcf, + 0x2d, 0x4e, 0x07, 0x69, 0xc8, 0x2d, 0x4e, 0x87, 0xe8, 0x50, 0x8a, 0xe6, 0xe2, 0xf2, 0x2d, 0x4e, + 0xf7, 0x4b, 0x2d, 0x0f, 0x4e, 0x4d, 0x4d, 0x11, 0x92, 0xe2, 0xe2, 0x28, 0x28, 0xca, 0x2f, 0xc8, + 0x2f, 0x4e, 0x2d, 0x92, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x82, 0xf3, 0x85, 0xf8, 0xb8, 0x98, + 0x0a, 0x32, 0x25, 0x98, 0xc0, 0xa2, 0x4c, 0x05, 0x99, 0x42, 0x42, 0x5c, 0x2c, 0x49, 0xa9, 0x25, + 0x89, 0x12, 0xcc, 0x60, 0x11, 0x30, 0xdb, 0x8a, 0xb7, 0xe9, 0xf9, 0x06, 0x2d, 0xb8, 0x16, 0x25, + 0x11, 0x2e, 0x21, 0x84, 0xe1, 0x41, 0xa9, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 0xa9, 0x46, 0x49, 0x5c, + 0xcc, 0xbe, 0xc5, 0xe9, 0x42, 0xd1, 0x5c, 0xec, 0x30, 0x6b, 0x95, 0xf5, 0x70, 0xb8, 0x5b, 0x0f, + 0xa1, 0x5d, 0x4a, 0x9b, 0x08, 0x45, 0x30, 0x3b, 0x9c, 0xfc, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, + 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, + 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x34, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, + 0x1f, 0x64, 0x20, 0x38, 0x18, 0x92, 0xf3, 0x73, 0xc0, 0x1c, 0x5d, 0x48, 0xe8, 0x56, 0x20, 0x87, + 0x6f, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x58, 0x9d, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, + 0xa3, 0xb8, 0xf8, 0x1c, 0x84, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + NewSeed(ctx context.Context, in *MsgNewSeed, opts ...grpc.CallOption) (*MsgNewSeedResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) NewSeed(ctx context.Context, in *MsgNewSeed, opts ...grpc.CallOption) (*MsgNewSeedResponse, error) { + out := new(MsgNewSeedResponse) + err := c.cc.Invoke(ctx, "/sedachain.randomness.v1.Msg/NewSeed", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + NewSeed(context.Context, *MsgNewSeed) (*MsgNewSeedResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) NewSeed(ctx context.Context, req *MsgNewSeed) (*MsgNewSeedResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method NewSeed not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_NewSeed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgNewSeed) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).NewSeed(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/sedachain.randomness.v1.Msg/NewSeed", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).NewSeed(ctx, req.(*MsgNewSeed)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "sedachain.randomness.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "NewSeed", + Handler: _Msg_NewSeed_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "sedachain/randomness/v1/tx.proto", +} + +func (m *MsgNewSeed) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgNewSeed) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgNewSeed) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Beta) > 0 { + i -= len(m.Beta) + copy(dAtA[i:], m.Beta) + i = encodeVarintTx(dAtA, i, uint64(len(m.Beta))) + i-- + dAtA[i] = 0x1a + } + if len(m.Pi) > 0 { + i -= len(m.Pi) + copy(dAtA[i:], m.Pi) + i = encodeVarintTx(dAtA, i, uint64(len(m.Pi))) + i-- + dAtA[i] = 0x12 + } + if len(m.Proposer) > 0 { + i -= len(m.Proposer) + copy(dAtA[i:], m.Proposer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Proposer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgNewSeedResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgNewSeedResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgNewSeedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgNewSeed) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Proposer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Pi) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Beta) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgNewSeedResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgNewSeed) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgNewSeed: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgNewSeed: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proposer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proposer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pi", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pi = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Beta", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Beta = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgNewSeedResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgNewSeedResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgNewSeedResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/staking/expected_keepers.go b/x/staking/expected_keepers.go new file mode 100644 index 00000000..34dded8d --- /dev/null +++ b/x/staking/expected_keepers.go @@ -0,0 +1,15 @@ +package staking + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +type AccountKeeper interface { + stakingtypes.AccountKeeper + + NewAccountWithAddress(ctx context.Context, addr sdk.AccAddress) sdk.AccountI + SetAccount(ctx context.Context, acc sdk.AccountI) +} diff --git a/x/staking/module.go b/x/staking/module.go new file mode 100644 index 00000000..1259838c --- /dev/null +++ b/x/staking/module.go @@ -0,0 +1,50 @@ +package staking + +import ( + "github.com/CosmWasm/wasmd/x/wasm/exported" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +var ( + _ module.AppModule = AppModule{} +) + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements an application module for the staking module. +type AppModule struct { + staking.AppModule + stakingKeeper *stakingkeeper.Keeper + accountKeeper AccountKeeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule( + cdc codec.Codec, + keeper *keeper.Keeper, + ak AccountKeeper, + bk stakingtypes.BankKeeper, + ls exported.Subspace, +) AppModule { + am := staking.NewAppModule(cdc, keeper, ak, bk, ls) + return AppModule{ + AppModule: am, + stakingKeeper: keeper, + accountKeeper: ak, + } +} + +// RegisterServices registers module services. +func (am AppModule) RegisterServices(cfg module.Configurator) { + stakingtypes.RegisterMsgServer(cfg.MsgServer(), NewMsgServerImpl(am.stakingKeeper, am.accountKeeper)) + + querier := stakingkeeper.Querier{Keeper: am.stakingKeeper} + stakingtypes.RegisterQueryServer(cfg.QueryServer(), querier) +} diff --git a/x/staking/msg_server.go b/x/staking/msg_server.go new file mode 100644 index 00000000..ae8b2965 --- /dev/null +++ b/x/staking/msg_server.go @@ -0,0 +1,66 @@ +package staking + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +var _ stakingtypes.MsgServer = msgServer{} + +type msgServer struct { + stakingtypes.MsgServer + accountKeeper AccountKeeper +} + +func NewMsgServerImpl(keeper *stakingkeeper.Keeper, accKeeper AccountKeeper) stakingtypes.MsgServer { + ms := &msgServer{ + MsgServer: stakingkeeper.NewMsgServerImpl(keeper), + accountKeeper: accKeeper, + } + return ms +} + +func (k msgServer) CreateValidator(ctx context.Context, msg *stakingtypes.MsgCreateValidator) (*stakingtypes.MsgCreateValidatorResponse, error) { + // create an account based on consensus key to send NewSeed txs when proposing blocks + pk, ok := msg.Pubkey.GetCachedValue().(cryptotypes.PubKey) + if !ok { + return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", pk) + } + + addr := sdk.AccAddress(pk.Address().Bytes()) + acc := k.accountKeeper.NewAccountWithAddress(ctx, addr) + k.accountKeeper.SetAccount(ctx, acc) + + return k.MsgServer.CreateValidator(ctx, msg) +} + +func (k msgServer) EditValidator(ctx context.Context, msg *stakingtypes.MsgEditValidator) (*stakingtypes.MsgEditValidatorResponse, error) { + return k.MsgServer.EditValidator(ctx, msg) +} + +func (k msgServer) Delegate(ctx context.Context, msg *stakingtypes.MsgDelegate) (*stakingtypes.MsgDelegateResponse, error) { + return k.MsgServer.Delegate(ctx, msg) +} + +func (k msgServer) BeginRedelegate(ctx context.Context, msg *stakingtypes.MsgBeginRedelegate) (*stakingtypes.MsgBeginRedelegateResponse, error) { + return k.MsgServer.BeginRedelegate(ctx, msg) +} + +func (k msgServer) Undelegate(ctx context.Context, msg *stakingtypes.MsgUndelegate) (*stakingtypes.MsgUndelegateResponse, error) { + return k.MsgServer.Undelegate(ctx, msg) +} + +func (k msgServer) CancelUnbondingDelegation(ctx context.Context, msg *stakingtypes.MsgCancelUnbondingDelegation) (*stakingtypes.MsgCancelUnbondingDelegationResponse, error) { + return k.MsgServer.CancelUnbondingDelegation(ctx, msg) +} + +func (k msgServer) UpdateParams(ctx context.Context, msg *stakingtypes.MsgUpdateParams) (*stakingtypes.MsgUpdateParamsResponse, error) { + return k.MsgServer.UpdateParams(ctx, msg) +}