Skip to content

Commit

Permalink
[DFI-444] currencies_register mod: gov proposal adding currency (#150)
Browse files Browse the repository at this point in the history
* [DFI-444] currencies_register mod: gov proposal adding currency added; denom validation unified across all mods;

* [DFI-444] isToken and owner args removed from the proposal
  • Loading branch information
Mikhail Kornilov authored Jun 30, 2020
1 parent 1b47aca commit 72b2772
Show file tree
Hide file tree
Showing 26 changed files with 527 additions and 119 deletions.
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ func NewDnServiceApp(logger log.Logger, db dbm.DB, config *config.VMConfig, base
// The Governance keeper.
app.govRouter = gov.NewRouter()
app.govRouter.AddRoute(vm.GovRouterKey, vm.NewGovHandler(app.vmKeeper))
app.govRouter.AddRoute(currencies_register.GovRouterKey, currencies_register.NewGovHandler(app.crKeeper))

app.govKeeper = gov.NewKeeper(
cdc,
Expand Down
85 changes: 83 additions & 2 deletions app/gov_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
package app

import (
"encoding/hex"
"os"
"path"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"

"github.com/dfinance/dnode/cmd/config"
"github.com/dfinance/dnode/helpers/tests"
cliTester "github.com/dfinance/dnode/helpers/tests/clitester"
"github.com/dfinance/dnode/x/common_vm"
)

const govUpdModuleV1 = `
Expand Down Expand Up @@ -156,7 +159,7 @@ func Test_VmGovStdlibUpdate(t *testing.T) {
// Add DVM stdlib update proposal for module version 1 (cover the min deposit)
{
tx := ct.TxVmStdlibUpdateProposal(senderAddr, moduleV1BytecodePath, "http://ya.ru", "Foo module V1 added", -1, config.GovMinDeposit)
ct.SubmitAndConfirmProposal(tx)
ct.SubmitAndConfirmProposal(tx, true)
}

// Check module added and script works now
Expand All @@ -179,7 +182,7 @@ func Test_VmGovStdlibUpdate(t *testing.T) {
// Add DVM stdlib update proposal for module version 2
{
tx := ct.TxVmStdlibUpdateProposal(senderAddr, moduleV2BytecodePath, "http://ya.ru", "Foo module V2 added", -1, config.GovMinDeposit)
ct.SubmitAndConfirmProposal(tx)
ct.SubmitAndConfirmProposal(tx, true)
}

// Check module writeSet changed
Expand All @@ -192,3 +195,81 @@ func Test_VmGovStdlibUpdate(t *testing.T) {
require.NotEqual(t, moduleV1WriteSet, moduleV2WriteSet)
}
}

func Test_CRGovAddCurrency(t *testing.T) {
ct := cliTester.New(
t,
true,
cliTester.DaemonLogLevelOption("x/currencies_register:info,x/gov:info,main:info,state:info,*:error"),
)
defer ct.Close()

senderAddr := ct.Accounts["validator1"].Address

// New currency info
crDenom := "tst"
crDecimals := uint8(8)
crPathHex := "0102030405060708090A0B0C0D0E0FA1A2A3A4A5A6A7A8A9AAABACADAEAFB1B2B3"
crTotalSupply, ok := sdk.NewIntFromString("100000000000")
require.True(t, ok)

// Check invalid arguments for AddCurrencyProposal Tx
{
// invalid from
{
tx := ct.TxCRAddCurrencyProposal("invalid_from", crDenom, crPathHex, crDecimals, crTotalSupply, config.GovMinDeposit)
tx.CheckFailedWithErrorSubstring("keyring")
}

// invalid denom
{
tx := ct.TxCRAddCurrencyProposal(senderAddr, "invalid1", crPathHex, crDecimals, crTotalSupply, config.GovMinDeposit)
tx.CheckFailedWithErrorSubstring("denom")
}

// invalid path
{
tx := ct.TxCRAddCurrencyProposal(senderAddr, crDenom, "_", crDecimals, crTotalSupply, config.GovMinDeposit)
tx.CheckFailedWithErrorSubstring("path")
}

// invalid decimals
{
tx := ct.TxCRAddCurrencyProposal(senderAddr, crDenom, crPathHex, crDecimals, crTotalSupply, config.GovMinDeposit)
tx.ChangeCmdArg("8", "abc")
tx.CheckFailedWithErrorSubstring("decimals")
}

// invalid totalSupply
{
tx := ct.TxCRAddCurrencyProposal(senderAddr, crDenom, crPathHex, crDecimals, crTotalSupply, config.GovMinDeposit)
tx.ChangeCmdArg(crTotalSupply.String(), "abc")
tx.CheckFailedWithErrorSubstring("totalSupply")
}
}

// Add proposal
{
tx := ct.TxCRAddCurrencyProposal(senderAddr, crDenom, crPathHex, crDecimals, crTotalSupply, config.GovMinDeposit)
ct.SubmitAndConfirmProposal(tx, false)
}

// Check currency added
{
req, crInfo := ct.QueryCurrencyInfo(crDenom)
req.CheckSucceeded()

require.Equal(t, crDenom, string(crInfo.Denom))
require.Equal(t, crDecimals, crInfo.Decimals)
require.Equal(t, false, crInfo.IsToken)
require.Equal(t, common_vm.StdLibAddress, crInfo.Owner)
require.Equal(t, crTotalSupply.BigInt().String(), crInfo.TotalSupply.String())
}

// Check writeSet is stored
{
q, writeSet := ct.QueryVmData(hex.EncodeToString(common_vm.StdLibAddress), crPathHex)
q.CheckSucceeded()
require.NotEmpty(t, writeSet)
}
}
29 changes: 15 additions & 14 deletions helpers/tests/clitester/cli_tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ func (ct *CLITester) ConfirmCall(uniqueID string) {
// Contract 1: plannedBlockHeight must be -1 on txRequest creation.
// Contract 2: proposalTx must cover proposal minDeposit.
// Contract 3: not concurrent safe.
func (ct *CLITester) SubmitAndConfirmProposal(proposalTx *TxRequest) {
func (ct *CLITester) SubmitAndConfirmProposal(proposalTx *TxRequest, isPlannedProposal bool) {
// get current proposals count
prevProposalsCount := 0
{
Expand All @@ -483,21 +483,20 @@ func (ct *CLITester) SubmitAndConfirmProposal(proposalTx *TxRequest) {
}
}

// calculate the planned height
plannedHeight := int64(0)
{
if isPlannedProposal {
// calculate the planned height
curHeight, err := ct.GetCurrentBlockHeight()
require.NoError(ct.t, err, "GetCurrentBlockHeight failed")

plannedHeight = curHeight + 20
}

// modify the plannedBlockHeight argument and emit the Tx
{
// modify the plannedBlockHeight argument
proposalTx.ChangeCmdArg("-1", strconv.FormatInt(plannedHeight, 10))
proposalTx.CheckSucceeded()
}

// emit the Tx
proposalTx.CheckSucceeded()

// check proposal added
proposalID := uint64(0)
{
Expand Down Expand Up @@ -526,13 +525,15 @@ func (ct *CLITester) SubmitAndConfirmProposal(proposalTx *TxRequest) {
require.Equal(ct.t, proposal.Status, gov.StatusPassed, "proposal didn't pass")
}

// wait for scheduler
{
curHeight, err := ct.GetCurrentBlockHeight()
require.NoError(ct.t, err, "GetCurrentBlockHeight failed")
if isPlannedProposal {
// wait for scheduler
{
curHeight, err := ct.GetCurrentBlockHeight()
require.NoError(ct.t, err, "GetCurrentBlockHeight failed")

if curHeight < plannedHeight {
ct.WaitForNextBlocks(plannedHeight - curHeight)
if curHeight < plannedHeight {
ct.WaitForNextBlocks(plannedHeight - curHeight)
}
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions helpers/tests/clitester/cli_tester_txs.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,25 @@ func (ct *CLITester) TxVmStdlibUpdateProposal(fromAddress, filePath, sourceUrl,
return r
}

func (ct *CLITester) TxCRAddCurrencyProposal(fromAddress, denom, path string, decimals uint8, totalSupply sdk.Int, deposit sdk.Coin) *TxRequest {
cmdArgs := []string{
"add-currency-proposal",
denom,
strconv.FormatUint(uint64(decimals), 10),
totalSupply.String(),
path,
fmt.Sprintf("--deposit=%s", deposit.String()),
}

r := ct.newTxRequest()
r.SetCmd(
"currencies_register",
fromAddress,
cmdArgs...)

return r
}

func (ct *CLITester) TxGovDeposit(fromAddress string, id uint64, deposit sdk.Coin) *TxRequest {
cmdArgs := []string{
"deposit",
Expand Down
2 changes: 2 additions & 0 deletions helpers/tests/clitester/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/supply"

"github.com/dfinance/dnode/x/currencies"
"github.com/dfinance/dnode/x/currencies_register"
"github.com/dfinance/dnode/x/genaccounts"
"github.com/dfinance/dnode/x/markets"
"github.com/dfinance/dnode/x/multisig"
Expand Down Expand Up @@ -77,6 +78,7 @@ var ModuleBasics = module.NewBasicManager(
currencies.AppModuleBasic{},
multisig.AppModuleBasic{},
oracle.AppModuleBasic{},
currencies_register.AppModuleBasic{},
vm.AppModuleBasic{},
orders.AppModuleBasic{},
markets.AppModuleBasic{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@ import (
"fmt"
"strings"
"unicode"

sdk "github.com/cosmos/cosmos-sdk/types"
)

func assetCodeFilter(code string) error {
func DenomFilter(denom string) error {
return stringFilter(
denom,
[]strFilterOpt{stringNotEmpty, validCoinDenom},
[]runeFilterOpt{runeIsASCII, runeIsLowerCasedLetter},
)
}

func AssetCodeFilter(code string) error {
return stringFilter(
code,
[]strFilterOpt{stringIsEmpty, newDelimiterStrFilterOpt("_")},
[]strFilterOpt{stringNotEmpty, newDelimiterStrFilterOpt("_")},
[]runeFilterOpt{runeIsASCII, newIsLowerCasedLetterOrDelimiter('_')},
)
}
Expand Down Expand Up @@ -40,14 +50,22 @@ func stringFilter(str string, strOpts []strFilterOpt, runeOpts []runeFilterOpt)
return nil
}

func stringIsEmpty(str string) error {
func stringNotEmpty(str string) error {
if len(str) == 0 {
return fmt.Errorf("empty")
}

return nil
}

func validCoinDenom(str string) error {
if err := sdk.ValidateDenom(str); err != nil {
return fmt.Errorf("invalid denom: %w", err)
}

return nil
}

func newDelimiterStrFilterOpt(delimiter string) strFilterOpt {
return func(str string) error {
if strings.HasPrefix(str, delimiter) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// +build unit

package types

import (
Expand Down Expand Up @@ -28,7 +26,7 @@ func Test_stringFilter(t *testing.T) {
require.Error(t, stringFilter("abc_123Def_®", nil, []runeFilterOpt{runeIsASCII, runeLetterIsLowerCase}))

// empty string
require.Error(t, stringFilter("", []strFilterOpt{stringIsEmpty}, nil))
require.Error(t, stringFilter("", []strFilterOpt{stringNotEmpty}, nil))

// delimiter: ok
require.NoError(t, stringFilter("abc_def", []strFilterOpt{newDelimiterStrFilterOpt("_")}, nil))
Expand All @@ -48,23 +46,40 @@ func Test_stringFilter(t *testing.T) {

func Test_assetCodeFilter(t *testing.T) {
// ok
require.NoError(t, assetCodeFilter("eth_usdt"))
require.NoError(t, AssetCodeFilter("eth_usdt"))

// fail: empty
require.Error(t, assetCodeFilter(""))
require.Error(t, AssetCodeFilter(""))

// fail: non lower cased letter
require.Error(t, assetCodeFilter("ETH_usdt"))
require.Error(t, AssetCodeFilter("ETH_usdt"))

// fail: invalid separator
require.Error(t, assetCodeFilter("eth:usdt"))
require.Error(t, AssetCodeFilter("eth:usdt"))

// fail: invalid separator
require.Error(t, assetCodeFilter("eth__usdt"))
require.Error(t, AssetCodeFilter("eth__usdt"))

// fail: non ASCII symbol
require.Error(t, AssetCodeFilter("eth®_usdt"))

// fail: non letter symbol
require.Error(t, AssetCodeFilter("eth_usdt1"))
}

func Test_denomFilter(t *testing.T) {
// ok
require.NoError(t, DenomFilter("dfi"))

// fail: empty
require.Error(t, DenomFilter(""))

// fail: non lower cased letter
require.Error(t, DenomFilter("Dfi"))

// fail: non ASCII symbol
require.Error(t, assetCodeFilter("eth®_usdt"))
require.Error(t, DenomFilter("eth®"))

// fail: non letter symbol
require.Error(t, assetCodeFilter("eth_usdt1"))
require.Error(t, DenomFilter("eth1"))
}
26 changes: 20 additions & 6 deletions x/currencies_register/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,32 @@ import (
)

const (
ModuleName = types.ModuleName
RouterKey = types.RouterKey
StoreKey = types.StoreKey
ModuleName = types.ModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
GovRouterKey = types.GovRouterKey
)

type (
Keeper = keeper.Keeper
Keeper = keeper.Keeper

GenesisState = types.GenesisState
GenesisCurrency = types.GenesisCurrency
CurrencyInfo = types.CurrencyInfo

CurrencyInfo = types.CurrencyInfo

AddCurrencyProposal = types.AddCurrencyProposal
)

var (
NewKeeper = keeper.NewKeeper
// variable aliases
ModuleCdc = types.ModuleCdc
// function aliases
NewKeeper = keeper.NewKeeper
NewQuerier = keeper.NewQuerier
RegisterCodec = types.RegisterCodec
DefaultGenesisState = types.DefaultGenesisState
NewAddCurrencyProposal = types.NewAddCurrencyProposal
// errors
ErrGovInvalidProposal = types.ErrGovInvalidProposal
)
Loading

0 comments on commit 72b2772

Please sign in to comment.