diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..2dbecbe0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.idea +.vscode +node_modules +release +.DS_Store +/scripts/ +test/.env +chain + +build diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f55a90ad..3e3e4a0c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # https://help.github.com/articles/about-codeowners -* @johnletey @mbreithecker @troykessler +* @mbreithecker @troykessler @shifty11 diff --git a/.github/README.md b/.github/README.md index bd63dfcf..ec21cb2b 100644 --- a/.github/README.md +++ b/.github/README.md @@ -38,3 +38,19 @@ You can verify the build information using the following command: ```shell kyved info ``` + +### Building docker image + +#### Root +To create a regular `kyve-network/kyve:${VERSION}` docker image with `kyved` binary only execute: +```bash +make docker-image +``` +To create the corresponding debug image containing a `sh` shell execute `make docker-image-debug`. + +#### Nonroot +To create a nonroot docker image `kyve-network/kyve:${VERSION}-nonroot` running with user `nonroot:65532`: +```bash +make docker-image-nonroot +``` +To create the corresponding debug image `kyve-network/kyve:${VERSION}-debug-nonroot` execute `make docker-image-debug-nonroot`. \ No newline at end of file diff --git a/.github/workflows/all.yml b/.github/workflows/all.yml new file mode 100644 index 00000000..c126f513 --- /dev/null +++ b/.github/workflows/all.yml @@ -0,0 +1,9 @@ +name: run all jobs +on: push + +jobs: + lint: + uses: ./.github/workflows/lint.yml + + test: + uses: ./.github/workflows/test.yml \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index accc8d20..5ec1f46f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,29 +1,39 @@ -on: push +name: lint +on: + workflow_call: jobs: buf: runs-on: ubuntu-latest steps: - # Run `git checkout` - - uses: actions/checkout@v3 + # Checkout the repository + - name: Checkout the repository + uses: actions/checkout@v4 # Install `buf` - - uses: bufbuild/buf-setup-action@v1 + - name: Install `buf` + uses: bufbuild/buf-setup-action@v1 with: github_token: ${{ github.token }} # Lint Protobuf files - - uses: bufbuild/buf-lint-action@v1 + - name: Lint Protobuf files + uses: bufbuild/buf-lint-action@v1 with: buf_token: ${{ secrets.BUF_TOKEN }} -# TODO(@john): Figure out why linting passes locally but not here. -# golangci: -# runs-on: ubuntu-latest -# steps: -# # Run `git checkout` -# - uses: actions/checkout@v3 -# # Install `go` -# - uses: actions/setup-go@v3 -# # Lint Go files -# - uses: golangci/golangci-lint-action@v3 -# with: -# args: --timeout=10m + golangci: + runs-on: ubuntu-latest + steps: + # Checkout the repository + - name: Checkout the repository + uses: actions/checkout@v4 + # Setup Golang + - name: 🐿 Setup Golang + uses: actions/setup-go@v4 + with: + go-version-file: 'go.mod' + # Lint go files with golangci-lint + - name: Lint go files with golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: latest + args: --timeout=10m diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..d069d018 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,19 @@ +name: test +on: + workflow_call: + +jobs: + test: + runs-on: ubuntu-latest + steps: + # Checkout the repository + - name: Check out repository code + uses: actions/checkout@v4 + # Setup Golang + - name: 🐿 Setup Golang + uses: actions/setup-go@v4 + with: + go-version-file: 'go.mod' + # Test & coverage report creation + - name: Test & coverage report creation + run: go test -cover -mod=readonly ./x/... \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..de9c3199 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +ARG IMG_TAG=latest + +# Compile the kyved binary +FROM golang:1.20-alpine AS kyved-builder + +# Install make +RUN apk add --no-cache make + +WORKDIR /go/src + +# Install dependencies +COPY go.mod go.sum* ./ +RUN --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=cache,target=/root/go/pkg/mod \ + go mod download +COPY . . + +ENV ENV=mainnet +RUN make install + +# Copy binary to a distroless container +FROM gcr.io/distroless/static-debian11:$IMG_TAG + +COPY --from=kyved-builder "/go/bin/kyved" /usr/local/bin/ +EXPOSE 26656 26657 1317 9090 + +ENTRYPOINT ["kyved"] \ No newline at end of file diff --git a/Makefile b/Makefile index 054d00b6..50784932 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ COMMIT := $(shell git log -1 --format='%H') GO_VERSION := $(shell go version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1,2) -VERSION := v1.4.0 # $(shell echo $(shell git describe --tags) | sed 's/^v//') + +# VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//') +VERSION := v1.4.0 TEAM_ALLOCATION := 165000000000000 ifeq ($(ENV),kaon) @@ -73,6 +75,36 @@ release: ensure_environment ensure_version @rm kyved @echo "✅ Completed release creation!" +############################################################################### +### Docker Build ### +############################################################################### + +# Build a release image +docker-image: + @DOCKER_BUILDKIT=1 docker build -t kyve-network/kyve:${VERSION} . + @echo "✅ Completed docker image build!" + +# Build a release nonroot image +docker-image-nonroot: + @DOCKER_BUILDKIT=1 docker build \ + --build-arg IMG_TAG="nonroot" \ + -t kyve-network/kyve:${VERSION}-nonroot . + @echo "✅ Completed docker image build! (nonroot)" + +# Build a release debug image +docker-image-debug: + @DOCKER_BUILDKIT=1 docker build \ + --build-arg IMG_TAG="debug" \ + -t kyve-network/kyve:${VERSION}-debug . + @echo "✅ Completed docker image build! (debug)" + +# Build a release debug-nonroot image +docker-image-debug-nonroot: + @DOCKER_BUILDKIT=1 docker build \ + --build-arg IMG_TAG="debug-nonroot" \ + -t kyve-network/kyve:${VERSION}-debug-nonroot . + @echo "✅ Completed docker image build! (debug-nonroot)" + ############################################################################### ### Checks ### ############################################################################### @@ -91,7 +123,6 @@ endif ### Development ### ############################################################################### -# TODO(@john): Switch to the Docker image? dev: @ignite chain serve --reset-once --skip-proto --verbose @@ -112,12 +143,6 @@ lint: @go run $(golangci_lint_cmd) run --skip-dirs scripts --timeout=10m @echo "✅ Completed linting!" -# TODO(@john): Can we remove this since we use GolangCI? -vet: - @echo "🤖 Running vet..." - @go vet ./... - @echo "✅ Completed vet!" - ############################################################################### ### Protobuf ### ############################################################################### diff --git a/app/app.go b/app/app.go index 449cc89f..60df660f 100644 --- a/app/app.go +++ b/app/app.go @@ -98,7 +98,7 @@ import ( group "github.com/cosmos/cosmos-sdk/x/group/module" // IBC Core ibc "github.com/cosmos/ibc-go/v7/modules/core" - ibcClientHandler "github.com/cosmos/ibc-go/v7/modules/core/02-client" // TODO + ibcClientHandler "github.com/cosmos/ibc-go/v7/modules/core/02-client" ibcClientTypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" ibcPortTypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcExported "github.com/cosmos/ibc-go/v7/modules/core/exported" @@ -350,7 +350,7 @@ func NewKYVEApp( scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icaControllerTypes.SubModuleName) scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icaHostTypes.SubModuleName) - // TODO(@john): Seal x/capability keeper. + app.CapabilityKeeper.Seal() // add keepers app.AccountKeeper = authKeeper.NewAccountKeeper( @@ -389,7 +389,7 @@ func NewKYVEApp( appCodec, keys[mintTypes.StoreKey], app.StakingKeeper, - &app.StakersKeeper, // TODO(@john) + &app.StakersKeeper, // This is a pointer because the stakers keeper is not initialized yet. app.AccountKeeper, app.BankKeeper, authTypes.FeeCollectorName, diff --git a/app/upgrades/v1_4/upgrade.go b/app/upgrades/v1_4/upgrade.go index 25014a7d..78d3bdbd 100644 --- a/app/upgrades/v1_4/upgrade.go +++ b/app/upgrades/v1_4/upgrade.go @@ -32,6 +32,8 @@ import ( upgradeTypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) +//nolint:all +//goland:noinspection GoDeprecation func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, diff --git a/cmd/kyved/root.go b/cmd/kyved/root.go index 57d3c0d5..f3bbac67 100644 --- a/cmd/kyved/root.go +++ b/cmd/kyved/root.go @@ -103,7 +103,7 @@ func NewRootCmd(encodingConfig kyveApp.EncodingConfig) *cobra.Command { tmCli.NewCompletionCmd(rootCmd, true), debug.Cmd(), config.Cmd(), - pruning.PruningCmd(ac.createApp), + pruning.Cmd(ac.createApp, kyveApp.DefaultNodeHome), rpc.StatusCommand(), queryCommand(), diff --git a/testutil/integration/checks.go b/testutil/integration/checks.go index 33d5acb3..bcfde8a5 100644 --- a/testutil/integration/checks.go +++ b/testutil/integration/checks.go @@ -11,7 +11,7 @@ import ( "github.com/KYVENetwork/chain/x/delegation" delegationtypes "github.com/KYVENetwork/chain/x/delegation/types" globalTypes "github.com/KYVENetwork/chain/x/global/types" - "github.com/KYVENetwork/chain/x/pool" + poolmodule "github.com/KYVENetwork/chain/x/pool" querytypes "github.com/KYVENetwork/chain/x/query/types" "github.com/KYVENetwork/chain/x/stakers" stakertypes "github.com/KYVENetwork/chain/x/stakers/types" @@ -25,8 +25,7 @@ import ( func (suite *KeeperTestSuite) PerformValidityChecks() { // verify pool module suite.VerifyPoolModuleFundingStates() - // TODO(@troy,@max): Figure out a better way to check this when disabling pools. - // suite.VerifyPoolQueries() + suite.VerifyPoolQueries() suite.VerifyPoolGenesisImportExport() // verify funders module @@ -80,6 +79,15 @@ func (suite *KeeperTestSuite) VerifyPoolQueries() { poolsQuery = append(poolsQuery, activePoolsQuery.Pools...) poolsQuery = append(poolsQuery, disabledPoolsQuery.Pools...) + // sort pools by id + for i := range poolsQuery { + for j := range poolsQuery { + if poolsQuery[i].Id < poolsQuery[j].Id { + poolsQuery[i], poolsQuery[j] = poolsQuery[j], poolsQuery[i] + } + } + } + Expect(activePoolsQueryErr).To(BeNil()) Expect(disabledPoolsQueryErr).To(BeNil()) @@ -137,7 +145,7 @@ func (suite *KeeperTestSuite) VerifyPoolQueries() { } func (suite *KeeperTestSuite) VerifyPoolGenesisImportExport() { - genState := pool.ExportGenesis(suite.Ctx(), suite.App().PoolKeeper) + genState := poolmodule.ExportGenesis(suite.Ctx(), suite.App().PoolKeeper) // Delete all entries in Pool Store store := suite.Ctx().KVStore(suite.App().PoolKeeper.StoreKey()) @@ -145,7 +153,7 @@ func (suite *KeeperTestSuite) VerifyPoolGenesisImportExport() { err := genState.Validate() Expect(err).To(BeNil()) - pool.InitGenesis(suite.Ctx(), suite.App().PoolKeeper, *genState) + poolmodule.InitGenesis(suite.Ctx(), suite.App().PoolKeeper, *genState) } // ===================== diff --git a/x/delegation/keeper/msg_server_delegate_test.go b/x/delegation/keeper/msg_server_delegate_test.go index 93ae4273..c5880469 100644 --- a/x/delegation/keeper/msg_server_delegate_test.go +++ b/x/delegation/keeper/msg_server_delegate_test.go @@ -21,7 +21,7 @@ TEST CASES - msg_server_delegate.go * Payout delegators * Don't pay out rewards twice * Delegate to validator with 0 $KYVE -* TODO(@max): Delegate to multiple validators +* Delegate to multiple validators */ @@ -276,6 +276,16 @@ var _ = Describe("msg_server_delegate.go", Ordered, func() { }) // ACT + s.RunTxDelegatorSuccess(&types.MsgDelegate{ + Creator: i.DUMMY[1], + Staker: i.ALICE, + Amount: 200 * i.KYVE, + }) + s.RunTxDelegatorSuccess(&types.MsgDelegate{ + Creator: i.DUMMY[1], + Staker: i.BOB, + Amount: 200 * i.KYVE, + }) s.RunTxDelegatorSuccess(&types.MsgDelegate{ Creator: i.DUMMY[1], Staker: i.CHARLIE, @@ -286,8 +296,14 @@ var _ = Describe("msg_server_delegate.go", Ordered, func() { s.PerformValidityChecks() poolModuleBalance := s.GetBalanceFromModule(types.ModuleName) - Expect(poolModuleBalance).To(Equal(200*i.KYVE + aliceSelfDelegation + bobSelfDelegation)) - Expect(s.GetBalanceFromAddress(i.DUMMY[1])).To(Equal(800 * i.KYVE)) + Expect(poolModuleBalance).To(Equal(600*i.KYVE + aliceSelfDelegation + bobSelfDelegation)) + Expect(s.GetBalanceFromAddress(i.DUMMY[1])).To(Equal(400 * i.KYVE)) + + aliceDelegation := s.App().DelegationKeeper.GetDelegationAmount(s.Ctx(), i.ALICE) + Expect(aliceDelegation).To(Equal(200*i.KYVE + aliceSelfDelegation)) + + bobDelegation := s.App().DelegationKeeper.GetDelegationAmount(s.Ctx(), i.BOB) + Expect(bobDelegation).To(Equal(200*i.KYVE + bobSelfDelegation)) charlieDelegation := s.App().DelegationKeeper.GetDelegationAmount(s.Ctx(), i.CHARLIE) Expect(charlieDelegation).To(Equal(200 * i.KYVE)) diff --git a/x/delegation/keeper/msg_server_undelegate_test.go b/x/delegation/keeper/msg_server_undelegate_test.go index c1a6b1cb..f1883364 100644 --- a/x/delegation/keeper/msg_server_undelegate_test.go +++ b/x/delegation/keeper/msg_server_undelegate_test.go @@ -26,9 +26,6 @@ TEST CASES - msg_server_undelegate.go * JoinA, Slash, JoinB, PayoutReward * Slash twice * Start unbonding, slash twice, payout, await undelegation - -TODO(@max): joinA slash joinB slash -> remaining delegation - */ var _ = Describe("msg_server_undelegate.go", Ordered, func() { @@ -501,6 +498,11 @@ var _ = Describe("msg_server_undelegate.go", Ordered, func() { // ASSERT Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.ALICE, i.DUMMY[0])).To(Equal(uint64(666_666_666))) Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.ALICE, i.DUMMY[1])).To(Equal(uint64(2_666_666_666))) + + // must be the same as before + Expect(s.App().DelegationKeeper.GetDelegationAmount(s.Ctx(), i.ALICE)).To(Equal((50 + 25) * i.KYVE)) + Expect(s.App().DelegationKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.ALICE, i.DUMMY[0])).To(Equal(5 * i.KYVE)) + Expect(s.App().DelegationKeeper.GetDelegationAmountOfDelegator(s.Ctx(), i.ALICE, i.DUMMY[1])).To(Equal(20 * i.KYVE)) }) It("Slash twice", func() { diff --git a/x/delegation/keeper/msg_server_withdraw_rewards_test.go b/x/delegation/keeper/msg_server_withdraw_rewards_test.go index 4def289a..d4717773 100644 --- a/x/delegation/keeper/msg_server_withdraw_rewards_test.go +++ b/x/delegation/keeper/msg_server_withdraw_rewards_test.go @@ -4,6 +4,7 @@ import ( funderstypes "github.com/KYVENetwork/chain/x/funders/types" pooltypes "github.com/KYVENetwork/chain/x/pool/types" stakerstypes "github.com/KYVENetwork/chain/x/stakers/types" + sdk "github.com/cosmos/cosmos-sdk/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -18,10 +19,8 @@ TEST CASES - msg_server_withdraw_rewards.go * Payout rewards which cause rounding issues and withdraw * Withdraw from a non-existing delegator * Test invalid payouts to delegators - -* TODO(@max): Test withdrawal of rewards which are zero -* TODO(@max): Test withdrawal of rewards with multiple slashes - +* Withdraw rewards which are zero +* Withdraw rewards with multiple slashes */ var _ = Describe("msg_server_withdraw_rewards.go", Ordered, func() { @@ -173,4 +172,61 @@ var _ = Describe("msg_server_withdraw_rewards.go", Ordered, func() { Expect(err1).To(HaveOccurred()) Expect(err2).To(HaveOccurred()) }) + + It("Withdraw rewards which are zero", func() { + // ARRANGE + s.RunTxDelegatorSuccess(&types.MsgDelegate{ + Creator: i.DUMMY[0], + Staker: i.ALICE, + Amount: 1, + }) + startBalance := s.GetBalanceFromAddress(i.DUMMY[0]) + + // ACT + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.ALICE, i.DUMMY[0])).To(Equal(uint64(0))) + + s.RunTxDelegatorSuccess(&types.MsgWithdrawRewards{ + Creator: i.DUMMY[0], + Staker: i.ALICE, + }) + + // ASSERT + Expect(s.GetBalanceFromAddress(i.DUMMY[0])).To(Equal(startBalance)) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.ALICE, i.DUMMY[0])).To(Equal(uint64(0))) + }) + + It("Withdraw rewards with multiple slashes", func() { + // ARRANGE + s.RunTxDelegatorSuccess(&types.MsgDelegate{ + Creator: i.DUMMY[0], + Staker: i.ALICE, + Amount: 10 * i.KYVE, + }) + startBalance := s.GetBalanceFromAddress(i.DUMMY[0]) + + // ACT + params := s.App().DelegationKeeper.GetParams(s.Ctx()) + params.UploadSlash = sdk.MustNewDecFromStr("0.5") + s.App().DelegationKeeper.SetParams(s.Ctx(), params) + + // Slash 50% + s.App().DelegationKeeper.SlashDelegators(s.Ctx(), 0, i.ALICE, types.SLASH_TYPE_UPLOAD) + PayoutRewards(s, i.ALICE, 5*i.KYVE) + + // Slash 50% again + s.App().DelegationKeeper.SlashDelegators(s.Ctx(), 0, i.ALICE, types.SLASH_TYPE_UPLOAD) + PayoutRewards(s, i.ALICE, 5*i.KYVE) + + s.PerformValidityChecks() + + // ASSERT + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.ALICE, i.DUMMY[0])).To(Equal(10 * i.KYVE)) + + s.RunTxDelegatorSuccess(&types.MsgWithdrawRewards{ + Creator: i.DUMMY[0], + Staker: i.ALICE, + }) + Expect(s.App().DelegationKeeper.GetOutstandingRewards(s.Ctx(), i.ALICE, i.DUMMY[0])).To(Equal(uint64(0))) + Expect(s.GetBalanceFromAddress(i.DUMMY[0])).To(Equal(startBalance + 10*i.KYVE)) + }) })