Skip to content

Commit

Permalink
Merge branch 'main' into lending
Browse files Browse the repository at this point in the history
  • Loading branch information
lazyluis committed Jan 3, 2025
2 parents 045327b + 535d595 commit aa27ba9
Show file tree
Hide file tree
Showing 22 changed files with 845 additions and 582 deletions.
206 changes: 103 additions & 103 deletions api/side/btcbridge/btcbridge.pulsar.go

Large diffs are not rendered by default.

438 changes: 287 additions & 151 deletions api/side/btcbridge/params.pulsar.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/static/openapi.yml

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion local_node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ MAX_GAS=10000000000
# btcbridge params
BTC_VAULT=() # ("<address>" "<pk>" "<asset type>")
RUNES_VAULT=()
TRUSTED_BTC_RELAYER=""
TRUSTED_NON_BTC_RELAYER=""
TRUSTED_ORACLE=""
PROTOCOL_FEE_COLLECTOR=""
Expand Down Expand Up @@ -96,7 +97,6 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then
jq --arg denom "${DENOMS[0]}" '.app_state["crisis"]["constant_fee"]["denom"]=$denom' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq --arg denom "${DENOMS[0]}" '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]=$denom' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq --arg denom "${DENOMS[0]}" '.app_state["gov"]["params"]["min_deposit"][0]["denom"]=$denom' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq --arg gas "$BLOCK_GAS" '.app_state["feemarket"]["block_gas"]=$gas' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
# Set gas limit in genesis
jq --arg max_gas "$MAX_GAS" '.consensus_params["block"]["max_gas"]=$max_gas' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

Expand All @@ -120,6 +120,11 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then
jq --arg runes_vault_asset_type "${RUNES_VAULT[2]}" '.app_state["btcbridge"]["params"]["vaults"][1]["asset_type"]=$runes_vault_asset_type' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
fi

# set trusted btc relayer
if [ -n "$TRUSTED_BTC_RELAYER" ]; then
jq --arg relayer "$TRUSTED_BTC_RELAYER" '.app_state["btcbridge"]["params"]["trusted_btc_relayers"][0]=$relayer' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
fi

# set trusted non btc relayer
if [ -n "$TRUSTED_NON_BTC_RELAYER" ]; then
jq --arg relayer "$TRUSTED_NON_BTC_RELAYER" '.app_state["btcbridge"]["params"]["trusted_non_btc_relayers"][0]=$relayer' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
Expand Down
7 changes: 6 additions & 1 deletion local_node_dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ MAX_GAS=10000000000
# btcbridge params
BTC_VAULT=() # ("<address>" "<pk>" "<asset type>")
RUNES_VAULT=()
TRUSTED_BTC_RELAYER=""
TRUSTED_NON_BTC_RELAYER=""
TRUSTED_ORACLE=""
PROTOCOL_FEE_COLLECTOR=""
Expand Down Expand Up @@ -96,7 +97,6 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then
jq --arg denom "${DENOMS[0]}" '.app_state["crisis"]["constant_fee"]["denom"]=$denom' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq --arg denom "${DENOMS[0]}" '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]=$denom' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq --arg denom "${DENOMS[0]}" '.app_state["gov"]["params"]["min_deposit"][0]["denom"]=$denom' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
jq --arg gas "$BLOCK_GAS" '.app_state["feemarket"]["block_gas"]=$gas' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
# Set gas limit in genesis
jq --arg max_gas "$MAX_GAS" '.consensus_params["block"]["max_gas"]=$max_gas' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"

Expand All @@ -120,6 +120,11 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then
jq --arg runes_vault_asset_type "${RUNES_VAULT[2]}" '.app_state["btcbridge"]["params"]["vaults"][1]["asset_type"]=$runes_vault_asset_type' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
fi

# set trusted btc relayer
if [ -n "$TRUSTED_BTC_RELAYER" ]; then
jq --arg relayer "$TRUSTED_BTC_RELAYER" '.app_state["btcbridge"]["params"]["trusted_btc_relayers"][0]=$relayer' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
fi

# set trusted non btc relayer
if [ -n "$TRUSTED_NON_BTC_RELAYER" ]; then
jq --arg relayer "$TRUSTED_NON_BTC_RELAYER" '.app_state["btcbridge"]["params"]["trusted_non_btc_relayers"][0]=$relayer' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS"
Expand Down
4 changes: 2 additions & 2 deletions proto/side/btcbridge/btcbridge.proto
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ message DKGParticipant {
string moniker = 1;
// the operator address of the corresponding validator
string operator_address = 2;
// the consensus address of the corresponding validator
string consensus_address = 3;
// the consensus public key of the corresponding validator
string consensus_pubkey = 3;
}

enum DKGRequestStatus {
Expand Down
18 changes: 10 additions & 8 deletions proto/side/btcbridge/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,24 @@ message Params {
bool deposit_enabled = 4;
// Indicates if withdrawal is enabled
bool withdraw_enabled = 5;
// Trusted relayers to submit bitcoin block headers
repeated string trusted_btc_relayers = 6;
// Trusted relayers for non-btc asset deposit
repeated string trusted_non_btc_relayers = 6;
repeated string trusted_non_btc_relayers = 7;
// Trusted oracles for providing offchain data, e.g. bitcoin fee rate
repeated string trusted_oracles = 7;
repeated string trusted_oracles = 8;
// Period of validity for the fee rate
int64 fee_rate_validity_period = 8;
int64 fee_rate_validity_period = 9;
// Asset vaults
repeated Vault vaults = 9;
repeated Vault vaults = 10;
// Withdrawal params
WithdrawParams withdraw_params = 10 [(gogoproto.nullable) = false];
WithdrawParams withdraw_params = 11 [(gogoproto.nullable) = false];
// Protocol limitations
ProtocolLimits protocol_limits = 11 [(gogoproto.nullable) = false];
ProtocolLimits protocol_limits = 12 [(gogoproto.nullable) = false];
// Protocol fees
ProtocolFees protocol_fees = 12 [(gogoproto.nullable) = false];
ProtocolFees protocol_fees = 13 [(gogoproto.nullable) = false];
// TSS params
TSSParams tss_params = 13 [(gogoproto.nullable) = false];
TSSParams tss_params = 14 [(gogoproto.nullable) = false];
}

// AssetType defines the type of asset
Expand Down
102 changes: 57 additions & 45 deletions x/btcbridge/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"encoding/base64"
"fmt"
"math/big"

"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcutil"
Expand Down Expand Up @@ -95,73 +96,72 @@ func (k Keeper) SetBlockHeader(ctx sdk.Context, header *types.BlockHeader) {
store.Set(types.BtcBlockHeaderHeightKey(header.Height), []byte(header.Hash))
}

func (k Keeper) SetBlockHeaders(ctx sdk.Context, blockHeaders []*types.BlockHeader) error {
func (k Keeper) SetBlockHeaders(ctx sdk.Context, headers []*types.BlockHeader) {
for _, h := range headers {
k.SetBlockHeader(ctx, h)
}
}

func (k Keeper) InsertBlockHeaders(ctx sdk.Context, blockHeaders []*types.BlockHeader) error {
store := ctx.KVStore(k.storeKey)

// first check if some block header already exists
for _, header := range blockHeaders {
if store.Has(types.BtcBlockHeaderHashKey(header.Hash)) {
// return no error
return nil
}
startBlockHeader := blockHeaders[0]
newBestBlockHeader := blockHeaders[len(blockHeaders)-1]

// check if the starting block header already exists
if store.Has(types.BtcBlockHeaderHashKey(startBlockHeader.Hash)) {
// return no error
return nil
}

params := k.GetParams(ctx)

// get the best block header
best := k.GetBestBlockHeader(ctx)

for _, header := range blockHeaders {
// validate the block header
if err := header.Validate(); err != nil {
return err
if startBlockHeader.PreviousBlockHash == best.Hash {
if startBlockHeader.Height != best.Height+1 {
return errorsmod.Wrap(types.ErrInvalidBlockHeaders, "invalid block height")
}
} else {
// reorg detected
// check if the reorg depth exceeds the safe confirmations
if best.Height-startBlockHeader.Height+1 > uint64(params.Confirmations) {
return types.ErrInvalidReorgDepth
}

// check if the previous block exists
if !store.Has(types.BtcBlockHeaderHashKey(header.PreviousBlockHash)) {
return errorsmod.Wrap(types.ErrInvalidBlockHeader, "previous block does not exist")
if !store.Has(types.BtcBlockHeaderHashKey(startBlockHeader.PreviousBlockHash)) {
return errorsmod.Wrap(types.ErrInvalidBlockHeaders, "previous block does not exist")
}

// check the block height
prevBlock := k.GetBlockHeader(ctx, header.PreviousBlockHash)
if header.Height != prevBlock.Height+1 {
return errorsmod.Wrap(types.ErrInvalidBlockHeader, "incorrect block height")
prevBlock := k.GetBlockHeader(ctx, startBlockHeader.PreviousBlockHash)
if startBlockHeader.Height != prevBlock.Height+1 {
return errorsmod.Wrap(types.ErrInvalidBlockHeaders, "invalid block height")
}

// check whether it's next block header or not
if best.Hash != header.PreviousBlockHash {
// check if the reorg depth exceeds the safe confirmations
if best.Height-header.Height+1 > uint64(params.Confirmations) {
return types.ErrInvalidReorgDepth
}

// check if the new block header has more work than the old one
oldNode := k.GetBlockHeaderByHeight(ctx, header.Height)
worksOld := blockchain.CalcWork(types.BitsToTargetUint32(oldNode.Bits))
worksNew := blockchain.CalcWork(types.BitsToTargetUint32(header.Bits))
if sdk.GetConfig().GetBtcChainCfg().Net == wire.MainNet && worksNew.Cmp(worksOld) <= 0 || worksNew.Cmp(worksOld) < 0 {
return types.ErrForkedBlockHeader
}

// remove the block headers after the forked block header
// and consider the forked block header as the best block header
for i := header.Height; i <= best.Height; i++ {
ctx.Logger().Info("Removing block header: ", i)
thash := k.GetBlockHashByHeight(ctx, i)
store.Delete(types.BtcBlockHeaderHashKey(thash))
store.Delete(types.BtcBlockHeaderHeightKey(i))
}
// check if the new block headers has more work than the work accumulated from the forked block to the current tip
totalWorkOldToTip := k.CalcTotalWork(ctx, startBlockHeader.Height, best.Height)
totalWorkNew := types.BlockHeaders(blockHeaders).GetTotalWork()
if sdk.GetConfig().GetBtcChainCfg().Net == wire.MainNet && totalWorkNew.Cmp(totalWorkOldToTip) <= 0 || totalWorkNew.Cmp(totalWorkOldToTip) < 0 {
return errorsmod.Wrap(types.ErrInvalidBlockHeaders, "invalid forking block headers")
}

// set the block header
k.SetBlockHeader(ctx, header)

// update the best block header
best = header
// remove the block headers starting from the forked block height
for i := startBlockHeader.Height; i <= best.Height; i++ {
ctx.Logger().Info("Removing block header: ", i)
thash := k.GetBlockHashByHeight(ctx, i)
store.Delete(types.BtcBlockHeaderHashKey(thash))
store.Delete(types.BtcBlockHeaderHeightKey(i))
}
}

// set block headers
k.SetBlockHeaders(ctx, blockHeaders)

// set the best block header
k.SetBestBlockHeader(ctx, best)
k.SetBestBlockHeader(ctx, newBestBlockHeader)

return nil
}
Expand Down Expand Up @@ -210,6 +210,18 @@ func (k Keeper) IterateBlockHeaders(ctx sdk.Context, process func(header types.B
}
}

// CalcTotalWork calculates the total work of the given range of block headers
func (k Keeper) CalcTotalWork(ctx sdk.Context, startHeight uint64, endHeight uint64) *big.Int {
totalWork := new(big.Int)

for i := startHeight; i <= endHeight; i++ {
work := k.GetBlockHeaderByHeight(ctx, i).GetWork()
totalWork = new(big.Int).Add(totalWork, work)
}

return totalWork
}

// ValidateTransaction validates the given transaction
func (k Keeper) ValidateTransaction(ctx sdk.Context, txBytes string, prevTxBytes string, blockHash string, proof []string) (*btcutil.Tx, *btcutil.Tx, error) {
params := k.GetParams(ctx)
Expand Down
6 changes: 3 additions & 3 deletions x/btcbridge/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,13 @@ func (suite *KeeperTestSuite) TestWithdrawRunes() {
denom := fmt.Sprintf("%s/%s", types.RunesProtocolName, runeId)
coin := sdk.NewInt64Coin(denom, int64(amount))

_, err := suite.app.BtcBridgeKeeper.NewSigningRequest(suite.ctx, suite.sender, coin, int64(feeRate))
_, err := suite.app.BtcBridgeKeeper.NewRunesSigningRequest(suite.ctx, suite.sender, coin, int64(feeRate), suite.runesVault, suite.btcVault)
suite.ErrorIs(err, types.ErrInsufficientUTXOs, "should fail due to insufficient runes utxos")

amount = 100000000
coin = sdk.NewInt64Coin(denom, int64(amount))

_, err = suite.app.BtcBridgeKeeper.NewSigningRequest(suite.ctx, suite.sender, coin, int64(feeRate))
_, err = suite.app.BtcBridgeKeeper.NewRunesSigningRequest(suite.ctx, suite.sender, coin, int64(feeRate), suite.runesVault, suite.btcVault)
suite.ErrorIs(err, types.ErrInsufficientUTXOs, "should fail due to insufficient payment utxos")

paymentUTXOs := []*types.UTXO{
Expand All @@ -209,7 +209,7 @@ func (suite *KeeperTestSuite) TestWithdrawRunes() {
}
suite.setupUTXOs(paymentUTXOs)

req, err := suite.app.BtcBridgeKeeper.NewSigningRequest(suite.ctx, suite.sender, coin, int64(feeRate))
req, err := suite.app.BtcBridgeKeeper.NewRunesSigningRequest(suite.ctx, suite.sender, coin, int64(feeRate), suite.runesVault, suite.btcVault)
suite.NoError(err)

suite.False(suite.app.BtcBridgeKeeper.HasUTXO(suite.ctx, runesUTXOs[0].Txid, runesUTXOs[0].Vout), "runes utxo should be spent")
Expand Down
12 changes: 8 additions & 4 deletions x/btcbridge/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ func (m msgServer) SubmitBlockHeaders(goCtx context.Context, msg *types.MsgSubmi
return nil, err
}

// Set block headers
err := m.SetBlockHeaders(ctx, msg.BlockHeaders)
if !m.IsTrustedBtcRelayer(ctx, msg.Sender) {
return nil, types.ErrUntrustedBtcRelayer
}

// insert block headers
err := m.InsertBlockHeaders(ctx, msg.BlockHeaders)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -64,7 +68,7 @@ func (m msgServer) UpdateTrustedOracles(goCtx context.Context, msg *types.MsgUpd
}

if !m.IsTrustedOracle(ctx, msg.Sender) {
return nil, types.ErruntrustedOracle
return nil, types.ErrUntrustedOracle
}

// update oracles
Expand Down Expand Up @@ -138,7 +142,7 @@ func (m msgServer) SubmitFeeRate(goCtx context.Context, msg *types.MsgSubmitFeeR
}

if !m.IsTrustedOracle(ctx, msg.Sender) {
return nil, types.ErruntrustedOracle
return nil, types.ErrUntrustedOracle
}

m.SetFeeRate(ctx, msg.FeeRate)
Expand Down
36 changes: 16 additions & 20 deletions x/btcbridge/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ func (k Keeper) BtcDenom(ctx sdk.Context) string {
return k.GetParams(ctx).BtcVoucherDenom
}

// IsTrustedBtcRelayer returns true if the given address is a trusted btc relayer, false otherwise
func (k Keeper) IsTrustedBtcRelayer(ctx sdk.Context, addr string) bool {
trustedBtcRelayers := k.GetParams(ctx).TrustedNonBtcRelayers
if len(trustedBtcRelayers) == 0 {
return true
}

for _, relayer := range trustedBtcRelayers {
if relayer == addr {
return true
}
}

return false
}

// IsTrustedNonBtcRelayer returns true if the given address is a trusted non-btc relayer, false otherwise
func (k Keeper) IsTrustedNonBtcRelayer(ctx sdk.Context, addr string) bool {
for _, relayer := range k.GetParams(ctx).TrustedNonBtcRelayers {
Expand Down Expand Up @@ -86,23 +102,3 @@ func (k Keeper) GetMaxUtxoNum(ctx sdk.Context) int {

return int(params.WithdrawParams.MaxUtxoNum)
}

// EnableBridge enables the bridge deposit and withdrawal
func (k Keeper) EnableBridge(ctx sdk.Context) {
params := k.GetParams(ctx)

params.DepositEnabled = true
params.WithdrawEnabled = true

k.SetParams(ctx, params)
}

// DisableBridge disables the bridge deposit and withdrawal
func (k Keeper) DisableBridge(ctx sdk.Context) {
params := k.GetParams(ctx)

params.DepositEnabled = false
params.WithdrawEnabled = false

k.SetParams(ctx, params)
}
15 changes: 13 additions & 2 deletions x/btcbridge/keeper/tss.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"bytes"
"encoding/base64"
"time"

"github.com/btcsuite/btcd/btcutil/psbt"
Expand Down Expand Up @@ -169,13 +170,23 @@ func (k Keeper) IterateDKGCompletionRequests(ctx sdk.Context, id uint64, cb func
// InitiateDKG initiates the DKG request by the specified params
func (k Keeper) InitiateDKG(ctx sdk.Context, participants []*types.DKGParticipant, threshold uint32, vaultTypes []types.AssetType, enableTransfer bool, targetUtxoNum uint32) (*types.DKGRequest, error) {
for _, p := range participants {
consAddress, _ := sdk.ConsAddressFromHex(p.ConsensusAddress)
valAddr, _ := sdk.ValAddressFromBech32(p.OperatorAddress)

validator, err := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddress)
validator, err := k.stakingKeeper.GetValidator(ctx, valAddr)
if err != nil {
return nil, errorsmod.Wrap(types.ErrInvalidDKGParams, "non validator")
}

pubKey, err := validator.ConsPubKey()
if err != nil {
return nil, err
}

pubKeyBytes, _ := base64.StdEncoding.DecodeString(p.ConsensusPubkey)
if !bytes.Equal(pubKeyBytes, pubKey.Bytes()) {
errorsmod.Wrap(types.ErrInvalidDKGParams, "incorrect consensus public key")
}

if validator.Status != stakingtypes.Bonded {
return nil, errorsmod.Wrap(types.ErrInvalidDKGParams, "validator not bonded")
}
Expand Down
Loading

0 comments on commit aa27ba9

Please sign in to comment.