diff --git a/cmd/stakercli/daemon/daemoncommands.go b/cmd/stakercli/daemon/daemoncommands.go index f09bb54..c2f3fe3 100644 --- a/cmd/stakercli/daemon/daemoncommands.go +++ b/cmd/stakercli/daemon/daemoncommands.go @@ -161,11 +161,6 @@ var stakeFromPhase1Cmd = cli.Command{ Usage: "BTC address of the staker in hex", Required: true, }, - cli.Uint64Flag{ - Name: txInclusionHeightFlag, - Usage: "Expected BTC height at which transaction was included. This value is important to choose correct global parameters for transaction", - Required: true, - }, }, Action: stakeFromPhase1TxBTC, } @@ -399,10 +394,14 @@ func stakeFromPhase1TxBTC(ctx *cli.Context) error { return fmt.Errorf("error parsing file %s: %w", inputGlobalParamsFilePath, err) } - stakingTxInclusionHeight := ctx.Uint64(txInclusionHeightFlag) - paramsForHeight := globalParams.GetVersionedGlobalParamsByHeight(stakingTxInclusionHeight) + resp, err := client.BtcTxDetails(sctx, stakingTransactionHash) + if err != nil { + return fmt.Errorf("error to get btc tx and block data from staking tx %s: %w", stakingTransactionHash, err) + } + + paramsForHeight := globalParams.GetVersionedGlobalParamsByHeight(uint64(resp.Blk.Height)) if paramsForHeight == nil { - return fmt.Errorf("error getting param version from global params %s with height %d", inputGlobalParamsFilePath, stakingTxInclusionHeight) + return fmt.Errorf("error getting param version from global params %s with height %d", inputGlobalParamsFilePath, resp.Blk.Height) } stakerAddress := ctx.String(stakerAddressFlag) diff --git a/staker/stakerapp.go b/staker/stakerapp.go index 3236865..52ef828 100644 --- a/staker/stakerapp.go +++ b/staker/stakerapp.go @@ -24,6 +24,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -2334,6 +2335,25 @@ func (app *App) unlockAndCreatePop(stakerAddress btcutil.Address) (*cl.BabylonPo ) } +func (app *App) BtcTxAndBlock(txHash *chainhash.Hash) (*btcjson.TxRawResult, *btcjson.GetBlockHeaderVerboseResult, error) { + tx, err := app.wc.TxVerbose(txHash) + if err != nil { + return nil, nil, err + } + + blockHash, err := chainhash.NewHashFromStr(tx.BlockHash) + if err != nil { + return nil, nil, err + } + + blk, err := app.wc.BlockHeaderVerbose(blockHash) + if err != nil { + return nil, nil, err + } + + return tx, blk, nil +} + func checkConfirmationDepth(tipBlockHeight, txInclusionBlockHeight, confirmationTimeBlocks uint32) error { if txInclusionBlockHeight >= tipBlockHeight { return fmt.Errorf("inclusion block height: %d should be lower than current tip: %d", txInclusionBlockHeight, tipBlockHeight) diff --git a/stakerservice/client/rpcclient.go b/stakerservice/client/rpcclient.go index a4f4581..d42193c 100644 --- a/stakerservice/client/rpcclient.go +++ b/stakerservice/client/rpcclient.go @@ -110,6 +110,22 @@ func (c *StakerServiceJSONRPCClient) BtcDelegationFromBtcStakingTx( return result, nil } +func (c *StakerServiceJSONRPCClient) BtcTxDetails( + ctx context.Context, + txHash string, +) (*service.BtcTxAndBlockResponse, error) { + result := new(service.BtcTxAndBlockResponse) + + params := make(map[string]interface{}) + params["txHashStr"] = txHash + + _, err := c.client.Call(ctx, "btc_tx_blk_details", params, result) + if err != nil { + return nil, err + } + return result, nil +} + func parseCovenantsPubKeyToHex(pks ...*btcec.PublicKey) []string { pksHex := make([]string, len(pks)) for i, pk := range pks { diff --git a/stakerservice/service.go b/stakerservice/service.go index 6225414..ac3dc73 100644 --- a/stakerservice/service.go +++ b/stakerservice/service.go @@ -191,8 +191,30 @@ func parseCovenantPubKeyFromHex(pkStr string) (*btcec.PublicKey, error) { return pk, nil } -func (s *StakerService) stakingDetails(_ *rpctypes.Context, - stakingTxHash string) (*StakingDetails, error) { +func (s *StakerService) btcTxBlkDetails( + _ *rpctypes.Context, + txHashStr string, +) (*BtcTxAndBlockResponse, error) { + txHash, err := chainhash.NewHashFromStr(txHashStr) + if err != nil { + return nil, err + } + + tx, blk, err := s.staker.BtcTxAndBlock(txHash) + if err != nil { + return nil, err + } + + return &BtcTxAndBlockResponse{ + Tx: tx, + Blk: blk, + }, nil +} + +func (s *StakerService) stakingDetails( + _ *rpctypes.Context, + stakingTxHash string, +) (*StakingDetails, error) { txHash, err := chainhash.NewHashFromStr(stakingTxHash) if err != nil { return nil, err @@ -619,6 +641,7 @@ func (s *StakerService) GetRoutes() RoutesMap { "list_staking_transactions": rpc.NewRPCFunc(s.listStakingTransactions, "offset,limit"), "unbond_staking": rpc.NewRPCFunc(s.unbondStaking, "stakingTxHash"), "withdrawable_transactions": rpc.NewRPCFunc(s.withdrawableTransactions, "offset,limit"), + "btc_tx_blk_details": rpc.NewRPCFunc(s.btcTxBlkDetails, "txHashStr"), // watch api "watch_staking_tx": rpc.NewRPCFunc(s.watchStaking, "stakingTx,stakingTime,stakingValue,stakerBtcPk,fpBtcPks,slashingTx,slashingTxSig,stakerBabylonAddr,stakerAddress,stakerBtcSig,unbondingTx,slashUnbondingTx,slashUnbondingTxSig,unbondingTime,popType"), diff --git a/stakerservice/stakerdresponses.go b/stakerservice/stakerdresponses.go index a8e8486..ac52fbb 100644 --- a/stakerservice/stakerdresponses.go +++ b/stakerservice/stakerdresponses.go @@ -1,5 +1,7 @@ package stakerservice +import "github.com/btcsuite/btcd/btcjson" + type ResultHealth struct{} type ResultBtcDelegationFromBtcStakingTx struct { @@ -57,3 +59,8 @@ type WithdrawableTransactionsResponse struct { LastWithdrawableTransactionIndex string `json:"last_transaction_index"` TotalTransactionCount string `json:"total_transaction_count"` } + +type BtcTxAndBlockResponse struct { + Tx *btcjson.TxRawResult `json:"tx"` + Blk *btcjson.GetBlockHeaderVerboseResult `json:"blk"` +} diff --git a/walletcontroller/client.go b/walletcontroller/client.go index 8dc0833..acae62e 100644 --- a/walletcontroller/client.go +++ b/walletcontroller/client.go @@ -270,12 +270,17 @@ func (w *RPCWalletController) getTxDetails(req notifier.ConfRequest, msg string) // Tx returns the raw transaction based on the transaction hash func (w *RPCWalletController) Tx(txHash *chainhash.Hash) (*btcutil.Tx, error) { - rawTx, err := w.Client.GetRawTransaction(txHash) - if err != nil { - return nil, err - } + return w.Client.GetRawTransaction(txHash) +} + +// TxVerbose returns the raw transaction verbose based on the transaction hash +func (w *RPCWalletController) TxVerbose(txHash *chainhash.Hash) (*btcjson.TxRawResult, error) { + return w.Client.GetRawTransactionVerbose(txHash) +} - return rawTx, nil +// BlockHeaderVerbose returns the block header data based on the block hash +func (w *RPCWalletController) BlockHeaderVerbose(blockHash *chainhash.Hash) (*btcjson.GetBlockHeaderVerboseResult, error) { + return w.Client.GetBlockHeaderVerbose(blockHash) } // Fetch info about transaction from mempool or blockchain, requires node to have enabled transaction index diff --git a/walletcontroller/interface.go b/walletcontroller/interface.go index 2dcd151..a57a351 100644 --- a/walletcontroller/interface.go +++ b/walletcontroller/interface.go @@ -4,6 +4,7 @@ import ( staking "github.com/babylonlabs-io/babylon/btcstaking" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -71,6 +72,8 @@ type WalletController interface { ListOutputs(onlySpendable bool) ([]Utxo, error) TxDetails(txHash *chainhash.Hash, pkScript []byte) (*notifier.TxConfirmation, TxStatus, error) Tx(txHash *chainhash.Hash) (*btcutil.Tx, error) + TxVerbose(txHash *chainhash.Hash) (*btcjson.TxRawResult, error) + BlockHeaderVerbose(blockHash *chainhash.Hash) (*btcjson.GetBlockHeaderVerboseResult, error) SignBip322NativeSegwit(msg []byte, address btcutil.Address) (wire.TxWitness, error) // SignOneInputTaprootSpendingTransaction signs transactions with one taproot input that // uses script spending path.