nockchain-grpc/wallet/nockchain_service.go

215 lines
5.4 KiB
Go
Raw Permalink Normal View History

2025-10-06 13:38:53 +07:00
package wallet
import (
context "context"
"fmt"
"github.com/phamminh0811/private-grpc/nockchain"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
type NockchainClient struct {
conn *grpc.ClientConn
client nockchain.NockchainServiceClient
appClient nockchain.NockAppServiceClient
2025-10-06 13:38:53 +07:00
}
// NewNockchainClient creates a new gRPC client connection
func NewNockchainClient(address string) (*NockchainClient, error) {
creds := credentials.NewClientTLSFromCert(nil, "")
conn, err := grpc.NewClient(
address,
grpc.WithTransportCredentials(creds),
)
if err != nil {
return nil, fmt.Errorf("failed to connect: %w", err)
}
client := nockchain.NewNockchainServiceClient(conn)
appClient := nockchain.NewNockAppServiceClient(conn)
2025-10-06 13:38:53 +07:00
return &NockchainClient{
conn: conn,
client: client,
appClient: appClient,
2025-10-06 13:38:53 +07:00
}, nil
}
func (nc *NockchainClient) Close() error {
return nc.conn.Close()
}
2025-11-04 10:38:31 +07:00
func (nc *NockchainClient) WalletGetBalance(req *nockchain.GetBalanceRequest) (*nockchain.Balance, error) {
2025-10-06 13:38:53 +07:00
pageToken := ""
allNotes := []*nockchain.BalanceEntry{}
var height *nockchain.BlockHeight
var blockId *nockchain.Hash
2025-11-04 10:38:31 +07:00
page := &nockchain.PageRequest{
ClientPageItemsLimit: 0,
PageToken: pageToken,
MaxBytes: 0,
}
2025-10-06 13:38:53 +07:00
for {
2025-11-04 10:38:31 +07:00
var request *nockchain.WalletGetBalanceRequest
switch req.Selector.(type) {
case *nockchain.GetBalanceRequest_Address:
request = &nockchain.WalletGetBalanceRequest{
Selector: &nockchain.WalletGetBalanceRequest_Address{
Address: &nockchain.Base58Pubkey{
Key: req.GetAddress(),
},
},
Page: page,
}
case *nockchain.GetBalanceRequest_FirstName:
request = &nockchain.WalletGetBalanceRequest{
Selector: &nockchain.WalletGetBalanceRequest_FirstName{
FirstName: &nockchain.Base58Hash{
Hash: req.GetFirstName(),
},
},
Page: page,
}
2025-10-06 13:38:53 +07:00
}
2025-11-04 10:38:31 +07:00
resp, err := nc.client.WalletGetBalance(context.Background(), request)
2025-10-06 13:38:53 +07:00
if err != nil {
return nil, err
}
2025-11-04 10:38:31 +07:00
balance := nockchain.Balance{}
2025-10-06 13:38:53 +07:00
switch resp.Result.(type) {
case *nockchain.WalletGetBalanceResponse_Balance:
balance = *resp.GetBalance()
case *nockchain.WalletGetBalanceResponse_Error:
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return nil, fmt.Errorf("invalid result type")
}
if height == nil {
height = balance.Height
blockId = balance.BlockId
}
if balance.Height != height || balance.BlockId != blockId {
return nil, fmt.Errorf("snapshot changed during pagination; retry")
}
allNotes = append(allNotes, balance.Notes...)
if balance.Page.NextPageToken == "" {
break
} else {
pageToken = balance.Page.NextPageToken
2025-11-04 10:38:31 +07:00
page.PageToken = pageToken
2025-10-06 13:38:53 +07:00
}
}
2025-11-04 10:38:31 +07:00
return &nockchain.Balance{
2025-10-06 13:38:53 +07:00
Notes: allNotes,
Height: height,
BlockId: blockId,
Page: &nockchain.PageResponse{
NextPageToken: "",
},
}, nil
}
func (nc *NockchainClient) TxAccepted(txId string) (*nockchain.TransactionAcceptedResponse, error) {
req := nockchain.TransactionAcceptedRequest{
TxId: &nockchain.Base58Hash{
Hash: txId,
},
}
resp, err := nc.client.TransactionAccepted(context.Background(), &req)
if err != nil {
return nil, err
}
switch resp.Result.(type) {
case *nockchain.TransactionAcceptedResponse_Accepted:
return resp, nil
case *nockchain.TransactionAcceptedResponse_Error:
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return nil, fmt.Errorf("invalid result type")
}
}
2025-10-07 11:10:08 +07:00
func (nc *NockchainClient) WalletSendTransaction(tx *nockchain.RawTx) (*nockchain.WalletSendTransactionResponse, error) {
2025-11-04 10:38:31 +07:00
spends := []*nockchain.SpendEntry{}
for _, namedSpend := range tx.NamedSpends {
spendEntry, err := ConvertNamedSpend(namedSpend)
2025-10-07 11:10:08 +07:00
if err != nil {
2025-11-04 10:38:31 +07:00
return nil, err
2025-10-07 11:10:08 +07:00
}
2025-11-04 10:38:31 +07:00
spends = append(spends, spendEntry)
2025-10-07 11:10:08 +07:00
}
req := nockchain.WalletSendTransactionRequest{
TxId: ParseHash(tx.TxId),
RawTx: &nockchain.RawTransaction{
2025-11-04 10:38:31 +07:00
Id: ParseHash(tx.TxId),
Version: &nockchain.NoteVersion{
Value: uint32(tx.Version),
2025-10-07 11:10:08 +07:00
},
2025-11-04 10:38:31 +07:00
Spends: spends,
2025-10-07 11:10:08 +07:00
},
}
resp, err := nc.client.WalletSendTransaction(context.Background(), &req)
if err != nil {
return nil, err
}
switch resp.Result.(type) {
case *nockchain.WalletSendTransactionResponse_Ack:
return resp, nil
case *nockchain.WalletSendTransactionResponse_Error:
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return nil, fmt.Errorf("invalid result type")
}
}
func (nc *NockchainClient) Peek(pid int32, path []byte) ([]byte, error) {
req := nockchain.PeekRequest{
Pid: pid,
Path: path,
}
resp, err := nc.appClient.Peek(context.Background(), &req)
if err != nil {
return nil, err
}
switch resp.Result.(type) {
case *nockchain.PeekResponse_Data:
return resp.GetData(), nil
case *nockchain.PeekResponse_Error:
return nil, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return nil, fmt.Errorf("invalid result type")
}
}
func (nc *NockchainClient) Poke(pid int32, wire *nockchain.Wire, payload []byte) (bool, error) {
req := nockchain.PokeRequest{
Pid: pid,
Wire: wire,
Payload: payload,
}
resp, err := nc.appClient.Poke(context.Background(), &req)
if err != nil {
return false, err
}
switch resp.Result.(type) {
case *nockchain.PokeResponse_Acknowledged:
return resp.GetAcknowledged(), nil
case *nockchain.PokeResponse_Error:
return false, fmt.Errorf("error: %s", resp.GetError().Message)
default:
return false, fmt.Errorf("invalid result type")
}
}