mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
merge release v0.12.1 updates (#724)
* use kava antehandler * add authenticated mempool decorator * add get authorised address methods * hook antehandler into app * refactor address fetcher interface * tidy up args to NewApp * remove unused function * tidy up after removing address fetcher interface * read authorized addresses from config * fix error message, and minor tidy * update cosmos-sdk and tendermint * clarify function name * add flags for mempool options
This commit is contained in:
parent
9472c09b91
commit
9c69ee2fbf
32
app/ante/ante.go
Normal file
32
app/ante/ante.go
Normal file
@ -0,0 +1,32 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/keeper"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
// NewAnteHandler returns an 'AnteHandler' that will run actions before a tx is sent to a module's handler.
|
||||
func NewAnteHandler(ak keeper.AccountKeeper, supplyKeeper types.SupplyKeeper, sigGasConsumer ante.SignatureVerificationGasConsumer, addressFetchers ...AddressFetcher) sdk.AnteHandler {
|
||||
decorators := []sdk.AnteDecorator{}
|
||||
|
||||
decorators = append(decorators, ante.NewSetUpContextDecorator()) // outermost AnteDecorator. SetUpContext must be called first
|
||||
|
||||
if len(addressFetchers) > 0 {
|
||||
decorators = append(decorators, NewAuthenticatedMempoolDecorator(addressFetchers...))
|
||||
}
|
||||
decorators = append(decorators,
|
||||
ante.NewMempoolFeeDecorator(),
|
||||
ante.NewValidateBasicDecorator(),
|
||||
ante.NewValidateMemoDecorator(ak),
|
||||
ante.NewConsumeGasForTxSizeDecorator(ak),
|
||||
ante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators
|
||||
ante.NewValidateSigCountDecorator(ak),
|
||||
ante.NewDeductFeeDecorator(ak, supplyKeeper),
|
||||
ante.NewSigGasConsumeDecorator(ak, sigGasConsumer),
|
||||
ante.NewSigVerificationDecorator(ak),
|
||||
ante.NewIncrementSequenceDecorator(ak), // innermost AnteDecorator
|
||||
)
|
||||
return sdk.ChainAnteDecorators(decorators...)
|
||||
}
|
202
app/ante/ante_test.go
Normal file
202
app/ante/ante_test.go
Normal file
@ -0,0 +1,202 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp/helpers"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmdb "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/bep3"
|
||||
"github.com/kava-labs/kava/x/pricefeed"
|
||||
)
|
||||
|
||||
func TestAppAnteHandler(t *testing.T) {
|
||||
testPrivKeys, testAddresses := app.GeneratePrivKeyAddressPairs(10)
|
||||
unauthed := testAddresses[0:2]
|
||||
unathedKeys := testPrivKeys[0:2]
|
||||
deputy := testAddresses[2]
|
||||
deputyKey := testPrivKeys[2]
|
||||
oracles := testAddresses[3:6]
|
||||
oraclesKeys := testPrivKeys[3:6]
|
||||
manual := testAddresses[6:]
|
||||
manualKeys := testPrivKeys[6:]
|
||||
|
||||
db := tmdb.NewMemDB()
|
||||
tApp := app.TestApp{
|
||||
App: *app.NewApp(log.NewNopLogger(), db, nil,
|
||||
app.AppOptions{
|
||||
MempoolEnableAuth: true,
|
||||
MempoolAuthAddresses: manual,
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
chainID := "internal-test-chain"
|
||||
tApp = tApp.InitializeFromGenesisStatesWithTimeAndChainID(
|
||||
time.Date(1998, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
chainID,
|
||||
NewAuthGenStateWithSameCoins(
|
||||
sdk.NewCoins(sdk.NewInt64Coin("ukava", 1_000_000_000)),
|
||||
testAddresses,
|
||||
),
|
||||
newBep3GenStateMulti(deputy),
|
||||
newPricefeedGenStateMulti(oracles),
|
||||
)
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
address sdk.AccAddress
|
||||
privKey crypto.PrivKey
|
||||
expectPass bool
|
||||
}{
|
||||
{
|
||||
name: "unauthorized",
|
||||
address: unauthed[1],
|
||||
privKey: unathedKeys[1],
|
||||
expectPass: false,
|
||||
},
|
||||
{
|
||||
name: "oracle",
|
||||
address: oracles[1],
|
||||
privKey: oraclesKeys[1],
|
||||
expectPass: true,
|
||||
},
|
||||
{
|
||||
name: "deputy",
|
||||
address: deputy,
|
||||
privKey: deputyKey,
|
||||
expectPass: true,
|
||||
},
|
||||
{
|
||||
name: "manual",
|
||||
address: manual[1],
|
||||
privKey: manualKeys[1],
|
||||
expectPass: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
stdTx := helpers.GenTx(
|
||||
[]sdk.Msg{
|
||||
bank.NewMsgSend(
|
||||
tc.address,
|
||||
testAddresses[0],
|
||||
sdk.NewCoins(sdk.NewInt64Coin("ukava", 1_000_000)),
|
||||
),
|
||||
},
|
||||
sdk.NewCoins(), // no fee
|
||||
helpers.DefaultGenTxGas,
|
||||
chainID,
|
||||
[]uint64{0},
|
||||
[]uint64{0}, // fixed sequence numbers will cause tests to fail sig verification if the same address is used twice
|
||||
tc.privKey,
|
||||
)
|
||||
txBytes, err := auth.DefaultTxEncoder(tApp.Codec())(stdTx)
|
||||
require.NoError(t, err)
|
||||
|
||||
res := tApp.CheckTx(
|
||||
abci.RequestCheckTx{
|
||||
Tx: txBytes,
|
||||
Type: abci.CheckTxType_New,
|
||||
},
|
||||
)
|
||||
|
||||
if tc.expectPass {
|
||||
require.Zero(t, res.Code, res.Log)
|
||||
} else {
|
||||
require.NotZero(t, res.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func NewAuthGenStateWithSameCoins(coins sdk.Coins, addresses []sdk.AccAddress) app.GenesisState {
|
||||
coinsList := make([]sdk.Coins, len(addresses))
|
||||
for i := range addresses {
|
||||
coinsList[i] = coins
|
||||
}
|
||||
return app.NewAuthGenState(addresses, coinsList)
|
||||
}
|
||||
|
||||
func newPricefeedGenStateMulti(oracles []sdk.AccAddress) app.GenesisState {
|
||||
pfGenesis := pricefeed.GenesisState{
|
||||
Params: pricefeed.Params{
|
||||
Markets: []pricefeed.Market{
|
||||
{MarketID: "btc:usd", BaseAsset: "btc", QuoteAsset: "usd", Oracles: oracles, Active: true},
|
||||
{MarketID: "xrp:usd", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: oracles, Active: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
return app.GenesisState{pricefeed.ModuleName: pricefeed.ModuleCdc.MustMarshalJSON(pfGenesis)}
|
||||
}
|
||||
|
||||
func newBep3GenStateMulti(deputyAddress sdk.AccAddress) app.GenesisState {
|
||||
bep3Genesis := bep3.GenesisState{
|
||||
Params: bep3.Params{
|
||||
AssetParams: bep3.AssetParams{
|
||||
bep3.AssetParam{
|
||||
Denom: "bnb",
|
||||
CoinID: 714,
|
||||
SupplyLimit: bep3.SupplyLimit{
|
||||
Limit: sdk.NewInt(350000000000000),
|
||||
TimeLimited: false,
|
||||
TimeBasedLimit: sdk.ZeroInt(),
|
||||
TimePeriod: time.Hour,
|
||||
},
|
||||
Active: true,
|
||||
DeputyAddress: deputyAddress,
|
||||
FixedFee: sdk.NewInt(1000),
|
||||
MinSwapAmount: sdk.OneInt(),
|
||||
MaxSwapAmount: sdk.NewInt(1000000000000),
|
||||
MinBlockLock: bep3.DefaultMinBlockLock,
|
||||
MaxBlockLock: bep3.DefaultMaxBlockLock,
|
||||
},
|
||||
bep3.AssetParam{
|
||||
Denom: "inc",
|
||||
CoinID: 9999,
|
||||
SupplyLimit: bep3.SupplyLimit{
|
||||
Limit: sdk.NewInt(100000000000000),
|
||||
TimeLimited: true,
|
||||
TimeBasedLimit: sdk.NewInt(50000000000),
|
||||
TimePeriod: time.Hour,
|
||||
},
|
||||
Active: false,
|
||||
DeputyAddress: deputyAddress,
|
||||
FixedFee: sdk.NewInt(1000),
|
||||
MinSwapAmount: sdk.OneInt(),
|
||||
MaxSwapAmount: sdk.NewInt(100000000000),
|
||||
MinBlockLock: bep3.DefaultMinBlockLock,
|
||||
MaxBlockLock: bep3.DefaultMaxBlockLock,
|
||||
},
|
||||
},
|
||||
},
|
||||
Supplies: bep3.AssetSupplies{
|
||||
bep3.NewAssetSupply(
|
||||
sdk.NewCoin("bnb", sdk.ZeroInt()),
|
||||
sdk.NewCoin("bnb", sdk.ZeroInt()),
|
||||
sdk.NewCoin("bnb", sdk.ZeroInt()),
|
||||
sdk.NewCoin("bnb", sdk.ZeroInt()),
|
||||
time.Duration(0),
|
||||
),
|
||||
bep3.NewAssetSupply(
|
||||
sdk.NewCoin("inc", sdk.ZeroInt()),
|
||||
sdk.NewCoin("inc", sdk.ZeroInt()),
|
||||
sdk.NewCoin("inc", sdk.ZeroInt()),
|
||||
sdk.NewCoin("inc", sdk.ZeroInt()),
|
||||
time.Duration(0),
|
||||
),
|
||||
},
|
||||
PreviousBlockTime: bep3.DefaultPreviousBlockTime,
|
||||
}
|
||||
return app.GenesisState{bep3.ModuleName: bep3.ModuleCdc.MustMarshalJSON(bep3Genesis)}
|
||||
}
|
63
app/ante/authorized.go
Normal file
63
app/ante/authorized.go
Normal file
@ -0,0 +1,63 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
var _ sigVerifiableTx = (*authtypes.StdTx)(nil) // assert StdTx implements SigVerifiableTx
|
||||
|
||||
// SigVerifiableTx defines a Tx interface for all signature verification decorators
|
||||
type sigVerifiableTx interface {
|
||||
GetSigners() []sdk.AccAddress
|
||||
}
|
||||
|
||||
// AddressFetcher is a type signature for functions used by the AuthenticatedMempoolDecorator to get authorized addresses.
|
||||
type AddressFetcher func(sdk.Context) []sdk.AccAddress
|
||||
|
||||
// AuthenticatedMempoolDecorator blocks all txs from reaching the mempool unless they're signed by one of the authorzed addresses.
|
||||
// It only runs before entry to mempool (CheckTx), and not in consensus (DeliverTx)
|
||||
type AuthenticatedMempoolDecorator struct {
|
||||
addressFetchers []AddressFetcher
|
||||
}
|
||||
|
||||
func NewAuthenticatedMempoolDecorator(fetchers ...AddressFetcher) AuthenticatedMempoolDecorator {
|
||||
return AuthenticatedMempoolDecorator{
|
||||
addressFetchers: fetchers,
|
||||
}
|
||||
}
|
||||
|
||||
func (amd AuthenticatedMempoolDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// This is only for local mempool purposes, and thus is only run on check tx.
|
||||
if ctx.IsCheckTx() && !simulate {
|
||||
sigTx, ok := tx.(sigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx must be sig verifiable tx")
|
||||
}
|
||||
if !commonAddressesExist(sigTx.GetSigners(), amd.fetchAuthorizedAddresses(ctx)) {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "tx contains no signers authorized for this mempool")
|
||||
}
|
||||
}
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
func (amd AuthenticatedMempoolDecorator) fetchAuthorizedAddresses(ctx sdk.Context) []sdk.AccAddress {
|
||||
addrs := []sdk.AccAddress{}
|
||||
for _, fetch := range amd.addressFetchers {
|
||||
addrs = append(addrs, fetch(ctx)...)
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// commonAddressesExist checks if there is any intersection between two lists of addresses
|
||||
func commonAddressesExist(addresses1, addresses2 []sdk.AccAddress) bool {
|
||||
for _, a1 := range addresses1 {
|
||||
for _, a2 := range addresses2 {
|
||||
if a1.Equals(a2) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
144
app/ante/authorized_test.go
Normal file
144
app/ante/authorized_test.go
Normal file
@ -0,0 +1,144 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp/helpers"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
||||
"github.com/kava-labs/kava/x/bep3"
|
||||
)
|
||||
|
||||
var (
|
||||
_ sdk.AnteHandler = (&MockAnteHandler{}).AnteHandle
|
||||
)
|
||||
|
||||
type MockAnteHandler struct {
|
||||
WasCalled bool
|
||||
}
|
||||
|
||||
func (mah *MockAnteHandler) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
|
||||
mah.WasCalled = true
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
func mockAddressFetcher(addresses ...sdk.AccAddress) AddressFetcher {
|
||||
return func(sdk.Context) []sdk.AccAddress { return addresses }
|
||||
}
|
||||
|
||||
func TestAuthenticatedMempoolDecorator_AnteHandle_NotCheckTx(t *testing.T) {
|
||||
testPrivKeys, testAddresses := generatePrivKeyAddressPairs(5)
|
||||
fetcher := mockAddressFetcher(testAddresses[1:]...)
|
||||
|
||||
decorator := NewAuthenticatedMempoolDecorator(fetcher)
|
||||
tx := helpers.GenTx(
|
||||
[]sdk.Msg{
|
||||
bep3.NewMsgClaimAtomicSwap(
|
||||
testAddresses[0],
|
||||
[]byte{},
|
||||
[]byte{},
|
||||
),
|
||||
},
|
||||
sdk.NewCoins(), // no fee
|
||||
helpers.DefaultGenTxGas,
|
||||
"testing-chain-id",
|
||||
[]uint64{0},
|
||||
[]uint64{0},
|
||||
testPrivKeys[0], // address is not authorized
|
||||
)
|
||||
mmd := MockAnteHandler{}
|
||||
ctx := sdk.Context{}.WithIsCheckTx(false) // run as it would be during block update ('DeliverTx'), not just checking entry to mempool
|
||||
|
||||
_, err := decorator.AnteHandle(ctx, tx, false, mmd.AnteHandle)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.True(t, mmd.WasCalled)
|
||||
}
|
||||
|
||||
func TestAuthenticatedMempoolDecorator_AnteHandle_Pass(t *testing.T) {
|
||||
testPrivKeys, testAddresses := generatePrivKeyAddressPairs(5)
|
||||
fetcher := mockAddressFetcher(testAddresses[1:]...)
|
||||
|
||||
decorator := NewAuthenticatedMempoolDecorator(fetcher)
|
||||
|
||||
tx := helpers.GenTx(
|
||||
[]sdk.Msg{
|
||||
bank.NewMsgSend(
|
||||
testAddresses[0],
|
||||
testAddresses[1],
|
||||
sdk.NewCoins(sdk.NewInt64Coin("ukava", 100_000_000)),
|
||||
),
|
||||
bep3.NewMsgClaimAtomicSwap(
|
||||
testAddresses[2],
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
},
|
||||
sdk.NewCoins(), // no fee
|
||||
helpers.DefaultGenTxGas,
|
||||
"testing-chain-id",
|
||||
[]uint64{0, 123},
|
||||
[]uint64{0, 123},
|
||||
testPrivKeys[0], // not in list of authorized addresses
|
||||
testPrivKeys[2],
|
||||
)
|
||||
mmd := MockAnteHandler{}
|
||||
ctx := sdk.Context{}.WithIsCheckTx(true)
|
||||
|
||||
_, err := decorator.AnteHandle(ctx, tx, false, mmd.AnteHandle)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.True(t, mmd.WasCalled)
|
||||
}
|
||||
|
||||
func TestAuthenticatedMempoolDecorator_AnteHandle_Reject(t *testing.T) {
|
||||
testPrivKeys, testAddresses := generatePrivKeyAddressPairs(5)
|
||||
fetcher := mockAddressFetcher(testAddresses[1:]...)
|
||||
|
||||
decorator := NewAuthenticatedMempoolDecorator(fetcher)
|
||||
|
||||
tx := helpers.GenTx(
|
||||
[]sdk.Msg{
|
||||
bank.NewMsgSend(
|
||||
testAddresses[0],
|
||||
testAddresses[1],
|
||||
sdk.NewCoins(sdk.NewInt64Coin("ukava", 100_000_000)),
|
||||
),
|
||||
},
|
||||
sdk.NewCoins(), // no fee
|
||||
helpers.DefaultGenTxGas,
|
||||
"testing-chain-id",
|
||||
[]uint64{0},
|
||||
[]uint64{0},
|
||||
testPrivKeys[0], // not in list of authorized addresses
|
||||
)
|
||||
mmd := MockAnteHandler{}
|
||||
ctx := sdk.Context{}.WithIsCheckTx(true)
|
||||
|
||||
_, err := decorator.AnteHandle(ctx, tx, false, mmd.AnteHandle)
|
||||
|
||||
require.Error(t, err)
|
||||
require.False(t, mmd.WasCalled)
|
||||
}
|
||||
|
||||
// generatePrivKeyAddressPairsFromRand generates (deterministically) a total of n private keys and addresses.
|
||||
func generatePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
|
||||
r := rand.New(rand.NewSource(12345)) // make the generation deterministic
|
||||
keys = make([]crypto.PrivKey, n)
|
||||
addrs = make([]sdk.AccAddress, n)
|
||||
for i := 0; i < n; i++ {
|
||||
secret := make([]byte, 32)
|
||||
_, err := r.Read(secret)
|
||||
if err != nil {
|
||||
panic("Could not read randomness")
|
||||
}
|
||||
keys[i] = secp256k1.GenPrivKeySecp256k1(secret)
|
||||
addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
|
||||
}
|
||||
return
|
||||
}
|
32
app/app.go
32
app/app.go
@ -33,6 +33,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/upgrade"
|
||||
upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client"
|
||||
|
||||
"github.com/kava-labs/kava/app/ante"
|
||||
"github.com/kava-labs/kava/x/auction"
|
||||
"github.com/kava-labs/kava/x/bep3"
|
||||
"github.com/kava-labs/kava/x/cdp"
|
||||
@ -116,6 +117,16 @@ var (
|
||||
// Verify app interface at compile time
|
||||
var _ simapp.App = (*App)(nil)
|
||||
|
||||
// AppOptions bundles several configuration params for an App.
|
||||
// The zero value can be used as a sensible default.
|
||||
type AppOptions struct {
|
||||
SkipLoadLatest bool
|
||||
SkipUpgradeHeights map[int64]bool
|
||||
InvariantCheckPeriod uint
|
||||
MempoolEnableAuth bool
|
||||
MempoolAuthAddresses []sdk.AccAddress
|
||||
}
|
||||
|
||||
// App represents an extended ABCI application
|
||||
type App struct {
|
||||
*bam.BaseApp
|
||||
@ -159,9 +170,7 @@ type App struct {
|
||||
}
|
||||
|
||||
// NewApp returns a reference to an initialized App.
|
||||
func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
skipUpgradeHeights map[int64]bool, invCheckPeriod uint,
|
||||
baseAppOptions ...func(*bam.BaseApp)) *App {
|
||||
func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts AppOptions, baseAppOptions ...func(*bam.BaseApp)) *App {
|
||||
|
||||
cdc := MakeCodec()
|
||||
|
||||
@ -182,7 +191,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
var app = &App{
|
||||
BaseApp: bApp,
|
||||
cdc: cdc,
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
invCheckPeriod: appOpts.InvariantCheckPeriod,
|
||||
keys: keys,
|
||||
tkeys: tkeys,
|
||||
}
|
||||
@ -257,12 +266,12 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
)
|
||||
app.crisisKeeper = crisis.NewKeeper(
|
||||
crisisSubspace,
|
||||
invCheckPeriod,
|
||||
app.invCheckPeriod,
|
||||
app.supplyKeeper,
|
||||
auth.FeeCollectorName,
|
||||
)
|
||||
app.upgradeKeeper = upgrade.NewKeeper(
|
||||
skipUpgradeHeights,
|
||||
appOpts.SkipUpgradeHeights,
|
||||
keys[upgrade.StoreKey],
|
||||
app.cdc,
|
||||
)
|
||||
@ -473,11 +482,18 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
// initialize the app
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.supplyKeeper, auth.DefaultSigVerificationGasConsumer))
|
||||
var antehandler sdk.AnteHandler
|
||||
if appOpts.MempoolEnableAuth {
|
||||
var getAuthorizedAddresses ante.AddressFetcher = func(sdk.Context) []sdk.AccAddress { return appOpts.MempoolAuthAddresses }
|
||||
antehandler = ante.NewAnteHandler(app.accountKeeper, app.supplyKeeper, auth.DefaultSigVerificationGasConsumer, app.bep3Keeper.GetAuthorizedAddresses, app.pricefeedKeeper.GetAuthorizedAddresses, getAuthorizedAddresses)
|
||||
} else {
|
||||
antehandler = ante.NewAnteHandler(app.accountKeeper, app.supplyKeeper, auth.DefaultSigVerificationGasConsumer)
|
||||
}
|
||||
app.SetAnteHandler(antehandler)
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
||||
// load store
|
||||
if loadLatest {
|
||||
if !appOpts.SkipLoadLatest {
|
||||
err := app.LoadLatestVersion(app.keys[bam.MainStoreKey])
|
||||
if err != nil {
|
||||
tmos.Exit(err.Error())
|
||||
|
@ -16,11 +16,11 @@ import (
|
||||
|
||||
func TestExport(t *testing.T) {
|
||||
db := db.NewMemDB()
|
||||
app := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
|
||||
app := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, AppOptions{})
|
||||
setGenesis(app)
|
||||
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
newApp := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
|
||||
newApp := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, AppOptions{})
|
||||
_, _, err := newApp.ExportAppStateAndValidators(false, []string{})
|
||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||
}
|
||||
@ -28,7 +28,7 @@ func TestExport(t *testing.T) {
|
||||
// ensure that black listed addresses are properly set in bank keeper
|
||||
func TestBlackListedAddrs(t *testing.T) {
|
||||
db := db.NewMemDB()
|
||||
app := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, 0)
|
||||
app := NewApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, AppOptions{})
|
||||
|
||||
for acc := range mAccPerms {
|
||||
require.Equal(t, !allowedReceivingModAcc[acc], app.bankKeeper.BlacklistedAddr(app.supplyKeeper.GetModuleAddress(acc)))
|
||||
|
@ -85,7 +85,7 @@ func TestFullAppSimulation(t *testing.T) {
|
||||
require.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
|
||||
app := NewApp(logger, db, nil, true, map[int64]bool{}, simapp.FlagPeriodValue, fauxMerkleModeOpt)
|
||||
app := NewApp(logger, db, nil, AppOptions{InvariantCheckPeriod: simapp.FlagPeriodValue}, fauxMerkleModeOpt)
|
||||
require.Equal(t, appName, app.Name())
|
||||
|
||||
// run randomized simulation
|
||||
@ -117,7 +117,7 @@ func TestAppImportExport(t *testing.T) {
|
||||
require.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
|
||||
app := NewApp(logger, db, nil, true, map[int64]bool{}, simapp.FlagPeriodValue, fauxMerkleModeOpt)
|
||||
app := NewApp(logger, db, nil, AppOptions{InvariantCheckPeriod: simapp.FlagPeriodValue}, fauxMerkleModeOpt)
|
||||
require.Equal(t, appName, app.Name())
|
||||
|
||||
// Run randomized simulation
|
||||
@ -151,7 +151,7 @@ func TestAppImportExport(t *testing.T) {
|
||||
require.NoError(t, os.RemoveAll(newDir))
|
||||
}()
|
||||
|
||||
newApp := NewApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, simapp.FlagPeriodValue, fauxMerkleModeOpt)
|
||||
newApp := NewApp(log.NewNopLogger(), newDB, nil, AppOptions{InvariantCheckPeriod: simapp.FlagPeriodValue}, fauxMerkleModeOpt)
|
||||
require.Equal(t, appName, newApp.Name())
|
||||
|
||||
var genesisState GenesisState
|
||||
@ -212,7 +212,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
|
||||
require.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
|
||||
app := NewApp(logger, db, nil, true, map[int64]bool{}, simapp.FlagPeriodValue, fauxMerkleModeOpt)
|
||||
app := NewApp(logger, db, nil, AppOptions{InvariantCheckPeriod: simapp.FlagPeriodValue}, fauxMerkleModeOpt)
|
||||
require.Equal(t, appName, app.Name())
|
||||
|
||||
// Run randomized simulation
|
||||
@ -251,7 +251,7 @@ func TestAppSimulationAfterImport(t *testing.T) {
|
||||
require.NoError(t, os.RemoveAll(newDir))
|
||||
}()
|
||||
|
||||
newApp := NewApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, simapp.FlagPeriodValue, fauxMerkleModeOpt)
|
||||
newApp := NewApp(log.NewNopLogger(), newDB, nil, AppOptions{InvariantCheckPeriod: simapp.FlagPeriodValue}, fauxMerkleModeOpt)
|
||||
require.Equal(t, appName, newApp.Name())
|
||||
|
||||
newApp.InitChain(abci.RequestInitChain{
|
||||
@ -284,7 +284,7 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||
for j := 0; j < numTimesToRunPerSeed; j++ {
|
||||
logger := log.NewNopLogger()
|
||||
db := dbm.NewMemDB()
|
||||
app := NewApp(logger, db, nil, true, map[int64]bool{}, simapp.FlagPeriodValue, interBlockCacheOpt())
|
||||
app := NewApp(logger, db, nil, AppOptions{InvariantCheckPeriod: simapp.FlagPeriodValue}, interBlockCacheOpt())
|
||||
|
||||
fmt.Printf(
|
||||
"running non-determinism simulation; seed %d: attempt: %d/%d\n",
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
@ -62,7 +61,7 @@ func NewTestApp() TestApp {
|
||||
SetBip44CoinType(config)
|
||||
|
||||
db := tmdb.NewMemDB()
|
||||
app := NewApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, 0)
|
||||
app := NewApp(log.NewNopLogger(), db, nil, AppOptions{})
|
||||
return TestApp{App: *app}
|
||||
}
|
||||
|
||||
@ -188,8 +187,7 @@ func NewAuthGenState(addresses []sdk.AccAddress, coins []sdk.Coins) GenesisState
|
||||
return GenesisState{auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(authGenesis)}
|
||||
}
|
||||
|
||||
// GeneratePrivKeyAddressPairsFromRand generates (deterministically) a total of n private keys and addresses.
|
||||
// TODO only generate secp256 keys?
|
||||
// GeneratePrivKeyAddressPairsFromRand generates (deterministically) a total of n secp256k1 private keys and addresses.
|
||||
func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) {
|
||||
r := rand.New(rand.NewSource(12345)) // make the generation deterministic
|
||||
keys = make([]crypto.PrivKey, n)
|
||||
@ -200,11 +198,7 @@ func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccA
|
||||
if err != nil {
|
||||
panic("Could not read randomness")
|
||||
}
|
||||
if r.Int63()%2 == 0 {
|
||||
keys[i] = secp256k1.GenPrivKeySecp256k1(secret)
|
||||
} else {
|
||||
keys[i] = ed25519.GenPrivKeyFromSecret(secret)
|
||||
}
|
||||
keys[i] = secp256k1.GenPrivKeySecp256k1(secret)
|
||||
addrs[i] = sdk.AccAddress(keys[i].PubKey().Address())
|
||||
}
|
||||
return
|
||||
|
17
app/utils.go
17
app/utils.go
@ -1,17 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// ExportStateToJSON util function to export the app state to JSON
|
||||
func ExportStateToJSON(app *App, path string) error {
|
||||
fmt.Println("exporting app state...")
|
||||
appState, _, err := app.ExportAppStateAndValidators(false, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(path, []byte(appState), 0644)
|
||||
}
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@ -28,7 +29,11 @@ import (
|
||||
)
|
||||
|
||||
// kvd custom flags
|
||||
const flagInvCheckPeriod = "inv-check-period"
|
||||
const (
|
||||
flagInvCheckPeriod = "inv-check-period"
|
||||
flagMempoolEnableAuth = "mempool.enable-authentication"
|
||||
flagMempoolAuthAddresses = "mempool.authorized-addresses"
|
||||
)
|
||||
|
||||
var invCheckPeriod uint
|
||||
|
||||
@ -72,7 +77,23 @@ func main() {
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "KA", app.DefaultNodeHome)
|
||||
rootCmd.PersistentFlags().UintVar(&invCheckPeriod, flagInvCheckPeriod,
|
||||
0, "Assert registered invariants every N blocks")
|
||||
err := executor.Execute()
|
||||
startCmd, _, err := rootCmd.Find([]string{"start"})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not find 'start' command on root command: %s", err))
|
||||
}
|
||||
startCmd.Flags().Bool(flagMempoolEnableAuth, false, "Configure the mempool to only accept transactions from authorized addresses")
|
||||
err = viper.BindPFlag(flagMempoolEnableAuth, startCmd.Flags().Lookup(flagMempoolEnableAuth))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to bind flag: %s", err))
|
||||
}
|
||||
startCmd.Flags().StringSlice(flagMempoolAuthAddresses, []string{}, "Additional addresses to accept transactions from when the mempool is running in authorized mode (comma separated kava addresses)")
|
||||
err = viper.BindPFlag(flagMempoolAuthAddresses, startCmd.Flags().Lookup(flagMempoolAuthAddresses))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to bind flag: %s", err))
|
||||
}
|
||||
|
||||
// run main command
|
||||
err = executor.Execute()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -95,8 +116,21 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mempoolEnableAuth := viper.GetBool(flagMempoolEnableAuth)
|
||||
mempoolAuthAddresses, err := accAddressesFromBech32(viper.GetStringSlice(flagMempoolAuthAddresses)...)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not get authorized address from config: %v", err))
|
||||
}
|
||||
|
||||
return app.NewApp(
|
||||
logger, db, traceStore, true, skipUpgradeHeights, invCheckPeriod,
|
||||
logger, db, traceStore,
|
||||
app.AppOptions{
|
||||
SkipLoadLatest: false,
|
||||
SkipUpgradeHeights: skipUpgradeHeights,
|
||||
InvariantCheckPeriod: invCheckPeriod,
|
||||
MempoolEnableAuth: mempoolEnableAuth,
|
||||
MempoolAuthAddresses: mempoolAuthAddresses,
|
||||
},
|
||||
baseapp.SetPruning(pruningOpts),
|
||||
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
|
||||
baseapp.SetHaltHeight(viper.GetUint64(server.FlagHaltHeight)),
|
||||
@ -110,13 +144,33 @@ func exportAppStateAndTMValidators(
|
||||
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
|
||||
if height != -1 {
|
||||
tempApp := app.NewApp(logger, db, traceStore, false, map[int64]bool{}, uint(1))
|
||||
opts := app.AppOptions{
|
||||
SkipLoadLatest: true,
|
||||
InvariantCheckPeriod: uint(1),
|
||||
}
|
||||
tempApp := app.NewApp(logger, db, traceStore, opts)
|
||||
err := tempApp.LoadHeight(height)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return tempApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||
}
|
||||
tempApp := app.NewApp(logger, db, traceStore, true, map[int64]bool{}, uint(1))
|
||||
opts := app.AppOptions{
|
||||
SkipLoadLatest: false,
|
||||
InvariantCheckPeriod: uint(1),
|
||||
}
|
||||
tempApp := app.NewApp(logger, db, traceStore, opts)
|
||||
return tempApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||
}
|
||||
|
||||
func accAddressesFromBech32(addresses ...string) ([]sdk.AccAddress, error) {
|
||||
var decodedAddresses []sdk.AccAddress
|
||||
for _, s := range addresses {
|
||||
a, err := sdk.AccAddressFromBech32(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decodedAddresses = append(decodedAddresses, a)
|
||||
}
|
||||
return decodedAddresses, nil
|
||||
}
|
||||
|
4
go.mod
4
go.mod
@ -3,12 +3,12 @@ module github.com/kava-labs/kava
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/cosmos/cosmos-sdk v0.39.1
|
||||
github.com/cosmos/cosmos-sdk v0.39.2
|
||||
github.com/gorilla/mux v1.7.4
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/viper v1.6.3
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/tendermint/tendermint v0.33.7
|
||||
github.com/tendermint/tendermint v0.33.9
|
||||
github.com/tendermint/tm-db v0.5.1
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
46
go.sum
46
go.sum
@ -1,7 +1,7 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2BylwQY=
|
||||
github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904=
|
||||
github.com/99designs/keyring v1.1.6 h1:kVDC2uCgVwecxCk+9zoCt2uEL6dt+dfVzMvGgnVcIuM=
|
||||
github.com/99designs/keyring v1.1.6/go.mod h1:16e0ds7LGQQcT59QqkTg72Hh5ShM51Byv5PEmW6uoRU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg=
|
||||
@ -68,8 +68,8 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cosmos/cosmos-sdk v0.39.1 h1:vhjf9PZh9ph8btAj9aBpHoVITgVVjNBpM3x5Gl/Vwac=
|
||||
github.com/cosmos/cosmos-sdk v0.39.1/go.mod h1:ry2ROl5n+f2/QXpKJo3rdWNJwll00z7KhIVcxNcl16M=
|
||||
github.com/cosmos/cosmos-sdk v0.39.2 h1:nLfCJMkUuFt7ansi/YvCxwwxLFrgHCA3cYP4sJKYQdk=
|
||||
github.com/cosmos/cosmos-sdk v0.39.2/go.mod h1:VNUluciWBFj2vkhpMcp8rYZL/kCw0FtNc7SseUjE1KM=
|
||||
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
|
||||
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
|
||||
github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
|
||||
@ -88,8 +88,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU=
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b h1:HBah4D48ypg3J7Np4N+HY/ZR76fx3HEUGxDU6Uk39oQ=
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
@ -150,9 +150,13 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
|
||||
github.com/golang/snappy v0.0.2/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 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@ -160,6 +164,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@ -285,6 +291,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
|
||||
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
@ -426,11 +434,11 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM
|
||||
github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso=
|
||||
github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ=
|
||||
github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
|
||||
github.com/tendermint/iavl v0.14.0 h1:Jkff+IFrXxRWtH9Jn/ga/2cxNnzMTv58xEKgCJsKUBg=
|
||||
github.com/tendermint/iavl v0.14.0/go.mod h1:QmfViflFiXzxKLQE4tAUuWQHq+RSuQFxablW5oJZ6sE=
|
||||
github.com/tendermint/iavl v0.14.1 h1:jz7YOvGiPwmcqqVMcSMjxCu4WXtQYGhKdKrWTTJ5EKs=
|
||||
github.com/tendermint/iavl v0.14.1/go.mod h1:QmfViflFiXzxKLQE4tAUuWQHq+RSuQFxablW5oJZ6sE=
|
||||
github.com/tendermint/tendermint v0.33.5/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM=
|
||||
github.com/tendermint/tendermint v0.33.7 h1:b5CQD8ggDtl4u0EbXzabi0MaOw9NrcXker6ijEkAE74=
|
||||
github.com/tendermint/tendermint v0.33.7/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM=
|
||||
github.com/tendermint/tendermint v0.33.9 h1:rRKIfu5qAXX5f9bwX1oUXSZz/ALFJjDuivhkbGUQxiU=
|
||||
github.com/tendermint/tendermint v0.33.9/go.mod h1:0yUs9eIuuDq07nQql9BmI30FtYGcEC60Tu5JzB5IezM=
|
||||
github.com/tendermint/tm-db v0.5.1 h1:H9HDq8UEA7Eeg13kdYckkgwwkQLBnJGgX4PgLJRhieY=
|
||||
github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
@ -470,6 +478,8 @@ golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+
|
||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
|
||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@ -499,6 +509,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -529,9 +541,14 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgm
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201013132646-2da7054afaeb h1:HS9IzC4UFbpMBLQUDSQcU+ViVT1vdFCQVjdPVpTlZrs=
|
||||
golang.org/x/sys v0.0.0-20201013132646-2da7054afaeb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@ -565,6 +582,8 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn
|
||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
@ -575,18 +594,21 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k=
|
||||
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -139,3 +139,28 @@ func (k Keeper) GetSupplyLimit(ctx sdk.Context, denom string) (types.SupplyLimit
|
||||
}
|
||||
return asset.SupplyLimit, nil
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
// Cross Asset Getters
|
||||
// ------------------------------------------
|
||||
|
||||
// GetAuthorizedAddresses returns a list of addresses that have special authorization within this module, eg all the deputies.
|
||||
func (k Keeper) GetAuthorizedAddresses(ctx sdk.Context) []sdk.AccAddress {
|
||||
assetParams, found := k.GetAssets(ctx)
|
||||
if !found {
|
||||
// no assets params is a valid genesis state
|
||||
return nil
|
||||
}
|
||||
addresses := []sdk.AccAddress{}
|
||||
uniqueAddresses := map[string]bool{}
|
||||
|
||||
for _, ap := range assetParams {
|
||||
a := ap.DeputyAddress
|
||||
// de-dup addresses
|
||||
if _, found := uniqueAddresses[a.String()]; !found {
|
||||
addresses = append(addresses, a)
|
||||
}
|
||||
uniqueAddresses[a.String()] = true
|
||||
}
|
||||
return addresses
|
||||
}
|
||||
|
@ -116,6 +116,14 @@ func (suite *ParamsTestSuite) TestGetAssetByCoinID() {
|
||||
suite.Equal(asset, res)
|
||||
}
|
||||
|
||||
func (suite *ParamsTestSuite) TestGetAuthorizedAddresses() {
|
||||
deputyAddresses := suite.keeper.GetAuthorizedAddresses(suite.ctx)
|
||||
// the test params use the same deputy address for two assets
|
||||
expectedAddresses := []sdk.AccAddress{suite.addrs[0]}
|
||||
|
||||
suite.Require().ElementsMatch(expectedAddresses, deputyAddresses)
|
||||
}
|
||||
|
||||
func (suite *AssetTestSuite) TestValidateLiveAsset() {
|
||||
type args struct {
|
||||
coin sdk.Coin
|
||||
|
@ -59,3 +59,20 @@ func (k Keeper) GetMarket(ctx sdk.Context, marketID string) (types.Market, bool)
|
||||
}
|
||||
return types.Market{}, false
|
||||
}
|
||||
|
||||
// GetAuthorizedAddresses returns a list of addresses that have special authorization within this module, eg the oracles of all markets.
|
||||
func (k Keeper) GetAuthorizedAddresses(ctx sdk.Context) []sdk.AccAddress {
|
||||
oracles := []sdk.AccAddress{}
|
||||
uniqueOracles := map[string]bool{}
|
||||
|
||||
for _, m := range k.GetMarkets(ctx) {
|
||||
for _, o := range m.Oracles {
|
||||
// de-dup list of oracles
|
||||
if _, found := uniqueOracles[o.String()]; !found {
|
||||
oracles = append(oracles, o)
|
||||
}
|
||||
uniqueOracles[o.String()] = true
|
||||
}
|
||||
}
|
||||
return oracles
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/pricefeed"
|
||||
"github.com/kava-labs/kava/x/pricefeed/keeper"
|
||||
)
|
||||
|
||||
@ -38,15 +39,32 @@ func (suite *KeeperTestSuite) SetupTest() {
|
||||
func (suite *KeeperTestSuite) TestGetSetOracles() {
|
||||
params := suite.keeper.GetParams(suite.ctx)
|
||||
suite.Equal([]sdk.AccAddress(nil), params.Markets[0].Oracles)
|
||||
|
||||
params.Markets[0].Oracles = suite.addrs
|
||||
suite.NotPanics(func() { suite.keeper.SetParams(suite.ctx, params) })
|
||||
params = suite.keeper.GetParams(suite.ctx)
|
||||
suite.Equal(suite.addrs, params.Markets[0].Oracles)
|
||||
|
||||
addr, err := suite.keeper.GetOracle(suite.ctx, params.Markets[0].MarketID, suite.addrs[0])
|
||||
suite.NoError(err)
|
||||
suite.Equal(suite.addrs[0], addr)
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestGetAuthorizedAddresses() {
|
||||
_, oracles := app.GeneratePrivKeyAddressPairs(5)
|
||||
params := pricefeed.Params{
|
||||
Markets: []pricefeed.Market{
|
||||
{MarketID: "btc:usd", BaseAsset: "btc", QuoteAsset: "usd", Oracles: oracles[:3], Active: true},
|
||||
{MarketID: "xrp:usd", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: oracles[2:], Active: true},
|
||||
{MarketID: "xrp:usd:30", BaseAsset: "xrp", QuoteAsset: "usd", Oracles: nil, Active: true},
|
||||
},
|
||||
}
|
||||
suite.keeper.SetParams(suite.ctx, params)
|
||||
|
||||
actualOracles := suite.keeper.GetAuthorizedAddresses(suite.ctx)
|
||||
|
||||
suite.Require().ElementsMatch(oracles, actualOracles)
|
||||
}
|
||||
func TestKeeperTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(KeeperTestSuite))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user