consensus/monero/client/client.go
2022-10-08 20:55:01 +02:00

113 lines
2.4 KiB
Go

package client
import (
"bytes"
"context"
"encoding/hex"
"errors"
"fmt"
"git.gammaspectra.live/P2Pool/go-monero/pkg/rpc"
"git.gammaspectra.live/P2Pool/go-monero/pkg/rpc/daemon"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/block"
"git.gammaspectra.live/P2Pool/p2pool-observer/types"
"log"
"sync"
"sync/atomic"
"time"
)
var client atomic.Pointer[Client]
var lock sync.Mutex
var address = "http://localhost:18081"
func SetClientSettings(addr string) {
lock.Lock()
defer lock.Unlock()
address = addr
client.Store(nil)
}
func GetClient() *Client {
if c := client.Load(); c == nil {
lock.Lock()
defer lock.Unlock()
if c = client.Load(); c == nil {
//fallback for lock racing
if c, err := newClient(); err != nil {
log.Panic(err)
} else {
client.Store(c)
return c
}
}
return c
} else {
return c
}
}
// Client TODO: ratelimit
type Client struct {
c *rpc.Client
d *daemon.Client
throttler <-chan time.Time
}
func newClient() (*Client, error) {
c, err := rpc.NewClient(address)
if err != nil {
return nil, err
}
return &Client{
c: c,
d: daemon.NewClient(c),
throttler: time.Tick(time.Second / 2),
}, nil
}
func (c *Client) GetCoinbaseTransaction(txId types.Hash) (*block.CoinbaseTransaction, error) {
<-c.throttler
if result, err := c.d.GetTransactions(context.Background(), []string{txId.String()}); err != nil {
return nil, err
} else {
if len(result.Txs) != 1 {
return nil, errors.New("invalid transaction count")
}
if buf, err := hex.DecodeString(result.Txs[0].PrunedAsHex); err != nil {
return nil, err
} else {
tx := &block.CoinbaseTransaction{}
if err = tx.FromReader(bytes.NewReader(buf)); err != nil {
return nil, err
}
if tx.Id() != txId {
return nil, fmt.Errorf("expected %s, got %s", txId.String(), tx.Id().String())
}
return tx, nil
}
}
}
func (c *Client) GetBlockHeaderByHeight(height uint64) (*daemon.GetBlockHeaderByHeightResult, error) {
<-c.throttler
if result, err := c.d.GetBlockHeaderByHeight(context.Background(), height); err != nil {
return nil, err
} else {
return result, nil
}
}
func (c *Client) GetBlockTemplate(address string) (*daemon.GetBlockTemplateResult, error) {
<-c.throttler
if result, err := c.d.GetBlockTemplate(context.Background(), address, 60); err != nil {
return nil, err
} else {
return result, nil
}
}