Skip to content

Commit

Permalink
multi: implement listsinceblock RPC
Browse files Browse the repository at this point in the history
  • Loading branch information
torkelrogstad committed Aug 1, 2024
1 parent 163326f commit b72c954
Show file tree
Hide file tree
Showing 6 changed files with 446 additions and 199 deletions.
507 changes: 329 additions & 178 deletions gen/bitcoin/bitcoind/v1alpha/bitcoin.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.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/barebitcoin/btc-buf

go 1.20

replace github.com/btcsuite/btcd => github.com/barebitcoin/btcd v0.23.5-0.20240516074637-57d6cb01f3d7
replace github.com/btcsuite/btcd => github.com/barebitcoin/btcd v0.23.5-0.20240801062541-540ec1572b9c

require (
connectrpc.com/connect v1.16.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ connectrpc.com/grpchealth v1.3.0/go.mod h1:3vpqmX25/ir0gVgW6RdnCPPZRcR6HvqtXX5RN
connectrpc.com/grpcreflect v1.2.0 h1:Q6og1S7HinmtbEuBvARLNwYmTbhEGRpHDhqrPNlmK+U=
connectrpc.com/grpcreflect v1.2.0/go.mod h1:nwSOKmE8nU5u/CidgHtPYk1PFI3U9ignz7iDMxOYkSY=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/barebitcoin/btcd v0.23.5-0.20240516074637-57d6cb01f3d7 h1:2FW+gECdFu2cumrQccj4tZ8jBPaAwG06NflWI5wISwk=
github.com/barebitcoin/btcd v0.23.5-0.20240516074637-57d6cb01f3d7/go.mod h1:KOxHr/Iw2H6MSwkBcgpbVk1+bTNVqSswDmQubAo6Www=
github.com/barebitcoin/btcd v0.23.5-0.20240801062541-540ec1572b9c h1:iy8YRWso+FHqsJufUINYkwxDE0jCjbFmoCLF+xAIdyk=
github.com/barebitcoin/btcd v0.23.5-0.20240801062541-540ec1572b9c/go.mod h1:KOxHr/Iw2H6MSwkBcgpbVk1+bTNVqSswDmQubAo6Www=
github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE=
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
Expand Down
12 changes: 12 additions & 0 deletions proto/bitcoin/bitcoind/v1alpha/bitcoin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ service BitcoinService {

// Fetches in-wallet transactions
rpc GetTransaction(GetTransactionRequest) returns (GetTransactionResponse);
rpc ListSinceBlock(ListSinceBlockRequest) returns (ListSinceBlockResponse);

// Wallet stuff
rpc GetNewAddress(GetNewAddressRequest) returns (GetNewAddressResponse);
Expand Down Expand Up @@ -447,3 +448,14 @@ message BumpFeeResponse {
double new_fee = 3;
repeated string errors = 4;
}

message ListSinceBlockRequest {
string wallet = 1;

// If set, the block hash to list transactions since, otherwise list all transactions.
string txid = 2;
}

message ListSinceBlockResponse {
repeated GetTransactionResponse transactions = 1;
}
90 changes: 72 additions & 18 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,46 @@ func (b *Bitcoind) rpcForWallet(ctx context.Context, wallet string) (*rpcclient.
return rpc, nil
}

// ListSinceBlock implements bitcoindv1alphaconnect.BitcoinServiceHandler.
func (b *Bitcoind) ListSinceBlock(ctx context.Context, c *connect.Request[pb.ListSinceBlockRequest]) (*connect.Response[pb.ListSinceBlockResponse], error) {
rpc, err := b.rpcForWallet(ctx, c.Msg.Wallet)
if err != nil {
return nil, err
}

hash, err := newChainHash(c.Msg.Txid)
if err != nil {
return nil, err
}

return withCancel[*btcjson.ListSinceBlockResult, pb.ListSinceBlockResponse](ctx,
func(ctx context.Context) (*btcjson.ListSinceBlockResult, error) {
return rpc.ListSinceBlock(ctx, hash)
},
func(r *btcjson.ListSinceBlockResult) *pb.ListSinceBlockResponse {
return &pb.ListSinceBlockResponse{
Transactions: lo.Map(r.Transactions, func(tx btcjson.ListTransactionsResult, idx int) *pb.GetTransactionResponse {
return &pb.GetTransactionResponse{
Amount: tx.Amount,
Fee: lo.FromPtr(tx.Fee),
Confirmations: int32(tx.Confirmations),
BlockHash: tx.BlockHash,
BlockIndex: uint32(lo.FromPtr(tx.BlockIndex)),
BlockTime: nil,
Txid: tx.TxID,
WalletConflicts: tx.WalletConflicts,
ReplacedByTxid: tx.ReplacedByTXID,
ReplacesTxid: tx.ReplacesTXID,
Time: timestamppb.New(time.Unix(tx.Time, 0)),
TimeReceived: timestamppb.New(time.Unix(tx.TimeReceived, 0)),
Bip125Replaceable: parseReplaceable(tx.BIP125Replaceable),
}
}),
}
},
)
}

// BumpFee implements bitcoindv1alphaconnect.BitcoinServiceHandler.
func (b *Bitcoind) BumpFee(ctx context.Context, c *connect.Request[pb.BumpFeeRequest]) (*connect.Response[pb.BumpFeeResponse], error) {
rpc, err := b.rpcForWallet(ctx, c.Msg.Wallet)
Expand Down Expand Up @@ -353,7 +393,7 @@ func (b *Bitcoind) GetBlock(ctx context.Context, c *connect.Request[pb.GetBlockR
return nil, connect.NewError(connect.CodeUnimplemented, fmt.Errorf("bad verbosity: %s", c.Msg.Verbosity))
}

hash, err := chainhash.NewHashFromStr(c.Msg.Hash)
hash, err := newChainHash(c.Msg.Hash)
if err != nil {
return nil, err
}
Expand All @@ -379,9 +419,9 @@ func (b *Bitcoind) GetRawTransaction(ctx context.Context, c *connect.Request[pb.
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(`"txid" is a required argument`))
}

hash, err := chainhash.NewHashFromStr(c.Msg.Txid)
hash, err := newChainHash(c.Msg.Txid)
if err != nil {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("invalid txid"))
return nil, err
}

if !c.Msg.Verbose {
Expand Down Expand Up @@ -453,9 +493,9 @@ func (b *Bitcoind) GetTransaction(ctx context.Context, c *connect.Request[pb.Get
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New(`"txid" is a required argument`))
}

hash, err := chainhash.NewHashFromStr(c.Msg.Txid)
hash, err := newChainHash(c.Msg.Txid)
if err != nil {
return nil, connect.NewError(connect.CodeInvalidArgument, errors.New("invalid txid"))
return nil, err
}

rpc, err := b.rpcForWallet(ctx, c.Msg.Wallet)
Expand Down Expand Up @@ -502,18 +542,6 @@ func (b *Bitcoind) GetTransaction(ctx context.Context, c *connect.Request[pb.Get
details = append(details, detail)
}

replaceable := func(in string) pb.GetTransactionResponse_Replaceable {
switch in {
case "unknown":
return pb.GetTransactionResponse_REPLACEABLE_UNSPECIFIED
case "yes":
return pb.GetTransactionResponse_REPLACEABLE_YES
case "no":
return pb.GetTransactionResponse_REPLACEABLE_NO
default:
return 0
}
}
var blockTime *timestamppb.Timestamp
if res.BlockTime != 0 {
blockTime = timestamppb.New(time.Unix(res.BlockTime, 0))
Expand All @@ -534,7 +562,7 @@ func (b *Bitcoind) GetTransaction(ctx context.Context, c *connect.Request[pb.Get
Time: timestamppb.New(time.Unix(res.Time, 0)),
TimeReceived: timestamppb.New(time.Unix(res.TimeReceived, 0)),
Details: details,
Bip125Replaceable: replaceable(res.BIP125Replaceable),
Bip125Replaceable: parseReplaceable(res.BIP125Replaceable),
}
},
)
Expand Down Expand Up @@ -909,3 +937,29 @@ func handleBtcJsonErrors() connect.Interceptor {
}
})
}

func newChainHash(in string) (*chainhash.Hash, error) {
if in == "" {
return nil, nil
}

hash, err := chainhash.NewHashFromStr(in)
if err != nil {
return nil, connect.NewError(connect.CodeInvalidArgument, err)
}

return hash, nil
}

func parseReplaceable(in string) pb.GetTransactionResponse_Replaceable {
switch in {
case "unknown":
return pb.GetTransactionResponse_REPLACEABLE_UNSPECIFIED
case "yes":
return pb.GetTransactionResponse_REPLACEABLE_YES
case "no":
return pb.GetTransactionResponse_REPLACEABLE_NO
default:
return 0
}
}

0 comments on commit b72c954

Please sign in to comment.