Skip to content

Commit

Permalink
feat: Implement BTCHeaderBytes and BTCHeaderHashBytes types (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
vitsalis authored Jun 27, 2022
1 parent d668179 commit f9716e3
Show file tree
Hide file tree
Showing 21 changed files with 396 additions and 404 deletions.
12 changes: 6 additions & 6 deletions proto/babylon/btclightclient/btclightclient.proto
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
syntax = "proto3";
package babylon.btclightclient.v1;

option go_package = "github.com/babylonchain/babylon/x/btclightclient/types";
import "gogoproto/gogo.proto";

// BTCHeader defines the structure of the incoming message bytes
message BTCHeaderBytes {
bytes header_bytes = 1;
}
option go_package = "github.com/babylonchain/babylon/x/btclightclient/types";

// BaseBTCHeader corresponds to the oldest BTC header maintained in storage
// It is denoted by the header bytes and the height
message BaseBTCHeader {
BTCHeaderBytes header = 1;
bytes header = 1 [
(gogoproto.customtype) = "github.com/babylonchain/babylon/types.BTCHeaderBytes"
];
uint64 height = 2;
}

1 change: 0 additions & 1 deletion proto/babylon/btclightclient/genesis.proto
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
syntax = "proto3";
package babylon.btclightclient.v1;


import "gogoproto/gogo.proto";
import "babylon/btclightclient/params.proto";
import "babylon/btclightclient/btclightclient.proto";
Expand Down
9 changes: 7 additions & 2 deletions proto/babylon/btclightclient/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "babylon/btclightclient/params.proto";
import "babylon/btclightclient/btclightclient.proto";

option go_package = "github.com/babylonchain/babylon/x/btclightclient/types";

Expand Down Expand Up @@ -42,14 +43,18 @@ message QueryHashesRequest {

// QueryHashesResponse is response type for the Query/Hashes RPC method.
message QueryHashesResponse {
repeated bytes hashes = 1;
repeated bytes hashes = 1 [
(gogoproto.customtype) = "github.com/babylonchain/babylon/types.BTCHeaderHashBytes"
];

cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryContainsRequest is request type for the Query/Contains RPC method.
// It involves checking whether a hash is maintained by the module.
message QueryContainsRequest {
bytes hash = 1;
bytes hash = 1 [
(gogoproto.customtype) = "github.com/babylonchain/babylon/types.BTCHeaderHashBytes"
];
}

// QueryContainsResponse is response type for the Query/Contains RPC method.
Expand Down
5 changes: 4 additions & 1 deletion proto/babylon/btclightclient/tx.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
syntax = "proto3";
package babylon.btclightclient.v1;

import "gogoproto/gogo.proto";
import "babylon/btclightclient/btclightclient.proto";


Expand All @@ -14,6 +15,8 @@ service Msg {
// MsgInsertHeader defines the message for incoming header bytes
message MsgInsertHeader {
string signer = 1;
BTCHeaderBytes header = 2;
bytes header = 2 [
(gogoproto.customtype) = "github.com/babylonchain/babylon/types.BTCHeaderBytes"
];
}
message MsgInsertHeaderResponse {}
100 changes: 100 additions & 0 deletions types/btc_header_bytes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package types

import (
"bytes"
"encoding/hex"
"encoding/json"
"github.com/btcsuite/btcd/wire"
)

type BTCHeaderBytes []byte

func NewBTCHeaderBytesFromHex(hex string) (BTCHeaderBytes, error) {
var headerBytes BTCHeaderBytes
err := headerBytes.UnmarshalHex(hex)
if err != nil {
return nil, err
}
return headerBytes, nil
}

func (m BTCHeaderBytes) MarshalJSON() ([]byte, error) {
hex, err := m.MarshalHex()
if err != nil {
return nil, err
}
return json.Marshal(hex)
}

func (m *BTCHeaderBytes) UnmarshalJSON(bz []byte) error {
var headerHexStr string
err := json.Unmarshal(bz, &headerHexStr)

if err != nil {
return err
}

return m.UnmarshalHex(headerHexStr)
}

func (m BTCHeaderBytes) Marshal() ([]byte, error) {
return m, nil
}

func (m *BTCHeaderBytes) Unmarshal(data []byte) error {
*m = data
return nil
}

func (m BTCHeaderBytes) MarshalHex() (string, error) {
btcdHeader, err := m.ToBlockHeader()
if err != nil {
return "", err
}

var buf bytes.Buffer
btcdHeader.Serialize(&buf)
return hex.EncodeToString(buf.Bytes()), nil
}

func (m *BTCHeaderBytes) UnmarshalHex(header string) error {
// Decode the hash string from hex
decoded, err := hex.DecodeString(header)
if err != nil {
return err
}

return m.Unmarshal(decoded)
}

func (m BTCHeaderBytes) MarshalTo(data []byte) (int, error) {
copy(data, m)
return len(data), nil
}

func (m *BTCHeaderBytes) Size() int {
bz, _ := m.Marshal()
return len(bz)
}

func (m BTCHeaderBytes) ToBlockHeader() (*wire.BlockHeader, error) {
// Create an empty header
header := &wire.BlockHeader{}

// The Deserialize method expects an io.Reader instance
reader := bytes.NewReader(m)
// Decode the header bytes
err := header.Deserialize(reader)
// There was a parsing error
if err != nil {
return nil, err
}
return header, nil
}

func (m *BTCHeaderBytes) FromBlockHeader(header *wire.BlockHeader) {
var buf bytes.Buffer
header.Serialize(&buf)

*m = buf.Bytes()
}
91 changes: 91 additions & 0 deletions types/btc_header_hash_bytes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package types

import (
"encoding/json"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)

type BTCHeaderHashBytes []byte

func NewBTCHeaderHashBytesFromHex(hex string) (BTCHeaderHashBytes, error) {
var hashBytes BTCHeaderHashBytes
err := hashBytes.UnmarshalHex(hex)
if err != nil {
return nil, err
}
return hashBytes, nil
}

func (m BTCHeaderHashBytes) MarshalJSON() ([]byte, error) {
hex, err := m.MarshalHex()
if err != nil {
return nil, err
}
// Marshal the JSON from hex format
return json.Marshal(hex)
}

func (m *BTCHeaderHashBytes) UnmarshalJSON(bz []byte) error {
var headerHashStr string
err := json.Unmarshal(bz, &headerHashStr)
if err != nil {
return err
}

return m.UnmarshalHex(headerHashStr)
}

func (m BTCHeaderHashBytes) Marshal() ([]byte, error) {
// Just return the bytes
return m, nil
}

func (m *BTCHeaderHashBytes) Unmarshal(bz []byte) error {
*m = bz
return nil
}

func (m *BTCHeaderHashBytes) MarshalHex() (string, error) {
chHash, err := m.ToChainhash()
if err != nil {
return "", err
}

return chHash.String(), nil
}

func (m *BTCHeaderHashBytes) UnmarshalHex(hash string) error {
decoded, err := chainhash.NewHashFromStr(hash)
if err != nil {
return err
}

// Copy the bytes into the instance
return m.Unmarshal(decoded[:])
}

func (m BTCHeaderHashBytes) MarshalTo(data []byte) (int, error) {
copy(data, m)
return len(data), nil
}

func (m *BTCHeaderHashBytes) Size() int {
bz, _ := m.Marshal()
return len(bz)
}

func (m BTCHeaderHashBytes) ToChainhash() (*chainhash.Hash, error) {
return chainhash.NewHash(m)
}

func (m *BTCHeaderHashBytes) FromChainhash(hash *chainhash.Hash) {
var headerHashBytes BTCHeaderHashBytes
headerHashBytes.Unmarshal(hash[:])
*m = headerHashBytes
}

func (m BTCHeaderHashBytes) reverse() {
for i := 0; i < chainhash.HashSize/2; i++ {
m[i], m[chainhash.HashSize-1-i] = m[chainhash.HashSize-1-i], m[i]
}
}
6 changes: 4 additions & 2 deletions x/btclightclient/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ func CmdTxInsertHeader() *cobra.Command {
return err
}

headerBytes := []byte(args[0])
msg := types.NewMsgInsertHeader(clientCtx.GetFromAddress(), headerBytes)
msg, err := types.NewMsgInsertHeader(clientCtx.GetFromAddress(), args[0])
if err != nil {
return err
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
Expand Down
5 changes: 3 additions & 2 deletions x/btclightclient/genesis_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package btclightclient_test

import (
"encoding/hex"
bbl "github.com/babylonchain/babylon/types"
"testing"

keepertest "github.com/babylonchain/babylon/testutil/keeper"
Expand All @@ -12,7 +12,8 @@ import (
)

func TestGenesis(t *testing.T) {
headerBytes, _ := hex.DecodeString(types.DefaultBaseHeaderHex)
headerBytes, _ := bbl.NewBTCHeaderBytesFromHex(types.DefaultBaseHeaderHex)

genesisState := types.GenesisState{
Params: types.DefaultParams(),
BaseBtcHeader: types.DefaultBaseBTCHeader(headerBytes, types.DefaultBaseHeaderHeight),
Expand Down
8 changes: 5 additions & 3 deletions x/btclightclient/keeper/base_btc_header.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
bbl "github.com/babylonchain/babylon/types"
"github.com/babylonchain/babylon/x/btclightclient/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
Expand All @@ -23,8 +24,9 @@ func (k Keeper) GetBaseBTCHeader(ctx sdk.Context) types.BaseBTCHeader {
return types.BaseBTCHeader{}
}

headerBytes := types.BtcdHeaderToBytes(baseBtcdHeader)
return types.BaseBTCHeader{Header: headerBytes, Height: height}
var headerBytes bbl.BTCHeaderBytes
headerBytes.FromBlockHeader(baseBtcdHeader)
return types.BaseBTCHeader{Header: &headerBytes, Height: height}
}

// SetBaseBTCHeader checks whether a base BTC header exists and
Expand All @@ -35,7 +37,7 @@ func (k Keeper) SetBaseBTCHeader(ctx sdk.Context, baseBTCHeader types.BaseBTCHea
panic("A base BTC Header has already been set")
}

btcdHeader, err := types.BytesToBtcdHeader(baseBTCHeader.Header)
btcdHeader, err := baseBTCHeader.Header.ToBlockHeader()
if err != nil {
panic("Base BTC Header bytes do not correspond to btcd header")
}
Expand Down
5 changes: 3 additions & 2 deletions x/btclightclient/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"context"
bbl "github.com/babylonchain/babylon/types"
"github.com/babylonchain/babylon/x/btclightclient/types"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -25,7 +26,7 @@ func (k Keeper) Hashes(ctx context.Context, req *types.QueryHashesRequest) (*typ
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
var hashes [][]byte
var hashes []bbl.BTCHeaderHashBytes

sdkCtx := sdk.UnwrapSDKContext(ctx)

Expand All @@ -49,7 +50,7 @@ func (k Keeper) Contains(ctx context.Context, req *types.QueryContainsRequest) (
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
chHash, err := types.BytesToChainhash(req.Hash)
chHash, err := req.Hash.ToChainhash()
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion x/btclightclient/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (m msgServer) InsertHeader(ctx context.Context, msg *types.MsgInsertHeader)
// that will get rejected.

// Get Btcd header from bytes
btcdHeader, err := types.BytesToBtcdHeader(msg.Header)
btcdHeader, err := msg.Header.ToBlockHeader()
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit f9716e3

Please sign in to comment.