Browse Source

Thread safe cache with separate ingestor

master
Aditya Kulkarni 5 years ago
parent
commit
a8cc2424a2
  1. 29
      cmd/server/main.go
  2. 32
      common/cache.go
  3. 136
      common/common.go
  4. 35
      frontend/service.go
  5. 91
      walletrpc/service.pb.go
  6. 1
      walletrpc/service.proto

29
cmd/server/main.go

@ -23,6 +23,8 @@ import (
var log *logrus.Entry
var logger = logrus.New()
var cacheSize = 10000
func init() {
logger.SetFormatter(&logrus.TextFormatter{
//DisableColors: true,
@ -77,7 +79,6 @@ func loggerFromContext(ctx context.Context) *logrus.Entry {
type Options struct {
bindAddr string `json:"bind_address,omitempty"`
dbPath string `json:"db_path"`
tlsCertPath string `json:"tls_cert_path,omitempty"`
tlsKeyPath string `json:"tls_cert_key,omitempty"`
logLevel uint64 `json:"log_level,omitempty"`
@ -88,7 +89,6 @@ type Options struct {
func main() {
opts := &Options{}
flag.StringVar(&opts.bindAddr, "bind-addr", "127.0.0.1:9067", "the address to listen on")
flag.StringVar(&opts.dbPath, "db-path", "", "the path to a sqlite database file")
flag.StringVar(&opts.tlsCertPath, "tls-cert", "", "the path to a TLS certificate (optional)")
flag.StringVar(&opts.tlsKeyPath, "tls-key", "", "the path to a TLS key file (optional)")
flag.Uint64Var(&opts.logLevel, "log-level", uint64(logrus.InfoLevel), "log level (logrus 1-7)")
@ -98,7 +98,7 @@ func main() {
// TODO support config from file and env vars
flag.Parse()
if opts.dbPath == "" || opts.zcashConfPath == "" {
if opts.zcashConfPath == "" {
flag.Usage()
os.Exit(1)
}
@ -161,7 +161,7 @@ func main() {
}
// Get the sapling activation height from the RPC
saplingHeight, chainName, branchID, err := common.GetSaplingInfo(rpcClient)
saplingHeight, blockHeight, chainName, branchID, err := common.GetSaplingInfo(rpcClient)
if err != nil {
log.WithFields(logrus.Fields{
"error": err,
@ -170,12 +170,24 @@ func main() {
log.Info("Got sapling height ", saplingHeight, " chain ", chainName, " branchID ", branchID)
// Initialize the cache
cache := common.NewBlockCache(cacheSize)
stopChan := make(chan bool, 1)
// Start the block cache importer at latestblock - 100k(cache size)
cacheStart := blockHeight - cacheSize
if cacheStart < saplingHeight {
cacheStart = saplingHeight
}
go common.BlockIngestor(rpcClient, cache, log, stopChan, cacheStart)
// Compact transaction service initialization
service, err := frontend.NewSQLiteStreamer(rpcClient, log)
service, err := frontend.NewSQLiteStreamer(rpcClient, cache, log)
if err != nil {
log.WithFields(logrus.Fields{
"db_path": opts.dbPath,
"error": err,
"error": err,
}).Fatal("couldn't create SQL backend")
}
defer service.(*frontend.SqlStreamer).GracefulStop()
@ -200,7 +212,10 @@ func main() {
log.WithFields(logrus.Fields{
"signal": s.String(),
}).Info("caught signal, stopping gRPC server")
// Stop the server
server.GracefulStop()
// Stop the block ingestor
stopChan <- true
}()
log.Infof("Starting gRPC server on %s", opts.bindAddr)

32
common/cache.go

@ -2,6 +2,7 @@ package common
import (
"bytes"
"sync"
"github.com/adityapk00/lightwalletd/walletrpc"
"github.com/pkg/errors"
@ -14,9 +15,11 @@ type BlockCache struct {
LastBlock int
m map[int]*walletrpc.CompactBlock
mutex sync.RWMutex
}
func New(maxEntries int) *BlockCache {
func NewBlockCache(maxEntries int) *BlockCache {
return &BlockCache{
MaxEntries: maxEntries,
FirstBlock: -1,
@ -26,25 +29,18 @@ func New(maxEntries int) *BlockCache {
}
func (c *BlockCache) Add(height int, block *walletrpc.CompactBlock) error {
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
} else if height >= c.FirstBlock && height <= c.LastBlock {
// Overwriting an existing entry. If so, then remove all
// subsequent blocks, since this might be a reorg
for i := height; i <= c.LastBlock; i++ {
//println("Deleteing at height", i)
delete(c.m, i)
}
c.LastBlock = height - 1
}
if height != c.LastBlock+1 {
return errors.New("Blocks need to be added sequentially")
}
// 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 errors.New("Prev hash of the block didn't match")
}
@ -66,6 +62,9 @@ func (c *BlockCache) Add(height int, block *walletrpc.CompactBlock) error {
}
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
@ -79,3 +78,10 @@ func (c *BlockCache) Get(height int) *walletrpc.CompactBlock {
//println("Cache returned")
return c.m[height]
}
func (c *BlockCache) GetLatestBlock() int {
c.mutex.RLock()
defer c.mutex.RUnlock()
return c.LastBlock
}

136
common/common.go

@ -1,19 +1,21 @@
package common
import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"github.com/adityapk00/lightwalletd/parser"
"github.com/adityapk00/lightwalletd/walletrpc"
"github.com/btcsuite/btcd/rpcclient"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
func GetSaplingInfo(rpcClient *rpcclient.Client) (int, string, string, error) {
func GetSaplingInfo(rpcClient *rpcclient.Client) (int, int, string, string, error) {
result, rpcErr := rpcClient.RawRequest("getblockchaininfo", make([]json.RawMessage, 0))
var err error
@ -25,15 +27,15 @@ func GetSaplingInfo(rpcClient *rpcclient.Client) (int, string, string, error) {
errCode, err = strconv.ParseInt(errParts[0], 10, 32)
//Check to see if we are requesting a height the zcashd doesn't have yet
if err == nil && errCode == -8 {
return -1, "", "", nil
return -1, -1, "", "", nil
}
return -1, "", "", errors.Wrap(rpcErr, "error requesting block")
return -1, -1, "", "", errors.Wrap(rpcErr, "error requesting block")
}
var f interface{}
err = json.Unmarshal(result, &f)
if err != nil {
return -1, "", "", errors.Wrap(err, "error reading JSON response")
return -1, -1, "", "", errors.Wrap(err, "error reading JSON response")
}
chainName := f.(map[string]interface{})["chain"].(string)
@ -42,10 +44,12 @@ func GetSaplingInfo(rpcClient *rpcclient.Client) (int, string, string, error) {
saplingJSON := upgradeJSON.(map[string]interface{})["76b809bb"] // Sapling ID
saplingHeight := saplingJSON.(map[string]interface{})["activationheight"].(float64)
blockHeight := f.(map[string]interface{})["headers"].(float64)
consensus := f.(map[string]interface{})["consensus"]
branchID := consensus.(map[string]interface{})["nextblock"].(string)
return int(saplingHeight), chainName, branchID, nil
return int(saplingHeight), int(blockHeight), chainName, branchID, nil
}
func getBlockFromRPC(rpcClient *rpcclient.Client, height int) (*walletrpc.CompactBlock, error) {
@ -91,6 +95,78 @@ func getBlockFromRPC(rpcClient *rpcclient.Client, height int) (*walletrpc.Compac
return block.ToCompact(), nil
}
func BlockIngestor(rpcClient *rpcclient.Client, cache *BlockCache, log *logrus.Entry,
stopChan chan bool, startHeight int) {
reorgCount := -1
height := startHeight
timeoutCount := 0
hash := ""
phash := ""
// Start listening for new blocks
for {
select {
case <-stopChan:
break
case <-time.After(15 * time.Second):
for {
if reorgCount > 0 {
reorgCount = -1
height -= 10
}
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 zcashd node 3 times")
break
}
}
if block != nil {
log.Info("Ingestor adding block to cache: ", height)
cache.Add(height, block)
if timeoutCount > 0 {
timeoutCount--
}
phash = hex.EncodeToString(block.PrevHash)
//check for reorgs once we have inital block hash from startup
if hash != phash && reorgCount != -1 {
reorgCount++
log.WithFields(logrus.Fields{
"height": height,
"hash(reversed)": hash,
"phash(reversed)": phash,
"reorg": reorgCount,
}).Warn("REORG")
} else {
hash = hex.EncodeToString(block.Hash)
}
if reorgCount == -1 {
hash = hex.EncodeToString(block.Hash)
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)
@ -98,51 +174,19 @@ func GetBlock(rpcClient *rpcclient.Client, cache *BlockCache, height int) (*wall
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
}
// Store the block in the cache, but test for reorg first
prevBlock := cache.Get(height - 1)
if prevBlock != nil {
if !bytes.Equal(prevBlock.Hash, block.PrevHash) {
// Reorg!
reorgCount := 0
cacheBlock := cache.Get(height - reorgCount)
rpcBlocks := []*walletrpc.CompactBlock{}
for ; reorgCount <= 100 &&
cacheBlock != nil &&
!bytes.Equal(block.PrevHash, cacheBlock.Hash); reorgCount++ {
block, err = getBlockFromRPC(rpcClient, height-reorgCount-1)
if err != nil {
return nil, err
}
_ = append(rpcBlocks, block)
cacheBlock = cache.Get(height - reorgCount - 2)
}
if reorgCount == 100 {
return nil, errors.New("Max reorg depth exceeded")
}
// At this point, the block.prevHash == cache.hash
// Store all blocks starting with 'block'
for i := len(rpcBlocks) - 1; i >= 0; i-- {
cache.Add(int(rpcBlocks[i].Height), rpcBlocks[i])
}
}
}
cache.Add(height, block)
return block, nil
}

35
frontend/service.go

@ -27,39 +27,25 @@ type SqlStreamer struct {
log *logrus.Entry
}
func NewSQLiteStreamer(client *rpcclient.Client, log *logrus.Entry) (walletrpc.CompactTxStreamerServer, error) {
return &SqlStreamer{common.New(100000), client, log}, nil
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) GetLatestBlock(ctx context.Context, placeholder *walletrpc.ChainSpec) (*walletrpc.BlockID, error) {
result, rpcErr := s.client.RawRequest("getinfo", make([]json.RawMessage, 0))
var err error
var errCode int64
func (s *SqlStreamer) GetCache() *common.BlockCache {
return s.cache
}
// 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 zcashd doesn't have yet
if err == nil && errCode == -8 {
return nil, errors.New("Don't have the requested block")
}
return nil, err
}
func (s *SqlStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc.ChainSpec) (*walletrpc.BlockID, error) {
latestBlock := s.cache.GetLatestBlock()
var f interface{}
err = json.Unmarshal(result, &f)
if err != nil {
return nil, err
if latestBlock == -1 {
return nil, errors.New("Cache is empty. Server is probably not yet ready.")
}
latestBlock := f.(map[string]interface{})["blocks"].(float64)
// TODO: also return block hashes here
return &walletrpc.BlockID{Height: uint64(latestBlock)}, nil
}
@ -243,7 +229,7 @@ func (s *SqlStreamer) GetTransaction(ctx context.Context, txf *walletrpc.TxFilte
// GetLightdInfo gets the LightWalletD (this server) info
func (s *SqlStreamer) GetLightdInfo(ctx context.Context, in *walletrpc.Empty) (*walletrpc.LightdInfo, error) {
saplingHeight, chainName, consensusBranchId, err := common.GetSaplingInfo(s.client)
saplingHeight, blockHeight, chainName, consensusBranchId, err := common.GetSaplingInfo(s.client)
if err != nil {
s.log.WithFields(logrus.Fields{
@ -261,6 +247,7 @@ func (s *SqlStreamer) GetLightdInfo(ctx context.Context, in *walletrpc.Empty) (*
ChainName: chainName,
SaplingActivationHeight: uint64(saplingHeight),
ConsensusBranchId: consensusBranchId,
BlockHeight: uint64(blockHeight),
}, nil
}

91
walletrpc/service.pb.go

@ -346,6 +346,7 @@ type LightdInfo struct {
ChainName string `protobuf:"bytes,4,opt,name=chainName,proto3" json:"chainName,omitempty"`
SaplingActivationHeight uint64 `protobuf:"varint,5,opt,name=saplingActivationHeight,proto3" json:"saplingActivationHeight,omitempty"`
ConsensusBranchId string `protobuf:"bytes,6,opt,name=consensusBranchId,proto3" json:"consensusBranchId,omitempty"`
BlockHeight uint64 `protobuf:"varint,7,opt,name=blockHeight,proto3" json:"blockHeight,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -418,6 +419,13 @@ func (m *LightdInfo) GetConsensusBranchId() string {
return ""
}
func (m *LightdInfo) GetBlockHeight() uint64 {
if m != nil {
return m.BlockHeight
}
return 0
}
type TransparentAddress struct {
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@ -520,47 +528,48 @@ func init() {
func init() { proto.RegisterFile("service.proto", fileDescriptor_a0b84a42fa06f626) }
var fileDescriptor_a0b84a42fa06f626 = []byte{
// 630 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x55, 0x5d, 0x4f, 0x13, 0x41,
0x14, 0xa5, 0xd0, 0xed, 0xc7, 0x6d, 0x81, 0x30, 0x11, 0x6d, 0x1a, 0x54, 0x1c, 0x63, 0xe2, 0x83,
0xd9, 0x10, 0xc4, 0xe8, 0x83, 0x2f, 0xb4, 0x7e, 0x35, 0x41, 0xa3, 0xd3, 0x3e, 0xe1, 0x03, 0x19,
0x76, 0x87, 0xee, 0x4a, 0xbb, 0xb3, 0x99, 0x19, 0x4a, 0xf5, 0xc7, 0xf8, 0xfb, 0xfc, 0x19, 0xce,
0xc7, 0x96, 0x6e, 0x03, 0x4b, 0xfb, 0xb6, 0x77, 0xe6, 0xde, 0x73, 0xce, 0x3d, 0x73, 0x6f, 0x0b,
0x9b, 0x92, 0x89, 0x49, 0x1c, 0x30, 0x3f, 0x15, 0x5c, 0x71, 0xb4, 0x1b, 0x50, 0x19, 0xf9, 0x7f,
0xfc, 0x6b, 0x3a, 0x1a, 0x31, 0xe5, 0xcb, 0xf0, 0xd2, 0x17, 0x69, 0xd0, 0xde, 0x0d, 0xf8, 0x38,
0xa5, 0x81, 0x3a, 0xbb, 0xe0, 0x62, 0x4c, 0x95, 0x74, 0xd9, 0xf8, 0x0d, 0x54, 0x3b, 0x23, 0x1e,
0x5c, 0xf6, 0x3e, 0xa0, 0x87, 0x50, 0x89, 0x58, 0x3c, 0x8c, 0x54, 0xab, 0xb4, 0x5f, 0x7a, 0x59,
0x26, 0x59, 0x84, 0x10, 0x94, 0x23, 0x0d, 0xd9, 0x5a, 0xd7, 0xa7, 0x4d, 0x62, 0xbf, 0xb1, 0x02,
0xb0, 0x65, 0x84, 0x26, 0x43, 0x86, 0x8e, 0xc0, 0x93, 0x8a, 0x0a, 0x57, 0xd8, 0x38, 0x7c, 0xe2,
0xdf, 0x29, 0xc1, 0xcf, 0x88, 0x88, 0x4b, 0x46, 0x07, 0xb0, 0xc1, 0x92, 0xd0, 0xc2, 0x2e, 0xaf,
0x31, 0xa9, 0xf8, 0x17, 0xd4, 0x06, 0xd3, 0x4f, 0xf1, 0x48, 0x31, 0x61, 0x38, 0xcf, 0xcd, 0xdd,
0xaa, 0x9c, 0x36, 0x19, 0x3d, 0x00, 0x2f, 0x4e, 0x42, 0x36, 0xb5, 0xac, 0x65, 0xe2, 0x82, 0x9b,
0x0e, 0x37, 0x72, 0x1d, 0xbe, 0x87, 0x2d, 0x42, 0xaf, 0x07, 0x82, 0x26, 0x52, 0xbb, 0x16, 0xf3,
0xc4, 0x64, 0x85, 0x54, 0x51, 0x4b, 0xa8, 0xb3, 0xcc, 0x77, 0xce, 0xb3, 0xf5, 0xbc, 0x67, 0xf8,
0x3b, 0x34, 0xfb, 0x5a, 0x31, 0x61, 0x32, 0xe5, 0x89, 0x64, 0x68, 0x0f, 0xea, 0x4c, 0x08, 0x2e,
0xba, 0x3c, 0x64, 0x16, 0xc0, 0x23, 0xf3, 0x03, 0x84, 0xa1, 0x69, 0x83, 0xaf, 0x4c, 0x4a, 0x3a,
0x64, 0x16, 0xab, 0x4e, 0x16, 0xce, 0x70, 0x03, 0xea, 0xdd, 0x88, 0xc6, 0x49, 0x3f, 0x65, 0x01,
0xae, 0x82, 0xf7, 0x71, 0x9c, 0xaa, 0xdf, 0xf8, 0x5f, 0x09, 0xe0, 0xc4, 0x30, 0x86, 0xbd, 0xe4,
0x82, 0xa3, 0x16, 0x54, 0x27, 0x4c, 0x48, 0xad, 0xd6, 0x92, 0xd4, 0xc9, 0x2c, 0x34, 0x42, 0x27,
0x5a, 0x10, 0x17, 0x19, 0x78, 0x16, 0x19, 0x6a, 0x45, 0xc3, 0x50, 0xf4, 0xaf, 0xd2, 0x94, 0xeb,
0x17, 0x34, 0x16, 0xd4, 0xc8, 0xc2, 0x99, 0x11, 0x1f, 0x18, 0xea, 0x6f, 0x74, 0xcc, 0x5a, 0x65,
0x5b, 0x3e, 0x3f, 0x40, 0xef, 0xe0, 0x91, 0xa4, 0xe9, 0x28, 0x4e, 0x86, 0xc7, 0xda, 0xa7, 0x09,
0x35, 0x5e, 0x7d, 0x71, 0x9e, 0x78, 0xd6, 0x93, 0xa2, 0x6b, 0xf4, 0x0a, 0x76, 0x02, 0xe3, 0x4e,
0x22, 0xaf, 0x64, 0x47, 0x1b, 0x1d, 0x44, 0xbd, 0xb0, 0x55, 0xb1, 0xf8, 0xb7, 0x2f, 0xb0, 0x0f,
0xc8, 0xbe, 0x46, 0x4a, 0x05, 0x4b, 0xd4, 0xb1, 0xd6, 0xa7, 0x9d, 0x31, 0x1d, 0x53, 0xf7, 0x39,
0xeb, 0x38, 0x0b, 0xb1, 0x80, 0xc7, 0xb7, 0xf3, 0xed, 0x38, 0x64, 0x13, 0x54, 0x58, 0x8a, 0xde,
0x82, 0x27, 0xcc, 0x60, 0x67, 0xb3, 0xf9, 0xec, 0xbe, 0xd9, 0xb2, 0x1b, 0x40, 0x5c, 0xfe, 0xe1,
0x5f, 0x0f, 0x76, 0xba, 0x6e, 0xcf, 0x06, 0xd3, 0xbe, 0x12, 0x4c, 0x1b, 0x24, 0xd0, 0x00, 0xb6,
0x3e, 0x33, 0x75, 0x42, 0x15, 0x93, 0xca, 0xd6, 0xa0, 0xfd, 0x02, 0xc4, 0x9b, 0x17, 0x6e, 0x2f,
0x99, 0x67, 0xbc, 0x86, 0x7e, 0x40, 0x4d, 0xa3, 0x3a, 0xbc, 0x25, 0xd9, 0xed, 0xe7, 0x45, 0x7c,
0x4e, 0xab, 0x4d, 0xd3, 0x90, 0x3f, 0x61, 0x73, 0x06, 0xe9, 0x16, 0x7b, 0x79, 0xe7, 0x2b, 0x42,
0x1f, 0x94, 0xd0, 0xa9, 0x75, 0x21, 0xbf, 0x50, 0x4f, 0x0b, 0x4a, 0x67, 0x3b, 0xde, 0x7e, 0x51,
0x90, 0xb0, 0xb8, 0x98, 0x5a, 0xf8, 0x19, 0x6c, 0x9b, 0x75, 0xcb, 0x83, 0xaf, 0x56, 0x5b, 0x28,
0x3f, 0xbf, 0xbd, 0x9a, 0x40, 0xc0, 0xb6, 0x16, 0x9f, 0x0d, 0xd1, 0x60, 0x1a, 0x87, 0x12, 0x1d,
0x15, 0xa9, 0xbf, 0x6f, 0xe8, 0x56, 0x6e, 0x49, 0x1b, 0x46, 0xec, 0x6b, 0xe4, 0xb6, 0x7b, 0xaf,
0xa0, 0xd6, 0xfe, 0x14, 0xb4, 0x8b, 0xde, 0x6a, 0x0e, 0x80, 0xd7, 0x3a, 0x8d, 0xd3, 0xba, 0xbb,
0xd6, 0x37, 0xe7, 0x15, 0xfb, 0x17, 0xf0, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0x2f,
0xbf, 0xf7, 0x41, 0x06, 0x00, 0x00,
// 643 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x55, 0xdd, 0x6e, 0x13, 0x3d,
0x10, 0xed, 0x4f, 0xb6, 0x69, 0x26, 0xfd, 0x51, 0xad, 0xaf, 0x1f, 0x51, 0x54, 0xa0, 0x18, 0x21,
0x71, 0x81, 0x56, 0x55, 0x29, 0x82, 0x0b, 0x6e, 0xda, 0xf2, 0x57, 0xa9, 0x20, 0x70, 0x72, 0x55,
0x2e, 0x2a, 0x77, 0xd7, 0xcd, 0x2e, 0x4d, 0xd6, 0x2b, 0xdb, 0x4d, 0x03, 0x8f, 0xc0, 0x43, 0xf0,
0xac, 0xd8, 0xe3, 0x4d, 0xb3, 0x51, 0xd9, 0x26, 0x77, 0x3b, 0xe3, 0x99, 0x73, 0x8e, 0x8f, 0x67,
0x12, 0x58, 0xd7, 0x42, 0x0d, 0xd3, 0x48, 0x84, 0xb9, 0x92, 0x46, 0x92, 0xed, 0x88, 0xeb, 0x24,
0xfc, 0x15, 0xde, 0xf0, 0x7e, 0x5f, 0x98, 0x50, 0xc7, 0x57, 0xa1, 0xca, 0xa3, 0xf6, 0x76, 0x24,
0x07, 0x39, 0x8f, 0xcc, 0xf9, 0xa5, 0x54, 0x03, 0x6e, 0xb4, 0xaf, 0xa6, 0xaf, 0xa0, 0x7e, 0xd4,
0x97, 0xd1, 0xd5, 0xc9, 0x3b, 0xf2, 0x3f, 0xac, 0x24, 0x22, 0xed, 0x25, 0xa6, 0xb5, 0xb8, 0xbb,
0xf8, 0xbc, 0xc6, 0x8a, 0x88, 0x10, 0xa8, 0x25, 0x16, 0xb2, 0xb5, 0x64, 0xb3, 0x6b, 0x0c, 0xbf,
0xa9, 0x01, 0xc0, 0x36, 0xc6, 0xb3, 0x9e, 0x20, 0x07, 0x10, 0x68, 0xc3, 0x95, 0x6f, 0x6c, 0xee,
0x3f, 0x0a, 0xff, 0x29, 0x21, 0x2c, 0x88, 0x98, 0x2f, 0x26, 0x7b, 0xb0, 0x2c, 0xb2, 0x18, 0x61,
0x67, 0xf7, 0xb8, 0x52, 0xfa, 0x03, 0x56, 0xbb, 0xa3, 0x0f, 0x69, 0xdf, 0x08, 0xe5, 0x38, 0x2f,
0xdc, 0xd9, 0xbc, 0x9c, 0x58, 0x4c, 0xfe, 0x83, 0x20, 0xcd, 0x62, 0x31, 0x42, 0xd6, 0x1a, 0xf3,
0xc1, 0xed, 0x0d, 0x97, 0x4b, 0x37, 0x7c, 0x0b, 0x1b, 0x8c, 0xdf, 0x74, 0x15, 0xcf, 0xb4, 0x75,
0x2d, 0x95, 0x99, 0xab, 0x8a, 0xb9, 0xe1, 0x48, 0x68, 0xab, 0xdc, 0x77, 0xc9, 0xb3, 0xa5, 0xb2,
0x67, 0xf4, 0x2b, 0xac, 0x75, 0xac, 0x62, 0x26, 0x74, 0x2e, 0x33, 0x2d, 0xc8, 0x0e, 0x34, 0x84,
0x52, 0x52, 0x1d, 0xcb, 0x58, 0x20, 0x40, 0xc0, 0x26, 0x09, 0x42, 0x61, 0x0d, 0x83, 0xcf, 0x42,
0x6b, 0xde, 0x13, 0x88, 0xd5, 0x60, 0x53, 0x39, 0xda, 0x84, 0xc6, 0x71, 0xc2, 0xd3, 0xac, 0x93,
0x8b, 0x88, 0xd6, 0x21, 0x78, 0x3f, 0xc8, 0xcd, 0x4f, 0xfa, 0x7b, 0x09, 0xe0, 0xd4, 0x31, 0xc6,
0x27, 0xd9, 0xa5, 0x24, 0x2d, 0xa8, 0x0f, 0x85, 0xd2, 0x56, 0x2d, 0x92, 0x34, 0xd8, 0x38, 0x74,
0x42, 0x87, 0x56, 0x90, 0x54, 0x05, 0x78, 0x11, 0x39, 0x6a, 0xc3, 0xe3, 0x58, 0x75, 0xae, 0xf3,
0x5c, 0xda, 0x17, 0x74, 0x16, 0xac, 0xb2, 0xa9, 0x9c, 0x13, 0x1f, 0x39, 0xea, 0x2f, 0x7c, 0x20,
0x5a, 0x35, 0x6c, 0x9f, 0x24, 0xc8, 0x1b, 0x78, 0xa0, 0x79, 0xde, 0x4f, 0xb3, 0xde, 0xa1, 0xf5,
0x69, 0xc8, 0x9d, 0x57, 0x9f, 0xbc, 0x27, 0x01, 0x7a, 0x52, 0x75, 0x4c, 0x5e, 0xc0, 0x56, 0xe4,
0xdc, 0xc9, 0xf4, 0xb5, 0x3e, 0xb2, 0x46, 0x47, 0xc9, 0x49, 0xdc, 0x5a, 0x41, 0xfc, 0xbb, 0x07,
0x64, 0x17, 0x9a, 0xf8, 0x86, 0x05, 0x76, 0x1d, 0xb1, 0xcb, 0x29, 0x1a, 0x02, 0xc1, 0xf7, 0xca,
0xb9, 0x12, 0x99, 0x39, 0xb4, 0x37, 0xb0, 0xde, 0x39, 0x4f, 0xb8, 0xff, 0x1c, 0x7b, 0x52, 0x84,
0x54, 0xc1, 0xc3, 0xbb, 0xf5, 0x38, 0x30, 0xc5, 0x8c, 0x55, 0xb6, 0x92, 0xd7, 0x10, 0x28, 0x37,
0xfa, 0xc5, 0xf4, 0x3e, 0xb9, 0x6f, 0xfa, 0x70, 0x47, 0x98, 0xaf, 0xdf, 0xff, 0x13, 0xc0, 0xd6,
0xb1, 0xdf, 0xc4, 0xee, 0xa8, 0x63, 0x94, 0xb0, 0x16, 0x2a, 0xd2, 0x85, 0x8d, 0x8f, 0xc2, 0x9c,
0x72, 0x23, 0xb4, 0xc1, 0x1e, 0xb2, 0x5b, 0x81, 0x78, 0x3b, 0x03, 0xed, 0x19, 0x13, 0x4f, 0x17,
0xc8, 0x37, 0x58, 0xb5, 0xa8, 0x1e, 0x6f, 0x46, 0x75, 0xfb, 0x69, 0x15, 0x9f, 0xd7, 0x8a, 0x65,
0x16, 0xf2, 0x3b, 0xac, 0x8f, 0x21, 0xfd, 0xea, 0xcf, 0xbe, 0xf9, 0x9c, 0xd0, 0x7b, 0x8b, 0xe4,
0x0c, 0x5d, 0x28, 0xaf, 0xdc, 0xe3, 0x8a, 0xd6, 0xf1, 0xaf, 0x40, 0xfb, 0x59, 0x45, 0xc1, 0xf4,
0xea, 0x5a, 0xe1, 0xe7, 0xb0, 0xe9, 0x16, 0xb2, 0x0c, 0x3e, 0x5f, 0x6f, 0xa5, 0xfc, 0xf2, 0x7e,
0x5b, 0x02, 0x05, 0x9b, 0x56, 0x7c, 0x31, 0x44, 0xdd, 0x51, 0x1a, 0x6b, 0x72, 0x50, 0xa5, 0xfe,
0xbe, 0xa1, 0x9b, 0xfb, 0x4a, 0xd6, 0x30, 0x86, 0xaf, 0x51, 0xda, 0xff, 0x9d, 0x8a, 0x5e, 0xfc,
0xb1, 0x68, 0x57, 0xbd, 0xd5, 0x04, 0x80, 0x2e, 0x1c, 0x35, 0xcf, 0x1a, 0xfe, 0xd8, 0x9e, 0x5c,
0xac, 0xe0, 0x9f, 0xc4, 0xcb, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x75, 0x7c, 0x9a, 0xee, 0x63,
0x06, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

1
walletrpc/service.proto

@ -51,6 +51,7 @@ message LightdInfo {
string chainName = 4;
uint64 saplingActivationHeight = 5;
string consensusBranchId = 6; // This should really be u32 or []byte, but string for readability
uint64 blockHeight = 7;
}
message TransparentAddress {

Loading…
Cancel
Save