forked from cerc-io/laconicd-deprecated
update fork
This commit is contained in:
@@ -10,18 +10,18 @@ import (
|
||||
)
|
||||
|
||||
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
|
||||
// Value to the corresponding evm type.
|
||||
// value to the corresponding EVM type.
|
||||
func NewDecodeStore() func(kvA, kvB kv.Pair) string {
|
||||
return func(kvA, kvB kv.Pair) string {
|
||||
switch {
|
||||
case bytes.Equal(kvA.Key[:1], types.KeyPrefixStorage):
|
||||
storageHashA := common.BytesToHash(kvA.Value).Hex()
|
||||
storageHashB := common.BytesToHash(kvB.Value).Hex()
|
||||
storageA := common.BytesToHash(kvA.Value).Hex()
|
||||
storageB := common.BytesToHash(kvB.Value).Hex()
|
||||
|
||||
return fmt.Sprintf("%v\n%v", storageHashA, storageHashB)
|
||||
return fmt.Sprintf("%v\n%v", storageA, storageB)
|
||||
case bytes.Equal(kvA.Key[:1], types.KeyPrefixCode):
|
||||
codeHashA := common.BytesToHash(kvA.Value).Hex()
|
||||
codeHashB := common.BytesToHash(kvB.Value).Hex()
|
||||
codeHashA := common.Bytes2Hex(kvA.Value)
|
||||
codeHashB := common.Bytes2Hex(kvB.Value)
|
||||
|
||||
return fmt.Sprintf("%v\n%v", codeHashA, codeHashB)
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package simulation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/kv"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// TestDecodeStore tests that evm simulation decoder decodes the key value pairs as expected.
|
||||
func TestDecodeStore(t *testing.T) {
|
||||
dec := NewDecodeStore()
|
||||
|
||||
hash := common.BytesToHash([]byte("hash"))
|
||||
code := common.Bytes2Hex([]byte{1, 2, 3})
|
||||
|
||||
kvPairs := kv.Pairs{
|
||||
Pairs: []kv.Pair{
|
||||
{Key: types.KeyPrefixCode, Value: common.FromHex(code)},
|
||||
{Key: types.KeyPrefixStorage, Value: hash.Bytes()},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
expectedLog string
|
||||
}{
|
||||
{"Code", fmt.Sprintf("%v\n%v", code, code)},
|
||||
{"Storage", fmt.Sprintf("%v\n%v", hash, hash)},
|
||||
{"other", ""},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
i, tt := i, tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
switch i {
|
||||
case len(tests) - 1:
|
||||
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
|
||||
default:
|
||||
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -10,21 +10,45 @@ import (
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
)
|
||||
|
||||
// GenExtraEIPs randomly generates specific extra eips or not.
|
||||
func genExtraEIPs(r *rand.Rand) []int64 {
|
||||
const (
|
||||
extraEIPsKey = "extra_eips"
|
||||
)
|
||||
|
||||
// GenExtraEIPs defines a set of extra EIPs with 50% probability
|
||||
func GenExtraEIPs(r *rand.Rand) []int64 {
|
||||
var extraEIPs []int64
|
||||
if r.Uint32()%2 == 0 {
|
||||
// 50% chance of having extra EIPs
|
||||
if r.Intn(2) == 0 {
|
||||
extraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
|
||||
}
|
||||
return extraEIPs
|
||||
}
|
||||
|
||||
// RandomizedGenState generates a random GenesisState for nft
|
||||
// GenEnableCreate enables the EnableCreate param with 80% probability
|
||||
func GenEnableCreate(r *rand.Rand) bool {
|
||||
// 80% chance of enabling create contract
|
||||
enableCreate := r.Intn(100) < 80
|
||||
return enableCreate
|
||||
}
|
||||
|
||||
// GenEnableCall enables the EnableCall param with 80% probability
|
||||
func GenEnableCall(r *rand.Rand) bool {
|
||||
// 80% chance of enabling evm account transfer and calling contract
|
||||
enableCall := r.Intn(100) < 80
|
||||
return enableCall
|
||||
}
|
||||
|
||||
// RandomizedGenState generates a random GenesisState for the EVM module
|
||||
func RandomizedGenState(simState *module.SimulationState) {
|
||||
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig())
|
||||
if simState.Rand.Uint32()%2 == 0 {
|
||||
params = types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig(), 1344, 1884, 2200, 2929, 3198, 3529)
|
||||
}
|
||||
// evm params
|
||||
var extraEIPs []int64
|
||||
|
||||
simState.AppParams.GetOrGenerate(
|
||||
simState.Cdc, extraEIPsKey, &extraEIPs, simState.Rand,
|
||||
func(r *rand.Rand) { extraEIPs = GenExtraEIPs(r) },
|
||||
)
|
||||
|
||||
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig(), extraEIPs...)
|
||||
evmGenesis := types.NewGenesisState(params, []types.GenesisAccount{})
|
||||
|
||||
bz, err := json.MarshalIndent(evmGenesis, "", " ")
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package simulation_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/evm/simulation"
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
)
|
||||
|
||||
// TestRandomizedGenState tests the normal scenario of applying RandomizedGenState.
|
||||
// Abonormal scenarios are not tested here.
|
||||
func TestRandomizedGenState(t *testing.T) {
|
||||
registry := codectypes.NewInterfaceRegistry()
|
||||
types.RegisterInterfaces(registry)
|
||||
cdc := codec.NewProtoCodec(registry)
|
||||
|
||||
s := rand.NewSource(1)
|
||||
r := rand.New(s)
|
||||
|
||||
simState := module.SimulationState{
|
||||
AppParams: make(simtypes.AppParams),
|
||||
Cdc: cdc,
|
||||
Rand: r,
|
||||
NumBonded: 3,
|
||||
Accounts: simtypes.RandomAccounts(r, 3),
|
||||
InitialStake: sdkmath.NewInt(1000),
|
||||
GenState: make(map[string]json.RawMessage),
|
||||
}
|
||||
|
||||
simulation.RandomizedGenState(&simState)
|
||||
|
||||
var evmGenesis types.GenesisState
|
||||
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &evmGenesis)
|
||||
|
||||
require.Equal(t, true, evmGenesis.Params.GetEnableCreate())
|
||||
require.Equal(t, true, evmGenesis.Params.GetEnableCall())
|
||||
require.Equal(t, types.DefaultEVMDenom, evmGenesis.Params.GetEvmDenom())
|
||||
require.Equal(t, simulation.GenExtraEIPs(r), evmGenesis.Params.GetExtraEIPs())
|
||||
require.Equal(t, types.DefaultChainConfig(), evmGenesis.Params.GetChainConfig())
|
||||
|
||||
require.Equal(t, len(evmGenesis.Accounts), 0)
|
||||
}
|
||||
@@ -7,32 +7,29 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/math"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
|
||||
"github.com/cerc-io/laconicd/encoding"
|
||||
"github.com/cerc-io/laconicd/server/config"
|
||||
"github.com/cerc-io/laconicd/tests"
|
||||
"github.com/cerc-io/laconicd/x/evm/keeper"
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -118,7 +115,8 @@ func SimulateEthSimpleTransfer(ak types.AccountKeeper, k *keeper.Keeper) simtype
|
||||
}
|
||||
|
||||
// SimulateEthCreateContract simulate create an ERC20 contract.
|
||||
// It makes operationSimulateEthCallContract the future operations of SimulateEthCreateContract to ensure valid contract call.
|
||||
// It makes operationSimulateEthCallContract the future operations of SimulateEthCreateContract
|
||||
// to ensure valid contract call.
|
||||
func SimulateEthCreateContract(ak types.AccountKeeper, k *keeper.Keeper) simtypes.Operation {
|
||||
return func(
|
||||
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||
@@ -128,7 +126,7 @@ func SimulateEthCreateContract(ak types.AccountKeeper, k *keeper.Keeper) simtype
|
||||
from := common.BytesToAddress(simAccount.Address)
|
||||
nonce := k.GetNonce(ctx, from)
|
||||
|
||||
ctorArgs, err := types.ERC20Contract.ABI.Pack("", from, math.NewIntWithDecimal(1000, 18).BigInt())
|
||||
ctorArgs, err := types.ERC20Contract.ABI.Pack("", from, sdkmath.NewIntWithDecimal(1000, 18).BigInt())
|
||||
if err != nil {
|
||||
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not pack owner and supply"), nil, err
|
||||
}
|
||||
@@ -206,21 +204,28 @@ func SimulateEthTx(
|
||||
}
|
||||
|
||||
// CreateRandomValidEthTx create the ethereum tx with valid random values
|
||||
func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes) (ethTx *types.MsgEthereumTx, err error) {
|
||||
estimateGas, err := EstimateGas(ctx, from, to, data)
|
||||
func CreateRandomValidEthTx(ctx *simulateContext,
|
||||
from,
|
||||
to *common.Address,
|
||||
amount *big.Int,
|
||||
data *hexutil.Bytes,
|
||||
) (ethTx *types.MsgEthereumTx, err error) {
|
||||
gasCap := ctx.rand.Uint64()
|
||||
estimateGas, err := EstimateGas(ctx, from, to, data, gasCap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// we suppose that gasLimit should be larger than estimateGas to ensure tx validity
|
||||
gasLimit := estimateGas + uint64(ctx.rand.Intn(int(sdktx.MaxGasWanted-estimateGas)))
|
||||
ethChainID := ctx.keeper.ChainID()
|
||||
chainConfig := ctx.keeper.GetParams(ctx.context).ChainConfig.EthereumConfig(ethChainID)
|
||||
gasPrice := ctx.keeper.BaseFee(ctx.context, chainConfig)
|
||||
gasPrice := ctx.keeper.GetBaseFee(ctx.context, chainConfig)
|
||||
gasFeeCap := new(big.Int).Add(gasPrice, big.NewInt(int64(ctx.rand.Int())))
|
||||
gasTipCap := big.NewInt(int64(ctx.rand.Int()))
|
||||
nonce := ctx.keeper.GetNonce(ctx.context, *from)
|
||||
|
||||
if amount == nil {
|
||||
amount, err = RandomTransferableAmount(ctx, *from, gasLimit, gasFeeCap)
|
||||
amount, err = RandomTransferableAmount(ctx, *from, estimateGas, gasFeeCap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -231,8 +236,51 @@ func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amou
|
||||
return ethTx, nil
|
||||
}
|
||||
|
||||
// EstimateGas estimates the gas used by quering the keeper.
|
||||
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes, gasCap uint64) (gas uint64, err error) {
|
||||
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
|
||||
Args: args,
|
||||
GasCap: gasCap,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.Gas, nil
|
||||
}
|
||||
|
||||
// RandomTransferableAmount generates a random valid transferable amount.
|
||||
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
|
||||
func RandomTransferableAmount(ctx *simulateContext, address common.Address, estimateGas uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
|
||||
balance := ctx.keeper.GetBalance(ctx.context, address)
|
||||
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(estimateGas)))
|
||||
if (feeLimit.Cmp(balance)) > 0 {
|
||||
return nil, ErrNoEnoughBalance
|
||||
}
|
||||
spendable := new(big.Int).Sub(balance, feeLimit)
|
||||
if spendable.Cmp(big.NewInt(0)) == 0 {
|
||||
amount = new(big.Int).Set(spendable)
|
||||
return amount, nil
|
||||
}
|
||||
simAmount, err := simtypes.RandPositiveInt(ctx.rand, sdkmath.NewIntFromBigInt(spendable))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amount = simAmount.BigInt()
|
||||
return amount, nil
|
||||
}
|
||||
|
||||
// GetSignedTx sign the ethereum tx and packs it as a signing.Tx .
|
||||
func GetSignedTx(ctx *simulateContext, txBuilder client.TxBuilder, msg *types.MsgEthereumTx, prv cryptotypes.PrivKey) (signedTx signing.Tx, err error) {
|
||||
func GetSignedTx(
|
||||
ctx *simulateContext,
|
||||
txBuilder client.TxBuilder,
|
||||
msg *types.MsgEthereumTx,
|
||||
prv cryptotypes.PrivKey,
|
||||
) (signedTx signing.Tx, err error) {
|
||||
builder, ok := txBuilder.(tx.ExtensionOptionsTxBuilder)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("can not initiate ExtensionOptionsTxBuilder")
|
||||
@@ -256,48 +304,10 @@ func GetSignedTx(ctx *simulateContext, txBuilder client.TxBuilder, msg *types.Ms
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fees := sdk.NewCoins(sdk.NewCoin(ctx.keeper.GetParams(ctx.context).EvmDenom, sdk.NewIntFromBigInt(txData.Fee())))
|
||||
fees := sdk.NewCoins(sdk.NewCoin(ctx.keeper.GetParams(ctx.context).EvmDenom, sdkmath.NewIntFromBigInt(txData.Fee())))
|
||||
builder.SetFeeAmount(fees)
|
||||
builder.SetGasLimit(msg.GetGas())
|
||||
|
||||
signedTx = builder.GetTx()
|
||||
return signedTx, nil
|
||||
}
|
||||
|
||||
// RandomTransferableAmount generates a random valid transferable amount.
|
||||
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
|
||||
func RandomTransferableAmount(ctx *simulateContext, address common.Address, gasLimit uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
|
||||
balance := ctx.keeper.GetBalance(ctx.context, address)
|
||||
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(gasLimit)))
|
||||
if (feeLimit.Cmp(balance)) > 0 {
|
||||
return nil, ErrNoEnoughBalance
|
||||
}
|
||||
spendable := new(big.Int).Sub(balance, feeLimit)
|
||||
if spendable.Cmp(big.NewInt(0)) == 0 {
|
||||
amount = new(big.Int).Set(spendable)
|
||||
return amount, nil
|
||||
}
|
||||
simAmount, err := simtypes.RandPositiveInt(ctx.rand, sdk.NewIntFromBigInt(spendable))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
amount = simAmount.BigInt()
|
||||
return amount, nil
|
||||
}
|
||||
|
||||
// EstimateGas estimates the gas used by quering the keeper.
|
||||
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes) (gas uint64, err error) {
|
||||
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
|
||||
Args: args,
|
||||
GasCap: config.DefaultGasCap,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.Gas, nil
|
||||
}
|
||||
|
||||
@@ -7,21 +7,34 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/evm/types"
|
||||
amino "github.com/cosmos/cosmos-sdk/codec"
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
const (
|
||||
keyExtraEIPs = "ExtraEIPs"
|
||||
)
|
||||
|
||||
// ParamChanges defines the parameters that can be modified by param change proposals
|
||||
// on the simulation.
|
||||
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
|
||||
return []simtypes.ParamChange{
|
||||
simulation.NewSimParamChange(types.ModuleName, keyExtraEIPs,
|
||||
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyExtraEIPs),
|
||||
func(r *rand.Rand) string {
|
||||
return fmt.Sprintf("\"%d\"", genExtraEIPs(r))
|
||||
extraEIPs := GenExtraEIPs(r)
|
||||
amino := amino.NewLegacyAmino()
|
||||
bz, err := amino.MarshalJSON(extraEIPs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(bz)
|
||||
},
|
||||
),
|
||||
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyEnableCreate),
|
||||
func(r *rand.Rand) string {
|
||||
return fmt.Sprintf("%v", GenEnableCreate(r))
|
||||
},
|
||||
),
|
||||
simulation.NewSimParamChange(types.ModuleName, string(types.ParamStoreKeyEnableCall),
|
||||
func(r *rand.Rand) string {
|
||||
return fmt.Sprintf("%v", GenEnableCall(r))
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package simulation_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cerc-io/laconicd/x/evm/simulation"
|
||||
)
|
||||
|
||||
// TestParamChanges tests the paramChanges are generated as expected.
|
||||
func TestParamChanges(t *testing.T) {
|
||||
s := rand.NewSource(1)
|
||||
r := rand.New(s)
|
||||
|
||||
extraEIPs := simulation.GenExtraEIPs(r)
|
||||
bz, err := json.Marshal(extraEIPs)
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := []struct {
|
||||
composedKey string
|
||||
key string
|
||||
simValue string
|
||||
subspace string
|
||||
}{
|
||||
{"evm/EnableExtraEIPs", "EnableExtraEIPs", string(bz), "evm"},
|
||||
{"evm/EnableCreate", "EnableCreate", fmt.Sprintf("%v", simulation.GenEnableCreate(r)), "evm"},
|
||||
{"evm/EnableCall", "EnableCall", fmt.Sprintf("%v", simulation.GenEnableCall(r)), "evm"},
|
||||
}
|
||||
|
||||
paramChanges := simulation.ParamChanges(r)
|
||||
|
||||
require.Len(t, paramChanges, 3)
|
||||
|
||||
for i, p := range paramChanges {
|
||||
require.Equal(t, expected[i].composedKey, p.ComposedKey())
|
||||
require.Equal(t, expected[i].key, p.Key())
|
||||
require.Equal(t, expected[i].simValue, p.SimValue()(r))
|
||||
require.Equal(t, expected[i].subspace, p.Subspace())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user