QUIC Transaction Submission
Example
package main
import (
"context"
"crypto/tls"
"fmt"
"io"
"net"
"os"
"time"
quic "github.com/quic-go/quic-go"
)
const (
authOK byte = 0x00
maxTxSize = 1232
)
type NextblockQuicClient struct {
conn quic.Connection
}
func Connect(ctx context.Context, serverAddr string, apiKey string) (*NextblockQuicClient, error) {
host, _, err := net.SplitHostPort(serverAddr)
if err != nil {
return nil, fmt.Errorf("invalid server address: %w", err)
}
conn, err := quic.DialAddr(ctx, serverAddr, &tls.Config{
ServerName: host,
NextProtos: []string{"nb-tx/1"},
MinVersion: tls.VersionTLS13,
}, &quic.Config{
KeepAlivePeriod: 15 * time.Second,
MaxIdleTimeout: 60 * time.Second,
})
if err != nil {
return nil, fmt.Errorf("quic dial failed: %w", err)
}
authStream, err := conn.OpenStreamSync(ctx)
if err != nil {
conn.CloseWithError(1, "auth stream failed")
return nil, fmt.Errorf("open auth stream: %w", err)
}
if _, err := authStream.Write([]byte(apiKey)); err != nil {
conn.CloseWithError(1, "auth write failed")
return nil, fmt.Errorf("write api key: %w", err)
}
if err := authStream.Close(); err != nil {
conn.CloseWithError(1, "auth close failed")
return nil, fmt.Errorf("close auth stream: %w", err)
}
response := make([]byte, 1)
if _, err := io.ReadFull(authStream, response); err != nil {
conn.CloseWithError(1, "auth read failed")
return nil, fmt.Errorf("read auth response: %w", err)
}
if response[0] != authOK {
conn.CloseWithError(1, "auth rejected")
return nil, fmt.Errorf("authentication rejected")
}
return &NextblockQuicClient{conn: conn}, nil
}
func (c *NextblockQuicClient) SendTransaction(ctx context.Context, rawTx []byte) error {
if len(rawTx) > maxTxSize {
return fmt.Errorf("transaction too large: %d", len(rawTx))
}
stream, err := c.conn.OpenUniStreamSync(ctx)
if err != nil {
return fmt.Errorf("open tx stream: %w", err)
}
if _, err := stream.Write(rawTx); err != nil {
return fmt.Errorf("write tx bytes: %w", err)
}
return stream.Close()
}
func (c *NextblockQuicClient) Close() error {
return c.conn.CloseWithError(0, "client closing")
}
func main() {
ctx := context.Background()
apiKey := os.Getenv("NEXTBLOCK_API_KEY")
if apiKey == "" {
panic("set NEXTBLOCK_API_KEY before running")
}
client, err := Connect(ctx, "frankfurt.nextblock.io:11100", apiKey)
if err != nil {
panic(err)
}
defer client.Close()
// Replace this with the serialized bytes of your signed Solana transaction.
// Example with solana-go: rawTx, err := tx.MarshalBinary()
rawTx := []byte{0, 1, 2, 3}
if err := client.SendTransaction(ctx, rawTx); err != nil {
panic(err)
}
fmt.Println("transaction queued")
}What To Replace
Notes
Last updated