From c1299c404b026dc8b4f7f8071a0aee0396d0fdd9 Mon Sep 17 00:00:00 2001 From: Vitalis Salis Date: Sat, 12 Oct 2024 15:00:47 +0300 Subject: [PATCH] chore: Use int64 for fee config and other type fixes The libraries that we depend to use int64 for satoshi amount denominations. To be fully compatible with them, it is better if we use similar types instead of doing conversions. Further, this PR fixes some other type conversions and minor errors found by gosec. --- CHANGELOG.md | 5 +++ Dockerfile | 2 +- babylonclient/babyloncontroller.go | 43 ++++++++++++----------- babylonclient/msgsender.go | 10 +++--- babylonclient/pop.go | 4 +-- cmd/stakercli/admin/admin.go | 2 +- cmd/stakercli/daemon/daemoncommands.go | 18 +--------- cmd/stakercli/transaction/parsers.go | 11 ++++++ cmd/stakercli/transaction/transactions.go | 22 ++++++++---- staker/babylontypes.go | 4 +-- staker/stakerapp.go | 24 ++++++------- stakercfg/config.go | 30 +++++++--------- stakerservice/client/rpcclient.go | 6 +--- stakerservice/service.go | 43 ++++++++++++++--------- 14 files changed, 117 insertions(+), 107 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6624ba9..db9bda6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [#53](https://github.com/babylonlabs-io/btc-staker/pull/53) Use only quorum of signatures when building unbonding transaction witness +### Misc Improvements + +* [51](https://github.com/babylonlabs-io/btc-staker/pull/51) Use int64 + for satoshi amount related values. + ## v0.7.0 ### Api breaking diff --git a/Dockerfile b/Dockerfile index 066a09d..1b24426 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22.3 as builder +FROM golang:1.22.3 AS builder # Install cli tools for building and final image RUN apt-get update && apt-get install -y make git bash gcc curl jq diff --git a/babylonclient/babyloncontroller.go b/babylonclient/babyloncontroller.go index 5b1522b..7a9a625 100644 --- a/babylonclient/babyloncontroller.go +++ b/babylonclient/babyloncontroller.go @@ -134,12 +134,9 @@ func (bc *BabylonController) Stop() error { } func (bc *BabylonController) Params() (*StakingParams, error) { - // TODO: uint64 are quite silly types for these params, probably uint8 or uint16 would be enough - // as we do not expect finalization to be more than 255 or in super extreme 65535 // TODO: it would probably be good to have separate methods for those var bccParams *bcctypes.Params if err := retry.Do(func() error { - response, err := bc.bbnClient.BTCCheckpointParams() if err != nil { return err @@ -174,15 +171,15 @@ func (bc *BabylonController) Params() (*StakingParams, error) { return nil, err } - if bccParams.CheckpointFinalizationTimeout > math.MaxUint16 { - return nil, fmt.Errorf("checkpoint finalization timeout is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) - } - - minUnbondingTime := sdkmath.Max[uint16]( - uint16(bccParams.CheckpointFinalizationTimeout), - stakingTrackerParams.MinUnbondingTime, + minUnbondingTimeU64 := sdkmath.Max[uint64]( + bccParams.CheckpointFinalizationTimeout, + uint64(stakingTrackerParams.MinUnbondingTime), ) + if minUnbondingTimeU64 > math.MaxUint16 { + return nil, fmt.Errorf("minimum unbonding time should fit in a uint16") + } + return &StakingParams{ ConfirmationTimeBlocks: uint32(bccParams.BtcConfirmationDepth), FinalizationTimeoutBlocks: uint32(bccParams.CheckpointFinalizationTimeout), @@ -191,7 +188,7 @@ func (bc *BabylonController) Params() (*StakingParams, error) { MinSlashingTxFeeSat: stakingTrackerParams.MinSlashingFee, SlashingRate: stakingTrackerParams.SlashingRate, CovenantQuruomThreshold: stakingTrackerParams.CovenantQuruomThreshold, - MinUnbondingTime: minUnbondingTime, + MinUnbondingTime: uint16(minUnbondingTimeU64), UnbondingFee: stakingTrackerParams.UnbondingFee, MinStakingTime: stakingTrackerParams.MinStakingTime, MaxStakingTime: stakingTrackerParams.MaxStakingTime, @@ -470,7 +467,7 @@ func (bc *BabylonController) QueryStakingTracker() (*StakingTrackerResponse, err return nil, err } - // check this early than covenant config makes sense, so that rest of the + // check early that the covenant config makes sense, so that rest of the // code can assume that: // 1. covenant quorum is less or equal to number of covenant pks // 2. covenant pks are not empty @@ -478,7 +475,7 @@ func (bc *BabylonController) QueryStakingTracker() (*StakingTrackerResponse, err return nil, fmt.Errorf("empty list of covenant pks: %w", ErrInvalidValueReceivedFromBabylonNode) } - if response.Params.CovenantQuorum > uint32(len(response.Params.CovenantPks)) { + if int(response.Params.CovenantQuorum) > len(response.Params.CovenantPks) { return nil, fmt.Errorf("covenant quorum is bigger than number of covenant pks: %w", ErrInvalidValueReceivedFromBabylonNode) } @@ -492,15 +489,18 @@ func (bc *BabylonController) QueryStakingTracker() (*StakingTrackerResponse, err covenantPks = append(covenantPks, covenantBtcPk) } - if response.Params.MinUnbondingTimeBlocks > math.MaxUint16 { + minUnbondingTimeBlocksU32 := response.Params.MinUnbondingTimeBlocks + if minUnbondingTimeBlocksU32 > math.MaxUint16 { return nil, fmt.Errorf("min unbonding time is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) } - if response.Params.MinStakingTimeBlocks > math.MaxUint16 { + minStakingTimeBlocksU32 := response.Params.MinStakingTimeBlocks + if minStakingTimeBlocksU32 > math.MaxUint16 { return nil, fmt.Errorf("min staking time is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) } - if response.Params.MaxStakingTimeBlocks > math.MaxUint16 { + maxStakingTimeBlocksU32 := response.Params.MaxStakingTimeBlocks + if maxStakingTimeBlocksU32 > math.MaxUint16 { return nil, fmt.Errorf("max staking time is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) } @@ -523,10 +523,10 @@ func (bc *BabylonController) QueryStakingTracker() (*StakingTrackerResponse, err CovenantPks: covenantPks, MinSlashingFee: btcutil.Amount(response.Params.MinSlashingTxFeeSat), CovenantQuruomThreshold: response.Params.CovenantQuorum, - MinUnbondingTime: uint16(response.Params.MinUnbondingTimeBlocks), + MinUnbondingTime: uint16(minUnbondingTimeBlocksU32), UnbondingFee: btcutil.Amount(response.Params.UnbondingFeeSat), - MinStakingTime: uint16(response.Params.MinStakingTimeBlocks), - MaxStakingTime: uint16(response.Params.MaxStakingTimeBlocks), + MinStakingTime: uint16(minStakingTimeBlocksU32), + MaxStakingTime: uint16(maxStakingTimeBlocksU32), MinStakingValue: btcutil.Amount(response.Params.MinStakingValueSat), MaxStakingValue: btcutil.Amount(response.Params.MaxStakingValueSat), }, nil @@ -798,14 +798,15 @@ func (bc *BabylonController) QueryDelegationInfo(stakingTxHash *chainhash.Hash) return retry.Unrecoverable(fmt.Errorf("malformed unbonding transaction: %s: %w", err.Error(), ErrInvalidValueReceivedFromBabylonNode)) } - if resp.BtcDelegation.UnbondingTime > math.MaxUint16 { + unbondingTimeU32 := resp.BtcDelegation.UnbondingTime + if unbondingTimeU32 > math.MaxUint16 { return retry.Unrecoverable(fmt.Errorf("malformed unbonding time: %d: %w", resp.BtcDelegation.UnbondingTime, ErrInvalidValueReceivedFromBabylonNode)) } udi = &UndelegationInfo{ UnbondingTransaction: tx, CovenantUnbondingSignatures: coventSigInfos, - UnbondingTime: uint16(resp.BtcDelegation.UnbondingTime), + UnbondingTime: uint16(unbondingTimeU32), } } diff --git a/babylonclient/msgsender.go b/babylonclient/msgsender.go index 367b788..82bba9c 100644 --- a/babylonclient/msgsender.go +++ b/babylonclient/msgsender.go @@ -21,12 +21,12 @@ var ( type sendDelegationRequest struct { utils.Request[*pv.RelayerTxResponse] dg *DelegationData - requiredInclusionBlockDepth uint64 + requiredInclusionBlockDepth uint32 } func newSendDelegationRequest( dg *DelegationData, - requiredInclusionBlockDepth uint64, + requiredInclusionBlockDepth uint32, ) sendDelegationRequest { return sendDelegationRequest{ Request: utils.NewRequest[*pv.RelayerTxResponse](), @@ -100,7 +100,7 @@ func (b *BabylonMsgSender) Stop() { // isBabylonBtcLcReady checks if Babylon BTC light client is ready to receive delegation func (b *BabylonMsgSender) isBabylonBtcLcReady( - requiredInclusionBlockDepth uint64, + requiredInclusionBlockDepth uint32, req *DelegationData, ) error { // no need to consult Babylon if we send delegation without inclusion proof @@ -121,7 +121,7 @@ func (b *BabylonMsgSender) isBabylonBtcLcReady( return fmt.Errorf("error while getting delegation data: %w", err) } - if depth < requiredInclusionBlockDepth { + if uint32(depth) < requiredInclusionBlockDepth { return fmt.Errorf("btc lc not ready, required depth: %d, current depth: %d: %w", requiredInclusionBlockDepth, depth, ErrBabylonBtcLightClientNotReady) } @@ -247,7 +247,7 @@ func (m *BabylonMsgSender) handleSentToBabylon() { func (m *BabylonMsgSender) SendDelegation( dg *DelegationData, - requiredInclusionBlockDepth uint64, + requiredInclusionBlockDepth uint32, ) (*pv.RelayerTxResponse, error) { req := newSendDelegationRequest(dg, requiredInclusionBlockDepth) diff --git a/babylonclient/pop.go b/babylonclient/pop.go index 464eac5..5734980 100644 --- a/babylonclient/pop.go +++ b/babylonclient/pop.go @@ -13,7 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -type BabylonBtcPopType int +type BabylonBtcPopType uint32 const ( SchnorrType BabylonBtcPopType = iota @@ -39,7 +39,7 @@ func NewBabylonPop(t BabylonBtcPopType, btcSigOverBbnAddr []byte) (*BabylonPop, }, nil } -// NewBabylonBip322Pop build proper BabylonPop in BIP322 style, it verifies the +// NewBabylonBip322Pop build proper BabylonPop in BIP322 style, it verifies // the bip322 signature validity func NewBabylonBip322Pop( msg []byte, diff --git a/cmd/stakercli/admin/admin.go b/cmd/stakercli/admin/admin.go index 865c89a..641fa8a 100644 --- a/cmd/stakercli/admin/admin.go +++ b/cmd/stakercli/admin/admin.go @@ -62,7 +62,7 @@ func dumpCfg(c *cli.Context) error { dir, _ := path.Split(configPath) if _, err := os.Stat(dir); os.IsNotExist(err) { - if err := os.MkdirAll(dir, os.ModePerm); err != nil { + if err := os.MkdirAll(dir, os.ModeDir); err != nil { return cli.NewExitError( fmt.Sprintf("could not create config directory: %s", err.Error()), 1, diff --git a/cmd/stakercli/daemon/daemoncommands.go b/cmd/stakercli/daemon/daemoncommands.go index 0d20d97..fe13558 100644 --- a/cmd/stakercli/daemon/daemoncommands.go +++ b/cmd/stakercli/daemon/daemoncommands.go @@ -36,7 +36,6 @@ const ( limitFlag = "limit" fpPksFlag = "finality-providers-pks" stakingTransactionHashFlag = "staking-transaction-hash" - feeRateFlag = "fee-rate" stakerAddressFlag = "staker-address" ) @@ -168,10 +167,6 @@ var unbondCmd = cli.Command{ Usage: "Hash of original staking transaction in bitcoin hex format", Required: true, }, - cli.IntFlag{ - Name: feeRateFlag, - Usage: "fee rate to pay for unbonding tx in sats/kb", - }, }, Action: unbond, } @@ -372,18 +367,7 @@ func unbond(ctx *cli.Context) error { stakingTransactionHash := ctx.String(stakingTransactionHashFlag) - feeRate := ctx.Int(feeRateFlag) - - if feeRate < 0 { - return cli.NewExitError("Fee rate must be non-negative", 1) - } - - var fr *int = nil - if feeRate > 0 { - fr = &feeRate - } - - result, err := client.UnbondStaking(sctx, stakingTransactionHash, fr) + result, err := client.UnbondStaking(sctx, stakingTransactionHash) if err != nil { return err } diff --git a/cmd/stakercli/transaction/parsers.go b/cmd/stakercli/transaction/parsers.go index 9e570cb..9457cf5 100644 --- a/cmd/stakercli/transaction/parsers.go +++ b/cmd/stakercli/transaction/parsers.go @@ -97,3 +97,14 @@ func parseTagFromHex(tagHex string) ([]byte, error) { return tag, nil } + +func parseCovenantQuorumFromCliCtx(ctx *cli.Context) (uint32, error) { + covenantQuorumUint64 := ctx.Uint64(covenantQuorumFlag) + if covenantQuorumUint64 == 0 { + return 0, fmt.Errorf("covenant quorum should be greater than 0") + } + if covenantQuorumUint64 > math.MaxUint32 { + return 0, fmt.Errorf("covenant quorum should be less or equal to %d", math.MaxUint32) + } + return uint32(covenantQuorumUint64), nil +} diff --git a/cmd/stakercli/transaction/transactions.go b/cmd/stakercli/transaction/transactions.go index 9cac11a..da16aad 100644 --- a/cmd/stakercli/transaction/transactions.go +++ b/cmd/stakercli/transaction/transactions.go @@ -294,7 +294,10 @@ func createPhase1StakingTransaction(ctx *cli.Context) error { return err } - covenantQuorum := uint32(ctx.Uint64(covenantQuorumFlag)) + covenantQuorum, err := parseCovenantQuorumFromCliCtx(ctx) + if err != nil { + return err + } _, tx, err := btcstaking.BuildV0IdentifiableStakingOutputsAndTx( tag, @@ -402,12 +405,14 @@ func checkPhase1StakingTransaction(ctx *cli.Context) error { } covenantMembersPks, err := parseCovenantKeysFromCliCtx(ctx) - if err != nil { return err } - covenantQuorum := uint32(ctx.Uint64(covenantQuorumFlag)) + covenantQuorum, err := parseCovenantQuorumFromCliCtx(ctx) + if err != nil { + return err + } stakingTx, err := btcstaking.ParseV0StakingTx( tx, @@ -439,9 +444,14 @@ func checkPhase1StakingTransaction(ctx *cli.Context) error { } } - timeBlocks := ctx.Int64(helpers.StakingTimeBlocksFlag) - if timeBlocks > 0 && uint16(timeBlocks) != stakingTx.OpReturnData.StakingTime { - return fmt.Errorf("staking time in tx %d do not match with flag %d", stakingTx.OpReturnData.StakingTime, timeBlocks) + if ctx.Int64(helpers.StakingTimeBlocksFlag) != 0 { + timeBlocks, err := parseLockTimeBlocksFromCliCtx(ctx, helpers.StakingTimeBlocksFlag) + if err != nil { + return err + } + if timeBlocks != stakingTx.OpReturnData.StakingTime { + return fmt.Errorf("staking time in tx %d do not match with flag %d", stakingTx.OpReturnData.StakingTime, timeBlocks) + } } txAmount := stakingTx.StakingOutput.Value diff --git a/staker/babylontypes.go b/staker/babylontypes.go index 5bebdcd..7f8c0af 100644 --- a/staker/babylontypes.go +++ b/staker/babylontypes.go @@ -28,10 +28,10 @@ type inclusionInfo struct { type sendDelegationRequest struct { txHash chainhash.Hash - // optional field, if not provided, delegation will be send to Babylon without + // optional field, if not provided, delegation will be sent to Babylon without // the inclusion proof inclusionInfo *inclusionInfo - requiredInclusionBlockDepth uint64 + requiredInclusionBlockDepth uint32 } func (app *StakerApp) buildOwnedDelegation( diff --git a/staker/stakerapp.go b/staker/stakerapp.go index 618e069..ccdb03b 100644 --- a/staker/stakerapp.go +++ b/staker/stakerapp.go @@ -28,7 +28,6 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btcwallet/wallet/txrules" "github.com/cometbft/cometbft/crypto/tmhash" sdk "github.com/cosmos/cosmos-sdk/types" notifier "github.com/lightningnetwork/lnd/chainntnfs" @@ -98,9 +97,6 @@ const ( defaultWalletUnlockTimeout = 15 - // Set minimum fee to 1 sat/byte, as in standard rules policy - MinFeePerKb = txrules.DefaultRelayFeePerKb - // If we fail to send unbonding tx to btc for any reason we will retry in this time unbondingSendRetryTimeout = 1 * time.Minute @@ -293,9 +289,13 @@ func (app *StakerApp) Start() error { } // we registered for notifications with `nil` so we should receive best block - // immeadiatly + // immediately select { case block := <-blockEventNotifier.Epochs: + if block.Height < 0 { + startErr = errors.New("block height is negative") + return + } app.currentBestBlockHeight.Store(uint32(block.Height)) case <-app.quit: startErr = errors.New("staker app quit before finishing start") @@ -541,7 +541,7 @@ func (app *StakerApp) checkTransactionsStatus() error { } // In our scan we only record transactions which state need to be checked, as`ScanTrackedTransactions` - // is long running read transaction, it could dead lock with write transactions which we would need + // is long-running read transaction, it could deadlock with write transactions which we would need // to use to update transaction state. err = app.txTracker.ScanTrackedTransactions(func(tx *stakerdb.StoredTransaction) error { // TODO : We need to have another stare like UnstakeTransaction sent and store @@ -638,7 +638,7 @@ func (app *StakerApp) checkTransactionsStatus() error { req := &sendDelegationRequest{ txHash: *txHashCopy, inclusionInfo: nil, - requiredInclusionBlockDepth: uint64(stakingParams.ConfirmationTimeBlocks), + requiredInclusionBlockDepth: stakingParams.ConfirmationTimeBlocks, } app.wg.Add(1) @@ -742,7 +742,7 @@ func (app *StakerApp) checkTransactionsStatus() error { inclusionBlock: details.Block, inclusionProof: iclusionProof, }, - requiredInclusionBlockDepth: uint64(stakingParams.ConfirmationTimeBlocks), + requiredInclusionBlockDepth: stakingParams.ConfirmationTimeBlocks, } app.wg.Add(1) @@ -1371,7 +1371,7 @@ func (app *StakerApp) handleStakingEvents() { req := &sendDelegationRequest{ txHash: ev.stakingTxHash, inclusionInfo: nil, - requiredInclusionBlockDepth: uint64(ev.requiredDepthOnBtcChain), + requiredInclusionBlockDepth: ev.requiredDepthOnBtcChain, } storedTx, stakerAddress := app.mustGetTransactionAndStakerAddress(&ev.stakingTxHash) @@ -1524,7 +1524,7 @@ func (app *StakerApp) handleStakingEvents() { inclusionBlock: ev.inlusionBlock, inclusionProof: proof, }, - requiredInclusionBlockDepth: uint64(ev.blockDepth), + requiredInclusionBlockDepth: ev.blockDepth, } storedTx, stakerAddress := app.mustGetTransactionAndStakerAddress(&ev.stakingTxHash) @@ -2143,7 +2143,7 @@ func (app *StakerApp) ListActiveFinalityProviders(limit uint64, offset uint64) ( return app.babylonClient.QueryFinalityProviders(limit, offset) } -// Initiates whole unbonding process. Whole process looks like this: +// UnbondStaking initiates whole unbonding process. Whole process looks like this: // 1. Unbonding data is build based on exsitng staking transaction data // 2. Unbonding data is sent to babylon as part of undelegete request // 3. If request is successful, unbonding transaction is registred in db and @@ -2154,7 +2154,7 @@ func (app *StakerApp) ListActiveFinalityProviders(limit uint64, offset uint64) ( // This function returns control to the caller after step 3. Later is up to the caller // to check what is state of unbonding transaction func (app *StakerApp) UnbondStaking( - stakingTxHash chainhash.Hash, feeRate *btcutil.Amount) (*chainhash.Hash, error) { + stakingTxHash chainhash.Hash) (*chainhash.Hash, error) { // check we are not shutting down select { case <-app.quit: diff --git a/stakercfg/config.go b/stakercfg/config.go index 85c4a22..1437907 100644 --- a/stakercfg/config.go +++ b/stakercfg/config.go @@ -23,19 +23,13 @@ import ( ) const ( - defaultDataDirname = "data" - defaultTLSCertFilename = "tls.cert" - defaultTLSKeyFilename = "tls.key" - defaultLogLevel = "info" - defaultLogDirname = "logs" - defaultLogFilename = "stakerd.log" - DefaultRPCPort = 15812 - // DefaultAutogenValidity is the default validity of a self-signed - // certificate. The value corresponds to 14 months - // (14 months * 30 days * 24 hours). - defaultTLSCertDuration = 14 * 30 * 24 * time.Hour - defaultConfigFileName = "stakerd.conf" - defaultFeeMode = "static" + defaultDataDirname = "data" + defaultLogLevel = "info" + defaultLogDirname = "logs" + defaultLogFilename = "stakerd.log" + DefaultRPCPort = 15812 + defaultConfigFileName = "stakerd.conf" + defaultFeeMode = "static" // We are using 2 sat/vbyte as default min fee rate, as currently our size estimates // for different transaction types are not very accurate and if we would use 1 sat/vbyte (minimum accepted by bitcoin network) // we risk into having transactions rejected by the network due to low fee. @@ -105,8 +99,8 @@ type BtcNodeBackendConfig struct { Nodetype string `long:"nodetype" description:"type of node to connect to {bitcoind, btcd}"` WalletType string `long:"wallettype" description:"type of wallet to connect to {bitcoind, btcwallet}"` FeeMode string `long:"feemode" description:"fee mode to use for fee estimation {static, dynamic}. In dynamic mode fee will be estimated using backend node"` - MinFeeRate uint64 `long:"minfeerate" description:"minimum fee rate to use for fee estimation in sat/vbyte. If fee estimation by connected btc node returns a lower fee rate, this value will be used instead"` - MaxFeeRate uint64 `long:"maxfeerate" description:"maximum fee rate to use for fee estimation in sat/vbyte. If fee estimation by connected btc node returns a higher fee rate, this value will be used instead. It is also used as fallback if fee estimation by connected btc node fails and as fee rate in case of static estimator"` + MinFeeRate int64 `long:"minfeerate" description:"minimum fee rate to use for fee estimation in sat/vbyte. If fee estimation by connected btc node returns a lower fee rate, this value will be used instead"` + MaxFeeRate int64 `long:"maxfeerate" description:"maximum fee rate to use for fee estimation in sat/vbyte. If fee estimation by connected btc node returns a higher fee rate, this value will be used instead. It is also used as fallback if fee estimation by connected btc node fails and as fee rate in case of static estimator"` Btcd *Btcd `group:"btcd" namespace:"btcd"` Bitcoind *Bitcoind `group:"bitcoind" namespace:"bitcoind"` EstimationMode types.FeeEstimationMode @@ -305,7 +299,7 @@ func LoadConfig() (*Config, *logrus.Logger, *zap.Logger, error) { // TODO: Add log rotation // At this point we know config is valid, create logger which also log to file logFilePath := filepath.Join(cleanCfg.LogDir, defaultLogFilename) - f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) if err != nil { return nil, nil, nil, err } @@ -443,11 +437,11 @@ func ValidateConfig(cfg Config) (*Config, error) { return nil, mkErr(fmt.Sprintf("invalid fee estimation mode: %s", cfg.BtcNodeBackendConfig.Nodetype)) } - if cfg.BtcNodeBackendConfig.MinFeeRate == 0 { + if cfg.BtcNodeBackendConfig.MinFeeRate <= 0 { return nil, mkErr("minfeerate rate must be greater than 0") } - if cfg.BtcNodeBackendConfig.MaxFeeRate == 0 { + if cfg.BtcNodeBackendConfig.MaxFeeRate <= 0 { return nil, mkErr("maxfeerate rate must be greater than 0") } diff --git a/stakerservice/client/rpcclient.go b/stakerservice/client/rpcclient.go index 7e64855..4dbbe26 100644 --- a/stakerservice/client/rpcclient.go +++ b/stakerservice/client/rpcclient.go @@ -195,16 +195,12 @@ func (c *StakerServiceJsonRpcClient) WatchStaking( return result, nil } -func (c *StakerServiceJsonRpcClient) UnbondStaking(ctx context.Context, txHash string, feeRate *int) (*service.UnbondingResponse, error) { +func (c *StakerServiceJsonRpcClient) UnbondStaking(ctx context.Context, txHash string) (*service.UnbondingResponse, error) { result := new(service.UnbondingResponse) params := make(map[string]interface{}) params["stakingTxHash"] = txHash - if feeRate != nil { - params["feeRate"] = feeRate - } - _, err := c.client.Call(ctx, "unbond_staking", params, result) if err != nil { diff --git a/stakerservice/service.go b/stakerservice/service.go index 66e4026..189ec84 100644 --- a/stakerservice/service.go +++ b/stakerservice/service.go @@ -192,11 +192,13 @@ type PageParams struct { Limit uint64 } -func getPageParams(offsetPtr *int, limitPtr *int) PageParams { +func getPageParams(offsetPtr *int, limitPtr *int) (*PageParams, error) { var limit uint64 if limitPtr == nil { limit = defaultLimit + } else if *limitPtr < 0 { + return nil, fmt.Errorf("limit cannot be negative") } else { limit = uint64(*limitPtr) } @@ -209,19 +211,24 @@ func getPageParams(offsetPtr *int, limitPtr *int) PageParams { if offsetPtr == nil { offset = defaultOffset + } else if *offsetPtr < 0 { + return nil, fmt.Errorf("offset cannot be negative") } else { offset = uint64(*offsetPtr) } - return PageParams{ + return &PageParams{ Offset: offset, Limit: limit, - } + }, nil } func (s *StakerService) providers(_ *rpctypes.Context, offset, limit *int) (*FinalityProvidersResponse, error) { - pageParams := getPageParams(offset, limit) + pageParams, err := getPageParams(offset, limit) + if err != nil { + return nil, err + } providersResp, err := s.staker.ListActiveFinalityProviders(pageParams.Limit, pageParams.Offset) @@ -249,7 +256,10 @@ func (s *StakerService) providers(_ *rpctypes.Context, offset, limit *int) (*Fin } func (s *StakerService) listStakingTransactions(_ *rpctypes.Context, offset, limit *int) (*ListStakingTransactionsResponse, error) { - pageParams := getPageParams(offset, limit) + pageParams, err := getPageParams(offset, limit) + if err != nil { + return nil, err + } txResult, err := s.staker.StoredTransactions(pageParams.Limit, pageParams.Offset) @@ -273,7 +283,10 @@ func (s *StakerService) listStakingTransactions(_ *rpctypes.Context, offset, lim } func (s *StakerService) withdrawableTransactions(_ *rpctypes.Context, offset, limit *int) (*WithdrawableTransactionsResponse, error) { - pageParams := getPageParams(offset, limit) + pageParams, err := getPageParams(offset, limit) + if err != nil { + return nil, err + } txResult, err := s.staker.WithdrawableTransactions(pageParams.Limit, pageParams.Offset) @@ -514,21 +527,14 @@ func (s *StakerService) watchStaking( }, nil } -func (s *StakerService) unbondStaking(_ *rpctypes.Context, stakingTxHash string, feeRate *int) (*UnbondingResponse, error) { +func (s *StakerService) unbondStaking(_ *rpctypes.Context, stakingTxHash string) (*UnbondingResponse, error) { txHash, err := chainhash.NewHashFromStr(stakingTxHash) if err != nil { return nil, err } - var feeRateBtc *btcutil.Amount = nil - - if feeRate != nil { - amt := btcutil.Amount(*feeRate) - feeRateBtc = &amt - } - - unbondingTxHash, err := s.staker.UnbondStaking(*txHash, feeRateBtc) + unbondingTxHash, err := s.staker.UnbondStaking(*txHash) if err != nil { return nil, err @@ -572,8 +578,11 @@ func (s *StakerService) RunUntilShutdown(ctx context.Context) error { defer func() { s.logger.Info("Closing database...") - s.db.Close() - s.logger.Info("Database closed") + if err := s.db.Close(); err != nil { + s.logger.Errorf("Error closing database: %v", err) + } else { + s.logger.Info("Database closed") + } }() mkErr := func(format string, args ...interface{}) error {