Browse Source

more

master v0.1-alpha
jahway603 3 years ago
parent
commit
b8c2b8f138
  1. 3
      .gitignore
  2. 3
      AUTHORS
  3. 4
      Makefile
  4. 51
      cmd/root.go
  5. 14
      cmd/version.go
  6. 118
      common/cache.go
  7. 277
      common/common.go
  8. 6
      contrib/debian/copyright
  9. 67
      doc/man/highlited.1
  10. 39
      frontend/rpc_client.go
  11. 333
      frontend/service.go
  12. 14
      util/build.sh
  13. 15
      util/build_arm.sh

3
.gitignore

@ -0,0 +1,3 @@
highlited
cert.pem
key.pem

3
AUTHORS

@ -0,0 +1,3 @@
# The Hush Developers
Jahway603 https://git.hush.is/jahway603 https://github.com/jahway603

4
Makefile

@ -1,9 +1,9 @@
# Copyright (c) 2021 Jahway603 & The Hush Developers
# Released under the GPLv3
#
# HightLightD (Hush) Makefile
# HighLited (Hush) Makefile
# author: jahway603
PROJECT_NAME := "highlightd"
PROJECT_NAME := "highlited"
GOCMD=go
GOTEST=$(GOCMD) test
GOVET=$(GOCMD) vet

51
cmd/root.go

@ -1,25 +1,46 @@
// Copyright 2021 Jahway603 & The Hush developers
// Released under the GPLv3
// Living that Highd life!
package cmd
import (
"context"
"fmt"
"net"
"os"
"os/signal"
"syscall"
"time"
"git.hush.is/jahway603/highlited/common"
//"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
//"google.golang.org/grpc"
//"google.golang.org/grpc/credentials"
//"google.golang.org/grpc/peer"
//"google.golang.org/grpc/reflection"
)
var cfgFile string
//var log *logrus.Entry
//var logger = logrus.New()
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "highlited",
Short: "A 'high' version of Hush lightwalletd",
Short: "The high life version of Hush lightwalletd",
Long: `I am exploring Golang and this is a testbed to add
new features to Hush lightwalletd over the long term.`,
// Uncomment the following line if your bare application
// has an action associated with it:
Run: func(cmd *cobra.Command, args []string) { fmt.Println("Welcome to HightLigtD...") },
new features to Hush lightwalletd.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Welcome to Hush HightLightd...")
opts := &common.Options{
GRPCBindAddr: viper.GetString("grpc-bind-addr"),
}
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
@ -32,15 +53,16 @@ func init() {
rootCmd.AddCommand(versionCmd)
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.highlited.yaml)")
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is the file .highlited in the current directory)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
rootCmd.Flags().String("grpc-bind-addr", "127.0.0.1:9067", "the address to listen for grpc on")
viper.BindPFlag("grpc-bind-addr", rootCmd.Flags().Lookup("grpc-bind-addr"))
viper.SetDefault("grpc-bind-addr", "127.0.0.1:9067")
}
// initConfig reads in config file and ENV variables if set.
@ -49,13 +71,8 @@ func initConfig() {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)
// Search config in home directory with name ".highlited" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
// Look in the current directory for a configuration file
viper.AddConfigPath(".")
viper.SetConfigName(".highlited")
}

14
cmd/version.go

@ -12,14 +12,14 @@ import (
// versionCmd represents the version command
var versionCmd = &cobra.Command{
Use: "version",
Short: "Display highlightd version",
Long: `Display highlightd version as we get this cooking...`,
Short: "Display highlited version",
Long: `Display highlited version as we get this cooking...`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("hightlightd version: v0.1.0-alpha")
fmt.Println("hightlightd author: jahway603")
fmt.Println("hightlited version: v0.0.1-alpha")
fmt.Println("hightlited author: jahway603")
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}
//func init() {
// rootCmd.AddCommand(versionCmd)
//}

118
common/cache.go

@ -0,0 +1,118 @@
package common
import (
"bytes"
"sync"
"git.hush.is/hush/lightwalletd/walletrpc"
"github.com/golang/protobuf/proto"
)
type BlockCacheEntry struct {
data []byte
hash []byte
}
type BlockCache struct {
MaxEntries int
FirstBlock int
LastBlock int
m map[int]*BlockCacheEntry
mutex sync.RWMutex
}
func NewBlockCache(maxEntries int) *BlockCache {
return &BlockCache{
MaxEntries: maxEntries,
FirstBlock: -1,
LastBlock: -1,
m: make(map[int]*BlockCacheEntry),
}
}
func (c *BlockCache) Add(height int, block *walletrpc.CompactBlock) (error, bool) {
c.mutex.Lock()
defer c.mutex.Unlock()
//println("Cache add", height)
if c.FirstBlock == -1 && c.LastBlock == -1 {
// If this is the first block, prep the data structure
c.FirstBlock = height
c.LastBlock = height - 1
}
// If we're adding a block in the middle of the cache, remove all
// blocks after it, since this might be a reorg, and we don't want
// Any outdated blocks returned
if height >= c.FirstBlock && height <= c.LastBlock {
for i := height; i <= c.LastBlock; i++ {
delete(c.m, i)
}
c.LastBlock = height - 1
}
// Don't allow out-of-order blocks. This is more of a sanity check than anything
// If there is a reorg, then the ingestor needs to handle it.
if c.m[height-1] != nil && !bytes.Equal(block.PrevHash, c.m[height-1].hash) {
return nil, true
}
// Add the entry and update the counters
data, err := proto.Marshal(block)
if err != nil {
println("Error marshalling block!")
return err, false
}
c.m[height] = &BlockCacheEntry{
data: data,
hash: block.GetHash(),
}
c.LastBlock = height
// If the cache is full, remove the oldest block
if c.LastBlock-c.FirstBlock+1 > c.MaxEntries {
//println("Deleteing at height", c.FirstBlock)
delete(c.m, c.FirstBlock)
c.FirstBlock = c.FirstBlock + 1
}
//println("Cache size is ", len(c.m))
return nil, false
}
func (c *BlockCache) Get(height int) *walletrpc.CompactBlock {
c.mutex.RLock()
defer c.mutex.RUnlock()
//println("Cache get", height)
if c.LastBlock == -1 || c.FirstBlock == -1 {
return nil
}
if height < c.FirstBlock || height > c.LastBlock {
//println("Cache miss: index out of range")
return nil
}
//println("Cache returned")
serialized := &walletrpc.CompactBlock{}
err := proto.Unmarshal(c.m[height].data, serialized)
if err != nil {
println("Error unmarshalling compact block")
return nil
}
return serialized
}
func (c *BlockCache) GetLatestBlock() int {
c.mutex.RLock()
defer c.mutex.RUnlock()
return c.LastBlock
}

277
common/common.go

@ -0,0 +1,277 @@
package common
import (
"encoding/hex"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"git.hush.is/hush/lightwalletd/parser"
"git.hush.is/hush/lightwalletd/walletrpc"
"github.com/btcsuite/btcd/rpcclient"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
var (
Version = "v0.0.1-alpha"
BuildUser = "jahway603"
)
// highlightd CLI options
type Options struct {
GRPCBindAddr string `json:"grpc_bind_address,omitempty"`
tlsCertPath string `json:"tls_cert_path,omitempty"`
tlsKeyPath string `json:"tls_cert_key,omitempty"`
noTLS bool `json:no_tls,omitempty`
logLevel uint64 `json:"log_level,omitempty"`
logPath string `json:"log_file,omitempty"`
hush3ConfPath string `json:"hush3_conf,omitempty"`
cacheSize int `json:"hush3_conf,omitempty"`
}
func GetSaplingInfo(rpcClient *rpcclient.Client) (int, int, string, string, int, int, int, error) {
result, rpcErr := rpcClient.RawRequest("getblockchaininfo", make([]json.RawMessage, 0))
var err error
var errCode int64
// For some reason, the error responses are not JSON
if rpcErr != nil {
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
//Check to see if we are requesting a height the hushd doesn't have yet
if err == nil && errCode == -8 {
return -1, -1, "", "", -1, -1, -1, nil
}
return -1, -1, "", "", -1, -1, -1, errors.Wrap(rpcErr, "error requesting block")
}
var f interface{}
err = json.Unmarshal(result, &f)
if err != nil {
return -1, -1, "", "", -1, -1, -1, errors.Wrap(err, "error reading JSON response")
}
chainName := f.(map[string]interface{})["chain"].(string)
upgradeJSON := f.(map[string]interface{})["upgrades"]
saplingJSON := upgradeJSON.(map[string]interface{})["76b809bb"] // Sapling ID
saplingHeight := saplingJSON.(map[string]interface{})["activationheight"].(float64)
blockHeight := f.(map[string]interface{})["headers"].(float64)
difficulty := f.(map[string]interface{})["difficulty"].(float64)
longestchain := f.(map[string]interface{})["longestchain"].(float64)
notarized := f.(map[string]interface{})["notarized"].(float64)
consensus := f.(map[string]interface{})["consensus"]
branchID := consensus.(map[string]interface{})["nextblock"].(string)
return int(saplingHeight), int(blockHeight), chainName, branchID, int(difficulty), int(longestchain), int(notarized), nil
}
func GetCoinsupply(rpcClient *rpcclient.Client) (string, string, int, int, int, int, error) {
result1, rpcErr := rpcClient.RawRequest("coinsupply", make([]json.RawMessage, 0))
var err error
var errCode int64
// For some reason, the error responses are not JSON
if rpcErr != nil {
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
//Check to see if we are requesting a height the hushd doesn't have yet
if err == nil && errCode == -8 {
return "", "", -1, -1, -1, -1, nil
}
return "", "", -1, -1, -1, -1, errors.Wrap(rpcErr, "error requesting coinsupply")
}
var f interface{}
err = json.Unmarshal(result1, &f)
if err != nil {
return "", "", -1, -1, -1, -1, errors.Wrap(err, "error reading JSON response")
}
result := f.(map[string]interface{})["result"].(string)
coin := f.(map[string]interface{})["coin"].(string)
height := f.(map[string]interface{})["height"].(float64)
supply := f.(map[string]interface{})["supply"].(float64)
zfunds := f.(map[string]interface{})["zfunds"].(float64)
total := f.(map[string]interface{})["total"].(float64)
return result, coin, int(height), int(supply), int(zfunds), int(total), nil
}
func getBlockFromRPC(rpcClient *rpcclient.Client, height int) (*walletrpc.CompactBlock, error) {
params := make([]json.RawMessage, 2)
params[0] = json.RawMessage("\"" + strconv.Itoa(height) + "\"")
params[1] = json.RawMessage("0")
result, rpcErr := rpcClient.RawRequest("getblock", params)
var err error
var errCode int64
// For some reason, the error responses are not JSON
if rpcErr != nil {
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
//Check to see if we are requesting a height the hushd doesn't have yet
if err == nil && errCode == -8 {
return nil, nil
}
return nil, errors.Wrap(rpcErr, "error requesting block")
}
var blockDataHex string
err = json.Unmarshal(result, &blockDataHex)
if err != nil {
return nil, errors.Wrap(err, "error reading JSON response")
}
blockData, err := hex.DecodeString(blockDataHex)
if err != nil {
return nil, errors.Wrap(err, "error decoding getblock output")
}
block := parser.NewBlock()
rest, err := block.ParseFromSlice(blockData)
if err != nil {
return nil, errors.Wrap(err, "error parsing block")
}
if len(rest) != 0 {
return nil, errors.New("received overlong message")
}
return block.ToCompact(), nil
}
func BlockIngestor(rpcClient *rpcclient.Client, cache *BlockCache, log *logrus.Entry,
stopChan chan bool, startHeight int) {
reorgCount := 0
height := startHeight
timeoutCount := 0
// Start listening for new blocks
for {
select {
case <-stopChan:
break
case <-time.After(15 * time.Second):
for {
if reorgCount > 0 {
height -= 10
}
if reorgCount > 10 {
log.Error("Reorg exceeded max of 100 blocks! Help!")
return
}
block, err := getBlockFromRPC(rpcClient, height)
if err != nil {
log.WithFields(logrus.Fields{
"height": height,
"error": err,
}).Warn("error with getblock")
timeoutCount++
if timeoutCount == 3 {
log.WithFields(logrus.Fields{
"timeouts": timeoutCount,
}).Warn("unable to issue RPC call to hushd node 3 times")
break
}
}
if block != nil {
if timeoutCount > 0 {
timeoutCount--
}
log.Info("Ingestor adding block to cache: ", height)
err, reorg := cache.Add(height, block)
if err != nil {
log.Error("Error adding block to cache: ", err)
continue
}
//check for reorgs once we have inital block hash from startup
if reorg {
reorgCount++
log.WithFields(logrus.Fields{
"height": height,
"hash": displayHash(block.Hash),
"phash": displayHash(block.PrevHash),
"reorg": reorgCount,
}).Warn("REORG")
} else {
reorgCount = 0
height++
}
} else {
break
}
}
}
}
}
func GetBlock(rpcClient *rpcclient.Client, cache *BlockCache, height int) (*walletrpc.CompactBlock, error) {
// First, check the cache to see if we have the block
block := cache.Get(height)
if block != nil {
return block, nil
}
// If a block was not found, make sure user is requesting a historical block
if height > cache.GetLatestBlock() {
return nil, errors.New(
fmt.Sprintf(
"Block requested is newer than latest block. Requested: %d Latest: %d",
height, cache.GetLatestBlock()))
}
block, err := getBlockFromRPC(rpcClient, height)
if err != nil {
return nil, err
}
return block, nil
}
func GetBlockRange(rpcClient *rpcclient.Client, cache *BlockCache,
blockOut chan<- walletrpc.CompactBlock, errOut chan<- error, start, end int) {
// Go over [start, end] inclusive
for i := start; i <= end; i++ {
block, err := GetBlock(rpcClient, cache, i)
if err != nil {
errOut <- err
return
}
blockOut <- *block
}
errOut <- nil
}
func displayHash(hash []byte) string {
rhash := make([]byte, len(hash))
copy(rhash, hash)
// Reverse byte order
for i := 0; i < len(rhash)/2; i++ {
j := len(rhash) - 1 - i
rhash[i], rhash[j] = rhash[j], rhash[i]
}
return hex.EncodeToString(rhash)
}

6
contrib/debian/copyright

@ -0,0 +1,6 @@
Files: *
Copyright: 2019-2021, The Hush developers
2018-2019, The Zcash developers
License: GPLv3
Comment: https://hush.is/developers

67
doc/man/highlited.1

@ -0,0 +1,67 @@
.TH LIGHTWALLET "29" "October 2021" "hightlited v0.0.1" "User Commands"
.SH NAME
lightwalletd \- manual page for hush highlited v0.0.1
.SH DESCRIPTION
.B lightwalletd
runs a lightwallet daemon for a Hush Silent Dragon Lite node while puffing...
.PP
In order to ensure you are adequately protecting your privacy when using Hush,
please see <https://hush.is/security/>.
.SS "Usage:"
.TP
.B highlited [options]
Start Hush highlited
.TP
highlited --help
List available command line options
.TP
highlited --version
Display version information
.SH OPTIONS
.HP
\fB\-help | -h | -?
.IP
Display command line options
.HP
\fB\-conf-file\fR [conf_file location]
.IP
Configures your HUSH3.conf file location [Required to run]. Typically ~/.hush/HUSH3/HUSH3.conf
.HP
\fB\-bind-addr \fRhost.net:chosen_port
.IP
Set host.net to either a FQDN or 127.0.0.1 depending on your configuration [Required to run]. Most common port is 9067 unless changed.
.HP
\fB\-no-tls
.IP
Disable TLS, serve un-encrypted traffic. Toggle depending on your configuration.
.HP
\fB\-cache-size \fRint
.IP
Set number of blocks to hold in the cache (default 40000)
.HP
\fB\-log-file \fRstring
.IP
Set log file to write to
.HP
\fB\-log-level \fRuint
.IP
log level (logrus 1-7) (default 4)
.HP
\fB\-tls-cert \fRstring
.IP
the path to a TLS certificate (optional)
.HP
\fB\-tls-key \fRstring
.IP
the path to a TLS key file (optional)
.SH COPYRIGHT
In order to ensure you are adequately protecting your privacy when using Hush,
please see <https://hush.is/security/>.
Copyright (C) 2021 Jahway603 and The Hush Developers
This is experimental Free Software! Fuck Yeah!!!!!
Distributed under the GPLv3 software license, see the accompanying file COPYING
or <https://www.gnu.org/licenses/gpl-3.0.en.html>.

39
frontend/rpc_client.go

@ -0,0 +1,39 @@
package frontend
// copied exactly from hush lightwalletd with this comment as only change
import (
"net"
"github.com/btcsuite/btcd/rpcclient"
"github.com/pkg/errors"
ini "gopkg.in/ini.v1"
)
func NewZRPCFromConf(confPath string) (*rpcclient.Client, error) {
cfg, err := ini.Load(confPath)
if err != nil {
return nil, errors.Wrap(err, "failed to read config file")
}
rpcaddr := cfg.Section("").Key("rpcbind").String()
rpcport := cfg.Section("").Key("rpcport").String()
username := cfg.Section("").Key("rpcuser").String()
password := cfg.Section("").Key("rpcpassword").String()
return NewZRPCFromCreds(net.JoinHostPort(rpcaddr, rpcport), username, password)
}
func NewZRPCFromCreds(addr, username, password string) (*rpcclient.Client, error) {
// Connect to local hush RPC server using HTTP POST mode.
connCfg := &rpcclient.ConnConfig{
Host: addr,
User: username,
Pass: password,
HTTPPostMode: true, // Hush only supports HTTP POST mode
DisableTLS: true, // Hush does not provide TLS by default
}
// Notice the notification parameter is nil since notifications are
// not supported in HTTP POST mode.
return rpcclient.New(connCfg, nil)
}

333
frontend/service.go

@ -0,0 +1,333 @@
package frontend
import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"regexp"
"strconv"
"strings"
"time"
"github.com/btcsuite/btcd/rpcclient"
"github.com/sirupsen/logrus"
"git.hush.is/hush/lightwalletd/walletrpc"
"git.hush.is/jahway603/highlited/common"
)
var (
ErrUnspecified = errors.New("request for unspecified identifier")
)
// the service type
type SqlStreamer struct {
cache *common.BlockCache
client *rpcclient.Client
log *logrus.Entry
}
func NewSQLiteStreamer(client *rpcclient.Client, cache *common.BlockCache, log *logrus.Entry) (walletrpc.CompactTxStreamerServer, error) {
return &SqlStreamer{cache, client, log}, nil
}
func (s *SqlStreamer) GracefulStop() error {
return nil
}
func (s *SqlStreamer) GetCache() *common.BlockCache {
return s.cache
}
func (s *SqlStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc.ChainSpec) (*walletrpc.BlockID, error) {
latestBlock := s.cache.GetLatestBlock()
if latestBlock == -1 {
return nil, errors.New("Cache is empty. Server is probably not yet ready.")
}
// TODO: also return block hashes here
return &walletrpc.BlockID{Height: uint64(latestBlock)}, nil
}
func (s *SqlStreamer) GetAddressTxids(addressBlockFilter *walletrpc.TransparentAddressBlockFilter, resp walletrpc.CompactTxStreamer_GetAddressTxidsServer) error {
var err error
var errCode int64
// Test to make sure Address is a single t address
match, err := regexp.Match("^R[a-zA-Z0-9]{33}$", []byte(addressBlockFilter.Address))
if err != nil || !match {
s.log.Errorf("Unrecognized address: %s", addressBlockFilter.Address)
return nil
}
params := make([]json.RawMessage, 1)
st := "{\"addresses\": [\"" + addressBlockFilter.Address + "\"]," +
"\"start\": " + strconv.FormatUint(addressBlockFilter.Range.Start.Height, 10) +
", \"end\": " + strconv.FormatUint(addressBlockFilter.Range.End.Height, 10) + "}"
params[0] = json.RawMessage(st)
result, rpcErr := s.client.RawRequest("getaddresstxids", params)
// For some reason, the error responses are not JSON
if rpcErr != nil {
s.log.Errorf("Got error: %s", rpcErr.Error())
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
//Check to see if we are requesting a height the hushd doesn't have yet
if err == nil && errCode == -8 {
return nil
}
return nil
}
var txids []string
err = json.Unmarshal(result, &txids)
if err != nil {
s.log.Errorf("Got error: %s", err.Error())
return nil
}
timeout, cancel := context.WithTimeout(resp.Context(), 30*time.Second)
defer cancel()
for _, txidstr := range txids {
txid, _ := hex.DecodeString(txidstr)
// Txid is read as a string, which is in big-endian order. But when converting
// to bytes, it should be little-endian
for left, right := 0, len(txid)-1; left < right; left, right = left+1, right-1 {
txid[left], txid[right] = txid[right], txid[left]
}
tx, err := s.GetTransaction(timeout, &walletrpc.TxFilter{Hash: txid})
if err != nil {
s.log.Errorf("Got error: %s", err.Error())
return nil
}
resp.Send(tx)
}
return nil
}
func (s *SqlStreamer) GetBlock(ctx context.Context, id *walletrpc.BlockID) (*walletrpc.CompactBlock, error) {
if id.Height == 0 && id.Hash == nil {
return nil, ErrUnspecified
}
// Precedence: a hash is more specific than a height. If we have it, use it first.
if id.Hash != nil {
// TODO: Get block by hash
return nil, errors.New("GetBlock by Hash is not yet implemented")
} else {
cBlock, err := common.GetBlock(s.client, s.cache, int(id.Height))
if err != nil {
return nil, err
}
return cBlock, err
}
}
func (s *SqlStreamer) GetBlockRange(span *walletrpc.BlockRange, resp walletrpc.CompactTxStreamer_GetBlockRangeServer) error {
blockChan := make(chan walletrpc.CompactBlock)
errChan := make(chan error)
go common.GetBlockRange(s.client, s.cache, blockChan, errChan, int(span.Start.Height), int(span.End.Height))
for {
select {
case err := <-errChan:
// this will also catch context.DeadlineExceeded from the timeout
return err
case cBlock := <-blockChan:
err := resp.Send(&cBlock)
if err != nil {
return err
}
}
}
return nil
}
func (s *SqlStreamer) GetTransaction(ctx context.Context, txf *walletrpc.TxFilter) (*walletrpc.RawTransaction, error) {
var txBytes []byte
var txHeight float64
if txf.Hash != nil {
txid := txf.Hash
for left, right := 0, len(txid)-1; left < right; left, right = left+1, right-1 {
txid[left], txid[right] = txid[right], txid[left]
}
leHashString := hex.EncodeToString(txid)
// First call to get the raw transaction bytes
params := make([]json.RawMessage, 1)
params[0] = json.RawMessage("\"" + leHashString + "\"")
result, rpcErr := s.client.RawRequest("getrawtransaction", params)
var err error
var errCode int64
// For some reason, the error responses are not JSON
if rpcErr != nil {
s.log.Errorf("Got error: %s", rpcErr.Error())
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
//Check to see if we are requesting a height the hushd doesn't have yet
if err == nil && errCode == -8 {
return nil, err
}
return nil, err
}
var txhex string
err = json.Unmarshal(result, &txhex)
if err != nil {
return nil, err
}
txBytes, err = hex.DecodeString(txhex)
if err != nil {
return nil, err
}
// Second call to get height
params = make([]json.RawMessage, 2)
params[0] = json.RawMessage("\"" + leHashString + "\"")
params[1] = json.RawMessage("1")
result, rpcErr = s.client.RawRequest("getrawtransaction", params)
// For some reason, the error responses are not JSON
if rpcErr != nil {
s.log.Errorf("Got error: %s", rpcErr.Error())
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
//Check to see if we are requesting a height the hushd doesn't have yet
if err == nil && errCode == -8 {
return nil, err
}
return nil, err
}
var txinfo interface{}
err = json.Unmarshal(result, &txinfo)
if err != nil {
return nil, err
}
txHeight = txinfo.(map[string]interface{})["height"].(float64)
return &walletrpc.RawTransaction{Data: txBytes, Height: uint64(txHeight)}, nil
}
if txf.Block.Hash != nil {
s.log.Error("Can't GetTransaction with a blockhash+num. Please call GetTransaction with txid")
return nil, errors.New("Can't GetTransaction with a blockhash+num. Please call GetTransaction with txid")
}
return &walletrpc.RawTransaction{Data: txBytes, Height: uint64(txHeight)}, nil
}
// GetLightdInfo gets the LightWalletD (this server) info
func (s *SqlStreamer) GetLightdInfo(ctx context.Context, in *walletrpc.Empty) (*walletrpc.LightdInfo, error) {
saplingHeight, blockHeight, chainName, consensusBranchId, difficulty, longestchain, notarized, err := common.GetSaplingInfo(s.client)
if err != nil {
s.log.WithFields(logrus.Fields{
"error": err,
}).Warn("Unable to get sapling activation height")
return nil, err
}
// TODO these are called Error but they aren't at the moment.
// A success will return code 0 and message txhash.
return &walletrpc.LightdInfo{
Version: "0.0.1-highlited",
Vendor: "Silentdragonlite HighLiteD",
TaddrSupport: true,
ChainName: chainName,
SaplingActivationHeight: uint64(saplingHeight),
ConsensusBranchId: consensusBranchId,
BlockHeight: uint64(blockHeight),
Difficulty: uint64(difficulty),
Longestchain: uint64(longestchain),
Notarized: uint64(notarized),
}, nil
}
// GetCoinsupply gets the Coinsupply info
func (s *SqlStreamer) GetCoinsupply(ctx context.Context, in *walletrpc.Empty) (*walletrpc.Coinsupply, error) {
result, coin, height, supply, zfunds, total, err := common.GetCoinsupply(s.client)
if err != nil {
s.log.WithFields(logrus.Fields{
"error": err,
}).Warn("Unable to get Coinsupply")
return nil, err
}
// TODO these are called Error but they aren't at the moment.
// A success will return code 0 and message txhash.
return &walletrpc.Coinsupply{
Result: result,
Coin: coin,
Height: uint64(height),
Supply: uint64(supply),
Zfunds: uint64(zfunds),
Total: uint64(total),
}, nil
}
// SendTransaction forwards raw transaction bytes to a hushd instance over JSON-RPC
func (s *SqlStreamer) SendTransaction(ctx context.Context, rawtx *walletrpc.RawTransaction) (*walletrpc.SendResponse, error) {
// sendrawtransaction "hexstring" ( allowhighfees )
//
// Submits raw transaction (serialized, hex-encoded) to local node and network.
//
// Also see createrawtransaction and signrawtransaction calls.
//
// Arguments:
// 1. "hexstring" (string, required) The hex string of the raw transaction)
// 2. allowhighfees (boolean, optional, default=false) Allow high fees
//
// Result:
// "hex" (string) The transaction hash in hex
// Construct raw JSON-RPC params
params := make([]json.RawMessage, 1)
txHexString := hex.EncodeToString(rawtx.Data)
params[0] = json.RawMessage("\"" + txHexString + "\"")
result, rpcErr := s.client.RawRequest("sendrawtransaction", params)
var err error
var errCode int64
var errMsg string
// For some reason, the error responses are not JSON
if rpcErr != nil {
errParts := strings.SplitN(rpcErr.Error(), ":", 2)
errMsg = strings.TrimSpace(errParts[1])
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
if err != nil {
// This should never happen. We can't panic here, but it's that class of error.
// This is why we need integration testing to work better than regtest currently does. TODO.
return nil, errors.New("SendTransaction couldn't parse error code")
}
} else {
errMsg = string(result)
}
// TODO these are called Error but they aren't at the moment.
// A success will return code 0 and message txhash.
return &walletrpc.SendResponse{
ErrorCode: int32(errCode),
ErrorMessage: errMsg,
}, nil
}

14
util/build.sh

@ -3,7 +3,7 @@
# Distributed under the GPLv3 software license, see the accompanying
# file LICENSE or https://www.gnu.org/licenses/gpl-3.0.en.html
# Purpose: Script to build HighLightD on x86 64-bit arch
# Purpose: Script to build HighLited on x86 64-bit arch
# Check if go is installed on system and exits if it is not
if ! [ -x "$(command -v go)" ]; then
@ -14,6 +14,8 @@ fi
echo ""
echo "Welcome to the Hush magic folks... the highd life"
echo ""
echo " H ... U ... S... H..."
echo ""
echo ' |\_/| D\___/\'
echo ' (0_0) (0_o)'
echo ' ==(Y)== (V)'
@ -23,9 +25,9 @@ echo ""
# now to compiling...
echo ""
echo "You have go installed, so starting to compile Hush highlightd for you..."
go build -o highlightd main.go
echo "You have go installed, so starting to compile Hush highlited for you..."
go build -o highlited main.go
echo ""
echo "Hush highlightd is now compiled for you. Enjoy and reach out if you need support."
echo "For options, run ./highlightd --help"
echo "For version info, run ./highlightd version"
echo "Hush highlited is now compiled for you. Enjoy and reach out if you need support."
echo "For options, run ./highlited --help"
echo "For version info, run ./highlited version"

15
util/build_arm.sh

@ -6,7 +6,6 @@
# Purpose: Script to build the ARM or aarch64 architecture,
# which is what the PinePhone boards are running
# Check if go is installed on system and exits if it is not
if ! [ -x "$(command -v go)" ]; then
echo 'Error: go is not installed. Install go and try again.' >&2
@ -16,6 +15,8 @@ fi
echo ""
echo "Welcome to the Hush magic folks... the highd life"
echo ""
echo " H ... U ... S... H..."
echo ""
echo ' |\_/| D\___/\'
echo ' (0_0) (0_o)'
echo ' ==(Y)== (V)'
@ -25,10 +26,10 @@ echo ""
# now to compiling...
echo ""
echo "You have go installed, so starting to compile Hush highlightd for you..."
env GOOS=linux GOARCH=arm64 go build -o highlightd_aarch64 main.go
mv highlightd_aarch64 highlightd
echo "You have go installed, so starting to compile Hush highlited for you..."
env GOOS=linux GOARCH=arm64 go build -o highlited_aarch64 main.go
mv highlited_aarch64 highlited
echo ""
echo "Hush highlightd is now compiled for your ARM farm or PineBook Pro. Enjoy and reach out if you need support."
echo "For options, run ./highlightd --help"
echo "For version info, run ./highlightd version"
echo "Hush highlited is now compiled for your ARM farm or PineBook Pro. Enjoy and reach out if you need support."
echo "For options, run ./highlited --help"
echo "For version info, run ./highlited version"

Loading…
Cancel
Save