Skip to content

Commit

Permalink
feat: add submit example with refactor of common functions
Browse files Browse the repository at this point in the history
Signed-off-by: Ales Verbic <[email protected]>
  • Loading branch information
verbotenj committed Jul 2, 2024
1 parent dc73e71 commit 2248c28
Show file tree
Hide file tree
Showing 3 changed files with 215 additions and 67 deletions.
121 changes: 121 additions & 0 deletions examples/submit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package main

import (
"context"
"encoding/hex"
"fmt"

"connectrpc.com/connect"
"github.com/utxorpc/go-codegen/utxorpc/v1alpha/submit"
utxorpc "github.com/utxorpc/go-sdk"
)

func main() {
ctx := context.Background()
baseUrl := "https://preview.utxorpc-v0.demeter.run"
// set API key for demeter
client := utxorpc.CreateUtxoRPCClient(baseUrl,
// set API key for demeter
utxorpc.WithHeaders(map[string]string{
"dmtr-api-key": "dmtr_utxorpc1...",
}),
)

// Set mode to "submitTx", "readMempool", "waitForTx", or "watchMempool" to select the desired example.
var mode string = "waitForTx"

switch mode {
case "submitTx":
submitTx(ctx, client, "Replace this with the signed transaction in CBOR format.")
case "readMempool":
readMempool(ctx, client)
case "waitForTx":
waitForTx(ctx, client)
case "watchMempool":
watchMempool(ctx, client)
default:
fmt.Println("Unknown mode:", mode)
}
}

func submitTx(ctx context.Context, client *utxorpc.UtxorpcClient, txCbor string) {
// Decode the transaction data from hex
txRawBytes, err := hex.DecodeString(txCbor)
if err != nil {
panic(fmt.Errorf("failed to decode transaction hash: %v", err))
}

// Create a SubmitTxRequest with the transaction data
tx := &submit.AnyChainTx{
Type: &submit.AnyChainTx_Raw{
Raw: txRawBytes,
},
}

// Create a list with one transaction
req := connect.NewRequest(&submit.SubmitTxRequest{
Tx: []*submit.AnyChainTx{tx},
})

fmt.Println("Connecting to utxorpc host:", client.URL())
resp, err := client.Submit.SubmitTx(ctx, req)
if err != nil {
utxorpc.HandleError(err)
}
fmt.Printf("Response: %+v\n", resp)
}

func readMempool(ctx context.Context, client *utxorpc.UtxorpcClient) {
req := connect.NewRequest(&submit.ReadMempoolRequest{})
client.AddHeadersToRequest(req)
fmt.Println("Connecting to utxorpc host:", client.URL())
resp, err := client.Submit.ReadMempool(ctx, req)
if err != nil {
utxorpc.HandleError(err)
}
fmt.Printf("Response: %+v\n", resp)
}

func waitForTx(ctx context.Context, client *utxorpc.UtxorpcClient) {
req := connect.NewRequest(&submit.WaitForTxRequest{})
client.AddHeadersToRequest(req)
fmt.Println("Connecting to utxorpc host:", client.URL())
stream, err := client.Submit.WaitForTx(ctx, req)
if err != nil {
utxorpc.HandleError(err)
}

fmt.Println("Connected to utxorpc host, watching mempool...")
for stream.Receive() {
resp := stream.Msg()
fmt.Printf("Stream response: %+v\n", resp)
}

if err := stream.Err(); err != nil {
fmt.Println("Stream ended with error:", err)
} else {
fmt.Println("Stream ended normally.")
}
}

func watchMempool(ctx context.Context, client *utxorpc.UtxorpcClient) {
req := connect.NewRequest(&submit.WatchMempoolRequest{})
client.AddHeadersToRequest(req)
fmt.Println("Connecting to utxorpc host:", client.URL())
stream, err := client.Submit.WatchMempool(ctx, req)
if err != nil {
utxorpc.HandleError(err)
}

fmt.Println("Connected to utxorpc host, watching mempool...")
for stream.Receive() {
resp := stream.Msg()
fmt.Printf("Stream response: %+v\n", resp)
}

if err := stream.Err(); err != nil {
fmt.Println("Stream ended with error:", err)
} else {
fmt.Println("Stream ended normally.")
}
}
70 changes: 15 additions & 55 deletions examples/sync/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,38 @@ package main

import (
"context"
"crypto/tls"
"encoding/hex"
"errors"
"fmt"
"log"
"net"
"net/http"

"connectrpc.com/connect"
sync "github.com/utxorpc/go-codegen/utxorpc/v1alpha/sync"
utxorpc "github.com/utxorpc/go-sdk"
"golang.org/x/net/http2"
)

func main() {
ctx := context.Background()
baseUrl := "https://preview.utxorpc-v0.demeter.run"
// set API key for demeter
apiKey := "dmtr_utxorpc1..."
client := createUtxoRPCClient(baseUrl)
client := utxorpc.CreateUtxoRPCClient(baseUrl,
// set API key for demeter
utxorpc.WithHeaders(map[string]string{
"dmtr-api-key": "dmtr_utxorpc1...",
}),
)

fetchBlock(ctx, client, apiKey)
followTip(ctx, client, apiKey, "230eeba5de6b0198f64a3e801f92fa1ebf0f3a42a74dbd1922187249ad3038e7")
followTip(ctx, client, apiKey, "")
fetchBlock(ctx, client)
followTip(ctx, client, "230eeba5de6b0198f64a3e801f92fa1ebf0f3a42a74dbd1922187249ad3038e7")
followTip(ctx, client, "")
}

func createHttpClient() *http.Client {
return &http.Client{
CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
},
Transport: &http2.Transport{
AllowHTTP: true,
DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) {
// If you're also using this client for non-h2c traffic, you may want
// to delegate to tls.Dial if the network isn't TCP or the addr isn't
// in an allowlist.
return net.Dial(network, addr)
},
},
}
}

func createUtxoRPCClient(baseUrl string) *utxorpc.UtxorpcClient {
httpClient := createHttpClient()
client := utxorpc.NewClient(httpClient, baseUrl)
return &client
}

func setAPIKeyHeader(req connect.AnyRequest, apiKey string) {
req.Header().Set("dmtr-api-key", apiKey)
}

func fetchBlock(ctx context.Context, client *utxorpc.UtxorpcClient, apiKey string) {
func fetchBlock(ctx context.Context, client *utxorpc.UtxorpcClient) {
req := connect.NewRequest(&sync.FetchBlockRequest{})
setAPIKeyHeader(req, apiKey)
client.AddHeadersToRequest(req)

fmt.Println("connecting to utxorpc host:", client.URL())
chainSync, err := client.ChainSync.FetchBlock(ctx, req)
if err != nil {
handleError(err)
utxorpc.HandleError(err)
}
fmt.Println("connected to utxorpc...")
for i, blockRef := range chainSync.Msg.Block {
Expand All @@ -73,7 +44,7 @@ func fetchBlock(ctx context.Context, client *utxorpc.UtxorpcClient, apiKey strin
}

// FollowTipRequest with Intersect
func followTip(ctx context.Context, client *utxorpc.UtxorpcClient, apiKey string, blockHash string) {
func followTip(ctx context.Context, client *utxorpc.UtxorpcClient, blockHash string) {
var req *connect.Request[sync.FollowTipRequest]

if blockHash == "" {
Expand All @@ -91,23 +62,12 @@ func followTip(ctx context.Context, client *utxorpc.UtxorpcClient, apiKey string
Intersect: []*sync.BlockRef{blockRef},
})
}

setAPIKeyHeader(req, apiKey)

client.AddHeadersToRequest(req)
fmt.Println("connecting to utxorpc host:", client.URL())
resp, err := client.ChainSync.FollowTip(ctx, req)
if err != nil {
handleError(err)
utxorpc.HandleError(err)
}
fmt.Println("connected to utxorpc...")
fmt.Printf("Response: %+v\n", resp)
}

func handleError(err error) {
fmt.Println(connect.CodeOf(err))
if connectErr := new(connect.Error); errors.As(err, &connectErr) {
fmt.Println(connectErr.Message())
fmt.Println(connectErr.Details())
}
panic(err)
}
91 changes: 79 additions & 12 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,51 @@
package sdk

import (
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"

"connectrpc.com/connect"
"github.com/utxorpc/go-codegen/utxorpc/v1alpha/query/queryconnect"
"github.com/utxorpc/go-codegen/utxorpc/v1alpha/submit/submitconnect"
"github.com/utxorpc/go-codegen/utxorpc/v1alpha/sync/syncconnect"
"github.com/utxorpc/go-codegen/utxorpc/v1alpha/watch/watchconnect"
"golang.org/x/net/http2"
)

type UtxorpcClient struct {
httpClient connect.HTTPClient
baseUrl string
headers map[string]string
ChainSync syncconnect.ChainSyncServiceClient
Query queryconnect.QueryServiceClient
Submit submitconnect.SubmitServiceClient
Watch watchconnect.WatchServiceClient
}

func NewClient(httpClient *http.Client, baseUrl string) UtxorpcClient {
var client UtxorpcClient
chainSyncClient := syncconnect.NewChainSyncServiceClient(httpClient, baseUrl, connect.WithGRPC())
queryClient := queryconnect.NewQueryServiceClient(httpClient, baseUrl, connect.WithGRPC())
submitClient := submitconnect.NewSubmitServiceClient(httpClient, baseUrl, connect.WithGRPC())
watchClient := watchconnect.NewWatchServiceClient(httpClient, baseUrl, connect.WithGRPC())
client.httpClient = httpClient
client.baseUrl = baseUrl
client.ChainSync = chainSyncClient
client.Query = queryClient
client.Submit = submitClient
client.Watch = watchClient
type ClientOptinon func(*UtxorpcClient)

func WithHeaders(headers map[string]string) ClientOptinon {
return func(client *UtxorpcClient) {
client.headers = headers
}
}

func NewClient(httpClient *http.Client, baseUrl string, options ...ClientOptinon) *UtxorpcClient {
client := &UtxorpcClient{
httpClient: httpClient,
baseUrl: baseUrl,
ChainSync: syncconnect.NewChainSyncServiceClient(httpClient, baseUrl, connect.WithGRPC()),
Query: queryconnect.NewQueryServiceClient(httpClient, baseUrl, connect.WithGRPC()),
Submit: submitconnect.NewSubmitServiceClient(httpClient, baseUrl, connect.WithGRPC()),
Watch: watchconnect.NewWatchServiceClient(httpClient, baseUrl, connect.WithGRPC()),
}

for _, option := range options {
option(client)
}
return client
}

Expand All @@ -41,3 +56,55 @@ func (u *UtxorpcClient) HTTPClient() connect.HTTPClient {
func (u *UtxorpcClient) URL() string {
return u.baseUrl
}

func createHttpClient() *http.Client {
return &http.Client{
CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
},
Transport: &http2.Transport{
AllowHTTP: true,
DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) {
// If you're also using this client for non-h2c traffic, you may want
// to delegate to tls.Dial if the network isn't TCP or the addr isn't
// in an allowlist.
return net.Dial(network, addr)
},
},
}
}

func CreateUtxoRPCClient(baseUrl string, options ...ClientOptinon) *UtxorpcClient {
httpClient := createHttpClient()
return NewClient(httpClient, baseUrl, options...)
}

func (u *UtxorpcClient) SetHeader(key, value string) {
if u.headers == nil {
u.headers = make(map[string]string)
}
u.headers[key] = value
}

func (u *UtxorpcClient) SetHeaders(headers map[string]string) {
u.headers = headers
}

func (u *UtxorpcClient) RemoveHeader(key string) {
delete(u.headers, key)
}

func (u *UtxorpcClient) AddHeadersToRequest(req connect.AnyRequest) {
for key, value := range u.headers {
req.Header().Set(key, value)
}
}

func HandleError(err error) {
fmt.Println(connect.CodeOf(err))
if connectErr := new(connect.Error); errors.As(err, &connectErr) {
fmt.Println(connectErr.Message())
fmt.Println(connectErr.Details())
}
panic(err)
}

0 comments on commit 2248c28

Please sign in to comment.