Skip to content

Commit

Permalink
feat(pricing): Add taxable did & resource messages, supply deflation,…
Browse files Browse the repository at this point in the history
… block rewards & `simapp` tests (#392)

* Raise of InitBlock order of execution

* Bump to include upstream AppHash fix

* Raised order of InitGenesis

* Debugging

* Debugging v2

* Restored ante & post, genesis validation improvements

* Cleanup

* Fix build

* Debugging

* Add JUnit report for Upgrade step

* Make protobuf and checksum tests work

* Separate unit and integration upgrade test

* Split fixed fee & simulation gas

* Upgrade test suits

* Fix namespaces

* Debugging

* Switched to broadcast block

* Switched to lite calc

* Debugging with default feedecorator

* Added fee payer flag

* Debugging

* Debugging v2

* Removed simulation checks

* Debugging

* Added basic frame & improvements on unit tx lifecycle

* Fixed return type

* Minor fixes

* Extract proto related migrations into it's own files

* Commit for sync

* Fix merge issues

* Fixes

* Fixed flag

* Fixed response types

* Slight fixes

* Switched base accounts

* Debugging

* Commit for sync

* Sync

* Debugging

* Debugging v2

* Debugging v3

* Switched to short quantities

* Added logs step

* Added overhead

* Cleanup

* Fixed to deterministic order of InitGenesis

* Switched to preceding lite validation

* Bump from retracted

* Debugging

* Debugging v2

* Misc

* Make IndyStyle migration works

* Merge with latest changes

* Makes linter happy

* Reviewing migrations

* Fix bug

* Fix merge conflicts

* Cherry picked

* `gofumpt -ed`

* Fixed non-deterministic behavior of InitGenesis

* Switched to hard typed fee params proto definitions

* Switched order of querying supply

* Bump Ginkgo & gas adjustment

* Tidied

* Bump adjustment

* Bumped adjustment

* Fix iterator issue

* Run test pipelines

* Clean up

* Review checksumm migration

* Restore build tags

* Extract simple migration helpers

* Implement version id migration

* Unstash

* Run it on pipelines

* Fix tests running on pipelines

* Fix cleanup

* Fix test reporting

* Remove redundant files

* Added integration pricing set

* Fixed start time

* Fixed start <> end

* Slight fixes

* Added fee grant params generator

* Added zero checks

* Running whole package

* Added empty base account & improvements

* Fixed validation

* Fixed falsy error codes

* Restored extras

* Fixed race conditions

* Add generic dataset implementation

* Slight fixes

* Cleanup

* Added extra base account

* Fixed denom

* Added extra headroom for insufficient funds cases

* Cleanup

* Fixed order

* Switched order for consequent executions and race conditions

* Bypass buf breaking

* Add uuid migration

* Cleanup

* Removed debug prints

* `gofumpt -ed`

* Add resource version links migration

* Fix build

* Add unit tests for UUID (#456)

* Move version setting to SetResource method

* Make UUID tests for migration

* Add tests for VersionId and create AddNewVersionMethod

* Clenup

Co-authored-by: Alexandr Kolesov <kolesov.alex.s@gmail.com>

* Fix version links migration

* Restore version links migration

* Cleanup

* Vresion map fix attempt

* Cleanup

* Simplify unit test workflow

* Add more migration handlers

* Update test.yml

* Try disabling version map fix

* Uncomment integration tests

* Reorganize file structure

* Restore vm fix, fix linter

* Add resource links test (#457)

Add tests for resource links

* Added upgrade handling for pricing

* Fixed path

* Fixed path v2

* Fixed path v3

* Fixed keys import

* Added binary replacement step

* Debugging

* Switched to another base account, race conditions

* Added co-dependency

* Switched dep

* Added extra output trim

* Removed dependency

* Fixed allocation

* Added debug section

* Fixed debug statements

* Added extra line trim

* Switched to helper

* Switched to json contents

* Restored top level proposal type

* Added file passing with permissions

* Debugging

* Bubble up debug output

* Restored post ping

* Switched to unescaped

* Fixed output trim redundant messages

* Removed bloat

* Cleanup

* Debugging

* Cleanup

* Debugging

* Fixed order

* Skip directly to version

* Fixed order

* Added v1 query

* Registered msg impl

* Added content proto def

* Added resource param change proposal

* Cleanup

* test(migration): Gingko tests for identity pricing migrations [DEV-1744] (#455)

* feat: Migrate fee_tests.go

* feat: ReStructure ante_test

* fix: Linting errors

* feat: Update error handling

* feat: Migrate keeper tests to ginkgo

* Add uuid migration for resource id

* Restored module version map tests

* Fixed key ref

* Commit for sync

* add checksum to datasets

* Add diddoc pre update

* Switched to previous state, non-altering results anyway

* Skip InitGenesis of did module

* Removed migrators as init migrations will be part of the upgrade handler

* Fix migration unit tests

* Merge with latest version

* Added explicit version set on resource module

* Fix tests for post checks

* Makes linter happy

* Fix pipelines

* Fix resource unit tests

* Better test structure

* Fix loader

* Debugging post did update

* For the previous commit

* Fix signature verification bug

* Added final default params

* Added module version map generic fix

* Fixed prop expected values

* Add did deactionvation

* Fix update and deactivate cases

* DIDDoc queries update

* Update tx_create_diddoc.go

* Update tx_deactivate_diddoc.go

* Update tx_update_diddoc.go

* Update query_diddoc.go

* Rename create-resource

* Update go.mod

* Update migration_did_protobuf.go

* Add resource default alternative url migration

* Enable default alternative url migration + add test for it, fix build

* Added resource creation after upgrade

* Fix tests

* Rename create-resource to create for tests

* Move resource creation before queries

* Fix resource tests

* Move directory structure

* Checkpoint of notes

* Resolving merge with migration tests

* Disabled temporarily breaking action

* Fixed build tags

* Fixed paths & removed redundant defs

* Fixed conditional explicit set on version map

* Restored pre tests

* Added import step

* Fixed codec entries

* Added separation of decoding stages

* Bypassing dead link temporarily

* Fixed order

* Added latest defaults

* Added prop expected values

* Fixed readme dead link

* Minor nits

* Remove redundant remarks & fixed typos

* Temp disabled buf breaking

* chore: Remove moved dir

* Bump gas adjustment

* Added explicit `gasLimit` cap on fixed fee decl

Co-authored-by: Alexandr Kolesov <kolesov.alex.s@gmail.com>
Co-authored-by: Ankur Banerjee <ankurdotb@users.noreply.github.com>
Co-authored-by: Andrew Nikitin <andrew.nikitin@cheqd.io>
Co-authored-by: DaevMithran <61043607+DaevMithran@users.noreply.github.com>
  • Loading branch information
5 people authored Dec 7, 2022
1 parent bf1f48b commit 22efe47
Show file tree
Hide file tree
Showing 133 changed files with 7,088 additions and 606 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ jobs:
- uses: bufbuild/buf-lint-action@v1

# Breaking change detection
- uses: bufbuild/buf-breaking-action@v1
with:
input: 'proto'
against: 'https://github.com/cheqd/cheqd-node.git#branch=develop,ref=HEAD~1,subdir=proto'
# - uses: bufbuild/buf-breaking-action@v1
# with:
# input: 'proto'
# against: 'https://github.com/cheqd/cheqd-node.git#branch=develop,ref=HEAD~1,subdir=proto'

super-lint:
name: "Super Linter"
Expand Down
48 changes: 37 additions & 11 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
go install github.com/onsi/ginkgo/v2/ginkgo@latest
- name: Run Ginkgo unit tests
run: ginkgo -r --race --randomize-all --randomize-suites --keep-going --trace --tags upgrade_unit --junit-report report-unit.xml
run: ginkgo -r --tags upgrade_unit --race --randomize-all --randomize-suites --keep-going --trace --junit-report report-unit.xml

- name: Upload unit tests result
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -91,8 +91,14 @@ jobs:

- name: Run Gingko integration tests
working-directory: ./tests/integration
run: ginkgo -r --race --randomize-suites --tags integration --keep-going --trace --junit-report ../../report-integration.xml

run: |
ginkgo -r --tags integration --race --randomize-suites --keep-going --trace --junit-report ../../report-integration.xml
- name: Show logs
if: failure()
working-directory: ./docker/localnet
run: docker compose --env-file build-latest.env logs --tail --follow

- name: Upload integration tests result
uses: actions/upload-artifact@v3
with:
Expand Down Expand Up @@ -144,22 +150,42 @@ jobs:
working-directory: ./tests/upgrade/integration
run: |
bash scripts/setup.sh
- name: Run pre-upgrade tests
working-directory: ./tests/upgrade
working-directory: ./tests/upgrade/integration
run: |
ginkgo -r --tags upgrade --race --tags upgrade_integration --focus-file pre_test.go
ginkgo -r --race --tags upgrade_integration --focus-file pre_test.go
- name: Restart network using new node version (build-latest)
working-directory: ./tests/upgrade/integration
run: |
bash scripts/upgrade.sh
- name: Run post-upgrade tests
working-directory: ./tests/upgrade
working-directory: ./tests/upgrade/integration
run: |
ginkgo -r --tags upgrade --race --tags upgrade_integration --focus-file post_test.go
ginkgo -r --race --tags upgrade_integration --focus-file post_test.go
- name: Download binary artifact (build-latest)
uses: actions/download-artifact@v3
id: download
with:
name: cheqd-noded
path: ${{ env.RUNNER_BIN_DIR }}
- name: Restore binary permissions
run: sudo chmod +x ${{ env.RUNNER_BIN_DIR }}/cheqd-noded
- name: Run integration tests on upgraded network
working-directory: ./tests/integration
run: |
ginkgo -r --tags integration --race --randomize-suites --keep-going --trace
- name: Show logs on failure
if: failure()
working-directory: ./docker/localnet
run: docker compose --env-file build-latest.env logs --tail --follow
- name: Submit governance fee parameter change proposals
working-directory: ./tests/upgrade/integration
run: |
ginkgo -r --race --tags upgrade_integration --focus-file param_change_proposal_test.go
- name: Run pricing integration tests after successful param change proposal
working-directory: ./tests/integration
run: |
ginkgo -r --tags integration --race --randomize-suites --keep-going --trace --skip-file cli_diddoc_test.go --skip-file cli_diddoc_negative_test.go --skip-file cli_resource_test.go --skip-file cli_resource_negative_test.go
- name: Cleanup after tests
working-directory: ./tests/upgrade/integration
run: |
Expand Down
13 changes: 13 additions & 0 deletions ante/ante_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ante_test

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestAnte(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Ante Suite")
}
22 changes: 22 additions & 0 deletions ante/expected_keepers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ante

import (
didtypes "github.com/cheqd/cheqd-node/x/did/types"
resourcetypes "github.com/cheqd/cheqd-node/x/resource/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

type BankKeeper interface {
SendCoins(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
}

type DidKeeper interface {
GetParams(ctx sdk.Context) (params didtypes.FeeParams)
}

type ResourceKeeper interface {
GetParams(ctx sdk.Context) (params resourcetypes.FeeParams)
}
180 changes: 180 additions & 0 deletions ante/fee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package ante

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error)

// DeductFeeDecorator deducts fees from the first signer of the tx
// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error
// Call next AnteHandler if fees successfully deducted
// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator
type DeductFeeDecorator struct {
accountKeeper ante.AccountKeeper
bankKeeper BankKeeper
feegrantKeeper ante.FeegrantKeeper
txFeeChecker TxFeeChecker
}

func NewDeductFeeDecorator(ak ante.AccountKeeper, bk BankKeeper, fk ante.FeegrantKeeper, tfc TxFeeChecker) DeductFeeDecorator {
if tfc == nil {
tfc = checkTxFeeWithValidatorMinGasPrices
}

return DeductFeeDecorator{
accountKeeper: ak,
bankKeeper: bk,
feegrantKeeper: fk,
txFeeChecker: tfc,
}
}

func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}

if !simulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas")
}

var (
priority int64
err error
)

fee := feeTx.GetFee()

// check if the tx is a taxable tx
// CONTRACT: Taxable tx is a tx that has at least 1 taxable related Msg.
taxable := IsTaxableTxLite(tx)
// if taxable, include in the mempool
if taxable {
// default priority of tx
newCtx := ctx.WithPriority(priority)
// posthandler will deduct the fee from the fee payer
return next(newCtx, tx, simulate)
}

// if not taxable, follow default
if !simulate {
fee, priority, err = dfd.txFeeChecker(ctx, tx)
if err != nil {
return ctx, err
}
}
if err := dfd.checkDeductFee(ctx, tx, fee); err != nil {
return ctx, err
}

newCtx := ctx.WithPriority(priority)

return next(newCtx, tx, simulate)
}

func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error {
feeTx, ok := sdkTx.(sdk.FeeTx)
if !ok {
return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}

if addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName); addr == nil {
return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName)
}

feePayer := feeTx.FeePayer()
feeGranter := feeTx.FeeGranter()
deductFeesFrom := feePayer

// if feegranter set deduct fee from feegranter account.
// this works with only when feegrant enabled.
if feeGranter != nil {
if dfd.feegrantKeeper == nil {
return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled")
} else if !feeGranter.Equals(feePayer) {
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, sdkTx.GetMsgs())
if err != nil {
return sdkerrors.Wrapf(err, "%s does not not allow to pay fees for %s", feeGranter, feePayer)
}
}

deductFeesFrom = feeGranter
}

deductFeesFromAcc := dfd.accountKeeper.GetAccount(ctx, deductFeesFrom)
if deductFeesFromAcc == nil {
return sdkerrors.ErrUnknownAddress.Wrapf("fee payer address: %s does not exist", deductFeesFrom)
}

// deduct the fees
if !fee.IsZero() {
err := DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, fee)
if err != nil {
return err
}
}

events := sdk.Events{
sdk.NewEvent(
sdk.EventTypeTx,
sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()),
sdk.NewAttribute(sdk.AttributeKeyFeePayer, deductFeesFrom.String()),
),
}
ctx.EventManager().EmitEvents(events)

return nil
}

// DeductFees deducts fees from the given account.
func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error {
if !fees.IsValid() {
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees)
}

err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
}

return nil
}

func IsSufficientFee(ctx sdk.Context, tax, reward, burn, feeProvided sdk.Coins, gasRequested int64) (bool, int64, error) {
// check if the provided fee is enough for `did`, `resource` module specific Msg
if !feeProvided.IsAnyGTE(tax) {
return false, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeProvided, tax)
}

// check with the default validator min gas prices based on rewards distribution
if ctx.IsCheckTx() {
minGasPrices := ctx.MinGasPrices()
if !minGasPrices.IsZero() {
requiredFees := make(sdk.Coins, len(minGasPrices))

// Determine the required fees by multiplying each required minimum gas
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
glDec := sdk.NewDec(int64(gasRequested))
for i, gp := range minGasPrices {
fee := gp.Amount.Mul(glDec)
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
}

// check if the fee is sufficient
if !reward.IsAnyGTE(requiredFees) {
return false, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", reward, requiredFees)
}
}
}

priority := getTxPriority(tax, gasRequested)

return true, priority, nil
}
Loading

0 comments on commit 22efe47

Please sign in to comment.