Skip to content

Commit 36f6e7b

Browse files
committed
optimize cet verification
1 parent 00e761b commit 36f6e7b

9 files changed

Lines changed: 601 additions & 420 deletions

File tree

api/side/lending/lending.pulsar.go

Lines changed: 223 additions & 165 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/side/lending/lending.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ message CetInfo {
255255
uint32 outcome_index = 2;
256256
string signature_point = 3;
257257
LeafScript script = 4 [(gogoproto.nullable) = false];
258+
uint32 sighash_type = 5;
258259
}
259260

260261
message LiquidationCet {

x/lending/keeper/dlc.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func (k Keeper) UpdateDLCMeta(ctx sdk.Context, loanId string, depositTxs []*psbt
4141
dlcMeta := k.GetDLCMeta(ctx, loanId)
4242

4343
vaultPkScript, _ := types.GetPkScriptFromAddress(loanId)
44+
dcmPkScript, _ := types.GetPkScriptFromPubKey(loan.DCM)
4445

4546
vaultUtxos, err := types.GetVaultUtxos(depositTxs, vaultPkScript)
4647
if err != nil {
@@ -63,7 +64,6 @@ func (k Keeper) UpdateDLCMeta(ctx sdk.Context, loanId string, depositTxs []*psbt
6364
repaymentScript, repaymentScriptControlBlock, _ := types.UnwrapLeafScript(dlcMeta.RepaymentScript)
6465

6566
for i := range liquidationCetPsbt.Inputs {
66-
liquidationCetPsbt.Inputs[i].SighashType = txscript.SigHashDefault
6767
liquidationCetPsbt.Inputs[i].TaprootInternalKey = internalKey
6868
liquidationCetPsbt.Inputs[i].TaprootLeafScript = []*psbt.TaprootTapLeafScript{
6969
{
@@ -74,8 +74,18 @@ func (k Keeper) UpdateDLCMeta(ctx sdk.Context, loanId string, depositTxs []*psbt
7474
}
7575
}
7676

77+
// get fee rate
78+
feeRate := k.btcbridgeKeeper.GetFeeRate(ctx)
79+
if err := k.btcbridgeKeeper.CheckFeeRate(ctx, feeRate); err != nil {
80+
return err
81+
}
82+
83+
// add DCM output to liquidation cet
84+
if err := types.AddDCMOutputToLiquidationCet(liquidationCetPsbt, liquidationScript, liquidationScriptControlBlock, dcmPkScript, feeRate.Value); err != nil {
85+
return err
86+
}
87+
7788
for i := range repaymentCetPsbt.Inputs {
78-
repaymentCetPsbt.Inputs[i].SighashType = txscript.SigHashDefault
7989
repaymentCetPsbt.Inputs[i].TaprootInternalKey = internalKey
8090
repaymentCetPsbt.Inputs[i].TaprootLeafScript = []*psbt.TaprootTapLeafScript{
8191
{
@@ -101,12 +111,7 @@ func (k Keeper) UpdateDLCMeta(ctx sdk.Context, loanId string, depositTxs []*psbt
101111
return err
102112
}
103113

104-
// get fee rate
105-
feeRate := k.BtcBridgeKeeper().GetFeeRate(ctx)
106-
if feeRate.Value == 0 {
107-
feeRate.Value = types.DefaultFeeRate
108-
}
109-
114+
// timeout refund transaction can be generated offchain as needed
110115
timeoutRefundTx, err := types.CreateTimeoutRefundTransaction(depositTxs, vaultPkScript, borrowerPkScript, internalKey, dlcMeta.TimeoutRefundScript, feeRate.Value)
111116
if err != nil {
112117
return err
@@ -179,9 +184,9 @@ func (k Keeper) GetCetInfos(ctx sdk.Context, loanId string, collateralAmount sdk
179184
k.UpdateDLCEventLiquidatedOutcome(ctx, loan, dlcEvent, liquidationPrice)
180185
}
181186

182-
liquidationCetInfo, _ := types.GetCetInfo(dlcEvent, types.LiquidatedOutcomeIndex, liquidationScript, liquidationScriptControlBlock)
183-
defaultLiquidationCetInfo, _ := types.GetCetInfo(dlcEvent, types.DefaultLiquidatedOutcomeIndex, liquidationScript, liquidationScriptControlBlock)
184-
repaymentCetInfo, _ := types.GetCetInfo(dlcEvent, types.RepaidOutcomeIndex, repaymentScript, repaymentScriptControlBlock)
187+
liquidationCetInfo, _ := types.GetCetInfo(dlcEvent, types.LiquidatedOutcomeIndex, liquidationScript, liquidationScriptControlBlock, types.BorrowerLiquidationCetSigHashType)
188+
defaultLiquidationCetInfo, _ := types.GetCetInfo(dlcEvent, types.DefaultLiquidatedOutcomeIndex, liquidationScript, liquidationScriptControlBlock, types.BorrowerLiquidationCetSigHashType)
189+
repaymentCetInfo, _ := types.GetCetInfo(dlcEvent, types.RepaidOutcomeIndex, repaymentScript, repaymentScriptControlBlock, types.DefaultSigHashType)
185190

186191
return []*types.CetInfo{
187192
liquidationCetInfo,

x/lending/keeper/msg_server_loan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ func (m msgServer) SubmitCets(goCtx context.Context, msg *types.MsgSubmitCets) (
199199
m.UpdateDLCEventLiquidatedOutcome(ctx, loan, dlcEvent, liquidationPrice)
200200

201201
// verify cets
202-
if err := types.VerifyCets(depositTxs, vaultPkScript, loan.BorrowerPubKey, loan.BorrowerAuthPubKey, loan.DCM, dlcEvent, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures); err != nil {
202+
if err := types.VerifyCets(m.GetDLCMeta(ctx, msg.LoanId), depositTxs, vaultPkScript, loan.BorrowerPubKey, loan.BorrowerAuthPubKey, loan.DCM, dlcEvent, msg.LiquidationCet, msg.LiquidationAdaptorSignatures, msg.DefaultLiquidationAdaptorSignatures, msg.RepaymentCet, msg.RepaymentSignatures); err != nil {
203203
return nil, err
204204
}
205205

x/lending/module/abci.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ func handleLiquidatedLoans(ctx sdk.Context, k keeper.Keeper) {
257257

258258
// build signed liquidation cet if both borrower adapted signatures(obviously exist) and DCM signatures already exist
259259
if len(cet.DCMSignatures) != 0 {
260-
signedTx, txHash, err := types.BuildSignedCet(cet.Tx, loan.BorrowerAuthPubKey, cet.BorrowerAdaptedSignatures, loan.DCM, cet.DCMSignatures)
260+
signedTx, txHash, err := types.BuildSignedCet(cet.Tx, loan.BorrowerAuthPubKey, cet.BorrowerAdaptedSignatures, loan.DCM, cet.DCMSignatures, cetType)
261261
if err != nil {
262262
k.Logger(ctx).Info("failed to build signed liquidation cet", "loan id", loan.VaultAddress, "err", err)
263263
} else {
@@ -331,7 +331,7 @@ func handleRepayments(ctx sdk.Context, k keeper.Keeper) {
331331
}
332332

333333
// build signed repayment cet
334-
signedTx, txHash, err := types.BuildSignedCet(dlcMeta.RepaymentCet.Tx, loan.BorrowerPubKey, dlcMeta.RepaymentCet.BorrowerSignatures, loan.DCM, dlcMeta.RepaymentCet.DCMAdaptedSignatures)
334+
signedTx, txHash, err := types.BuildSignedCet(dlcMeta.RepaymentCet.Tx, loan.BorrowerPubKey, dlcMeta.RepaymentCet.BorrowerSignatures, loan.DCM, dlcMeta.RepaymentCet.DCMAdaptedSignatures, types.CetType_REPAYMENT)
335335
if err != nil {
336336
k.Logger(ctx).Info("failed to build signed repayment cet", "loan id", loan.VaultAddress, "err", err)
337337
} else {

x/lending/types/bitcoin.go

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package types
22

33
import (
4+
"github.com/btcsuite/btcd/blockchain"
5+
"github.com/btcsuite/btcd/btcutil"
46
"github.com/btcsuite/btcd/btcutil/psbt"
57
"github.com/btcsuite/btcd/chaincfg/chainhash"
6-
"github.com/btcsuite/btcd/txscript"
8+
"github.com/btcsuite/btcd/mempool"
79
"github.com/btcsuite/btcd/wire"
810

911
btcbridgetypes "github.com/sideprotocol/side/x/btcbridge/types"
@@ -13,18 +15,15 @@ const (
1315
// default tx version
1416
TxVersion = 2
1517

16-
// default sig hash type
17-
DefaultSigHashType = txscript.SigHashDefault
18-
19-
// default fee rate
20-
DefaultFeeRate = int64(1)
18+
// default maximum allowed transaction weight
19+
MaxTransactionWeight = 400000
2120
)
2221

2322
// BuildPsbt builds a psbt from the given params
24-
func BuildPsbt(utxos []*btcbridgetypes.UTXO, recipientPkScript []byte, feeRate int64) (*psbt.Packet, error) {
23+
func BuildPsbt(utxos []*btcbridgetypes.UTXO, recipientPkScript []byte, feeRate int64, witnessSize int) (*psbt.Packet, error) {
2524
txOut := wire.NewTxOut(0, recipientPkScript)
2625

27-
unsignedTx, err := BuildUnsignedTransaction(utxos, txOut, feeRate)
26+
unsignedTx, err := BuildUnsignedTransaction(utxos, txOut, feeRate, witnessSize)
2827
if err != nil {
2928
return nil, err
3029
}
@@ -35,15 +34,14 @@ func BuildPsbt(utxos []*btcbridgetypes.UTXO, recipientPkScript []byte, feeRate i
3534
}
3635

3736
for i, utxo := range utxos {
38-
p.Inputs[i].SighashType = DefaultSigHashType
3937
p.Inputs[i].WitnessUtxo = wire.NewTxOut(int64(utxo.Amount), utxo.PubKeyScript)
4038
}
4139

4240
return p, nil
4341
}
4442

4543
// BuildUnsignedTransaction builds an unsigned tx from the given params
46-
func BuildUnsignedTransaction(utxos []*btcbridgetypes.UTXO, txOut *wire.TxOut, feeRate int64) (*wire.MsgTx, error) {
44+
func BuildUnsignedTransaction(utxos []*btcbridgetypes.UTXO, txOut *wire.TxOut, feeRate int64, witnessSize int) (*wire.MsgTx, error) {
4745
tx := wire.NewMsgTx(TxVersion)
4846

4947
inAmount := int64(0)
@@ -56,19 +54,19 @@ func BuildUnsignedTransaction(utxos []*btcbridgetypes.UTXO, txOut *wire.TxOut, f
5654

5755
tx.AddTxOut(txOut)
5856

59-
fee := btcbridgetypes.GetTxVirtualSize(tx, utxos) * feeRate
57+
fee := GetTxVirtualSize(tx, witnessSize) * feeRate
6058

6159
change := inAmount - outAmount - fee
6260
if change <= 0 {
63-
return nil, ErrFailedToBuildTx
61+
return nil, ErrInsufficientUTXOs
6462
}
6563

6664
txOut.Value += change
6765
if btcbridgetypes.IsDustOut(txOut) {
68-
return nil, ErrFailedToBuildTx
66+
return nil, ErrDustOutput
6967
}
7068

71-
if err := btcbridgetypes.CheckTransactionWeight(tx, utxos); err != nil {
69+
if err := CheckTransactionWeight(tx, witnessSize); err != nil {
7270
return nil, err
7371
}
7472

@@ -89,3 +87,36 @@ func AddUTXOToTx(tx *wire.MsgTx, utxo *btcbridgetypes.UTXO) {
8987

9088
tx.AddTxIn(txIn)
9189
}
90+
91+
// GetTxVirtualSize gets the virtual size of the given tx.
92+
func GetTxVirtualSize(tx *wire.MsgTx, witnessSize int) int64 {
93+
newTx := PopulateTxWithDummyWitness(tx, witnessSize)
94+
95+
return mempool.GetTxVirtualSize(btcutil.NewTx(newTx))
96+
}
97+
98+
// CheckTransactionWeight checks if the weight of the given tx exceeds the allowed maximum weight
99+
func CheckTransactionWeight(tx *wire.MsgTx, witnessSize int) error {
100+
newTx := PopulateTxWithDummyWitness(tx, witnessSize)
101+
102+
weight := blockchain.GetTransactionWeight(btcutil.NewTx(newTx))
103+
if weight > MaxTransactionWeight {
104+
return ErrMaxTransactionWeightExceeded
105+
}
106+
107+
return nil
108+
}
109+
110+
// PopulateTxWithDummyWitness populates the given tx with the dummy witness
111+
func PopulateTxWithDummyWitness(tx *wire.MsgTx, witnessSize int) *wire.MsgTx {
112+
newTx := tx.Copy()
113+
114+
for _, txIn := range newTx.TxIn {
115+
if len(txIn.Witness) == 0 {
116+
dummyWitness := make([]byte, witnessSize)
117+
txIn.Witness = wire.TxWitness{dummyWitness}
118+
}
119+
}
120+
121+
return newTx
122+
}

0 commit comments

Comments
 (0)