Skip to content

Commit

Permalink
complete bitcoin deposit
Browse files Browse the repository at this point in the history
  • Loading branch information
liangping committed May 24, 2024
1 parent 3062f2b commit 0ff99ba
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 9 deletions.
1 change: 1 addition & 0 deletions app/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ var moduleAccountPermissions = map[string][]string{
wasmTypes.ModuleName: {authtypes.Burner},
gmmmoduletypes.ModuleName: {authtypes.Minter, authtypes.Burner, authtypes.Staking},
yieldmoduletypes.ModuleName: {authtypes.Minter, authtypes.Burner, authtypes.Staking},
btclightclienttypes.ModuleName: {authtypes.Minter, authtypes.Burner},
}

// appModules return modules to initialize module manager.
Expand Down
42 changes: 42 additions & 0 deletions x/btclightclient/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package cli

import (
"fmt"
"strconv"

// "strings"

"github.com/sideprotocol/side/x/btclightclient/types"
Expand All @@ -24,6 +26,7 @@ func GetQueryCmd(_ string) *cobra.Command {

cmd.AddCommand(CmdQueryParams())
cmd.AddCommand(CmdBestBlock())
cmd.AddCommand(CmdQueryBlock())
// this line is used by starport scaffolding # 1

return cmd
Expand Down Expand Up @@ -82,3 +85,42 @@ func CmdBestBlock() *cobra.Command {

return cmd
}

// CmdQueryBlock returns the command to query the heights of the light client
func CmdQueryBlock() *cobra.Command {
cmd := &cobra.Command{
Use: "block [hash or height]",
Short: "Query block by hash or height",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

height, err := strconv.ParseUint(args[0], 10, 64)

if err != nil {
res, err := queryClient.QueryBlockHeaderByHash(cmd.Context(), &types.QueryBlockHeaderByHashRequest{Hash: args[0]})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
}

res, err := queryClient.QueryBlockHeaderByHeight(cmd.Context(), &types.QueryBlockHeaderByHeightRequest{Height: height})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
50 changes: 50 additions & 0 deletions x/btclightclient/genesis_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package btclightclient_test

// Path: x/btclightclient/genesis_test.go

import (
"bytes"
"encoding/hex"
"testing"

"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/wire"
keepertest "github.com/sideprotocol/side/testutil/keeper"
"github.com/sideprotocol/side/testutil/nullify"
"github.com/sideprotocol/side/x/btclightclient"
Expand Down Expand Up @@ -31,3 +37,47 @@ func TestGenesis(t *testing.T) {

// this line is used by starport scaffolding # genesis/test/assert
}

// TestSubmitTx tests the SubmitTx function
// func TestSubmitTx(t *testing.T) {

// // test tx: https://blockchain.info/tx/b657e22827039461a9493ede7bdf55b01579254c1630b0bfc9185ec564fc05ab?format=json

// k, ctx := keepertest.BtcLightClientKeeper(t)

// txHex := "02000000000101e5df234dbeff74d6da14754ebeea8ab0e2f60b1884566846cf6b36e8ceb5f5350100000000fdffffff02f0490200000000001600142ac13073e8d491428790481321a636696d00107681d7e205000000001600142bf3aa186cbdcbe88b70a67edcd5a32ce5e8e6d8024730440220081ee61d749ce8cedcf6eedde885579af2eb65ca67d29e6ae2c37109d81cbbb202203a1891ce45f91f159ccf04348ef37a3d1a12d89e5e01426e061326057e6c128d012103036bbdd77c9a932f37bd66175967c7fb7eb75ece06b87c1ad1716770cb3ca4ee79fc2a00"
// prevTxHex := "0200000000010183372652f2af9ab34b3a003efada6b054c75583185ac130de72599dfdf4e462b0100000000fdffffff02f0490200000000001600142ac13073e8d491428790481321a636696d001076a64ee50500000000160014a03614eef338681373de94a2dc2574de55da1980024730440220274250f6036bea0947daf4455ab4976f81721257d163fd952fb5b0c70470edc602202fba816be260219bbc40a8983c459cf05cf2209bf1e62e7ccbf78aec54db607f0121031cee21ef69fe68b240c3032616fa310c6a60a856c0a7e0c1298815c92fb2c61788fb2a00"

// msg := &types.MsgSubmitTransactionRequest{
// Sender: "",
// Blockhash: "000000000d73ecf25d3bf8e6ae65c35aa2a90e3271edff8bab90d87ed875f13b",
// TxBytes: "0100000001b3f7",
// PrevTxBytes: "0100000001b3f7",
// Proof: []string{"0100000001b3f7"},
// }
// // this line is used by starport scaffolding # handler/test/submit
// err := k.ProcessBitcoinDepositTransaction(ctx, msg)
// require.NoError(t, err)
// }

// Decode transaction
func TestDecodeTransaction(t *testing.T) {
hexStr := "02000000000101e5df234dbeff74d6da14754ebeea8ab0e2f60b1884566846cf6b36e8ceb5f5350100000000fdffffff02f0490200000000001600142ac13073e8d491428790481321a636696d00107681d7e205000000001600142bf3aa186cbdcbe88b70a67edcd5a32ce5e8e6d8024730440220081ee61d749ce8cedcf6eedde885579af2eb65ca67d29e6ae2c37109d81cbbb202203a1891ce45f91f159ccf04348ef37a3d1a12d89e5e01426e061326057e6c128d012103036bbdd77c9a932f37bd66175967c7fb7eb75ece06b87c1ad1716770cb3ca4ee79fc2a00"

// Decode the hex string to transaction
txBytes, err := hex.DecodeString(hexStr)
require.NoError(t, err)

// Create a new transaction
var tx wire.MsgTx
err = tx.Deserialize(bytes.NewReader(txBytes))
require.NoError(t, err)

uTx := btcutil.NewTx(&tx)

for _, input := range uTx.MsgTx().TxIn {
t.Log(input.PreviousOutPoint.String())
}

require.GreaterOrEqual(t, len(uTx.MsgTx().TxIn), 1)
}
27 changes: 19 additions & 8 deletions x/btclightclient/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ func (k Keeper) SetBlockHeaders(ctx sdk.Context, blockHeader []*types.BlockHeade
// 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))
Expand All @@ -139,7 +140,7 @@ func (k Keeper) SetBlockHeaders(ctx sdk.Context, blockHeader []*types.BlockHeade
// Process Bitcoin Deposit Transaction
func (k Keeper) ProcessBitcoinDepositTransaction(ctx sdk.Context, msg *types.MsgSubmitTransactionRequest) error {

ctx.Logger().Debug("Processing Transaction in block: ", msg.Blockhash)
ctx.Logger().Info("accept bitcoin deposit tx", "blockhash", msg.Blockhash)

param := k.GetParams(ctx)
header := k.GetBlockHeader(ctx, msg.Blockhash)
Expand Down Expand Up @@ -217,11 +218,17 @@ func (k Keeper) ProcessBitcoinDepositTransaction(ctx sdk.Context, msg *types.Msg
if err != nil {
return err
}

sender, err := pk.Address(types.ChainCfg)
if err != nil {
return err
}

// if pk.Class() != txscript.WitnessV1TaprootTy || pk.Class() != txscript.WitnessV0PubKeyHashTy || pk.Class() != txscript.WitnessV0ScriptHashTy {
// ctx.Logger().Error("Unsupported script type", "script", pk.Class(), "address", sender.EncodeAddress())
// return types.ErrUnsupportedScriptType
// }

// check if the proof is valid
root, err := chainhash.NewHashFromStr(header.MerkleRoot)
if err != nil {
Expand All @@ -233,24 +240,28 @@ func (k Keeper) ProcessBitcoinDepositTransaction(ctx sdk.Context, msg *types.Msg

for _, out := range uTx.MsgTx().TxOut {
// check if the output is a valid address
pk, err := txscript.ParsePkScript(out.PkScript)
pks, err := txscript.ParsePkScript(out.PkScript)
if err != nil {
return err
}
addr, err := pk.Address(types.ChainCfg)
addr, err := pks.Address(types.ChainCfg)
if err != nil {
return err
}

if slices.Contains(param.BtcVoucherAddress, addr.EncodeAddress()) {
// TODO remove the true
// check if the receiver is one of the voucher addresses
if true || slices.Contains(param.BtcVoucherAddress, addr.EncodeAddress()) {
// mint the voucher token
coins := sdk.NewCoins(sdk.NewCoin(param.BtcVoucherDenom, sdk.NewInt(int64(out.Value))))
coins := sdk.NewCoins(sdk.NewCoin(param.BtcVoucherDenom, sdk.NewInt(out.Value)))
senderAddr, err := sdk.AccAddressFromBech32(sender.EncodeAddress())
if err != nil {
return err
}
k.bankKeeper.MintCoins(ctx, types.ModuleName, coins)
k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, senderAddr, coins)

ctx.Logger().Info("Voucher token minted", "address", senderAddr.String(), "amount", coins.String())
}

}
Expand All @@ -260,10 +271,10 @@ func (k Keeper) ProcessBitcoinDepositTransaction(ctx sdk.Context, msg *types.Msg

func (k Keeper) GetBlockHeader(ctx sdk.Context, hash string) *types.BlockHeader {
store := ctx.KVStore(k.storeKey)
var blockHeader *types.BlockHeader
var blockHeader types.BlockHeader
bz := store.Get(types.BtcBlockHeaderHashKey(hash))
k.cdc.MustUnmarshal(bz, blockHeader)
return blockHeader
k.cdc.MustUnmarshal(bz, &blockHeader)
return &blockHeader
}

func (k Keeper) GetBlockHashByHeight(ctx sdk.Context, height uint64) string {
Expand Down
1 change: 1 addition & 0 deletions x/btclightclient/keeper/keeper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package keeper_test
6 changes: 6 additions & 0 deletions x/btclightclient/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,20 @@ func (m msgServer) SubmitTransaction(goCtx context.Context, msg *types.MsgSubmit
ctx := sdk.UnwrapSDKContext(goCtx)

if err := msg.ValidateBasic(); err != nil {
ctx.Logger().Error("Error validating basic", "error", err)
return nil, err
}

if err := m.ProcessBitcoinDepositTransaction(ctx, msg); err != nil {
ctx.Logger().Error("Error processing bitcoin deposit transaction", "error", err)
return nil, err
}

// Emit Events
m.EmitEvent(ctx, msg.Sender,
sdk.NewAttribute("blockhash", msg.Blockhash),
sdk.NewAttribute("txBytes", msg.TxBytes),
)

return &types.MsgSubmitTransactionResponse{}, nil

Expand Down
3 changes: 2 additions & 1 deletion x/btclightclient/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ var (

ErrInvalidBtcTransaction = errorsmod.Register(ModuleName, 3100, "invalid bitcoin transaction")
ErrBlockNotFound = errorsmod.Register(ModuleName, 3101, "block not found")
ErrTransactionNotIncluded = errorsmod.Register(ModuleName, 3101, "transaction not included in block")
ErrTransactionNotIncluded = errorsmod.Register(ModuleName, 3102, "transaction not included in block")
ErrNotConfirmed = errorsmod.Register(ModuleName, 3200, "transaction not confirmed")
ErrExceedMaxAcceptanceDepth = errorsmod.Register(ModuleName, 3201, "exceed max acceptance block depth")
ErrUnsupportedScriptType = errorsmod.Register(ModuleName, 3202, "unsupported script type")
)

0 comments on commit 0ff99ba

Please sign in to comment.