Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sign taproot thorugh psbt #21

Merged
merged 3 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion itest/bitcoind_node_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (h *BitcoindTestHandler) CreateWallet(walletName string, passphrase string)
// last false on the list will create legacy wallet. This is needed, as currently
// we are signing all taproot transactions by dumping the private key and signing it
// on app level. Descriptor wallets do not allow dumping private keys.
buff, _, err := h.m.ExecBitcoindCliCmd(h.t, []string{"createwallet", walletName, "false", "false", passphrase, "false", "false"})
buff, _, err := h.m.ExecBitcoindCliCmd(h.t, []string{"createwallet", walletName, "false", "false", passphrase})
require.NoError(h.t, err)

var response CreateWalletResponse
Expand Down
2 changes: 1 addition & 1 deletion itest/containers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type ImageConfig struct {
//nolint:deadcode
const (
dockerBitcoindRepository = "lncm/bitcoind"
dockerBitcoindVersionTag = "v24.0.1"
dockerBitcoindVersionTag = "v26.0"
)

// NewImageConfig returns ImageConfig needed for running e2e test.
Expand Down
88 changes: 57 additions & 31 deletions itest/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/babylonlabs-io/babylon/crypto/bip322"
btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types"
"github.com/cometbft/cometbft/crypto/tmhash"

staking "github.com/babylonlabs-io/babylon/btcstaking"
txformat "github.com/babylonlabs-io/babylon/btctxformatter"
Expand Down Expand Up @@ -139,7 +140,7 @@ type TestManager struct {
Db kvdb.Backend
Sa *staker.StakerApp
BabylonClient *babylonclient.BabylonController
WalletPrivKey *btcec.PrivateKey
WalletPubKey *btcec.PublicKey
MinerAddr btcutil.Address
serverStopper *signal.Interceptor
wg *sync.WaitGroup
Expand Down Expand Up @@ -294,7 +295,13 @@ func StartManager(
err = walletClient.UnlockWallet(20)
require.NoError(t, err)

walletPrivKey, err := c.DumpPrivKey(minerAddressDecoded)
info, err := c.GetAddressInfo(br.Address)
require.NoError(t, err)

pubKeyHex := *info.PubKey
pubKeyBytes, err := hex.DecodeString(pubKeyHex)
require.NoError(t, err)
walletPubKey, err := btcec.ParsePubKey(pubKeyBytes)
require.NoError(t, err)

interceptor, err := signal.Intercept()
Expand Down Expand Up @@ -334,7 +341,7 @@ func StartManager(
Db: dbbackend,
Sa: stakerApp,
BabylonClient: bl,
WalletPrivKey: walletPrivKey.PrivKey,
WalletPubKey: walletPubKey,
MinerAddr: minerAddressDecoded,
serverStopper: &interceptor,
wg: &wg,
Expand Down Expand Up @@ -809,13 +816,20 @@ func (tm *TestManager) sendWatchedStakingTx(
stakingTxSlashingPathInfo, err := stakingInfo.SlashingPathSpendInfo()
require.NoError(t, err)

slashSig, err := staking.SignTxWithOneScriptSpendInputFromScript(
slashingTx,
tx.TxOut[stakingOutputIdx],
tm.WalletPrivKey,
stakingTxSlashingPathInfo.RevealedLeaf.Script,
slashingSigResult, err := tm.Sa.Wallet().SignOneInputTaprootSpendingTransaction(
&walletcontroller.TaprootSigningRequest{
FundingOutput: stakingInfo.StakingOutput,
TxToSign: slashingTx,
SignerAddress: tm.MinerAddr,
SpendDescription: &walletcontroller.SpendPathDescription{
ControlBlock: &stakingTxSlashingPathInfo.ControlBlock,
ScriptLeaf: &stakingTxSlashingPathInfo.RevealedLeaf,
},
},
)

require.NoError(t, err)
require.NotNil(t, slashingSigResult.Signature)

serializedStakingTx, err := utils.SerializeBtcTransaction(tx)
require.NoError(t, err)
Expand Down Expand Up @@ -855,23 +869,35 @@ func (tm *TestManager) sendWatchedStakingTx(
)
require.NoError(t, err)

slashUnbondingSig, err := staking.SignTxWithOneScriptSpendInputFromScript(
slashUnbondingTx,
unbondingTx.TxOut[0],
tm.WalletPrivKey,
unbondingSlashingPathInfo.RevealedLeaf.Script,
slashingUnbondingSigResult, err := tm.Sa.Wallet().SignOneInputTaprootSpendingTransaction(
&walletcontroller.TaprootSigningRequest{
FundingOutput: unbondingTx.TxOut[0],
TxToSign: slashUnbondingTx,
SignerAddress: tm.MinerAddr,
SpendDescription: &walletcontroller.SpendPathDescription{
ControlBlock: &unbondingSlashingPathInfo.ControlBlock,
ScriptLeaf: &unbondingSlashingPathInfo.RevealedLeaf,
},
},
)

require.NoError(t, err)
require.NotNil(t, slashingUnbondingSigResult.Signature)

serializedUnbondingTx, err := utils.SerializeBtcTransaction(unbondingTx)
require.NoError(t, err)
serializedSlashUnbondingTx, err := utils.SerializeBtcTransaction(slashUnbondingTx)
require.NoError(t, err)

// TODO: Update pop when new version will be ready, for now using schnorr as we don't have
// easy way to generate bip322 sig on backend side
pop, err := btcstypes.NewPoPBTC(
testStakingData.StakerBabylonAddr,
tm.WalletPrivKey,
babylonAddrHash := tmhash.Sum(testStakingData.StakerBabylonAddr.Bytes())

sig, err := tm.Sa.Wallet().SignBip322NativeSegwit(babylonAddrHash, tm.MinerAddr)
require.NoError(t, err)

pop, err := babylonclient.NewBabylonBip322Pop(
babylonAddrHash,
sig,
tm.MinerAddr,
)
require.NoError(t, err)

Expand All @@ -888,16 +914,16 @@ func (tm *TestManager) sendWatchedStakingTx(
hex.EncodeToString(schnorr.SerializePubKey(testStakingData.StakerKey)),
fpBTCPKs,
hex.EncodeToString(serializedSlashingTx),
hex.EncodeToString(slashSig.Serialize()),
hex.EncodeToString(slashingSigResult.Signature.Serialize()),
testStakingData.StakerBabylonAddr.String(),
tm.MinerAddr.String(),
hex.EncodeToString(pop.BtcSig),
hex.EncodeToString(serializedUnbondingTx),
hex.EncodeToString(serializedSlashUnbondingTx),
hex.EncodeToString(slashUnbondingSig.Serialize()),
hex.EncodeToString(slashingUnbondingSigResult.Signature.Serialize()),
int(unbondingTme),
// Use schnor verification
int(btcstypes.BTCSigType_BIP340),
int(btcstypes.BTCSigType_BIP322),
)
require.NoError(t, err)

Expand Down Expand Up @@ -1077,7 +1103,7 @@ func TestStakingFailures(t *testing.T) {
require.NoError(t, err)
stakingTime := uint16(staker.GetMinStakingTime(params))

testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 10000, 1)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 10000, 1)
fpKey := hex.EncodeToString(schnorr.SerializePubKey(testStakingData.FinalityProviderBtcKeys[0]))

tm.createAndRegisterFinalityProviders(t, testStakingData)
Expand Down Expand Up @@ -1117,7 +1143,7 @@ func TestSendingStakingTransaction(t *testing.T) {
require.NoError(t, err)
stakingTime := uint16(staker.GetMinStakingTime(params))

testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 10000, 1)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 10000, 1)

hashed, err := chainhash.NewHash(datagen.GenRandomByteArray(r, 32))
require.NoError(t, err)
Expand Down Expand Up @@ -1197,7 +1223,7 @@ func TestMultipleWithdrawableStakingTransactions(t *testing.T) {
stakingTime4 := minStakingTime + 2
stakingTime5 := minStakingTime + 3

testStakingData1 := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime1, 10000, 1)
testStakingData1 := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime1, 10000, 1)
testStakingData2 := testStakingData1.withStakingTime(stakingTime2)
testStakingData3 := testStakingData1.withStakingTime(stakingTime3)
testStakingData4 := testStakingData1.withStakingTime(stakingTime4)
Expand Down Expand Up @@ -1257,7 +1283,7 @@ func TestSendingWatchedStakingTransaction(t *testing.T) {
params, err := cl.Params()
require.NoError(t, err)
stakingTime := uint16(staker.GetMinStakingTime(params))
testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 10000, 1)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 10000, 1)

tm.createAndRegisterFinalityProviders(t, testStakingData)

Expand All @@ -1279,7 +1305,7 @@ func TestRestartingTxNotDeepEnough(t *testing.T) {
params, err := cl.Params()
require.NoError(t, err)
stakingTime := uint16(staker.GetMinStakingTime(params))
testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 10000, 1)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 10000, 1)

tm.createAndRegisterFinalityProviders(t, testStakingData)
txHash := tm.sendStakingTxBTC(t, testStakingData)
Expand All @@ -1305,7 +1331,7 @@ func TestRestartingTxNotOnBabylon(t *testing.T) {
require.NoError(t, err)
stakingTime := uint16(staker.GetMinStakingTime(params))

testStakingData1 := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 10000, 1)
testStakingData1 := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 10000, 1)
testStakingData2 := testStakingData1.withStakingAmout(11000)

tm.createAndRegisterFinalityProviders(t, testStakingData1)
Expand Down Expand Up @@ -1347,7 +1373,7 @@ func TestStakingUnbonding(t *testing.T) {
require.NoError(t, err)
// large staking time
stakingTime := uint16(1000)
testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 50000, 1)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 50000, 1)

tm.createAndRegisterFinalityProviders(t, testStakingData)

Expand Down Expand Up @@ -1418,7 +1444,7 @@ func TestUnbondingRestartWaitingForSignatures(t *testing.T) {
require.NoError(t, err)
// large staking time
stakingTime := uint16(1000)
testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 50000, 1)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 50000, 1)

tm.createAndRegisterFinalityProviders(t, testStakingData)

Expand Down Expand Up @@ -1588,7 +1614,7 @@ func TestSendingStakingTransaction_Restaking(t *testing.T) {
stakingTime := uint16(staker.GetMinStakingTime(params))

// restaked to 5 finality providers
testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 10000, 5)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 10000, 5)

hashed, err := chainhash.NewHash(datagen.GenRandomByteArray(r, 32))
require.NoError(t, err)
Expand Down Expand Up @@ -1628,7 +1654,7 @@ func TestRecoverAfterRestartDuringWithdrawal(t *testing.T) {
require.NoError(t, err)
stakingTime := uint16(staker.GetMinStakingTime(params))

testStakingData := tm.getTestStakingData(t, tm.WalletPrivKey.PubKey(), stakingTime, 10000, 1)
testStakingData := tm.getTestStakingData(t, tm.WalletPubKey, stakingTime, 10000, 1)

hashed, err := chainhash.NewHash(datagen.GenRandomByteArray(r, 32))
require.NoError(t, err)
Expand Down
12 changes: 10 additions & 2 deletions staker/babylontypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ func (app *StakerApp) buildOwnedDelegation(
return nil, fmt.Errorf("error signing slashing transaction for staking transaction: %w", err)
}

if stakingSlashingSig.Signature == nil {
return nil, fmt.Errorf("failed to receive stakingSlashingSig.Signature ")
}

unbondingSlashingSig, err := app.signTaprootScriptSpendUsingWallet(
undelegationDesc.SlashUnbondingTransaction,
undelegationDesc.UnbondingTransaction.TxOut[0],
Expand All @@ -103,21 +107,25 @@ func (app *StakerApp) buildOwnedDelegation(
return nil, fmt.Errorf("error signing slashing transaction for unbonding transaction: %w", err)
}

if unbondingSlashingSig.Signature == nil {
return nil, fmt.Errorf("failed to receive unbondingSlashingSig.Signature ")
}

dg := createDelegationData(
externalData.stakerPublicKey,
req.inclusionBlock,
req.txIndex,
storedTx,
stakingSlashingTx,
stakingSlashingSig,
stakingSlashingSig.Signature,
externalData.babylonStakerAddr,
stakingTxInclusionProof,
&cl.UndelegationData{
UnbondingTransaction: undelegationDesc.UnbondingTransaction,
UnbondingTxValue: undelegationDesc.UnbondingTxValue,
UnbondingTxUnbondingTime: undelegationDesc.UnbondingTxUnbondingTime,
SlashUnbondingTransaction: undelegationDesc.SlashUnbondingTransaction,
SlashUnbondingTransactionSig: unbondingSlashingSig,
SlashUnbondingTransactionSig: unbondingSlashingSig.Signature,
},
)

Expand Down
18 changes: 11 additions & 7 deletions staker/stakerapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -944,14 +944,18 @@ func (app *StakerApp) sendUnbondingTxToBtcWithWitness(
return fmt.Errorf("failed to send unbondingtx. wallet signing error: %w", err)
}

if stakerUnbondingSig.Signature == nil {
return fmt.Errorf("failed to receive stakerUnbondingSig.Signature")
}

covenantSigantures := createWitnessSignaturesForPubKeys(
params.CovenantPks,
unbondingData.CovenantSignatures,
)

witness, err := unbondingSpendInfo.CreateUnbondingPathWitness(
covenantSigantures,
stakerUnbondingSig,
stakerUnbondingSig.Signature,
)

if err != nil {
Expand Down Expand Up @@ -1720,7 +1724,7 @@ func (app *StakerApp) signTaprootScriptSpendUsingWallet(
signerAddress btcutil.Address,
leaf *txscript.TapLeaf,
controlBlock *txscript.ControlBlock,
) (*schnorr.Signature, error) {
) (*walletcontroller.TaprootSigningResult, error) {

if err := app.wc.UnlockWallet(defaultWalletUnlockTimeout); err != nil {
return nil, fmt.Errorf("failed to unlock wallet before signing: %w", err)
Expand All @@ -1742,7 +1746,7 @@ func (app *StakerApp) signTaprootScriptSpendUsingWallet(
return nil, err
}

return resp.Signature, nil
return resp, nil
}

// SpendStake spends stake identified by stakingTxHash. Stake can be currently locked in
Expand Down Expand Up @@ -1832,15 +1836,15 @@ func (app *StakerApp) SpendStake(stakingTxHash *chainhash.Hash) (*chainhash.Hash
return nil, nil, fmt.Errorf("cannot spend staking output. Error building signature: %w", err)
}

witness, err := spendStakeTxInfo.fundingOutputSpendInfo.CreateTimeLockPathWitness(
stakerSig,
)
if stakerSig.FullInputWitness == nil {
return nil, nil, fmt.Errorf("failed to recevie full witness to spend staking transactions")
}

if err != nil {
return nil, nil, fmt.Errorf("cannot spend staking output. Error building witness: %w", err)
}

spendStakeTxInfo.spendStakeTx.TxIn[0].Witness = witness
spendStakeTxInfo.spendStakeTx.TxIn[0].Witness = stakerSig.FullInputWitness

// We do not check if transaction is spendable i.e the staking time has passed
// as this is validated in mempool so in of not meeting this time requirement
Expand Down
Loading
Loading