Update asset supply when params change (#604)

* fix: check asset supply

* update begin blocker

* add activation height and tests

* fix: verify outgoing swap recipient

* validate recipient address for outgoing swaps

* update activation time

* remove unused files

Co-authored-by: rhuairahrighairigh <ruaridh.odonnell@gmail.com>
This commit is contained in:
Kevin Davis 2020-06-29 17:38:26 -04:00 committed by GitHub
parent ad33296d98
commit 8001cbbfd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 167 additions and 5 deletions

View File

@ -9,4 +9,7 @@ import (
func BeginBlocker(ctx sdk.Context, k Keeper) { func BeginBlocker(ctx sdk.Context, k Keeper) {
k.UpdateExpiredAtomicSwaps(ctx) k.UpdateExpiredAtomicSwaps(ctx)
k.DeleteClosedAtomicSwapsFromLongtermStorage(ctx) k.DeleteClosedAtomicSwapsFromLongtermStorage(ctx)
if ctx.BlockTime().After(SupplyLimitUpgradeTime) {
k.UpdateAssetSupplies(ctx)
}
} }

View File

@ -2,6 +2,7 @@ package bep3_test
import ( import (
"testing" "testing"
"time"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
@ -226,7 +227,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
// Run the second begin blocker // Run the second begin blocker
bep3.BeginBlocker(tc.secondCtx, suite.keeper) bep3.BeginBlocker(tc.secondCtx, suite.keeper)
// Check each swap's availibility and status // Check each swap's availability and status
for _, swapID := range suite.swapIDs { for _, swapID := range suite.swapIDs {
_, found := suite.keeper.GetAtomicSwap(tc.secondCtx, swapID) _, found := suite.keeper.GetAtomicSwap(tc.secondCtx, swapID)
if tc.expectInStorage { if tc.expectInStorage {
@ -239,6 +240,61 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
} }
} }
func (suite *ABCITestSuite) TestBeginBlocker_UpdateAssetSupplies() {
// set new asset limit in the params
newBnbLimit := c("bnb", 100)
params := suite.keeper.GetParams(suite.ctx)
for i := range params.SupportedAssets {
if params.SupportedAssets[i].Denom != newBnbLimit.Denom {
continue
}
params.SupportedAssets[i].Limit = newBnbLimit.Amount
}
suite.keeper.SetParams(suite.ctx, params)
// store the old limit for future reference
supply, found := suite.keeper.GetAssetSupply(suite.ctx, []byte(newBnbLimit.Denom))
suite.True(found)
oldBnbLimit := supply.SupplyLimit
// run before the upgrade time, check limit was not changed
bep3.BeginBlocker(suite.ctx.WithBlockTime(bep3.SupplyLimitUpgradeTime.Add(-time.Hour)), suite.keeper)
supply, found = suite.keeper.GetAssetSupply(suite.ctx, []byte(newBnbLimit.Denom))
suite.True(found)
suite.True(supply.SupplyLimit.IsEqual(oldBnbLimit))
// run at precise upgrade time, check limit was not changed
bep3.BeginBlocker(suite.ctx.WithBlockTime(bep3.SupplyLimitUpgradeTime), suite.keeper)
supply, found = suite.keeper.GetAssetSupply(suite.ctx, []byte(newBnbLimit.Denom))
suite.True(found)
suite.True(supply.SupplyLimit.IsEqual(oldBnbLimit))
// run after upgrade time, check limit was changed
bep3.BeginBlocker(suite.ctx.WithBlockTime(bep3.SupplyLimitUpgradeTime.Add(time.Nanosecond)), suite.keeper)
supply, found = suite.keeper.GetAssetSupply(suite.ctx, []byte(newBnbLimit.Denom))
suite.True(found)
suite.True(supply.SupplyLimit.IsEqual(newBnbLimit))
// run again with new params, check limit was updated to new param limit
finalBnbLimit := c("bnb", 5000000000000)
params = suite.keeper.GetParams(suite.ctx)
for i := range params.SupportedAssets {
if params.SupportedAssets[i].Denom != finalBnbLimit.Denom {
continue
}
params.SupportedAssets[i].Limit = finalBnbLimit.Amount
}
suite.keeper.SetParams(suite.ctx, params)
bep3.BeginBlocker(suite.ctx.WithBlockTime(bep3.SupplyLimitUpgradeTime.Add(time.Hour)), suite.keeper)
supply, found = suite.keeper.GetAssetSupply(suite.ctx, []byte(newBnbLimit.Denom))
suite.True(found)
suite.True(supply.SupplyLimit.IsEqual(finalBnbLimit))
}
func TestABCITestSuite(t *testing.T) { func TestABCITestSuite(t *testing.T) {
suite.Run(t, new(ABCITestSuite)) suite.Run(t, new(ABCITestSuite))
} }

View File

@ -116,6 +116,7 @@ var (
KeyMinBlockLock = types.KeyMinBlockLock KeyMinBlockLock = types.KeyMinBlockLock
KeySupportedAssets = types.KeySupportedAssets KeySupportedAssets = types.KeySupportedAssets
ModuleCdc = types.ModuleCdc ModuleCdc = types.ModuleCdc
SupplyLimitUpgradeTime = types.SupplyLimitUpgradeTime
) )
type ( type (

View File

@ -113,3 +113,18 @@ func (k Keeper) DecrementOutgoingAssetSupply(ctx sdk.Context, coin sdk.Coin) err
k.SetAssetSupply(ctx, supply, []byte(coin.Denom)) k.SetAssetSupply(ctx, supply, []byte(coin.Denom))
return nil return nil
} }
// UpdateAssetSupplies applies updates to the asset limit from parameters to the asset supplies
func (k Keeper) UpdateAssetSupplies(ctx sdk.Context) {
params := k.GetParams(ctx)
for _, supportedAsset := range params.SupportedAssets {
asset, found := k.GetAssetSupply(ctx, []byte(supportedAsset.Denom))
if !found {
continue
}
if !asset.SupplyLimit.Amount.Equal(supportedAsset.Limit) {
asset.SupplyLimit = sdk.NewCoin(supportedAsset.Denom, supportedAsset.Limit)
k.SetAssetSupply(ctx, asset, []byte(supportedAsset.Denom))
}
}
}

View File

@ -413,6 +413,25 @@ func (suite *AssetTestSuite) TestDecrementOutgoingAssetSupply() {
} }
} }
func (suite *AssetTestSuite) TestUpdateAssetSupplies() {
// set new asset limit in the params
newBnbLimit := c("bnb", 100)
params := suite.keeper.GetParams(suite.ctx)
for i := range params.SupportedAssets {
if params.SupportedAssets[i].Denom != newBnbLimit.Denom {
continue
}
params.SupportedAssets[i].Limit = newBnbLimit.Amount
}
suite.keeper.SetParams(suite.ctx, params)
suite.keeper.UpdateAssetSupplies(suite.ctx)
supply, found := suite.keeper.GetAssetSupply(suite.ctx, []byte(newBnbLimit.Denom))
suite.True(found)
suite.True(supply.SupplyLimit.IsEqual(newBnbLimit))
}
func TestAssetTestSuite(t *testing.T) { func TestAssetTestSuite(t *testing.T) {
suite.Run(t, new(AssetTestSuite)) suite.Run(t, new(AssetTestSuite))
} }

View File

@ -69,6 +69,12 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
// Incoming swaps have already had their fees collected by the deputy during the relay process. // Incoming swaps have already had their fees collected by the deputy during the relay process.
err = k.IncrementIncomingAssetSupply(ctx, amount[0]) err = k.IncrementIncomingAssetSupply(ctx, amount[0])
case types.Outgoing: case types.Outgoing:
if ctx.BlockTime().After(types.SupplyLimitUpgradeTime) {
if !recipient.Equals(deputy) {
return sdkerrors.Wrapf(types.ErrInvalidOutgoingAccount, "%s", recipient)
}
}
// Outoing swaps must have a height span within the accepted range // Outoing swaps must have a height span within the accepted range
if heightSpan < k.GetMinBlockLock(ctx) || heightSpan > k.GetMaxBlockLock(ctx) { if heightSpan < k.GetMinBlockLock(ctx) || heightSpan > k.GetMaxBlockLock(ctx) {
return sdkerrors.Wrapf(types.ErrInvalidHeightSpan, "height span %d outside range [%d, %d]", heightSpan, k.GetMinBlockLock(ctx), k.GetMaxBlockLock(ctx)) return sdkerrors.Wrapf(types.ErrInvalidHeightSpan, "height span %d outside range [%d, %d]", heightSpan, k.GetMinBlockLock(ctx), k.GetMaxBlockLock(ctx))

View File

@ -146,7 +146,7 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
timestamp: suite.timestamps[0], timestamp: suite.timestamps[0],
heightSpan: types.DefaultMinBlockLock, heightSpan: types.DefaultMinBlockLock,
sender: suite.addrs[1], sender: suite.addrs[1],
recipient: suite.addrs[2], recipient: suite.deputy,
senderOtherChain: TestSenderOtherChain, senderOtherChain: TestSenderOtherChain,
recipientOtherChain: TestRecipientOtherChain, recipientOtherChain: TestRecipientOtherChain,
coins: cs(c(BNB_DENOM, 50000)), coins: cs(c(BNB_DENOM, 50000)),
@ -156,6 +156,60 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
true, true,
true, true,
}, },
{
"outgoing swap recipient before update",
types.SupplyLimitUpgradeTime.Add(-time.Hour),
args{
randomNumberHash: suite.randomNumberHashes[12],
timestamp: types.SupplyLimitUpgradeTime.Add(-time.Hour).Unix(),
heightSpan: types.DefaultMinBlockLock,
sender: suite.addrs[1],
recipient: suite.addrs[2],
senderOtherChain: TestUser1.String(),
recipientOtherChain: TestUser2.String(),
coins: cs(c(BNB_DENOM, 50000)),
crossChain: true,
direction: types.Outgoing,
},
true,
true,
},
{
"outgoing swap recipient at update time",
types.SupplyLimitUpgradeTime,
args{
randomNumberHash: suite.randomNumberHashes[13],
timestamp: types.SupplyLimitUpgradeTime.Unix(),
heightSpan: types.DefaultMinBlockLock,
sender: suite.addrs[1],
recipient: suite.addrs[2],
senderOtherChain: TestUser1.String(),
recipientOtherChain: TestUser2.String(),
coins: cs(c(BNB_DENOM, 50000)),
crossChain: true,
direction: types.Outgoing,
},
true,
true,
},
{
"outgoing swap recipient after update",
types.SupplyLimitUpgradeTime.Add(time.Nanosecond),
args{
randomNumberHash: suite.randomNumberHashes[14],
timestamp: types.SupplyLimitUpgradeTime.Add(time.Nanosecond).Unix(),
heightSpan: types.DefaultMinBlockLock,
sender: suite.addrs[1],
recipient: suite.addrs[2],
senderOtherChain: TestUser1.String(),
recipientOtherChain: TestUser2.String(),
coins: cs(c(BNB_DENOM, 50000)),
crossChain: true,
direction: types.Outgoing,
},
false,
false,
},
{ {
"outgoing swap amount not greater than fixed fee", "outgoing swap amount not greater than fixed fee",
@ -360,6 +414,7 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
for _, tc := range testCases { for _, tc := range testCases {
suite.Run(tc.name, func() { suite.Run(tc.name, func() {
// Increment current asset supply to support outgoing swaps // Increment current asset supply to support outgoing swaps
suite.ctx = suite.ctx.WithBlockTime(tc.blockTime)
if tc.args.direction == types.Outgoing { if tc.args.direction == types.Outgoing {
err := suite.keeper.IncrementCurrentAssetSupply(suite.ctx, tc.args.coins[0]) err := suite.keeper.IncrementCurrentAssetSupply(suite.ctx, tc.args.coins[0])
suite.Nil(err) suite.Nil(err)

View File

@ -41,4 +41,6 @@ var (
ErrSwapNotClaimable = sdkerrors.Register(ModuleName, 17, "atomic swap is not claimable") ErrSwapNotClaimable = sdkerrors.Register(ModuleName, 17, "atomic swap is not claimable")
// ErrInvalidAmount error for when a swap's amount is outside acceptable range // ErrInvalidAmount error for when a swap's amount is outside acceptable range
ErrInvalidAmount = sdkerrors.Register(ModuleName, 18, "amount is outside acceptable range") ErrInvalidAmount = sdkerrors.Register(ModuleName, 18, "amount is outside acceptable range")
// ErrInvalidOutgoingAccount error for when an outgoing swap has a recipient value that is not the deputy address
ErrInvalidOutgoingAccount = sdkerrors.Register(ModuleName, 19, "invalid recipient address for outgoing swap")
) )

View File

@ -1,6 +1,8 @@
package types package types
import ( import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
@ -19,13 +21,16 @@ const (
// DefaultParamspace default namestore // DefaultParamspace default namestore
DefaultParamspace = ModuleName DefaultParamspace = ModuleName
)
// DefaultLongtermStorageDuration is 1 week (assuming a block time of 7 seconds) // DefaultLongtermStorageDuration is 1 week (assuming a block time of 7 seconds)
const DefaultLongtermStorageDuration uint64 = 86400 DefaultLongtermStorageDuration uint64 = 86400
)
// Key prefixes // Key prefixes
var ( var (
// SupplyLimitUpgradeTime is the block time after which the asset supply limits are updated from params
SupplyLimitUpgradeTime time.Time = time.Date(2020, 7, 8, 14, 0, 0, 0, time.UTC)
AtomicSwapKeyPrefix = []byte{0x00} // prefix for keys that store AtomicSwaps AtomicSwapKeyPrefix = []byte{0x00} // prefix for keys that store AtomicSwaps
AtomicSwapByBlockPrefix = []byte{0x01} // prefix for keys of the AtomicSwapsByBlock index AtomicSwapByBlockPrefix = []byte{0x01} // prefix for keys of the AtomicSwapsByBlock index
AssetSupplyKeyPrefix = []byte{0x02} // prefix for keys that store global asset supply counts AssetSupplyKeyPrefix = []byte{0x02} // prefix for keys that store global asset supply counts