mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-27 16:55:21 +00:00
004837d7fc
* feat: remove non-determism from bep3 sims
154 lines
5.3 KiB
Go
154 lines
5.3 KiB
Go
package operations
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"math/rand"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
|
|
|
"github.com/kava-labs/kava/x/bep3"
|
|
"github.com/kava-labs/kava/x/bep3/keeper"
|
|
"github.com/kava-labs/kava/x/bep3/types"
|
|
)
|
|
|
|
var (
|
|
noOpMsg = simulation.NoOpMsg(bep3.ModuleName)
|
|
)
|
|
|
|
// SimulateMsgCreateAtomicSwap generates a MsgCreateAtomicSwap with random values
|
|
func SimulateMsgCreateAtomicSwap(ak auth.AccountKeeper, k keeper.Keeper) simulation.Operation {
|
|
handler := bep3.NewHandler(k)
|
|
|
|
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
|
|
simulation.OperationMsg, []simulation.FutureOperation, error) {
|
|
|
|
sender := k.GetBnbDeputyAddress(ctx)
|
|
recipient := simulation.RandomAcc(r, accs).Address
|
|
|
|
recipientOtherChain := simulation.RandStringOfLength(r, 43)
|
|
senderOtherChain := simulation.RandStringOfLength(r, 43)
|
|
|
|
// Generate cryptographically strong pseudo-random number
|
|
randomNumber, err := simulation.RandPositiveInt(r, sdk.NewInt(math.MaxInt64))
|
|
if err != nil {
|
|
return noOpMsg, nil, err
|
|
}
|
|
// Must use current blocktime instead of 'now' since initial blocktime was randomly generated
|
|
timestamp := ctx.BlockTime().Unix()
|
|
randomNumberHash := types.CalculateRandomHash(randomNumber.BigInt().Bytes(), timestamp)
|
|
|
|
// Randomly select an asset from supported assets
|
|
assets, found := k.GetAssets(ctx)
|
|
if !found {
|
|
return noOpMsg, nil, fmt.Errorf("no supported assets found")
|
|
}
|
|
asset := assets[r.Intn(len(assets))]
|
|
|
|
// Check that the sender has coins of this type
|
|
availableAmount := ak.GetAccount(ctx, sender).GetCoins().AmountOf(asset.Denom)
|
|
if !availableAmount.IsPositive() {
|
|
return noOpMsg, nil, fmt.Errorf("available amount must be positive")
|
|
}
|
|
|
|
// Get a random amount of the available coins
|
|
amount, err := simulation.RandPositiveInt(r, availableAmount)
|
|
if err != nil {
|
|
return noOpMsg, nil, err
|
|
}
|
|
|
|
// If we don't adjust the conversion factor, we'll be out of funds soon
|
|
adjustedAmount := amount.Int64() / int64(math.Pow10(8))
|
|
coin := sdk.NewInt64Coin(asset.Denom, adjustedAmount)
|
|
coins := sdk.NewCoins(coin)
|
|
expectedIncome := coin.String()
|
|
|
|
// We're assuming that sims are run with -NumBlocks=100
|
|
heightSpan := int64(55)
|
|
crossChain := true
|
|
|
|
msg := types.NewMsgCreateAtomicSwap(
|
|
sender, recipient, recipientOtherChain, senderOtherChain, randomNumberHash,
|
|
timestamp, coins, expectedIncome, heightSpan, crossChain)
|
|
|
|
if err := msg.ValidateBasic(); err != nil {
|
|
return noOpMsg, nil, fmt.Errorf("expected MsgCreateAtomicSwap to pass ValidateBasic: %s", err)
|
|
}
|
|
|
|
// Submit msg
|
|
ok := submitMsg(ctx, handler, msg)
|
|
|
|
// If created, construct a MsgClaimAtomicSwap or MsgRefundAtomicSwap future operation
|
|
var futureOp simulation.FutureOperation
|
|
if ok {
|
|
swapID := types.CalculateSwapID(msg.RandomNumberHash, msg.From, msg.SenderOtherChain)
|
|
acc := simulation.RandomAcc(r, accs)
|
|
evenOdd := r.Intn(2) + 1
|
|
if evenOdd%2 == 0 {
|
|
// Claim future operation
|
|
executionBlock := ctx.BlockHeight() + (msg.HeightSpan / 2)
|
|
futureOp = loadClaimFutureOp(acc.Address, swapID, randomNumber.BigInt().Bytes(), executionBlock, handler)
|
|
} else {
|
|
// Refund future operation
|
|
executionBlock := ctx.BlockHeight() + msg.HeightSpan
|
|
futureOp = loadRefundFutureOp(acc.Address, swapID, executionBlock, handler)
|
|
}
|
|
}
|
|
|
|
return simulation.NewOperationMsg(msg, ok, ""), []simulation.FutureOperation{futureOp}, nil
|
|
}
|
|
}
|
|
|
|
func loadClaimFutureOp(sender sdk.AccAddress, swapID []byte, randomNumber []byte, height int64, handler sdk.Handler) simulation.FutureOperation {
|
|
claimOp := func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
|
|
simulation.OperationMsg, []simulation.FutureOperation, error) {
|
|
|
|
// Build the refund msg and validate basic
|
|
claimMsg := types.NewMsgClaimAtomicSwap(sender, swapID, randomNumber)
|
|
if err := claimMsg.ValidateBasic(); err != nil {
|
|
return noOpMsg, nil, fmt.Errorf("expected MsgClaimAtomicSwap to pass ValidateBasic: %s", err)
|
|
}
|
|
|
|
// Test msg submission at target block height
|
|
ok := handler(ctx.WithBlockHeight(height), claimMsg).IsOK()
|
|
return simulation.NewOperationMsg(claimMsg, ok, ""), nil, nil
|
|
}
|
|
|
|
return simulation.FutureOperation{
|
|
BlockHeight: int(height),
|
|
Op: claimOp,
|
|
}
|
|
}
|
|
|
|
func loadRefundFutureOp(sender sdk.AccAddress, swapID []byte, height int64, handler sdk.Handler) simulation.FutureOperation {
|
|
refundOp := func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
|
|
simulation.OperationMsg, []simulation.FutureOperation, error) {
|
|
// Build the refund msg and validate basic
|
|
refundMsg := types.NewMsgRefundAtomicSwap(sender, swapID)
|
|
if err := refundMsg.ValidateBasic(); err != nil {
|
|
return noOpMsg, nil, fmt.Errorf("expected MsgRefundAtomicSwap to pass ValidateBasic: %s", err)
|
|
}
|
|
|
|
// Test msg submission at target block height
|
|
ok := handler(ctx.WithBlockHeight(height), refundMsg).IsOK()
|
|
return simulation.NewOperationMsg(refundMsg, ok, ""), nil, nil
|
|
}
|
|
|
|
return simulation.FutureOperation{
|
|
BlockHeight: int(height),
|
|
Op: refundOp,
|
|
}
|
|
}
|
|
|
|
func submitMsg(ctx sdk.Context, handler sdk.Handler, msg sdk.Msg) (ok bool) {
|
|
ctx, write := ctx.CacheContext()
|
|
ok = handler(ctx, msg).IsOK()
|
|
if ok {
|
|
write()
|
|
}
|
|
return ok
|
|
}
|