feat: set up project

This commit is contained in:
2023-07-19 11:47:46 +02:00
parent fac61db3f1
commit b426a36570
45 changed files with 2388 additions and 4 deletions

View File

@@ -0,0 +1,53 @@
package btc
import (
"fmt"
"net/http"
)
type BitcoinService struct {
host string
auth string
zmqAddress string
walletAddress string
client *http.Client
testNet bool
}
func NewBitcoinService(host, auth, zmqAddress, walletAddress string) *BitcoinService {
bs := BitcoinService{
host: host,
auth: auth,
zmqAddress: zmqAddress,
walletAddress: walletAddress,
client: &http.Client{},
}
from, err := bs.getAddressGroupings(false)
if err != nil {
panic(fmt.Errorf("bs.getAddressGroupings %s", err))
}
found := false
for _, a := range from {
if a.address == bs.walletAddress {
found = true
}
}
if !found {
return nil
}
return &bs
}
func (bc *BitcoinService) WithTestnet() *BitcoinService {
bc.testNet = true
return bc
}
func (bc *BitcoinService) Explorer(tx string) string {
if bc.testNet {
return "https://testnet.bitcoinexplorer.org/tx/" + tx
}
return "https://btcscan.org/tx/" + tx
}

View File

@@ -0,0 +1,61 @@
package btc
import (
"encoding/json"
)
type decodeRawTransactionResponseResult struct {
Txid string `json:"txid"`
Hash string `json:"hash"`
Version int `json:"version"`
Size int `json:"size"`
Vsize int `json:"vsize"`
Weight int `json:"weight"`
Locktime int `json:"locktime"`
Vin []struct {
Txid string `json:"txid"`
Vout int `json:"vout"`
ScriptSig struct {
Asm string `json:"asm"`
Hex string `json:"hex"`
} `json:"scriptSig"`
Txinwitness []string `json:"txinwitness"`
Sequence int64 `json:"sequence"`
} `json:"vin"`
Vout []struct {
Value float64 `json:"value"`
N int `json:"n"`
ScriptPubKey struct {
Asm string `json:"asm"`
Hex string `json:"hex"`
Address string `json:"address,omitempty"`
Type string `json:"type,omitempty"`
} `json:"scriptPubKey,omitempty"`
} `json:"vout"`
}
// func (d decodeRawTransactionResponseResult) getAddressRestFunds(amountPlusFee float64) string {
// address := ""
// for _, vout := range d.Vout {
// if vout.Value > amountPlusFee {
// address = vout.ScriptPubKey.Address
// }
// }
// return address
// }
type decodeRawTransactionResponse struct {
Result decodeRawTransactionResponseResult `json:"result"`
RPCResponse
}
func NewdecodeRawTransactionResponse(bts []byte) (*decodeRawTransactionResponse, error) {
resp := new(decodeRawTransactionResponse)
err := json.Unmarshal(bts, resp)
if err != nil {
return nil, err
}
return resp, nil
}

View File

@@ -0,0 +1,52 @@
package btc
import (
"encoding/json"
"fmt"
)
func NewGetBalanceParams() []interface{} {
return []interface{}{}
}
type GetBalanceResponse struct {
Result float64 `json:"result"`
RPCResponse
}
func NewGetBalanceResponse(bts []byte) (*GetBalanceResponse, error) {
resp := new(GetBalanceResponse)
err := json.Unmarshal(bts, resp)
if err != nil {
return nil, err
}
return resp, nil
}
func (b *BitcoinService) GetBalance() (float64, error) {
req := b.NewRPCRequest().WithMethod(GET_BALANCE)
if req == nil {
return 0.0, fmt.Errorf("NewRPCRequest %s is nil", GET_BALANCE)
}
resp, err := req.Call(NewGetBalanceParams()...)
if err != nil {
return 0.0, fmt.Errorf("req.Call: %s", err)
}
strinResp := string(resp)
if strinResp == "" {
return 0.0, fmt.Errorf("strinResp: %s", err)
}
trx, err := NewGetBalanceResponse(resp)
if err != nil {
return 0.0, fmt.Errorf("NewGetBalanceResponse: %s", err)
}
if trx.Error != nil {
return 0.0, fmt.Errorf("raw.Error: %+v", trx.Error)
}
return trx.Result, nil
}

View File

@@ -0,0 +1,14 @@
package btc
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_bitcoinService_GetBalance(t *testing.T) {
th := newTestHelper()
balance, err := th.b.GetBalance()
require.NoError(t, err)
require.Greater(t, balance, 0.0)
}

View File

@@ -0,0 +1,72 @@
package btc
import (
"encoding/json"
"fmt"
)
func NewGetBlockParams(blockHash string) []interface{} {
return []interface{}{blockHash}
}
type GetBlockResponse struct {
Result GetBlockResponseResult `json:"result"`
RPCResponse
}
type GetBlockResponseResult struct {
Hash string `json:"hash"`
Confirmations int `json:"confirmations"`
Height int `json:"height"`
Version int `json:"version"`
VersionHex string `json:"versionHex"`
Merkleroot string `json:"merkleroot"`
Time int `json:"time"`
Mediantime int `json:"mediantime"`
Nonce int `json:"nonce"`
Bits string `json:"bits"`
Difficulty float64 `json:"difficulty"`
Chainwork string `json:"chainwork"`
NTx int `json:"nTx"`
Previousblockhash string `json:"previousblockhash"`
Strippedsize int `json:"strippedsize"`
Size int `json:"size"`
Weight int `json:"weight"`
Tx []string `json:"tx"`
}
func NewGetBlockResponse(bts []byte) (*GetBlockResponse, error) {
resp := new(GetBlockResponse)
err := json.Unmarshal(bts, resp)
if err != nil {
return nil, err
}
return resp, nil
}
func (b *BitcoinService) getBlock(blockHash string) (*GetBlockResponseResult, error) {
req := b.NewRPCRequest().WithMethod(GET_BLOCK)
if req == nil {
return nil, fmt.Errorf("NewRPCRequest %s is nil", GET_BLOCK)
}
resp, err := req.Call(NewGetBlockParams(blockHash)...)
if err != nil {
return nil, fmt.Errorf("req.Call: %s", err)
}
strinResp := string(resp)
if strinResp == "" {
return nil, fmt.Errorf("strinResp: %s", err)
}
block, err := NewGetBlockResponse(resp)
if err != nil {
return nil, fmt.Errorf("NewGetBlockResponse: %s", err)
}
if block.Error != nil {
return nil, fmt.Errorf("raw.Error: %+v", block.Error)
}
return &block.Result, nil
}

View File

@@ -0,0 +1,16 @@
package btc
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_bitcoinService_GetBlock(t *testing.T) {
th := newTestHelper()
blockHash := "00000000000000043d385a031abd1f911aae1783810ec5f59a1db9e3ff7eac80"
block, err := th.b.getBlock(blockHash)
require.NoError(t, err)
require.NotNil(t, block)
require.Greater(t, len(block.Tx), 0)
}

View File

@@ -0,0 +1,114 @@
package btc
import (
"encoding/json"
"fmt"
"strings"
)
func getRawTransactionParams(trxid, blockchash string) []interface{} {
return []interface{}{trxid, true, blockchash}
}
type GetRawTransactionResponseResult struct {
InActiveChain bool `json:"in_active_chain"`
Txid string `json:"txid"`
Hash string `json:"hash"`
Version int `json:"version"`
Size int `json:"size"`
Vsize int `json:"vsize"`
Weight int `json:"weight"`
Locktime int `json:"locktime"`
Vin []struct {
Txid string `json:"txid"`
Vout int `json:"vout"`
ScriptSig struct {
Asm string `json:"asm"`
Hex string `json:"hex"`
} `json:"scriptSig"`
Txinwitness []string `json:"txinwitness"`
Sequence int64 `json:"sequence"`
} `json:"vin"`
Vout []GetRawTransactionResponseResultVout `json:"vout"`
Hex string `json:"hex"`
Blockhash string `json:"blockhash"`
Confirmations int `json:"confirmations"`
Time int `json:"time"`
Blocktime int `json:"blocktime"`
}
type GetRawTransactionResponseResultVout struct {
Value float64 `json:"value"`
N int `json:"n"`
ScriptPubKey struct {
Asm string `json:"asm"`
Hex string `json:"hex"`
Address string `json:"address,omitempty"`
Type string `json:"type"`
} `json:"scriptPubKey,omitempty"`
}
func (g GetRawTransactionResponseResult) getOpReturn() string {
opReturn := ""
for _, v := range g.Vout {
if strings.HasPrefix(v.ScriptPubKey.Asm, "OP_RETURN") {
opReturn = v.ScriptPubKey.Asm
break
}
}
if !strings.HasPrefix(opReturn, "OP_RETURN") {
return ""
}
hexMessage := strings.Split(opReturn, " ")[len(strings.Split(opReturn, " "))-1]
return hexMessage
}
type GetRawTransactionResponse struct {
Result GetRawTransactionResponseResult `json:"result"`
RPCResponse
}
func NewGetRawTransactionResponse(bts []byte) (*GetRawTransactionResponse, error) {
resp := new(GetRawTransactionResponse)
err := json.Unmarshal(bts, resp)
if err != nil {
return nil, err
}
return resp, nil
}
func (b *BitcoinService) getRawTransaction(trxid, blockhash string) (*GetRawTransactionResponseResult, error) {
req := b.NewRPCRequest().WithMethod(GET_RAW_TRANSACTION)
if req == nil {
return nil, fmt.Errorf("NewRPCRequest %s is nil", GET_RAW_TRANSACTION)
}
bts := getRawTransactionParams(trxid, blockhash)
if bts == nil {
return nil, fmt.Errorf("getRawTransactionParams is nil")
}
resp, err := req.Call(bts...)
if err != nil {
return nil, fmt.Errorf("req.Call: %s", err)
}
strinResp := string(resp)
if strinResp == "" {
return nil, fmt.Errorf("strinResp: %s", err)
}
trx, err := NewGetRawTransactionResponse(resp)
if err != nil {
return nil, fmt.Errorf("NewGetRawTransactionResponse: %s", err)
}
if trx.Error != nil {
return nil, fmt.Errorf("raw.Error: %+v", trx.Error)
}
if trx.Result.Txid != trxid {
return nil, fmt.Errorf("trx.Result.Txid: %s != trxid %s", trx.Result.Txid, trxid)
}
return &trx.Result, nil
}

View File

@@ -0,0 +1,25 @@
package btc
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_bitcoinService_getRawTransaction(t *testing.T) {
th := newTestHelper()
txid := "873d5516a9cacc065bb30831bf4855b058f59a2a4877e08e0e28c22c51c58e39"
tx, err := th.b.getTransaction(txid)
require.NoError(t, err)
rawTrx, err := th.b.getRawTransaction(tx.Txid, tx.Blockhash)
require.NoError(t, err)
require.Equal(t, rawTrx.Txid, txid)
require.NotEmpty(t, rawTrx.getOpReturn())
// hexMessage := rawTrx.getOpReturn()
// bts, err := hex.DecodeString(hexMessage)
// require.NoError(t, err)
// require.Equal(t, testMessage, string(bts))
}

View File

@@ -0,0 +1,84 @@
package btc
import (
"encoding/json"
"fmt"
)
func getTransactionParams(trxid string) []interface{} {
return []interface{}{trxid}
}
type GetTransactionResponseResult struct {
Amount float64 `json:"amount"`
Fee float64 `json:"fee"`
Confirmations int `json:"confirmations"`
Blockhash string `json:"blockhash"`
Blockheight int `json:"blockheight"`
Blockindex int `json:"blockindex"`
Blocktime int `json:"blocktime"`
Txid string `json:"txid"`
Walletconflicts []interface{} `json:"walletconflicts"`
Time int `json:"time"`
Timereceived int `json:"timereceived"`
Bip125Replaceable string `json:"bip125-replaceable"`
Details []struct {
Address string `json:"address,omitempty"`
Category string `json:"category"`
Amount float64 `json:"amount"`
Vout int `json:"vout"`
Fee float64 `json:"fee"`
Abandoned bool `json:"abandoned"`
} `json:"details"`
Hex string `json:"hex"`
}
type GetTransactionResponse struct {
Result GetTransactionResponseResult `json:"result"`
RPCResponse
}
func NewGetTransactionResponse(bts []byte) (*GetTransactionResponse, error) {
resp := new(GetTransactionResponse)
err := json.Unmarshal(bts, resp)
if err != nil {
return nil, err
}
return resp, nil
}
func (b *BitcoinService) getTransaction(trxid string) (*GetTransactionResponseResult, error) {
req := b.NewRPCRequest().WithMethod(GET_TRANSACTION)
if req == nil {
return nil, fmt.Errorf("NewRPCRequest %s is nil", GET_TRANSACTION)
}
bts := getTransactionParams(trxid)
if bts == nil {
return nil, fmt.Errorf("NewGetTransactionParams is nil")
}
resp, err := req.Call(bts...)
if err != nil {
return nil, fmt.Errorf("req.Call: %s", err)
}
strinResp := string(resp)
if strinResp == "" {
return nil, fmt.Errorf("strinResp: %s", err)
}
trx, err := NewGetTransactionResponse(resp)
if err != nil {
return nil, fmt.Errorf("NewGetTransactionResponse: %s", err)
}
if trx.Error != nil {
return nil, fmt.Errorf("raw.Error: %+v", trx.Error)
}
if trx.Result.Txid != trxid {
return nil, fmt.Errorf("trx.Result.Txid: %s != trxid %s", trx.Result.Txid, trxid)
}
return &trx.Result, nil
}

View File

@@ -0,0 +1,15 @@
package btc
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_bitcoinService_GetTransaction(t *testing.T) {
th := newTestHelper()
txid := "1dd9a1be3dc4feba3031cda110bd043535bc170a34a7664b231ccda3c3928e93"
trx, err := th.b.getTransaction(txid)
require.NoError(t, err)
require.Equal(t, trx.Txid, txid)
}

View File

@@ -0,0 +1,124 @@
package btc
import (
"encoding/json"
"fmt"
"log"
)
type ListAddressGroupingsResponse struct {
Result [][][]any `json:"result"`
Error any `json:"error"`
ID string `json:"id"`
}
func NewListAddressGroupingsResponse(bts []byte) (*ListAddressGroupingsResponse, error) {
resp := new(ListAddressGroupingsResponse)
err := json.Unmarshal(bts, resp)
if err != nil {
return nil, err
}
return resp, nil
}
// func (b *bitcoinService) listaddressgroupings() ([][]any, error) {
// req := b.NewRPCRequest().WithMethod(LIST_ADDRESS_GROUPINGS)
// if req == nil {
// return nil, fmt.Errorf("NewRPCRequest %s is nil", LIST_ADDRESS_GROUPINGS)
// }
// resp, err := req.Call(nil)
// if err != nil {
// return nil, fmt.Errorf("req.Call: %s", err)
// }
// strinResp := string(resp)
// if strinResp == "" {
// return nil, fmt.Errorf("strinResp: %s", err)
// }
// log.Println(strinResp)
// addressResp, err := NewListAddressGroupingsResponse(resp)
// if err != nil {
// return nil, fmt.Errorf("NewFundTransactionResponse: %s", err)
// }
// if addressResp.Error != nil {
// return nil, fmt.Errorf("raw.Error: %+v", addressResp.Error)
// }
// if len(addressResp.Result) != 1 {
// return nil, fmt.Errorf("no addresses found")
// }
// if len(addressResp.Result[0]) <= 0 {
// return nil, fmt.Errorf("no addresses found")
// }
// return addressResp.Result[0], nil
// }
type AddressGrouping struct {
address string
funds float64
}
func (b *BitcoinService) listaddressgroupingsWithFunds() ([]AddressGrouping, error) {
return b.getAddressGroupings(true)
}
func (b *BitcoinService) getAddressGroupings(withFunds bool) ([]AddressGrouping, error) {
req := b.NewRPCRequest().WithMethod(LIST_ADDRESS_GROUPINGS)
if req == nil {
return nil, fmt.Errorf("NewRPCRequest %s is nil", LIST_ADDRESS_GROUPINGS)
}
resp, err := req.Call()
if err != nil {
return nil, fmt.Errorf("req.Call: %s", err)
}
strinResp := string(resp)
if strinResp == "" {
return nil, fmt.Errorf("strinResp: %s", err)
}
addressResp, err := NewListAddressGroupingsResponse(resp)
if err != nil {
return nil, fmt.Errorf("NewListAddressGroupingsResponse: %s", err)
}
if addressResp.Error != nil {
return nil, fmt.Errorf("raw.Error: %+v", addressResp.Error)
}
if len(addressResp.Result) != 1 {
return nil, fmt.Errorf("no addresses found")
}
if len(addressResp.Result[0]) <= 0 {
return nil, fmt.Errorf("no addresses found")
}
var addressList []AddressGrouping
for i := range addressResp.Result[0] {
addressRaw, fundsRaw := addressResp.Result[0][i][0], addressResp.Result[0][i][1]
address, ok := addressRaw.(string)
if !ok {
log.Fatalf("Address is not a string: %v", addressRaw)
continue
}
funds, ok := fundsRaw.(float64)
if !ok {
log.Fatalf("Funds is not a float64: %v", fundsRaw)
continue
}
if withFunds && funds <= 0.0 {
continue
}
addressList = append(addressList, AddressGrouping{address: address, funds: funds})
}
return addressList, nil
}

View File

@@ -0,0 +1,17 @@
package btc
import (
"log"
"testing"
"github.com/stretchr/testify/require"
)
func Test_bitcoinService_listaddressgroupingsWithFunds(t *testing.T) {
th := newTestHelper()
addresslistWithFunds, err := th.b.listaddressgroupingsWithFunds()
require.NoError(t, err)
require.Greater(t, len(addresslistWithFunds), 0)
log.Println("addresslist", addresslistWithFunds)
}

View File

@@ -0,0 +1,79 @@
package btc
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"time"
"gitea.urkob.com/urko/btc-pay-checker/internal/domain"
)
func (b *BitcoinService) Notify(ctx context.Context, notifChan chan<- domain.Notification) {
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
q := &Zmq{}
if err := q.Connect(b.zmqAddress); err != nil {
log.Fatal("Failed to connect to ZeroMQ socket:", err)
}
blockChan := make(chan string)
go q.Listen(blockChan)
go func() {
for blockHash := range blockChan {
block, err := b.getBlock(blockHash)
if err != nil {
log.Println("Error b.GetBlock:", err)
continue
}
log.Println("block readed", block.Hash)
for _, txid := range block.Tx {
tx, err := b.getRawTransaction(txid, block.Hash)
if err != nil {
log.Println("Error b.getRawTransaction:", err)
continue
}
if !tx.InActiveChain {
log.Printf("tx is not active on chain | block %s | tx %s \n", blockHash, txid)
continue
}
receiverAddress := false
amount := 0.0
for _, output := range tx.Vout {
if output.ScriptPubKey.Address == b.walletAddress {
receiverAddress = true
amount = output.Value
break
}
}
if !receiverAddress {
continue
}
if receiverAddress {
log.Println("Transaction has been completed")
notifChan <- domain.Notification{
BlockHash: blockHash,
Tx: txid,
Amount: amount,
DoneAt: time.Now(),
}
break
}
}
}
}()
<-interrupt
if err := q.Close(); err != nil {
log.Println("Error closing ZeroMQ socket:", err)
}
}

View File

@@ -0,0 +1,92 @@
package btc
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
)
const (
GET_BLOCK RPCMethod = "getblock"
GET_BALANCE RPCMethod = "getbalance"
GET_RAW_TRANSACTION RPCMethod = "getrawtransaction"
GET_TRANSACTION RPCMethod = "gettransaction"
DECODE_RAW_TRANSACTION RPCMethod = "decoderawtransaction"
LIST_ADDRESS_GROUPINGS RPCMethod = "listaddressgroupings"
)
type RPCMethod string
type RPCRequest struct {
host string
auth string
Jsonrpc string `json:"jsonrpc"`
ID string `json:"id"`
Method RPCMethod `json:"method"`
Params []interface{} `json:"params,omitempty"`
debug bool
}
func (b *BitcoinService) NewRPCRequest() *RPCRequest {
return &RPCRequest{
host: b.host,
auth: b.auth,
Jsonrpc: "1.0",
ID: "curltest",
Params: make([]interface{}, 0),
}
}
func (r *RPCRequest) WithDebug() *RPCRequest {
r.debug = true
return r
}
func (r *RPCRequest) WithMethod(method RPCMethod) *RPCRequest {
r.Method = method
return r
}
func (r *RPCRequest) Call(params ...interface{}) ([]byte, error) {
if len(params) > 0 && params != nil {
r.Params = append(r.Params, params...)
}
reqBody, err := json.Marshal(r)
if err != nil {
fmt.Println(err)
return nil, err
}
if r.debug {
log.Printf("%s \n body: \n%s \n", r.Method, string(reqBody))
}
payload := bytes.NewReader(reqBody)
client := &http.Client{}
req, err := http.NewRequest(http.MethodPost, r.host, payload)
if err != nil {
fmt.Println(err)
return nil, err
}
req.Header.Add("Accept", "text/plain")
req.Header.Add("Authorization", r.auth)
req.Header.Add("Content-Type", "application/json")
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
if r.debug {
log.Printf("body response: \n%s \n", body)
}
return body, nil
}

View File

@@ -0,0 +1,27 @@
package btc
import (
"log"
"testing"
"github.com/stretchr/testify/require"
)
func TestCreateSendTransaction(t *testing.T) {
th := newTestHelper()
req := th.b.
NewRPCRequest().
WithMethod(GET_BALANCE)
require.NotNil(t, req)
resp, err := req.Call()
require.NoError(t, err)
strinResp := string(resp)
require.NotEmpty(t, string(strinResp))
log.Println(strinResp)
// unspent, err := NewListUnspentResponse(resp)
// require.NoError(t, err)
// require.Nil(t, unspent.Error)
// require.Greater(t, len(unspent.Result), 0)
}

View File

@@ -0,0 +1,11 @@
package btc
type RPCResponseError struct {
Code int `json:"code"`
Message string `json:"message"`
}
type RPCResponse struct {
Id string `json:"id"`
Error *RPCResponseError `json:"error"`
}

View File

@@ -0,0 +1,22 @@
package btc
import (
"gitea.urkob.com/urko/btc-pay-checker/kit"
"gitea.urkob.com/urko/btc-pay-checker/kit/cfg"
)
type testHelper struct {
testDeliveryAddress string
config *cfg.Config
b *BitcoinService
}
func newTestHelper() *testHelper {
config := cfg.NewConfig(kit.RootDir() + "/.test.env")
testDeliveryAddress := config.WalletAddress
return &testHelper{
config: config,
testDeliveryAddress: testDeliveryAddress,
b: NewBitcoinService(config.RpcHost, config.RpcAuth, config.RpcZmq, config.WalletAddress),
}
}

View File

@@ -0,0 +1,71 @@
package btc
import (
"encoding/hex"
"fmt"
"log"
zmq "github.com/pebbe/zmq4"
)
const (
TOPIC_RAWTX = "rawtx"
TOPIC_RAWBLOCK = "rawblock"
TOPIC_HASHBLOCK = "hashblock"
)
type Zmq struct {
subscriber *zmq.Socket
}
func (q *Zmq) Connect(address string) error {
subscriber, err := zmq.NewSocket(zmq.SUB)
if err != nil {
return fmt.Errorf("error creating ZeroMQ subscriber: %w", err)
}
if err := subscriber.Connect("tcp://" + address); err != nil {
return fmt.Errorf("error connecting to ZeroMQ socket: %w", err)
}
if err := subscriber.SetSubscribe(TOPIC_HASHBLOCK); err != nil {
return fmt.Errorf("subscriber.SetSubscribe: %w", err)
}
q.subscriber = subscriber
log.Println("subsribed to: " + address)
return nil
}
func (q *Zmq) Close() error {
return q.subscriber.Close()
}
func (q *Zmq) Listen(blocksChan chan<- string) {
if q.subscriber == nil {
log.Fatalln("subscriber cannot be nil")
return
}
log.Println("Listening for new blocks...")
for {
msgParts, err := q.subscriber.RecvMessageBytes(0)
if err != nil {
log.Println("Error receiving message:", err)
continue
}
if len(msgParts) < 2 {
log.Println("Received message part is too short:", msgParts)
continue
}
topic := string(msgParts[0])
switch topic {
case TOPIC_HASHBLOCK:
blockHash := hex.EncodeToString(msgParts[1])
blocksChan <- blockHash
case TOPIC_RAWTX:
// TODO: do something with raw tx
continue
}
}
}