diff --git a/babylonclient/babyloncontroller.go b/babylonclient/babyloncontroller.go index 69414e5..b292476 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,24 +171,24 @@ 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, + minUnbondingTimeU32 := sdkmath.Max[uint32]( + bccParams.CheckpointFinalizationTimeout, + uint32(stakingTrackerParams.MinUnbondingTime), ) + if minUnbondingTimeU32 > math.MaxUint16 { + return nil, fmt.Errorf("minimum unbonding time should fit in a uint16") + } + return &StakingParams{ - ConfirmationTimeBlocks: uint32(bccParams.BtcConfirmationDepth), - FinalizationTimeoutBlocks: uint32(bccParams.CheckpointFinalizationTimeout), + ConfirmationTimeBlocks: bccParams.BtcConfirmationDepth, + FinalizationTimeoutBlocks: bccParams.CheckpointFinalizationTimeout, SlashingPkScript: stakingTrackerParams.SlashingPkScript, CovenantPks: stakingTrackerParams.CovenantPks, MinSlashingTxFeeSat: stakingTrackerParams.MinSlashingFee, SlashingRate: stakingTrackerParams.SlashingRate, CovenantQuruomThreshold: stakingTrackerParams.CovenantQuruomThreshold, - MinUnbondingTime: minUnbondingTime, + MinUnbondingTime: uint16(minUnbondingTimeU32), 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 @@ -663,7 +663,7 @@ func (bc *BabylonController) QueryFinalityProvider(btcPubKey *btcec.PublicKey) ( }, nil } -func (bc *BabylonController) QueryHeaderDepth(headerHash *chainhash.Hash) (uint64, error) { +func (bc *BabylonController) QueryHeaderDepth(headerHash *chainhash.Hash) (uint32, error) { ctx, cancel := getQueryContext(bc.cfg.Timeout) defer cancel() @@ -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/interface.go b/babylonclient/interface.go index 77e33a0..de6a6b9 100644 --- a/babylonclient/interface.go +++ b/babylonclient/interface.go @@ -70,7 +70,7 @@ type BabylonClient interface { Undelegate(req *UndelegationRequest) (*pv.RelayerTxResponse, error) QueryFinalityProviders(limit uint64, offset uint64) (*FinalityProvidersClientResponse, error) QueryFinalityProvider(btcPubKey *btcec.PublicKey) (*FinalityProviderClientResponse, error) - QueryHeaderDepth(headerHash *chainhash.Hash) (uint64, error) + QueryHeaderDepth(headerHash *chainhash.Hash) (uint32, error) IsTxAlreadyPartOfDelegation(stakingTxHash *chainhash.Hash) (bool, error) QueryDelegationInfo(stakingTxHash *chainhash.Hash) (*DelegationInfo, error) } @@ -142,9 +142,9 @@ func (m *MockBabylonClient) QueryFinalityProvider(btcPubKey *btcec.PublicKey) (* } } -func (m *MockBabylonClient) QueryHeaderDepth(headerHash *chainhash.Hash) (uint64, error) { +func (m *MockBabylonClient) QueryHeaderDepth(headerHash *chainhash.Hash) (uint32, error) { // return always confirmed depth - return uint64(m.ClientParams.ConfirmationTimeBlocks) + 1, nil + return m.ClientParams.ConfirmationTimeBlocks + 1, nil } func (m *MockBabylonClient) IsTxAlreadyPartOfDelegation(stakingTxHash *chainhash.Hash) (bool, error) { diff --git a/babylonclient/msgsender.go b/babylonclient/msgsender.go index 367b788..5d4a6ec 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 @@ -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/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/go.mod b/go.mod index e87b4d7..043f56c 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( cosmossdk.io/errors v1.0.1 cosmossdk.io/math v1.3.0 github.com/avast/retry-go/v4 v4.5.1 - github.com/babylonlabs-io/babylon v0.12.0 + github.com/babylonlabs-io/babylon v0.9.3-0.20241011140836-d0eca74bbfa3 github.com/babylonlabs-io/networks/parameters v0.2.2 github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2 diff --git a/go.sum b/go.sum index 61c9a22..ace85e7 100644 --- a/go.sum +++ b/go.sum @@ -287,8 +287,8 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.44.312 h1:llrElfzeqG/YOLFFKjg1xNpZCFJ2xraIi3PqSuP+95k= github.com/aws/aws-sdk-go v1.44.312/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/babylonlabs-io/babylon v0.12.0 h1:s2OTcxpk0RzrkVBnVTfnPdJVYDSqnm/33YKPQqEzNCE= -github.com/babylonlabs-io/babylon v0.12.0/go.mod h1:ZOrTde9vs2xoqGTFw4xhupu2CMulnpywiuk0eh4kPOw= +github.com/babylonlabs-io/babylon v0.9.3-0.20241011140836-d0eca74bbfa3 h1:erQaMtdl2prSINrc4sL/SZrn4+nmEsJ0vzf1FJnN5G8= +github.com/babylonlabs-io/babylon v0.9.3-0.20241011140836-d0eca74bbfa3/go.mod h1:cxRwVqVLoJ39FpyovTEHJLu1lwwrM1tE8davu7nRHwY= github.com/babylonlabs-io/networks/parameters v0.2.2 h1:TCu39fZvjX5f6ZZrjhYe54M6wWxglNewuKu56yE+zrc= github.com/babylonlabs-io/networks/parameters v0.2.2/go.mod h1:iEJVOzaLsE33vpP7J4u+CRGfkSIfErUAwRmgCFCBpyI= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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 ff6dcbd..9aa0d94 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) @@ -1363,7 +1363,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) @@ -1516,7 +1516,7 @@ func (app *StakerApp) handleStakingEvents() { inclusionBlock: ev.inlusionBlock, inclusionProof: proof, }, - requiredInclusionBlockDepth: uint64(ev.blockDepth), + requiredInclusionBlockDepth: ev.blockDepth, } storedTx, stakerAddress := app.mustGetTransactionAndStakerAddress(&ev.stakingTxHash) @@ -2135,7 +2135,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 @@ -2146,7 +2146,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, _ *btcutil.Amount) (*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/service.go b/stakerservice/service.go index 66e4026..73cfa76 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) @@ -572,8 +585,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 {