Skip to content

Commit

Permalink
add test for debug and fix the issues identified by local test
Browse files Browse the repository at this point in the history
  • Loading branch information
TimmyExogenous committed Nov 26, 2024
1 parent c9e6035 commit afca8fd
Show file tree
Hide file tree
Showing 11 changed files with 479 additions and 183 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ $(BUILD_TARGETS): go.sum $(BUILDDIR)/
$(BUILDDIR)/:
mkdir -p $(BUILDDIR)/

build-test-tool:
CGO_ENABLED="1" go build $(BUILD_FLAGS) $(BUILD_ARGS) ./cmd/test-tool
install-test-tool:
CGO_ENABLED="1" go install $(BUILD_FLAGS) $(BUILD_ARGS) ./cmd/test-tool

build-reproducible: go.sum
$(DOCKER) rm latest-build || true
$(DOCKER) run --volume=$(CURDIR):/sources:ro \
Expand Down
48 changes: 39 additions & 9 deletions cmd/test-tool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,38 @@ import (
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"

"github.com/BurntSushi/toml"

"github.com/ExocoreNetwork/exocore/testutil/batch"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var configPath string
var homePath string

// Root command
var rootCmd = &cobra.Command{
Use: "app",
Short: "test tool application with external configuration",
Long: `This is a test tool application that loads configuration from an external file.`,
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
// Check if the subcommand is "init"
if cmd.Name() == initCmd.Name() {
// Skip manager initialization for the "init" command
return nil
}
// Initialize the manager before executing any command
var err error
config, err := loadConfig(configPath)
config, err := loadConfig(filepath.Join(homePath, batch.ConfigFileName))
if err != nil {
return fmt.Errorf("failed to load config: %v", err)
}

// Initialize the manager with the provided configuration file
appManager, err = batch.NewManager(context.Background(), config)
appManager, err = batch.NewManager(context.Background(), homePath, config)
if err != nil {
return fmt.Errorf("failed to initialize manager: %v", err)
}
Expand Down Expand Up @@ -64,8 +73,30 @@ var startCmd = &cobra.Command{
},
}

// init command
var initCmd = &cobra.Command{
Use: "init",
Short: "init the default config for the test tool",
Args: cobra.NoArgs,
Run: func(_ *cobra.Command, _ []string) {
configFilePath := filepath.Join(homePath, batch.ConfigFileName)
// Create or open the configuration file
file, err := os.Create(configFilePath)
if err != nil {
fmt.Printf("failed to create config file: %s", err)
}
defer file.Close()

// Serialize the default configuration to TOML format
encoder := toml.NewEncoder(file)
if err := encoder.Encode(batch.DefaultTestToolConfig); err != nil {
fmt.Printf("failed to encode config to TOML: %err", err)
}
},
}

// loadConfig loads the configuration file and parses it into the Config struct
func loadConfig(configPath string) (*batch.EndToEndConfig, error) {
func loadConfig(configPath string) (*batch.TestToolConfig, error) {
// Set the config file path and type (can be "yaml", "json", etc.)
viper.SetConfigFile(configPath)

Expand All @@ -75,7 +106,7 @@ func loadConfig(configPath string) (*batch.EndToEndConfig, error) {
}

// Unmarshal the config into a Config struct
var cfg batch.EndToEndConfig
var cfg batch.TestToolConfig
if err := viper.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("unable to decode into struct, %v", err)
}
Expand All @@ -85,10 +116,9 @@ func loadConfig(configPath string) (*batch.EndToEndConfig, error) {

func main() {
// Add persistent flag for the configuration file
rootCmd.PersistentFlags().StringVar(&configPath, "config", "test-tool-config.toml", "Path to the configuration file")

rootCmd.PersistentFlags().StringVar(&homePath, "home", ".", "Path to the config, db and keyRing file")
// Add subcommands
rootCmd.AddCommand(startCmd)
rootCmd.AddCommand(startCmd, initCmd)

// Execute the root command
if err := rootCmd.Execute(); err != nil {
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
cosmossdk.io/math v1.2.0
cosmossdk.io/simapp v0.0.0-20230608160436-666c345ad23d
cosmossdk.io/tools/rosetta v0.2.1
github.com/BurntSushi/toml v1.3.2
github.com/ExocoreNetwork/price-feeder v0.0.0-20241009094357-40e58e6f1694
github.com/agiledragon/gomonkey/v2 v2.11.0
github.com/armon/go-metrics v0.4.1
Expand Down Expand Up @@ -267,7 +268,8 @@ replace (
// use cosmos fork of keyring
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
// use Cosmos-SDK fork to enable Ledger functionality
github.com/cosmos/cosmos-sdk => github.com/evmos/cosmos-sdk v0.47.5-evmos.2
// github.com/cosmos/cosmos-sdk => github.com/evmos/cosmos-sdk v0.47.5-evmos.2
github.com/cosmos/cosmos-sdk => ../../cosmos-sdk
//fix cosmos-sdk error
github.com/cosmos/gogoproto => github.com/cosmos/gogoproto v1.4.10
// use Evmos geth fork
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM=
github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
Expand Down Expand Up @@ -829,8 +831,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
github.com/evmos/cosmos-sdk v0.47.5-evmos.2 h1:fyhM0NYw/FnP4ZBXzQ7k+G4fXhfdU07MONoYrGlOCpc=
github.com/evmos/cosmos-sdk v0.47.5-evmos.2/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c=
github.com/evmos/go-ethereum v1.10.26-evmos-rc2 h1:tYghk1ZZ8X4/OQ4YI9hvtm8aSN8OSqO0g9vo/sCMdBo=
github.com/evmos/go-ethereum v1.10.26-evmos-rc2/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
Expand Down
144 changes: 93 additions & 51 deletions testutil/batch/batch_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"strings"
"time"

sdkmath "cosmossdk.io/math"

"github.com/ExocoreNetwork/exocore/precompiles/assets"
"github.com/ExocoreNetwork/exocore/precompiles/delegation"
"github.com/ethereum/go-ethereum/accounts/abi"
Expand All @@ -14,20 +16,20 @@ import (
)

var (
AssetDecimalReduction = new(big.Int).Exp(big.NewInt(10), big.NewInt(DefaultAssetDecimal), nil)
DefaultDepositAmount = big.NewInt(0).Mul(big.NewInt(10000), AssetDecimalReduction)
HalfDefaultDepositAmount = big.NewInt(0).Quo(DefaultDepositAmount, big.NewInt(2))
AssetDecimalReduction = new(big.Int).Exp(big.NewInt(10), big.NewInt(DefaultAssetDecimal), nil)
DefaultDepositAmount = big.NewInt(0).Mul(big.NewInt(10000), AssetDecimalReduction)
)

type EnqueueTxParams struct {
staker *Staker
nonce *uint64
msgType string
IsCosmosTx bool
opAmount *big.Int
msgData []byte
assetID uint
operatorID uint
staker *Staker
nonce *uint64
msgType string
IsCosmosTx bool
opAmount sdkmath.Int
msgData []byte
assetID uint
operatorID uint
expectedCheckValue sdkmath.Int
}

func (m *Manager) enqueueTxAndSaveRecord(params *EnqueueTxParams) error {
Expand All @@ -37,16 +39,17 @@ func (m *Manager) enqueueTxAndSaveRecord(params *EnqueueTxParams) error {
return err
}
txRecord := &Transaction{
StakerID: params.staker.ID,
Type: params.msgType,
IsCosmosTx: params.IsCosmosTx,
OpAmount: params.opAmount.String(),
Nonce: *params.nonce,
Status: Queued,
CheckResult: WaitToCheck,
TestBatchID: helperRecord.CurrentBatchID,
AssetID: params.assetID,
OperatorID: params.operatorID,
StakerID: params.staker.ID,
Type: params.msgType,
IsCosmosTx: params.IsCosmosTx,
OpAmount: params.opAmount.String(),
Nonce: *params.nonce,
Status: Queued,
CheckResult: WaitToCheck,
TestBatchID: helperRecord.CurrentBatchID,
AssetID: params.assetID,
OperatorID: params.operatorID,
ExpectedCheckValue: params.expectedCheckValue.String(),
}
err = SaveObject(m, txRecord)
if err != nil {
Expand Down Expand Up @@ -89,12 +92,7 @@ func (m *Manager) EnqueueDepositWithdrawLSTTxs(msgType string) error {
if err != nil {
return err
}
opAmount := DefaultDepositAmount
if msgType == assets.MethodWithdrawLST {
// The remaining amount has been delegated to the operators.
// Therefore, we use half of the total deposit amount as the withdrawal amount.
opAmount = HalfDefaultDepositAmount
}
opAmount := sdkmath.NewIntFromBigInt(DefaultDepositAmount)

ethHTTPClient := m.NodeEVMHTTPClients[DefaultNodeIndex]
// construct and push all messages into the queue
Expand All @@ -110,14 +108,35 @@ func (m *Manager) EnqueueDepositWithdrawLSTTxs(msgType string) error {
if err != nil {
return err
}
// get the total deposit amount before deposit or withdrawal
stakerAssetInfo, err := m.QueryStakerAssetInfo(asset.ClientChainID, staker.EvmAddress().String(), asset.Address.String())
if err != nil {
logger.Error("EnqueueDepositWithdrawLSTTxs, error occurs when querying the staker asset info",
"staker", staker.EvmAddress().String(), "asset", asset.Address.String(), "err", err)
return err
}
expectedCheckValue := stakerAssetInfo.TotalDepositAmount
if msgType == assets.MethodDepositLST {
expectedCheckValue = expectedCheckValue.Add(opAmount)
} else {
if !stakerAssetInfo.WithdrawableAmount.IsPositive() {
logger.Error("EnqueueDepositWithdrawLSTTxs, the WithdrawableAmount isn't positive, skip the withdrawal", "staker", staker.EvmAddress().String(), "asset", asset.Address.String())
return nil
}
// withdraw all amount
opAmount = stakerAssetInfo.WithdrawableAmount
expectedCheckValue = expectedCheckValue.Sub(opAmount)
}

err = m.enqueueTxAndSaveRecord(&EnqueueTxParams{
staker: staker,
nonce: &nonce,
msgType: msgType,
IsCosmosTx: false,
opAmount: opAmount,
msgData: data,
assetID: assetId,
staker: staker,
nonce: &nonce,
msgType: msgType,
IsCosmosTx: false,
opAmount: opAmount,
msgData: data,
assetID: assetId,
expectedCheckValue: expectedCheckValue,
})
if err != nil {
return err
Expand Down Expand Up @@ -151,6 +170,8 @@ func (m *Manager) EnqueueDelegationTxs(msgType string) error {
}

ethHTTPClient := m.NodeEVMHTTPClients[DefaultNodeIndex]
opAmount := sdkmath.ZeroInt()
expectedCheckValue := sdkmath.ZeroInt()
// construct and push all messages into the queue
stakerOpFunc := func(stakerId uint, _ int64, staker *Staker) error {
nonce, err := ethHTTPClient.NonceAt(m.ctx, staker.Address, nil)
Expand All @@ -159,31 +180,52 @@ func (m *Manager) EnqueueDelegationTxs(msgType string) error {
"BatchDeposit: can't get staker's nonce, stakerId:%d, addr:%s,err:%s",
stakerId, staker.Address.String(), err)
}
// using DefaultDepositAmount/(2*operatorNumber) as the amount of each delegation.
// then we can use DefaultDepositAmount/2 as the withdrawal amount.
totalDelegationAmount := HalfDefaultDepositAmount

// todo: When calculating the delegation amount for the last operator, it's necessary
// to account for the precision loss caused by integer division. Otherwise, it could
// lead to failures in the deposit and withdrawal checks.
singleDelegationAmount := big.NewInt(0).Quo(totalDelegationAmount, big.NewInt(operatorNumber))

assetOpFunc := func(assetId uint, _ int64, asset *Asset) error {
// Each asset needs to perform delegate and undelegate operations on all operators.
stakerAssetInfo, err := m.QueryStakerAssetInfo(asset.ClientChainID, staker.EvmAddress().String(), asset.Address.String())
if err != nil {
logger.Error("EnqueueDelegationTxs, error occurs when querying the staker asset info",
"staker", staker.EvmAddress().String(), "asset", asset.Address.String(), "err", err)
return err
}
if msgType == delegation.MethodDelegate {
if !stakerAssetInfo.WithdrawableAmount.IsPositive() {
logger.Error("EnqueueDelegationTxs, the WithdrawableAmount isn't positive, skip the delegation", "staker", staker.EvmAddress().String(), "asset", asset.Address.String())
return nil
}
// delegates half of the withdrawable amount to the operators
opAmount = stakerAssetInfo.WithdrawableAmount.Quo(sdkmath.NewInt(2)).Quo(sdkmath.NewInt(operatorNumber))
}
operatorOpFunc := func(operatorId uint, _ int64, operator *Operator) error {
data, err := delegationAbi.Pack(msgType, asset.ClientChainID, nonce, PaddingAddressTo32(asset.Address), PaddingAddressTo32(staker.Address), []byte(operator.Address), singleDelegationAmount)
delegatedAmount, err := m.QueryDelegatedAmount(asset.ClientChainID, staker.EvmAddress().String(), asset.Address.String(), operator.Address)
if err != nil {
return err
}
if msgType == delegation.MethodUndelegate {
// undelegates all amount.
opAmount = delegatedAmount
} else {
expectedCheckValue = delegatedAmount.Add(opAmount)
}
if !opAmount.IsPositive() {
logger.Error("EnqueueDelegationTxs, the opAmount isn't positive, skip the test", "msgType", msgType, "staker", staker.EvmAddress().String(), "asset", asset.Address.String())
return nil
}
data, err := delegationAbi.Pack(msgType, asset.ClientChainID, nonce, PaddingAddressTo32(asset.Address), PaddingAddressTo32(staker.Address), []byte(operator.Address), opAmount)
if err != nil {
return err
}
err = m.enqueueTxAndSaveRecord(&EnqueueTxParams{
staker: staker,
nonce: &nonce,
msgType: msgType,
IsCosmosTx: false,
opAmount: singleDelegationAmount,
msgData: data,
assetID: assetId,
operatorID: operatorId,
staker: staker,
nonce: &nonce,
msgType: msgType,
IsCosmosTx: false,
opAmount: opAmount,
msgData: data,
assetID: assetId,
operatorID: operatorId,
expectedCheckValue: expectedCheckValue,

Check warning

Code scanning / CodeQL

Calling the system time Warning test

Calling the system time may be a possible source of non-determinism
})
if err != nil {
return err
Expand Down
Loading

0 comments on commit afca8fd

Please sign in to comment.