Skip to content

Commit

Permalink
rpc: add listactivesidechains
Browse files Browse the repository at this point in the history
  • Loading branch information
octobocto committed Sep 24, 2024
1 parent d0703c6 commit 4c453a3
Show file tree
Hide file tree
Showing 7 changed files with 491 additions and 37 deletions.
3 changes: 3 additions & 0 deletions drivechain/drivechain.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ func ValidateDepositAddress(depositAddress string) error {

return nil
}

//nolint:staticcheck
var ErrNoCTip = "No CTIP found for sidechain!"
338 changes: 301 additions & 37 deletions gen/bitcoin/drivechaind/v1/drivechain.pb.go

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions proto/bitcoin/drivechaind/v1/drivechain.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package bitcoin.drivechaind.v1;

service DrivechainService {
rpc CreateSidechainDeposit(CreateSidechainDepositRequest) returns (CreateSidechainDepositResponse);
rpc ListActiveSidechains(ListActiveSidechainsRequest) returns (ListActiveSidechainsResponse);
}

message CreateSidechainDepositRequest {
Expand All @@ -18,3 +19,20 @@ message CreateSidechainDepositRequest {
message CreateSidechainDepositResponse {
string txid = 1;
}

message ListActiveSidechainsRequest {}

message ListActiveSidechainsResponse {
message Sidechain {
string title = 1;
string description = 2;
uint32 nversion = 3;
string hashid1 = 4;
string hashid2 = 5;
int32 slot = 6;
int64 amount_satoshi = 7;
string chaintip_txid = 8;
}

repeated Sidechain sidechains = 1;
}
10 changes: 10 additions & 0 deletions server/commands/drivechain.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package commands

// Create a sidechain deposit of an amount to a given address.
type CreateSidechainDeposit struct {
Slot int `json:"slot"`
Destination string `json:"destination"`
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
}

// List active sidechains.
type ListActiveSidechains struct{}

// Returns the crtitical transaction index pair for sidechain in a specific slot
type ListSidechainCTip struct {
// The sidechain slot
Slot int `json:"slot"`
}
127 changes: 127 additions & 0 deletions server/drivechain_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,130 @@ func (b *Bitcoind) CreateSidechainDeposit(ctx context.Context, c *connect.Reques
},
)
}

type activeSidechain struct {
Title string `json:"title"`
Description string `json:"description"`
NVersion int `json:"nversion"`
HashID1 string `json:"hashid1"`
HashID2 string `json:"hashid2"`
}

// ListActiveSidechains implements drivechaindv1connect.DrivechainServiceHandler.
func (b *Bitcoind) ListActiveSidechains(ctx context.Context, _ *connect.Request[pb.ListActiveSidechainsRequest]) (*connect.Response[pb.ListActiveSidechainsResponse], error) {
return withCancel(ctx, func(ctx context.Context) ([]*pb.ListActiveSidechainsResponse_Sidechain, error) {
cmd, err := btcjson.NewCmd("listactivesidechains")
if err != nil {
return nil, fmt.Errorf("listactivesidechains new cmd: %w", err)
}

res, err := rpcclient.ReceiveFuture(b.rpc.SendCmd(ctx, cmd))
if err != nil {
return nil, fmt.Errorf("listactivesidechains send: %w", err)
}

var sidechains []activeSidechain
if err := json.Unmarshal(res, &sidechains); err != nil {
return nil, fmt.Errorf("listactivesidechains unmarshal response: %w", err)
}

// Log the unmarshaled sidechains for debugging
zerolog.Ctx(ctx).Debug().
Interface("sidechains", sidechains).
Msg("unmarshaled active sidechains")

pbSidechains := make([]*pb.ListActiveSidechainsResponse_Sidechain, 0, len(sidechains))
for _, sidechain := range sidechains {
pbSidechain, err := b.sidechainToProto(ctx, sidechain)
if err != nil {
return nil, fmt.Errorf("convert sidechain to proto: %w", err)
}

pbSidechains = append(pbSidechains, pbSidechain)
}

return pbSidechains, nil
},

func(sidechains []*pb.ListActiveSidechainsResponse_Sidechain) *pb.ListActiveSidechainsResponse {
return &pb.ListActiveSidechainsResponse{
Sidechains: sidechains,
}
},
)
}

func (b *Bitcoind) getChaintipInfo(ctx context.Context, sidechainSlot int) (btcutil.Amount, string, error) {
cmd, err := btcjson.NewCmd("listsidechainctip", sidechainSlot)
if err != nil {
return 0, "", fmt.Errorf("listsidechainctip new cmd: %w", err)
}
res, err := rpcclient.ReceiveFuture(b.rpc.SendCmd(ctx, cmd))
if err != nil {
return 0, "", fmt.Errorf("listsidechainctip send: %w", err)
}

var result struct {
Amount btcutil.Amount `json:"amount"`
TXID string `json:"txid"`
}
if err := json.Unmarshal(res, &result); err != nil {
return 0, "", fmt.Errorf("unmarshal listsidechainctip response: %w", err)
}

return result.Amount, result.TXID, nil
}

func (b *Bitcoind) sidechainToProto(
ctx context.Context, sidechain activeSidechain,
) (*pb.ListActiveSidechainsResponse_Sidechain, error) {
slot, err := chainToSlot(sidechain.Title)
if err != nil {
return nil, fmt.Errorf("convert chain to slot: %w", err)
}

balance, txid, err := b.getChaintipInfo(ctx, slot)
switch {
case err == nil:
// No error, proceed

case strings.Contains(err.Error(), drivechain.ErrNoCTip):
zerolog.Ctx(ctx).Warn().Int("slot", slot).Msg("no ctip for sidechain")
// That's okay, proceed

default:
return nil, fmt.Errorf("get balance for chain %s: %w", sidechain.Title, err)
}

return &pb.ListActiveSidechainsResponse_Sidechain{
Title: sidechain.Title,
Description: sidechain.Description,
Nversion: uint32(sidechain.NVersion),
Hashid1: sidechain.HashID1,
Hashid2: sidechain.HashID2,
Slot: int32(slot),
AmountSatoshi: int64(balance),
ChaintipTxid: txid,
}, nil
}

func chainToSlot(chain string) (int, error) {
switch chain {
case "Testchain":
return 0, nil
case "BitNames":
return 2, nil
case "BitAssets":
return 4, nil
case "ZSide":
return 5, nil
case "EthSide":
return 6, nil
case "Thunder":
return 9, nil
case "LatestCore":
return 11, nil
default:
return 0, fmt.Errorf("unknown chain: %s", chain)
}
}
2 changes: 2 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func init() {

// drivechain commands
btcjson.MustRegisterCmd("createsidechaindeposit", new(commands.CreateSidechainDeposit), btcjson.UFWalletOnly)
btcjson.MustRegisterCmd("listactivesidechains", new(commands.ListActiveSidechains), btcjson.UFWalletOnly)
btcjson.MustRegisterCmd("listsidechainctip", new(commands.ListSidechainCTip), btcjson.UFWalletOnly)
}

type Bitcoind struct {
Expand Down

0 comments on commit 4c453a3

Please sign in to comment.