Merge 'upstream/master'

This commit is contained in:
Aditya Kulkarni 2022-06-07 09:44:48 -05:00
commit 994e8a05f2
39 changed files with 2169 additions and 2114 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ lwd-api.html
*.orig *.orig
__debug_bin __debug_bin
.vscode .vscode
frontend/unittestcache/

View File

@ -60,6 +60,7 @@ var rootCmd = &cobra.Command{
GenCertVeryInsecure: viper.GetBool("gen-cert-very-insecure"), GenCertVeryInsecure: viper.GetBool("gen-cert-very-insecure"),
DataDir: viper.GetString("data-dir"), DataDir: viper.GetString("data-dir"),
Redownload: viper.GetBool("redownload"), Redownload: viper.GetBool("redownload"),
SyncFromHeight: viper.GetInt("sync-from-height"),
PingEnable: viper.GetBool("ping-very-insecure"), PingEnable: viper.GetBool("ping-very-insecure"),
Darkside: viper.GetBool("darkside-very-insecure"), Darkside: viper.GetBool("darkside-very-insecure"),
DarksideTimeout: viper.GetUint64("darkside-timeout"), DarksideTimeout: viper.GetUint64("darkside-timeout"),
@ -255,7 +256,11 @@ func startServer(opts *common.Options) error {
os.Stderr.WriteString(fmt.Sprintf("\n ** Can't create db directory: %s\n\n", dbPath)) os.Stderr.WriteString(fmt.Sprintf("\n ** Can't create db directory: %s\n\n", dbPath))
os.Exit(1) os.Exit(1)
} }
cache := common.NewBlockCache(dbPath, chainName, saplingHeight, opts.Redownload) syncFromHeight := opts.SyncFromHeight
if opts.Redownload {
syncFromHeight = 0
}
cache := common.NewBlockCache(dbPath, chainName, saplingHeight, syncFromHeight)
if !opts.Darkside { if !opts.Darkside {
go common.BlockIngestor(cache, 0 /*loop forever*/) go common.BlockIngestor(cache, 0 /*loop forever*/)
} else { } else {
@ -286,10 +291,6 @@ func startServer(opts *common.Options) error {
// Initialize price fetcher // Initialize price fetcher
common.StartPriceFetcher(dbPath, chainName) common.StartPriceFetcher(dbPath, chainName)
// Initialize mempool monitor
exitMempool := make(chan bool)
common.StartMempoolMonitor(cache, exitMempool)
// Start listening // Start listening
listener, err := net.Listen("tcp", opts.GRPCBindAddr) listener, err := net.Listen("tcp", opts.GRPCBindAddr)
if err != nil { if err != nil {
@ -309,7 +310,6 @@ func startServer(opts *common.Options) error {
"signal": s.String(), "signal": s.String(),
}).Info("caught signal, stopping gRPC server") }).Info("caught signal, stopping gRPC server")
exitMempool <- true
os.Exit(1) os.Exit(1)
}() }()
@ -350,6 +350,7 @@ func init() {
rootCmd.Flags().Bool("no-tls-very-insecure", false, "run without the required TLS certificate, only for debugging, DO NOT use in production") rootCmd.Flags().Bool("no-tls-very-insecure", false, "run without the required TLS certificate, only for debugging, DO NOT use in production")
rootCmd.Flags().Bool("gen-cert-very-insecure", false, "run with self-signed TLS certificate, only for debugging, DO NOT use in production") rootCmd.Flags().Bool("gen-cert-very-insecure", false, "run with self-signed TLS certificate, only for debugging, DO NOT use in production")
rootCmd.Flags().Bool("redownload", false, "re-fetch all blocks from zcashd; reinitialize local cache files") rootCmd.Flags().Bool("redownload", false, "re-fetch all blocks from zcashd; reinitialize local cache files")
rootCmd.Flags().Int("sync-from-height", -1, "re-fetch blocks from zcashd start at this height")
rootCmd.Flags().String("data-dir", "/var/lib/lightwalletd", "data directory (such as db)") rootCmd.Flags().String("data-dir", "/var/lib/lightwalletd", "data directory (such as db)")
rootCmd.Flags().Bool("ping-very-insecure", false, "allow Ping GRPC for testing") rootCmd.Flags().Bool("ping-very-insecure", false, "allow Ping GRPC for testing")
rootCmd.Flags().Bool("darkside-very-insecure", false, "run with GRPC-controllable mock zcashd for integration testing (shuts down after 30 minutes)") rootCmd.Flags().Bool("darkside-very-insecure", false, "run with GRPC-controllable mock zcashd for integration testing (shuts down after 30 minutes)")
@ -381,6 +382,8 @@ func init() {
viper.SetDefault("gen-cert-very-insecure", false) viper.SetDefault("gen-cert-very-insecure", false)
viper.BindPFlag("redownload", rootCmd.Flags().Lookup("redownload")) viper.BindPFlag("redownload", rootCmd.Flags().Lookup("redownload"))
viper.SetDefault("redownload", false) viper.SetDefault("redownload", false)
viper.BindPFlag("sync-from-height", rootCmd.Flags().Lookup("sync-from-height"))
viper.SetDefault("sync-from-height", -1)
viper.BindPFlag("data-dir", rootCmd.Flags().Lookup("data-dir")) viper.BindPFlag("data-dir", rootCmd.Flags().Lookup("data-dir"))
viper.SetDefault("data-dir", "/var/lib/lightwalletd") viper.SetDefault("data-dir", "/var/lib/lightwalletd")
viper.BindPFlag("ping-very-insecure", rootCmd.Flags().Lookup("ping-very-insecure")) viper.BindPFlag("ping-very-insecure", rootCmd.Flags().Lookup("ping-very-insecure"))
@ -409,8 +412,9 @@ func init() {
logrus.RegisterExitHandler(onexit) logrus.RegisterExitHandler(onexit)
// Indirect function for test mocking (so unit tests can talk to stub functions) // Indirect functions for test mocking (so unit tests can talk to stub functions)
common.Sleep = time.Sleep common.Time.Sleep = time.Sleep
common.Time.Now = time.Now
} }
// initConfig reads in config file and ENV variables if set. // initConfig reads in config file and ENV variables if set.
@ -421,7 +425,7 @@ func initConfig() {
} else { } else {
// Look in the current directory for a configuration file // Look in the current directory for a configuration file
viper.AddConfigPath(".") viper.AddConfigPath(".")
// Viper auto appends extention to this config name // Viper auto appends extension to this config name
// For example, lightwalletd.yml // For example, lightwalletd.yml
viper.SetConfigName("lightwalletd") viper.SetConfigName("lightwalletd")
} }

View File

@ -51,12 +51,12 @@ func (c *BlockCache) GetLatestHash() []byte {
return c.latestHash return c.latestHash
} }
// HashMismatch indicates if the given prev-hash doesn't match the most recent block's hash // HashMatch indicates if the given prev-hash matches the most recent block's hash
// so reorgs can be detected. // so reorgs can be detected.
func (c *BlockCache) HashMismatch(prevhash []byte) bool { func (c *BlockCache) HashMatch(prevhash []byte) bool {
c.mutex.RLock() c.mutex.RLock()
defer c.mutex.RUnlock() defer c.mutex.RUnlock()
return c.latestHash != nil && !bytes.Equal(c.latestHash, prevhash) return c.latestHash == nil || bytes.Equal(c.latestHash, prevhash)
} }
// Make the block at the given height the lowest height that we don't have. // Make the block at the given height the lowest height that we don't have.
@ -191,7 +191,8 @@ func (c *BlockCache) Reset(startHeight int) {
// NewBlockCache returns an instance of a block cache object. // NewBlockCache returns an instance of a block cache object.
// (No locking here, we assume this is single-threaded.) // (No locking here, we assume this is single-threaded.)
func NewBlockCache(dbPath string, chainName string, startHeight int, redownload bool) *BlockCache { // syncFromHeight < 0 means latest (tip) height.
func NewBlockCache(dbPath string, chainName string, startHeight int, syncFromHeight int) *BlockCache {
c := &BlockCache{} c := &BlockCache{}
c.firstBlock = startHeight c.firstBlock = startHeight
c.nextBlock = startHeight c.nextBlock = startHeight
@ -208,18 +209,20 @@ func NewBlockCache(dbPath string, chainName string, startHeight int, redownload
if err != nil { if err != nil {
Log.Fatal("open ", c.lengthsName, " failed: ", err) Log.Fatal("open ", c.lengthsName, " failed: ", err)
} }
if redownload {
if err := c.lengthsFile.Truncate(0); err != nil {
Log.Fatal("truncate lengths file failed: ", err)
}
if err := c.blocksFile.Truncate(0); err != nil {
Log.Fatal("truncate blocks file failed: ", err)
}
}
lengths, err := ioutil.ReadFile(c.lengthsName) lengths, err := ioutil.ReadFile(c.lengthsName)
if err != nil { if err != nil {
Log.Fatal("read ", c.lengthsName, " failed: ", err) Log.Fatal("read ", c.lengthsName, " failed: ", err)
} }
// 4 bytes per lengths[] value (block length)
if syncFromHeight >= 0 {
if syncFromHeight < startHeight {
syncFromHeight = startHeight
}
if (syncFromHeight-startHeight)*4 < len(lengths) {
// discard the entries at and beyond (newer than) the specified height
lengths = lengths[:(syncFromHeight-startHeight)*4]
}
}
// The last entry in starts[] is where to write the next block. // The last entry in starts[] is where to write the next block.
var offset int64 var offset int64

View File

@ -58,7 +58,7 @@ func TestCache(t *testing.T) {
// Pretend Sapling starts at 289460. // Pretend Sapling starts at 289460.
os.RemoveAll(unitTestPath) os.RemoveAll(unitTestPath)
cache = NewBlockCache(unitTestPath, unitTestChain, 289460, true) cache = NewBlockCache(unitTestPath, unitTestChain, 289460, 0)
// Initially cache is empty. // Initially cache is empty.
if cache.GetLatestHeight() != -1 { if cache.GetLatestHeight() != -1 {
@ -75,7 +75,7 @@ func TestCache(t *testing.T) {
fillCache(t) fillCache(t)
// Simulate a restart to ensure the db files are read correctly. // Simulate a restart to ensure the db files are read correctly.
cache = NewBlockCache(unitTestPath, unitTestChain, 289460, false) cache = NewBlockCache(unitTestPath, unitTestChain, 289460, -1)
// Should still be 6 blocks. // Should still be 6 blocks.
if cache.nextBlock != 289466 { if cache.nextBlock != 289466 {

View File

@ -42,6 +42,7 @@ type Options struct {
NoTLSVeryInsecure bool `json:"no_tls_very_insecure,omitempty"` NoTLSVeryInsecure bool `json:"no_tls_very_insecure,omitempty"`
GenCertVeryInsecure bool `json:"gen_cert_very_insecure,omitempty"` GenCertVeryInsecure bool `json:"gen_cert_very_insecure,omitempty"`
Redownload bool `json:"redownload"` Redownload bool `json:"redownload"`
SyncFromHeight int `json:"sync_from_height"`
DataDir string `json:"data_dir"` DataDir string `json:"data_dir"`
PingEnable bool `json:"ping_enable"` PingEnable bool `json:"ping_enable"`
Darkside bool `json:"darkside"` Darkside bool `json:"darkside"`
@ -53,10 +54,16 @@ type Options struct {
// in unit tests it points to a function to mock RPCs to zcashd. // in unit tests it points to a function to mock RPCs to zcashd.
var RawRequest func(method string, params []json.RawMessage) (json.RawMessage, error) var RawRequest func(method string, params []json.RawMessage) (json.RawMessage, error)
// Sleep allows a request to time.Sleep() to be mocked for testing; // Time allows time-related functions to be mocked for testing,
// in production, it points to the standard library time.Sleep(); // so that tests can be deterministic and so they don't require
// in unit tests it points to a mock function. // real time to elapse. In production, these point to the standard
var Sleep func(d time.Duration) // library `time` functions; in unit tests they point to mock
// functions (set by the specific test as required).
// More functions can be added later.
var Time struct {
Sleep func(d time.Duration)
Now func() time.Time
}
// Log as a global variable simplifies logging // Log as a global variable simplifies logging
var Log *logrus.Entry var Log *logrus.Entry
@ -109,9 +116,16 @@ type (
} }
SkipHash string SkipHash string
} }
Orchard struct {
Commitments struct {
FinalState string
}
SkipHash string
}
} }
// zcashd rpc "getrawtransaction" // zcashd rpc "getrawtransaction txid 1" (1 means verbose), there are
// many more fields but these are the only ones we current need.
ZcashdRpcReplyGetrawtransaction struct { ZcashdRpcReplyGetrawtransaction struct {
Hex string Hex string
Height int Height int
@ -129,7 +143,7 @@ type (
ZcashdRpcRequestGetaddressutxos struct { ZcashdRpcRequestGetaddressutxos struct {
Addresses []string `json:"addresses"` Addresses []string `json:"addresses"`
} }
ZcashdRpcReplyGetaddressutxos []struct { ZcashdRpcReplyGetaddressutxos struct {
Address string Address string
Txid string Txid string
OutputIndex int64 OutputIndex int64
@ -137,6 +151,11 @@ type (
Satoshis uint64 Satoshis uint64
Height int Height int
} }
// reply to getblock verbose=1 (json includes txid list)
ZcashRpcReplyGetblock1 struct {
Tx []string
}
) )
// FirstRPC tests that we can successfully reach zcashd through the RPC // FirstRPC tests that we can successfully reach zcashd through the RPC
@ -166,7 +185,7 @@ func FirstRPC() {
"error": rpcErr.Error(), "error": rpcErr.Error(),
"retry": retryCount, "retry": retryCount,
}).Warn("error with getblockchaininfo rpc, retrying...") }).Warn("error with getblockchaininfo rpc, retrying...")
Sleep(time.Duration(10+retryCount*5) * time.Second) // backoff Time.Sleep(time.Duration(10+retryCount*5) * time.Second) // backoff
} }
} }
@ -240,7 +259,7 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) {
params := make([]json.RawMessage, 2) params := make([]json.RawMessage, 2)
heightJSON, err := json.Marshal(strconv.Itoa(height)) heightJSON, err := json.Marshal(strconv.Itoa(height))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error marshaling height") Log.Fatal("getBlockFromRPC bad height argument", height, err)
} }
params[0] = heightJSON params[0] = heightJSON
params[1] = json.RawMessage("0") // non-verbose (raw hex) params[1] = json.RawMessage("0") // non-verbose (raw hex)
@ -279,6 +298,31 @@ func getBlockFromRPC(height int) (*walletrpc.CompactBlock, error) {
return nil, errors.New("received unexpected height block") return nil, errors.New("received unexpected height block")
} }
// `block.ParseFromSlice` correctly parses blocks containing v5 transactions, but
// incorrectly computes the IDs of the v5 transactions. We temporarily paper over this
// bug by fetching the correct txids via a second getblock RPC call.
// https://github.com/zcash/lightwalletd/issues/392
{
params[1] = json.RawMessage("1") // JSON with list of txids
result, rpcErr := RawRequest("getblock", params)
if rpcErr != nil {
return nil, errors.Wrap(rpcErr, "error requesting verbose block")
}
var block1 ZcashRpcReplyGetblock1
err = json.Unmarshal(result, &block1)
if err != nil {
return nil, err
}
for i, t := range block.Transactions() {
txid, err := hex.DecodeString(block1.Tx[i])
if err != nil {
return nil, errors.Wrap(err, "error decoding getblock txid")
}
// convert from big-endian
t.SetTxID(parser.Reverse(txid))
}
}
return block.ToCompact(), nil return block.ToCompact(), nil
} }
@ -303,11 +347,8 @@ func stopIngestor() {
// BlockIngestor runs as a goroutine and polls zcashd for new blocks, adding them // BlockIngestor runs as a goroutine and polls zcashd for new blocks, adding them
// to the cache. The repetition count, rep, is nonzero only for unit-testing. // to the cache. The repetition count, rep, is nonzero only for unit-testing.
func BlockIngestor(c *BlockCache, rep int) { func BlockIngestor(c *BlockCache, rep int) {
lastLog := time.Now() lastLog := Time.Now()
reorgCount := 0
lastHeightLogged := 0 lastHeightLogged := 0
retryCount := 0
wait := true
// Start listening for new blocks // Start listening for new blocks
for i := 0; rep == 0 || i < rep; i++ { for i := 0; rep == 0 || i < rep; i++ {
@ -318,110 +359,60 @@ func BlockIngestor(c *BlockCache, rep int) {
default: default:
} }
height := c.GetNextHeight() result, err := RawRequest("getbestblockhash", []json.RawMessage{})
block, err := getBlockFromRPC(height)
if err != nil { if err != nil {
Log.WithFields(logrus.Fields{ Log.WithFields(logrus.Fields{
"height": height, "error": err,
"error": err, }).Fatal("error zcashd getbestblockhash rpc")
}).Warn("error zcashd getblock rpc") }
retryCount++ var hashHex string
if retryCount > 10 { err = json.Unmarshal(result, &hashHex)
Log.WithFields(logrus.Fields{ if err != nil {
"timeouts": retryCount, Log.Fatal("bad getbestblockhash return:", err, result)
}).Fatal("unable to issue RPC call to zcashd node") }
} lastBestBlockHash := []byte{}
// Delay then retry the same height. lastBestBlockHash, err = hex.DecodeString(hashHex)
if err != nil {
Log.Fatal("error decoding getbestblockhash", err, hashHex)
}
height := c.GetNextHeight()
if string(lastBestBlockHash) == string(parser.Reverse(c.GetLatestHash())) {
// Synced
c.Sync() c.Sync()
Sleep(10 * time.Second) if lastHeightLogged != height-1 {
wait = true lastHeightLogged = height - 1
Log.Info("Waiting for block: ", height)
}
Time.Sleep(2 * time.Second)
lastLog = Time.Now()
continue continue
} }
retryCount = 0 var block *walletrpc.CompactBlock
if block == nil { block, err = getBlockFromRPC(height)
// No block at this height. if err != nil {
if height == c.GetFirstHeight() { Log.Fatal("getblock failed, will retry", err)
Log.Info("Waiting for zcashd height to reach Sapling activation height ",
"(", c.GetFirstHeight(), ")...")
reorgCount = 0
Sleep(20 * time.Second)
continue
}
// Check the current top block to see if there's a hash mismatch (i.e., a 1-block reorg)
curhash, err := getBestBlockHash()
if err != nil {
Log.WithFields(logrus.Fields{
"height": height,
"error": err,
}).Warn("error zcashd getblock rpc")
continue
}
if c.HashMismatch(curhash) {
// Current block has a hash mismatch
Log.WithFields(logrus.Fields{
"height": height - 1,
"hash": displayHash(curhash),
"phash": displayHash(c.GetLatestHash()),
"reorg": reorgCount,
}).Warn("REORG/Current Block")
c.Reorg(height - 1)
continue
}
if wait {
// Wait a bit then retry the same height.
c.Sync()
if lastHeightLogged+1 != height {
Log.Info("Ingestor waiting for block: ", height)
lastHeightLogged = height - 1
}
Sleep(2 * time.Second)
wait = false
continue
}
} }
if block == nil || c.HashMismatch(block.PrevHash) { if block != nil && c.HashMatch(block.PrevHash) {
// This may not be a reorg; it may be we're at the tip if err = c.Add(height, block); err != nil {
// and there's no new block yet, but we want to back up Log.Fatal("Cache add failed:", err)
// so we detect a reorg in which the new chain is the
// same length or shorter.
reorgCount++
if reorgCount > 100 {
Log.Fatal("Reorg exceeded max of 100 blocks! Help!")
} }
// Print the hash of the block that is getting reorg-ed away // Don't log these too often.
// as 'phash', not the prevhash of the block we just received. if DarksideEnabled || Time.Now().Sub(lastLog).Seconds() >= 4 {
if block != nil { lastLog = Time.Now()
Log.WithFields(logrus.Fields{ Log.Info("Adding block to cache ", height, " ", displayHash(block.Hash))
"height": height,
"hash": displayHash(block.Hash),
"phash": displayHash(c.GetLatestHash()),
"reorg": reorgCount,
}).Warn("REORG")
} else if reorgCount > 1 {
Log.WithFields(logrus.Fields{
"height": height,
"phash": displayHash(c.GetLatestHash()),
"reorg": reorgCount,
}).Warn("REORG")
} }
// Try backing up
c.Reorg(height - 1)
continue continue
} }
// We have a valid block to add. if height == c.GetFirstHeight() {
wait = true c.Sync()
reorgCount = 0 Log.Info("Waiting for zcashd height to reach Sapling activation height ",
if err := c.Add(height, block); err != nil { "(", c.GetFirstHeight(), ")...")
Log.Fatal("Cache add failed:", err) Time.Sleep(20 * time.Second)
} return
// Don't log these too often.
if time.Since(lastLog).Seconds() >= 4 && c.GetNextHeight() == height+1 && height != lastHeightLogged {
lastLog = time.Now()
lastHeightLogged = height
Log.Info("Ingestor adding block to cache: ", height)
} }
Log.Info("REORG: dropping block ", height-1, " ", displayHash(c.GetLatestHash()))
c.Reorg(height - 1)
} }
} }

View File

@ -5,6 +5,7 @@ package common
import ( import (
"bufio" "bufio"
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -33,6 +34,8 @@ var (
logger = logrus.New() logger = logrus.New()
blocks [][]byte // four test blocks blocks [][]byte // four test blocks
testcache *BlockCache
) )
// TestMain does common setup that's shared across multiple tests // TestMain does common setup that's shared across multiple tests
@ -59,6 +62,7 @@ func TestMain(m *testing.M) {
blockJSON, _ := json.Marshal(scan.Text()) blockJSON, _ := json.Marshal(scan.Text())
blocks = append(blocks, blockJSON) blocks = append(blocks, blockJSON)
} }
testcache = NewBlockCache(unitTestPath, unitTestChain, 380640, 0)
// Setup is done; run all tests. // Setup is done; run all tests.
exitcode := m.Run() exitcode := m.Run()
@ -77,6 +81,10 @@ func sleepStub(d time.Duration) {
sleepCount++ sleepCount++
sleepDuration += d sleepDuration += d
} }
func nowStub() time.Time {
start := time.Time{}
return start.Add(sleepDuration)
}
// ------------------------------------------ GetLightdInfo() // ------------------------------------------ GetLightdInfo()
@ -110,7 +118,7 @@ func getLightdInfoStub(method string, params []json.RawMessage) (json.RawMessage
func TestGetLightdInfo(t *testing.T) { func TestGetLightdInfo(t *testing.T) {
testT = t testT = t
RawRequest = getLightdInfoStub RawRequest = getLightdInfoStub
Sleep = sleepStub Time.Sleep = sleepStub
// This calls the getblockchaininfo rpc just to establish connectivity with zcashd // This calls the getblockchaininfo rpc just to establish connectivity with zcashd
FirstRPC() FirstRPC()
@ -155,8 +163,217 @@ func TestGetLightdInfo(t *testing.T) {
// ------------------------------------------ BlockIngestor() // ------------------------------------------ BlockIngestor()
func checkSleepMethod(count int, duration time.Duration, expected string, method string) {
if sleepCount != count {
testT.Fatal("unexpected sleep count")
}
if sleepDuration != duration*time.Second {
testT.Fatal("unexpected sleep duration")
}
if method != expected {
testT.Error("unexpected method")
}
}
// There are four test blocks, 0..3 // There are four test blocks, 0..3
func blockIngestorStub(method string, params []json.RawMessage) (json.RawMessage, error) {
step++
// request the first two blocks very quickly (syncing),
// then next block isn't yet available
switch step {
case 1:
checkSleepMethod(0, 0, "getbestblockhash", method)
// This hash doesn't matter, won't match anything
r, _ := json.Marshal("010101")
return r, nil
case 2:
checkSleepMethod(0, 0, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380640" {
testT.Fatal("incorrect height requested")
}
// height 380640
return blocks[0], nil
case 3:
checkSleepMethod(0, 0, "getbestblockhash", method)
// This hash doesn't matter, won't match anything
r, _ := json.Marshal("010101")
return r, nil
case 4:
checkSleepMethod(0, 0, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380641" {
testT.Fatal("incorrect height requested")
}
// height 380641
return blocks[1], nil
case 5:
// Return the expected block hash, so we're synced, should
// then sleep for 2 seconds, then another getbestblockhash
checkSleepMethod(0, 0, "getbestblockhash", method)
r, _ := json.Marshal(displayHash(testcache.GetLatestHash()))
return r, nil
case 6:
// Simulate still no new block, still synced, should
// sleep for 2 seconds, then another getbestblockhash
checkSleepMethod(1, 2, "getbestblockhash", method)
r, _ := json.Marshal(displayHash(testcache.GetLatestHash()))
return r, nil
case 7:
// Simulate new block (any non-matching hash will do)
checkSleepMethod(2, 4, "getbestblockhash", method)
r, _ := json.Marshal("aabb")
return r, nil
case 8:
checkSleepMethod(2, 4, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380642" {
testT.Fatal("incorrect height requested")
}
// height 380642
return blocks[2], nil
case 9:
// Simulate still no new block, still synced, should
// sleep for 2 seconds, then another getbestblockhash
checkSleepMethod(2, 4, "getbestblockhash", method)
r, _ := json.Marshal(displayHash(testcache.GetLatestHash()))
return r, nil
case 10:
// There are 3 blocks in the cache (380640-642), so let's
// simulate a 1-block reorg, new version (replacement) of 380642
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("4545")
return r, nil
case 11:
// It thinks there may simply be a new block, but we'll say
// there is no block at this height (380642 was replaced).
checkSleepMethod(3, 6, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380643" {
testT.Fatal("incorrect height requested")
}
return nil, errors.New("-8: Block height out of range")
case 12:
// It will re-ask the best hash (let's make no change)
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("4545")
return r, nil
case 13:
// It should have backed up one block
checkSleepMethod(3, 6, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380642" {
testT.Fatal("incorrect height requested")
}
// height 380642
return blocks[2], nil
case 14:
// We're back to the same state as case 9, and this time
// we'll make it back up 2 blocks (rather than one)
checkSleepMethod(3, 6, "getbestblockhash", method) // XXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXX
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("5656")
return r, nil
case 15:
// It thinks there may simply be a new block, but we'll say
// there is no block at this height (380642 was replaced).
checkSleepMethod(3, 6, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380643" {
testT.Fatal("incorrect height requested")
}
return nil, errors.New("-8: Block height out of range")
case 16:
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("5656")
return r, nil
case 17:
// Like case 13, it should have backed up one block, but
// this time we'll make it back up one more
checkSleepMethod(3, 6, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380642" {
testT.Fatal("incorrect height requested")
}
return nil, errors.New("-8: Block height out of range")
case 18:
checkSleepMethod(3, 6, "getbestblockhash", method)
// hash doesn't matter, just something that doesn't match
r, _ := json.Marshal("5656")
return r, nil
case 19:
// It should have backed up one more
checkSleepMethod(3, 6, "getblock", method)
var height string
err := json.Unmarshal(params[0], &height)
if err != nil {
testT.Fatal("could not unmarshal height")
}
if height != "380641" {
testT.Fatal("incorrect height requested")
}
return blocks[1], nil
}
testT.Error("blockIngestorStub called too many times")
return nil, nil
}
func TestBlockIngestor(t *testing.T) {
testT = t
RawRequest = blockIngestorStub
Time.Sleep = sleepStub
Time.Now = nowStub
os.RemoveAll(unitTestPath)
testcache = NewBlockCache(unitTestPath, unitTestChain, 380640, -1)
BlockIngestor(testcache, 11)
if step != 19 {
t.Error("unexpected final step", step)
}
step = 0
sleepCount = 0
sleepDuration = 0
os.RemoveAll(unitTestPath)
}
// ------------------------------------------ GetBlockRange()
// There are four test blocks, 0..3
// (probably don't need all these cases)
func getblockStub(method string, params []json.RawMessage) (json.RawMessage, error) { func getblockStub(method string, params []json.RawMessage) (json.RawMessage, error) {
if method != "getblock" {
testT.Error("unexpected method")
}
var height string var height string
err := json.Unmarshal(params[0], &height) err := json.Unmarshal(params[0], &height)
if err != nil { if err != nil {
@ -267,27 +484,11 @@ func getblockStub(method string, params []json.RawMessage) (json.RawMessage, err
return nil, nil return nil, nil
} }
func TestBlockIngestor(t *testing.T) {
testT = t
RawRequest = getblockStub
Sleep = sleepStub
os.RemoveAll(unitTestPath)
testcache := NewBlockCache(unitTestPath, unitTestChain, 380640, false)
BlockIngestor(testcache, 11)
if step != 11 {
t.Error("unexpected final step", step)
}
step = 0
sleepCount = 0
sleepDuration = 0
os.RemoveAll(unitTestPath)
}
func TestGetBlockRange(t *testing.T) { func TestGetBlockRange(t *testing.T) {
testT = t testT = t
RawRequest = getblockStub RawRequest = getblockStub
os.RemoveAll(unitTestPath) os.RemoveAll(unitTestPath)
testcache := NewBlockCache(unitTestPath, unitTestChain, 380640, true) testcache = NewBlockCache(unitTestPath, unitTestChain, 380640, 0)
blockChan := make(chan *walletrpc.CompactBlock) blockChan := make(chan *walletrpc.CompactBlock)
errChan := make(chan error) errChan := make(chan error)
go GetBlockRange(testcache, blockChan, errChan, 380640, 380642) go GetBlockRange(testcache, blockChan, errChan, 380640, 380642)
@ -366,7 +567,7 @@ func TestGetBlockRangeReverse(t *testing.T) {
testT = t testT = t
RawRequest = getblockStubReverse RawRequest = getblockStubReverse
os.RemoveAll(unitTestPath) os.RemoveAll(unitTestPath)
testcache := NewBlockCache(unitTestPath, unitTestChain, 380640, true) testcache = NewBlockCache(unitTestPath, unitTestChain, 380640, 0)
blockChan := make(chan *walletrpc.CompactBlock) blockChan := make(chan *walletrpc.CompactBlock)
errChan := make(chan error) errChan := make(chan error)
@ -414,3 +615,158 @@ func TestGenerateCerts(t *testing.T) {
t.Fatal("GenerateCerts returned nil") t.Fatal("GenerateCerts returned nil")
} }
} }
// ------------------------------------------ GetMempoolStream
// Note that in mocking zcashd's RPC replies here, we don't really need
// actual txids or transactions, or even strings with the correct format
// for those, except that a transaction must be a hex string.
func mempoolStub(method string, params []json.RawMessage) (json.RawMessage, error) {
step++
switch step {
case 1:
// This will be a getblockchaininfo request
if method != "getblockchaininfo" {
testT.Fatal("expecting blockchaininfo")
}
r, _ := json.Marshal(&ZcashdRpcReplyGetblockchaininfo{
BestBlockHash: "010203",
Blocks: 200,
})
return r, nil
case 2:
// No new block has arrived.
if method != "getblockchaininfo" {
testT.Fatal("expecting blockchaininfo")
}
r, _ := json.Marshal(&ZcashdRpcReplyGetblockchaininfo{
BestBlockHash: "010203",
Blocks: 200,
})
return r, nil
case 3:
// Expect a getrawmempool next.
if method != "getrawmempool" {
testT.Fatal("expecting getrawmempool")
}
// In reality, this would be a hex txid
r, _ := json.Marshal([]string{
"mempooltxid-1",
})
return r, nil
case 4:
// Next, it should ask for this transaction (non-verbose).
if method != "getrawtransaction" {
testT.Fatal("expecting getrawtransaction")
}
var txid string
json.Unmarshal(params[0], &txid)
if txid != "mempooltxid-1" {
testT.Fatal("unexpected txid")
}
r, _ := json.Marshal("aabb")
return r, nil
case 5:
// Simulate that still no new block has arrived ...
if method != "getblockchaininfo" {
testT.Fatal("expecting blockchaininfo")
}
r, _ := json.Marshal(&ZcashdRpcReplyGetblockchaininfo{
BestBlockHash: "010203",
Blocks: 200,
})
return r, nil
case 6:
// ... but there a second tx has arrived in the mempool
if method != "getrawmempool" {
testT.Fatal("expecting getrawmempool")
}
// In reality, this would be a hex txid
r, _ := json.Marshal([]string{
"mempooltxid-2",
"mempooltxid-1"})
return r, nil
case 7:
// The new mempool tx (and only that one) gets fetched
if method != "getrawtransaction" {
testT.Fatal("expecting getrawtransaction")
}
var txid string
json.Unmarshal(params[0], &txid)
if txid != "mempooltxid-2" {
testT.Fatal("unexpected txid")
}
r, _ := json.Marshal("ccdd")
return r, nil
case 8:
// A new block arrives, this will cause these two tx to be returned
if method != "getblockchaininfo" {
testT.Fatal("expecting blockchaininfo")
}
r, _ := json.Marshal(&ZcashdRpcReplyGetblockchaininfo{
BestBlockHash: "d1d2d3",
Blocks: 201,
})
return r, nil
}
testT.Fatal("ran out of cases")
return nil, nil
}
func TestMempoolStream(t *testing.T) {
testT = t
RawRequest = mempoolStub
Time.Sleep = sleepStub
Time.Now = nowStub
// In real life, wall time is not close to zero, simulate that.
sleepDuration = 1000 * time.Second
var replies []*walletrpc.RawTransaction
// The first request after startup immediately returns an empty list.
err := GetMempool(func(tx *walletrpc.RawTransaction) error {
t.Fatal("send to client function called on initial GetMempool call")
return nil
})
if err != nil {
t.Fatal("GetMempool failed")
}
// This should return two transactions.
err = GetMempool(func(tx *walletrpc.RawTransaction) error {
replies = append(replies, tx)
return nil
})
if err != nil {
t.Fatal("GetMempool failed")
}
if len(replies) != 2 {
t.Fatal("unexpected number of tx")
}
// The interface guarantees that the transactions will be returned
// in the order they entered the mempool.
if !bytes.Equal([]byte(replies[0].GetData()), []byte{0xaa, 0xbb}) {
t.Fatal("unexpected tx contents")
}
if replies[0].GetHeight() != 200 {
t.Fatal("unexpected tx height")
}
if !bytes.Equal([]byte(replies[1].GetData()), []byte{0xcc, 0xdd}) {
t.Fatal("unexpected tx contents")
}
if replies[1].GetHeight() != 200 {
t.Fatal("unexpected tx height")
}
// Time started at 1000 seconds (since 1970), and just over 4 seconds
// should have elapsed. The units here are nanoseconds.
if sleepDuration != 1004400000000 {
t.Fatal("unexpected end time")
}
if step != 8 {
t.Fatal("unexpected number of zcashd RPCs")
}
step = 0
sleepCount = 0
sleepDuration = 0
}

View File

@ -46,6 +46,9 @@ type darksideState struct {
// These transactions come from StageTransactions(); they will be merged into // These transactions come from StageTransactions(); they will be merged into
// activeBlocks by ApplyStaged() (and this list then cleared). // activeBlocks by ApplyStaged() (and this list then cleared).
stagedTransactions []stagedTx stagedTransactions []stagedTx
// Unordered list of replies
getAddressUtxos []ZcashdRpcReplyGetaddressutxos
} }
var state darksideState var state darksideState
@ -74,7 +77,7 @@ func DarksideInit(c *BlockCache, timeout int) {
// DarksideReset allows the wallet test code to specify values // DarksideReset allows the wallet test code to specify values
// that are returned by GetLightdInfo(). // that are returned by GetLightdInfo().
func DarksideReset(sa int, bi, cn string) error { func DarksideReset(sa int, bi, cn string) error {
Log.Info("Reset(saplingActivation=", sa, ")") Log.Info("DarksideReset(saplingActivation=", sa, ")")
stopIngestor() stopIngestor()
state = darksideState{ state = darksideState{
resetted: true, resetted: true,
@ -135,7 +138,7 @@ func setPrevhash() {
copy(blockBytes[4:4+32], prevhash) copy(blockBytes[4:4+32], prevhash)
} }
prevhash = block.GetEncodableHash() prevhash = block.GetEncodableHash()
Log.Info("active block height ", block.GetHeight(), " hash ", Log.Info("Darkside active block height ", block.GetHeight(), " hash ",
hex.EncodeToString(block.GetDisplayHash()), hex.EncodeToString(block.GetDisplayHash()),
" txcount ", block.GetTxCount()) " txcount ", block.GetTxCount())
} }
@ -150,7 +153,7 @@ func DarksideApplyStaged(height int) error {
if !state.resetted { if !state.resetted {
return errors.New("please call Reset first") return errors.New("please call Reset first")
} }
Log.Info("ApplyStaged(height=", height, ")") Log.Info("DarksideApplyStaged(height=", height, ")")
if height < state.startHeight { if height < state.startHeight {
return errors.New(fmt.Sprint("height ", height, return errors.New(fmt.Sprint("height ", height,
" is less than sapling activation height ", state.startHeight)) " is less than sapling activation height ", state.startHeight))
@ -209,9 +212,13 @@ func DarksideApplyStaged(height int) error {
block = append(block, tx.bytes...) block = append(block, tx.bytes...)
state.activeBlocks[tx.height-state.startHeight] = block state.activeBlocks[tx.height-state.startHeight] = block
} }
maxHeight := state.startHeight + len(state.activeBlocks) - 1
if height > maxHeight {
height = maxHeight
}
setPrevhash() setPrevhash()
state.latestHeight = height state.latestHeight = height
Log.Info("active blocks from ", state.startHeight, Log.Info("darkside: active blocks from ", state.startHeight,
" to ", state.startHeight+len(state.activeBlocks)-1, " to ", state.startHeight+len(state.activeBlocks)-1,
", latest presented height ", state.latestHeight) ", latest presented height ", state.latestHeight)
@ -241,7 +248,7 @@ func darksideStageBlock(caller string, b []byte) error {
if len(rest) != 0 { if len(rest) != 0 {
return errors.New("block serialization is too long") return errors.New("block serialization is too long")
} }
Log.Info(caller, "(height=", block.GetHeight(), ")") Log.Info(caller, "DarksideStageBlock(height=", block.GetHeight(), ")")
if block.GetHeight() < state.startHeight { if block.GetHeight() < state.startHeight {
return errors.New(fmt.Sprint("block height ", block.GetHeight(), return errors.New(fmt.Sprint("block height ", block.GetHeight(),
" is less than sapling activation height ", state.startHeight)) " is less than sapling activation height ", state.startHeight))
@ -256,7 +263,7 @@ func DarksideStageBlocks(url string) error {
if !state.resetted { if !state.resetted {
return errors.New("please call Reset first") return errors.New("please call Reset first")
} }
Log.Info("StageBlocks(url=", url, ")") Log.Info("DarksideStageBlocks(url=", url, ")")
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return err return err
@ -289,7 +296,7 @@ func DarksideStageBlockStream(blockHex string) error {
if !state.resetted { if !state.resetted {
return errors.New("please call Reset first") return errors.New("please call Reset first")
} }
Log.Info("StageBlocksStream()") Log.Info("DarksideStageBlocksStream()")
blockBytes, err := hex.DecodeString(blockHex) blockBytes, err := hex.DecodeString(blockHex)
if err != nil { if err != nil {
return err return err
@ -305,7 +312,7 @@ func DarksideStageBlocksCreate(height int32, nonce int32, count int32) error {
if !state.resetted { if !state.resetted {
return errors.New("please call Reset first") return errors.New("please call Reset first")
} }
Log.Info("StageBlocksCreate(height=", height, ", nonce=", nonce, ", count=", count, ")") Log.Info("DarksideStageBlocksCreate(height=", height, ", nonce=", nonce, ", count=", count, ")")
for i := 0; i < int(count); i++ { for i := 0; i < int(count); i++ {
fakeCoinbase := "0400008085202f890100000000000000000000000000000000000000000000000000" + fakeCoinbase := "0400008085202f890100000000000000000000000000000000000000000000000000" +
@ -410,6 +417,18 @@ func darksideRawRequest(method string, params []json.RawMessage) (json.RawMessag
} }
return json.Marshal(hex.EncodeToString(state.activeBlocks[index])) return json.Marshal(hex.EncodeToString(state.activeBlocks[index]))
case "getbestblockhash":
state.mutex.RLock()
defer state.mutex.RUnlock()
if len(state.activeBlocks) == 0 {
Log.Fatal("getbestblockhash: no blocks")
}
index := state.latestHeight - state.startHeight
block := parser.NewBlock()
block.ParseFromSlice(state.activeBlocks[index])
hash := hex.EncodeToString(block.GetDisplayHash())
return json.Marshal(hash)
case "getaddresstxids": case "getaddresstxids":
// Not required for minimal reorg testing. // Not required for minimal reorg testing.
return nil, errors.New("not implemented yet") return nil, errors.New("not implemented yet")
@ -459,6 +478,23 @@ func darksideRawRequest(method string, params []json.RawMessage) (json.RawMessag
} }
return json.Marshal(reply) return json.Marshal(reply)
case "getaddressutxos":
var req ZcashdRpcRequestGetaddressutxos
err := json.Unmarshal(params[0], &req)
if err != nil {
return nil, errors.New("failed to parse getaddressutxos JSON")
}
utxosReply := make([]ZcashdRpcReplyGetaddressutxos, 0)
for _, utxo := range state.getAddressUtxos {
for _, a := range req.Addresses {
if a == utxo.Address {
utxosReply = append(utxosReply, utxo)
break
}
}
}
return json.Marshal(utxosReply)
default: default:
return nil, errors.New("there was an attempt to call an unsupported RPC") return nil, errors.New("there was an attempt to call an unsupported RPC")
} }
@ -557,7 +593,7 @@ func DarksideStageTransactionsURL(height int, url string) error {
if !state.resetted { if !state.resetted {
return errors.New("please call Reset first") return errors.New("please call Reset first")
} }
Log.Info("StageTransactionsURL(height=", height, ", url=", url, ")") Log.Info("DarksideStageTransactionsURL(height=", height, ", url=", url, ")")
resp, err := http.Get(url) resp, err := http.Get(url)
if err != nil { if err != nil {
return err return err
@ -585,3 +621,13 @@ func DarksideStageTransactionsURL(height int, url string) error {
return scan.Err() return scan.Err()
} }
func DarksideAddAddressUtxo(arg ZcashdRpcReplyGetaddressutxos) error {
state.getAddressUtxos = append(state.getAddressUtxos, arg)
return nil
}
func DarksideClearAddressUtxos() error {
state.getAddressUtxos = nil
return nil
}

View File

@ -1,183 +1,156 @@
package common package common
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/adityapk00/lightwalletd/walletrpc" "github.com/adityapk00/lightwalletd/walletrpc"
) )
type txid string
var ( var (
// List of all mempool transactions // Set of mempool txids that have been seen during the current block interval.
txns map[string]*walletrpc.RawTransaction = make(map[string]*walletrpc.RawTransaction) // The zcashd RPC `getrawmempool` returns the entire mempool each time, so
// this allows us to ignore the txids that we've already seen.
g_txidSeen map[txid]struct{} = map[txid]struct{}{}
// List of all clients waiting to recieve mempool txns // List of transactions during current block interval, in order received. Each
clients []chan<- *walletrpc.RawTransaction // client thread can keep an index into this slice to record which transactions
// it's sent back to the client (everything before that index). The g_txidSeen
// map allows this list to not contain duplicates.
g_txList []*walletrpc.RawTransaction
// Latest hash of the blocks. If this changes, then close all the clients and flush the mempool // The most recent absolute time that we fetched the mempool and the latest
lastHash []byte // (tip) block hash (so we know when a new block has been mined).
g_lastTime time.Time
// A pointer to the blockcache // The most recent zcashd getblockchaininfo reply, for height and best block
blockcache *BlockCache // hash (tip) which is used to detect when a new block arrives.
g_lastBlockChainInfo *ZcashdRpcReplyGetblockchaininfo = &ZcashdRpcReplyGetblockchaininfo{}
// Mutex to lock the above 2 structs // Mutex to protect the above variables.
lock sync.Mutex g_lock sync.Mutex
// Since the mutex doesn't have a "try_lock" method, we'll have to improvize with this
refreshing int32 = 0
) )
// AddNewClient adds a new client to the list of clients to notify for mempool txns func GetMempool(sendToClient func(*walletrpc.RawTransaction) error) error {
func AddNewClient(client chan<- *walletrpc.RawTransaction) { g_lock.Lock()
index := 0
// Stay in this function until the tip block hash changes.
stayHash := g_lastBlockChainInfo.BestBlockHash
// Log.Infoln("Adding new client, sending ", len(txns), " transactions") // Wait for more transactions to be added to the list
for {
// Copy map locally // Don't fetch the mempool more often than every 2 seconds.
lock.Lock() now := Time.Now()
localmap := make(map[string]*walletrpc.RawTransaction) if now.After(g_lastTime.Add(2 * time.Second)) {
blockChainInfo, err := getLatestBlockChainInfo()
for k, rtx := range txns { if err != nil {
localmap[k] = rtx g_lock.Unlock()
} return err
lock.Unlock() }
if g_lastBlockChainInfo.BestBlockHash != blockChainInfo.BestBlockHash {
// Also send all pending mempool txns // A new block has arrived
for _, rtx := range localmap { g_lastBlockChainInfo = blockChainInfo
if client != nil { Log.Infoln("Latest Block changed, clearing everything")
client <- rtx // We're the first thread to notice, clear cached state.
g_txidSeen = map[txid]struct{}{}
g_txList = []*walletrpc.RawTransaction{}
g_lastTime = time.Time{}
break
}
if err = refreshMempoolTxns(); err != nil {
g_lock.Unlock()
return err
}
g_lastTime = now
}
// Send transactions we haven't sent yet, best to not do so while
// holding the mutex, since this call may get flow-controlled.
toSend := g_txList[index:]
index = len(g_txList)
g_lock.Unlock()
for _, tx := range toSend {
if err := sendToClient(tx); err != nil {
return err
}
}
Time.Sleep(200 * time.Millisecond)
g_lock.Lock()
if g_lastBlockChainInfo.BestBlockHash != stayHash {
break
} }
} }
g_lock.Unlock()
lock.Lock() return nil
if client != nil {
clients = append(clients, client)
}
lock.Unlock()
} }
// RefreshMempoolTxns gets all new mempool txns and sends any new ones to waiting clients // RefreshMempoolTxns gets all new mempool txns and sends any new ones to waiting clients
func refreshMempoolTxns() error { func refreshMempoolTxns() error {
// First check if another refresh is running, if it is, just return Log.Infoln("Refreshing mempool")
if !atomic.CompareAndSwapInt32(&refreshing, 0, 1) {
Log.Warnln("Another refresh in progress, returning")
return nil
}
// Set refreshing to 0 when we exit params := []json.RawMessage{}
defer atomic.StoreInt32(&refreshing, 0)
// Check if the blockchain has changed, and if it has, then clear everything
lock.Lock()
defer lock.Unlock()
if !bytes.Equal(lastHash, blockcache.GetLatestHash()) {
Log.Infoln("Block hash changed, clearing mempool clients")
// Flush all the clients
for _, client := range clients {
if client != nil {
close(client)
}
}
clients = make([]chan<- *walletrpc.RawTransaction, 0)
// Clear txns
txns = make(map[string]*walletrpc.RawTransaction)
lastHash = blockcache.GetLatestHash()
}
var mempoolList []string
params := make([]json.RawMessage, 0)
result, rpcErr := RawRequest("getrawmempool", params) result, rpcErr := RawRequest("getrawmempool", params)
if rpcErr != nil { if rpcErr != nil {
return rpcErr return rpcErr
} }
var mempoolList []string
err := json.Unmarshal(result, &mempoolList) err := json.Unmarshal(result, &mempoolList)
if err != nil { if err != nil {
return err return err
} }
//println("getrawmempool size ", len(mempoolList))
// Fetch all new mempool txns and add them into `newTxns` // Fetch all new mempool txns and add them into `newTxns`
for _, txidstr := range mempoolList { for _, txidstr := range mempoolList {
if _, ok := txns[txidstr]; !ok { if _, ok := g_txidSeen[txid(txidstr)]; ok {
txidJSON, err := json.Marshal(txidstr) // We've already fetched this transaction
if err != nil { continue
return err
}
// The "0" is because we only need the raw hex, which is returned as
// just a hex string, and not even a json string (with quotes).
params := []json.RawMessage{txidJSON, json.RawMessage("0")}
result, rpcErr := RawRequest("getrawtransaction", params)
if rpcErr != nil {
// Not an error; mempool transactions can disappear
continue
}
// strip the quotes
var txStr string
err = json.Unmarshal(result, &txStr)
if err != nil {
return err
}
// conver to binary
txBytes, err := hex.DecodeString(txStr)
if err != nil {
return err
}
newRtx := &walletrpc.RawTransaction{
Data: txBytes,
Height: uint64(blockcache.GetLatestHeight()),
}
// Notify waiting clients
for _, client := range clients {
if client != nil {
client <- newRtx
}
}
Log.Infoln("Adding new mempool txid", txidstr, " sending to ", len(clients), " clients")
txns[txidstr] = newRtx
} }
g_txidSeen[txid(txidstr)] = struct{}{}
// We haven't fetched this transaction already.
txidJSON, err := json.Marshal(txidstr)
if err != nil {
return err
}
// The "0" is because we only need the raw hex, which is returned as
// just a hex string, and not even a json string (with quotes).
params := []json.RawMessage{txidJSON, json.RawMessage("0")}
result, rpcErr := RawRequest("getrawtransaction", params)
if rpcErr != nil {
// Not an error; mempool transactions can disappear
continue
}
// strip the quotes
var txStr string
err = json.Unmarshal(result, &txStr)
if err != nil {
return err
}
txBytes, err := hex.DecodeString(txStr)
if err != nil {
return err
}
Log.Infoln("appending", txidstr)
newRtx := &walletrpc.RawTransaction{
Data: txBytes,
Height: uint64(g_lastBlockChainInfo.Blocks),
}
g_txList = append(g_txList, newRtx)
} }
return nil return nil
} }
// StartMempoolMonitor starts monitoring the mempool func getLatestBlockChainInfo() (*ZcashdRpcReplyGetblockchaininfo, error) {
func StartMempoolMonitor(cache *BlockCache, done <-chan bool) { result, rpcErr := RawRequest("getblockchaininfo", []json.RawMessage{})
go func() { if rpcErr != nil {
ticker := time.NewTicker(5 * time.Second) return nil, rpcErr
blockcache = cache }
lastHash = blockcache.GetLatestHash() var getblockchaininfoReply ZcashdRpcReplyGetblockchaininfo
err := json.Unmarshal(result, &getblockchaininfoReply)
for { if err != nil {
select { return nil, err
case <-ticker.C: }
go func() { return &getblockchaininfoReply, nil
//Log.Infoln("Ticker triggered")
err := refreshMempoolTxns()
if err != nil {
Log.Errorln("Mempool refresh error:", err.Error())
}
}()
case <-done:
for _, client := range clients {
close(client)
}
return
}
}
}()
} }

View File

@ -94,6 +94,16 @@ block height to another. This happens in two parts, first we create and apply
the "before reorg" state. Then we create the "after reorg" stage and apply the "before reorg" state. Then we create the "after reorg" stage and apply
it, which makes the reorg happen. it, which makes the reorg happen.
Here's a quick-start guide to simulating a reorg:
```
grpcurl -plaintext -d '{"saplingActivation": 663150,"branchID": "bad", "chainName":"x"}' localhost:9067 cash.z.wallet.sdk.rpc.DarksideStreamer/Reset
grpcurl -plaintext -d '{"url": "https://raw.githubusercontent.com/zcash-hackworks/darksidewalletd-test-data/master/basic-reorg/663150.txt"}' localhost:9067 cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocks
grpcurl -plaintext -d '{"height":663151,"count":10}' localhost:9067 cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocksCreate
grpcurl -plaintext -d '{"height":663160}' localhost:9067 cash.z.wallet.sdk.rpc.DarksideStreamer/ApplyStaged
grpcurl -plaintext -d '{"height":663155,"count":10,"nonce":44}' localhost:9067 cash.z.wallet.sdk.rpc.DarksideStreamer/StageBlocksCreate
grpcurl -plaintext -d '{"height":663164}' localhost:9067 cash.z.wallet.sdk.rpc.DarksideStreamer/ApplyStaged
```
#### Creating the Before-Reorg State #### Creating the Before-Reorg State
If you haven't already started darksidewalletd, please start it: If you haven't already started darksidewalletd, please start it:

View File

@ -10,16 +10,17 @@ docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all
## Setup .env file ## Setup .env file
Copy `.env.example` to `.env` and change any required paramaters. Copy `.env.example` to `.env` and change any required parameters.
| Variable | Usage | | Variable | Usage |
| ------------- |:-------------:| | ------------- |:-------------:|
| `GF_SECURITY_ADMIN_USER` | Grafana admin user name | | `GF_SECURITY_ADMIN_USER` | Grafana admin user name |
| `ZCASHD_RPCUSER` | zcashd rpc user | | `ZCASHD_RPCUSER` | zcashd rpc user |
| `ZCASHD_RPCPASSWORD` | zcashd rpc password |
| `ZCASHD_RPCPORT` | zcashd rpc port | | `ZCASHD_RPCPORT` | zcashd rpc port |
|`ZCASHD_ALLOWIP`| zcashd rpc allowed IPs (don't |change unless you know what you're doing)| |`ZCASHD_ALLOWIP`| zcashd rpc allowed IPs (don't change unless you know what you're doing)|
|`ZCASHD_DATADIR`| local location of zcasd data directory. `uid` 2001 needs write access| |`ZCASHD_DATADIR`| local location of zcashd data directory. `uid` 2001 needs write access|
|`ZCASHD_PARMDIR`| local location of zcasd data directory. `uid` 2001 needs read access| |`ZCASHD_PARMDIR`| local location of zcashd data directory. `uid` 2001 needs read access|
|`ZCASHD_NETWORK`| zcashd network to use, `testnet` or `mainnet`| |`ZCASHD_NETWORK`| zcashd network to use, `testnet` or `mainnet`|
|`ZCASHD_GEN`| should zcashd mine? `0` or `1` |`ZCASHD_GEN`| should zcashd mine? `0` or `1`
|`LWD_PORT`| port for lightwalletd to bind to| |`LWD_PORT`| port for lightwalletd to bind to|
@ -32,6 +33,28 @@ Copy `.env.example` to `.env` and change any required paramaters.
./buildenv.sh | tee .env ./buildenv.sh | tee .env
``` ```
## Edit the two zcash.conf files
There are two zcash.conf files; one read by zcashd, one read by lightwalletd.
### `$ZCASHD_DATADIR/zcash.conf`—read by zcashd
The zcashd's `zcash.conf` needs to look like:
```
rpcuser=zcashrpc
rpcpassword=TODO INSERT A RANDOM PASSWORD HERE
experimentalfeatures=1
lightwalletd=1
```
Replace `TODO INSERT A RANDOM PASSWORD HERE` with a random password, e.g. the output of `head -c 16 /dev/urandom | base64`.
`rpcuser` and `rpcpassword` must be set, as lightwalletd doesn't work with RPC cookies (see the [rpcpassword](https://zcash.readthedocs.io/en/latest/rtd_pages/zcash_conf_guide.html) documentation) for authentication.
`rpcuser` and `rpcpassword` in `.env` are only used by zcashd_exporter, but they also must be the same values as in `$ZCASHD_DATADIR/zcash.conf`
### `lightwalletd/docker/zcash.conf`—read by lightwalletd
The other `zcashd.conf`—the one read by lightwalletd—needs to have `rpcbind` (the address of the zcashd it will connect to) set to `zcashd`, and then docker-compose networking will make it resolve to the right IP address. Also, it needs to have the same `rpcuser` and `rpcpassword` values that are listed in `$ZCASHD_DATADIR/zcash.conf` to be able to authenticate.
## Build initial local docker image ## Build initial local docker image
`docker-compose build` `docker-compose build`
@ -77,7 +100,7 @@ This should then be taken to the `Zcashd node exporter` dashboard.
If all goes as planned, the dashboard should start populating data from the container services. If all goes as planned, the dashboard should start populating data from the container services.
If there are an issues, you can view all the `docker-compose` services under the `Explore` section. If there are any issues, you can view all the `docker-compose` services under the `Explore` section.
# Viewing container logs # Viewing container logs
@ -98,3 +121,18 @@ Loki as a rich query syntax to help with log in many ways, for example combine 2
![grafana-explore4](./images/grafana-explore-4.png) ![grafana-explore4](./images/grafana-explore-4.png)
See more here: https://github.com/grafana/loki/blob/master/docs/logql.md See more here: https://github.com/grafana/loki/blob/master/docs/logql.md
# Exposing `lightwalletd` to the network
Edit `docker-compose.yml` to look like
```
ports:
#- "127.0.0.1:$LWD_GRPC_PORT:$LWD_GRPC_PORT"
#- "127.0.0.1:$LWD_HTTP_PORT:$LWD_HTTP_PORT"
- "0.0.0.0:$LWD_GRPC_PORT:$LWD_GRPC_PORT"
- "0.0.0.0:$LWD_HTTP_PORT:$LWD_HTTP_PORT"
```
When you edit these lines in `docker-compose.yml`, stopping/starting the individual `lightwalletd` container doesn't actually make the changes happen—you have to stop/start the whole `docker-compose` ensemble of containers because the ports/network config stuff lives at that level and doesn't seem to be affected by individual container stop/starts. Also if you want to expose `lightwalletd` to the whole internet, you don't need to specify an IP address, `0.0.0.0` works as it should.

View File

@ -183,11 +183,15 @@
</li> </li>
<li> <li>
<a href="#cash.z.wallet.sdk.rpc.CompactOutput"><span class="badge">M</span>CompactOutput</a> <a href="#cash.z.wallet.sdk.rpc.CompactOrchardAction"><span class="badge">M</span>CompactOrchardAction</a>
</li> </li>
<li> <li>
<a href="#cash.z.wallet.sdk.rpc.CompactSpend"><span class="badge">M</span>CompactSpend</a> <a href="#cash.z.wallet.sdk.rpc.CompactSaplingOutput"><span class="badge">M</span>CompactSaplingOutput</a>
</li>
<li>
<a href="#cash.z.wallet.sdk.rpc.CompactSaplingSpend"><span class="badge">M</span>CompactSaplingSpend</a>
</li> </li>
<li> <li>
@ -408,7 +412,52 @@
<h3 id="cash.z.wallet.sdk.rpc.CompactOutput">CompactOutput</h3> <h3 id="cash.z.wallet.sdk.rpc.CompactOrchardAction">CompactOrchardAction</h3>
<p>https://github.com/zcash/zips/blob/main/zip-0225.rst#orchard-action-description-orchardaction</p><p>(but not all fields are needed)</p>
<table class="field-table">
<thead>
<tr><td>Field</td><td>Type</td><td>Label</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>nullifier</td>
<td><a href="#bytes">bytes</a></td>
<td></td>
<td><p>[32] The nullifier of the input note </p></td>
</tr>
<tr>
<td>cmx</td>
<td><a href="#bytes">bytes</a></td>
<td></td>
<td><p>[32] The x-coordinate of the note commitment for the output note </p></td>
</tr>
<tr>
<td>ephemeralKey</td>
<td><a href="#bytes">bytes</a></td>
<td></td>
<td><p>[32] An encoding of an ephemeral Pallas public key </p></td>
</tr>
<tr>
<td>ciphertext</td>
<td><a href="#bytes">bytes</a></td>
<td></td>
<td><p>[52] The note plaintext component of the encCiphertext field </p></td>
</tr>
</tbody>
</table>
<h3 id="cash.z.wallet.sdk.rpc.CompactSaplingOutput">CompactSaplingOutput</h3>
<p>output is a Sapling Output Description as described in section 7.4 of the</p><p>Zcash protocol spec. Total size is 948.</p> <p>output is a Sapling Output Description as described in section 7.4 of the</p><p>Zcash protocol spec. Total size is 948.</p>
@ -436,7 +485,7 @@
<td>ciphertext</td> <td>ciphertext</td>
<td><a href="#bytes">bytes</a></td> <td><a href="#bytes">bytes</a></td>
<td></td> <td></td>
<td><p>ciphertext and zkproof </p></td> <td><p>first 52 bytes of ciphertext </p></td>
</tr> </tr>
</tbody> </tbody>
@ -446,8 +495,8 @@
<h3 id="cash.z.wallet.sdk.rpc.CompactSpend">CompactSpend</h3> <h3 id="cash.z.wallet.sdk.rpc.CompactSaplingSpend">CompactSaplingSpend</h3>
<p>CompactSpend is a Sapling Spend Description as described in 7.3 of the Zcash</p><p>protocol specification.</p> <p>CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash</p><p>protocol specification.</p>
<table class="field-table"> <table class="field-table">
@ -507,18 +556,25 @@ in a pure-Sapling context, the fee will be calculable as:
<tr> <tr>
<td>spends</td> <td>spends</td>
<td><a href="#cash.z.wallet.sdk.rpc.CompactSpend">CompactSpend</a></td> <td><a href="#cash.z.wallet.sdk.rpc.CompactSaplingSpend">CompactSaplingSpend</a></td>
<td>repeated</td> <td>repeated</td>
<td><p>inputs </p></td> <td><p>inputs </p></td>
</tr> </tr>
<tr> <tr>
<td>outputs</td> <td>outputs</td>
<td><a href="#cash.z.wallet.sdk.rpc.CompactOutput">CompactOutput</a></td> <td><a href="#cash.z.wallet.sdk.rpc.CompactSaplingOutput">CompactSaplingOutput</a></td>
<td>repeated</td> <td>repeated</td>
<td><p>outputs </p></td> <td><p>outputs </p></td>
</tr> </tr>
<tr>
<td>actions</td>
<td><a href="#cash.z.wallet.sdk.rpc.CompactOrchardAction">CompactOrchardAction</a></td>
<td>repeated</td>
<td><p> </p></td>
</tr>
</tbody> </tbody>
</table> </table>
@ -836,6 +892,21 @@ into a specified block on the next ApplyStaged().</p></td>
<td><p>Clear the incoming transaction pool.</p></td> <td><p>Clear the incoming transaction pool.</p></td>
</tr> </tr>
<tr>
<td>AddAddressUtxo</td>
<td><a href="#cash.z.wallet.sdk.rpc.GetAddressUtxosReply">GetAddressUtxosReply</a></td>
<td><a href="#cash.z.wallet.sdk.rpc.Empty">Empty</a></td>
<td><p>Add a GetAddressUtxosReply entry to be returned by GetAddressUtxos().
There is no staging or applying for these, very simple.</p></td>
</tr>
<tr>
<td>ClearAddressUtxo</td>
<td><a href="#cash.z.wallet.sdk.rpc.Empty">Empty</a></td>
<td><a href="#cash.z.wallet.sdk.rpc.Empty">Empty</a></td>
<td><p>Clear the list of GetAddressUtxos entries (can&#39;t fail)</p></td>
</tr>
</tbody> </tbody>
</table> </table>
@ -1045,7 +1116,7 @@ into a specified block on the next ApplyStaged().</p></td>
<h3 id="cash.z.wallet.sdk.rpc.GetAddressUtxosArg">GetAddressUtxosArg</h3> <h3 id="cash.z.wallet.sdk.rpc.GetAddressUtxosArg">GetAddressUtxosArg</h3>
<p></p> <p>Results are sorted by height, which makes it easy to issue another</p><p>request that picks up from where the previous left off.</p>
<table class="field-table"> <table class="field-table">
@ -1055,9 +1126,9 @@ into a specified block on the next ApplyStaged().</p></td>
<tbody> <tbody>
<tr> <tr>
<td>address</td> <td>addresses</td>
<td><a href="#string">string</a></td> <td><a href="#string">string</a></td>
<td></td> <td>repeated</td>
<td><p> </p></td> <td><p> </p></td>
</tr> </tr>
@ -1092,6 +1163,13 @@ into a specified block on the next ApplyStaged().</p></td>
</thead> </thead>
<tbody> <tbody>
<tr>
<td>address</td>
<td><a href="#string">string</a></td>
<td></td>
<td><p> </p></td>
</tr>
<tr> <tr>
<td>txid</td> <td>txid</td>
<td><a href="#bytes">bytes</a></td> <td><a href="#bytes">bytes</a></td>
@ -1305,7 +1383,7 @@ into a specified block on the next ApplyStaged().</p></td>
<h3 id="cash.z.wallet.sdk.rpc.RawTransaction">RawTransaction</h3> <h3 id="cash.z.wallet.sdk.rpc.RawTransaction">RawTransaction</h3>
<p>RawTransaction contains the complete transaction data. It also optionally includes </p><p>the block height in which the transaction was included.</p> <p>RawTransaction contains the complete transaction data. It also optionally includes </p><p>the block height in which the transaction was included, or, when returned</p><p>by GetMempoolStream(), the latest block height.</p>
<table class="field-table"> <table class="field-table">
@ -1418,7 +1496,7 @@ into a specified block on the next ApplyStaged().</p></td>
<td>height</td> <td>height</td>
<td><a href="#uint64">uint64</a></td> <td><a href="#uint64">uint64</a></td>
<td></td> <td></td>
<td><p> </p></td> <td><p>block height </p></td>
</tr> </tr>
<tr> <tr>
@ -1436,12 +1514,19 @@ into a specified block on the next ApplyStaged().</p></td>
</tr> </tr>
<tr> <tr>
<td>tree</td> <td>saplingTree</td>
<td><a href="#string">string</a></td> <td><a href="#string">string</a></td>
<td></td> <td></td>
<td><p>sapling commitment tree state </p></td> <td><p>sapling commitment tree state </p></td>
</tr> </tr>
<tr>
<td>orchardTree</td>
<td><a href="#string">string</a></td>
<td></td>
<td><p>orchard commitment tree state </p></td>
</tr>
</tbody> </tbody>
</table> </table>
@ -1572,6 +1657,14 @@ match a shortened txid, they are all sent (none is excluded). Transactions
in the exclude list that don&#39;t exist in the mempool are ignored.</p></td> in the exclude list that don&#39;t exist in the mempool are ignored.</p></td>
</tr> </tr>
<tr>
<td>GetMempoolStream</td>
<td><a href="#cash.z.wallet.sdk.rpc.Empty">Empty</a></td>
<td><a href="#cash.z.wallet.sdk.rpc.RawTransaction">RawTransaction</a> stream</td>
<td><p>Return a stream of current Mempool transactions. This will keep the output stream open while
there are mempool transactions. It will close the returned stream when a new block is mined.</p></td>
</tr>
<tr> <tr>
<td>GetTreeState</td> <td>GetTreeState</td>
<td><a href="#cash.z.wallet.sdk.rpc.BlockID">BlockID</a></td> <td><a href="#cash.z.wallet.sdk.rpc.BlockID">BlockID</a></td>
@ -1607,7 +1700,7 @@ The block can be specified by either height or hash.</p></td>
<td>Ping</td> <td>Ping</td>
<td><a href="#cash.z.wallet.sdk.rpc.Duration">Duration</a></td> <td><a href="#cash.z.wallet.sdk.rpc.Duration">Duration</a></td>
<td><a href="#cash.z.wallet.sdk.rpc.PingResponse">PingResponse</a></td> <td><a href="#cash.z.wallet.sdk.rpc.PingResponse">PingResponse</a></td>
<td><p>Testing-only</p></td> <td><p>Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production)</p></td>
</tr> </tr>
</tbody> </tbody>

View File

@ -36,7 +36,7 @@ const (
func testsetup() (walletrpc.CompactTxStreamerServer, *common.BlockCache) { func testsetup() (walletrpc.CompactTxStreamerServer, *common.BlockCache) {
os.RemoveAll(unitTestPath) os.RemoveAll(unitTestPath)
cache := common.NewBlockCache(unitTestPath, unitTestChain, 380640, true) cache := common.NewBlockCache(unitTestPath, unitTestChain, 380640, 0)
lwd, err := NewLwdStreamer(cache, "main", false /* enablePing */) lwd, err := NewLwdStreamer(cache, "main", false /* enablePing */)
if err != nil { if err != nil {
os.Stderr.WriteString(fmt.Sprint("NewLwdStreamer failed:", err)) os.Stderr.WriteString(fmt.Sprint("NewLwdStreamer failed:", err))
@ -191,6 +191,9 @@ func TestGetLatestBlock(t *testing.T) {
if blockID.Height != 380640 { if blockID.Height != 380640 {
t.Fatal("unexpected blockID.height") t.Fatal("unexpected blockID.height")
} }
if string(blockID.Hash) != string(block.Hash) {
t.Fatal("unexpected blockID.hash")
}
step = 0 step = 0
} }

View File

@ -139,23 +139,14 @@ func (s *lwdStreamer) GetCurrentZECPrice(ctx context.Context, in *walletrpc.Empt
// GetLatestBlock returns the height of the best chain, according to zcashd. // GetLatestBlock returns the height of the best chain, according to zcashd.
func (s *lwdStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc.ChainSpec) (*walletrpc.BlockID, error) { func (s *lwdStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc.ChainSpec) (*walletrpc.BlockID, error) {
result, rpcErr := common.RawRequest("getblockchaininfo", []json.RawMessage{}) latestBlock := s.cache.GetLatestHeight()
if rpcErr != nil { latestHash := s.cache.GetLatestHash()
return nil, rpcErr
} if latestBlock == -1 {
var getblockchaininfoReply common.ZcashdRpcReplyGetblockchaininfo return nil, errors.New("Cache is empty. Server is probably not yet ready")
err := json.Unmarshal(result, &getblockchaininfoReply)
if err != nil {
return nil, err
} }
hash, err := hex.DecodeString(getblockchaininfoReply.BestBlockHash) return &walletrpc.BlockID{Height: uint64(latestBlock), Hash: latestHash}, nil
if err != nil {
return nil, err
}
common.Metrics.LatestBlockCounter.Inc()
return &walletrpc.BlockID{Height: uint64(getblockchaininfoReply.Blocks), Hash: parser.Reverse(hash)}, nil
} }
// GetTaddressTxids is a streaming RPC that returns transaction IDs that have // GetTaddressTxids is a streaming RPC that returns transaction IDs that have
@ -397,11 +388,12 @@ func (s *lwdStreamer) GetTreeState(ctx context.Context, id *walletrpc.BlockID) (
return nil, errors.New("zcashd did not return treestate") return nil, errors.New("zcashd did not return treestate")
} }
return &walletrpc.TreeState{ return &walletrpc.TreeState{
Network: s.chainName, Network: s.chainName,
Height: uint64(gettreestateReply.Height), Height: uint64(gettreestateReply.Height),
Hash: gettreestateReply.Hash, Hash: gettreestateReply.Hash,
Time: gettreestateReply.Time, Time: gettreestateReply.Time,
Tree: gettreestateReply.Sapling.Commitments.FinalState, SaplingTree: gettreestateReply.Sapling.Commitments.FinalState,
OrchardTree: gettreestateReply.Orchard.Commitments.FinalState,
}, nil }, nil
} }
@ -463,8 +455,9 @@ func (s *lwdStreamer) SendTransaction(ctx context.Context, rawtx *walletrpc.RawT
// Result: // Result:
// "hex" (string) The transaction hash in hex // "hex" (string) The transaction hash in hex
// Verify rawtx
if rawtx == nil || rawtx.Data == nil { if rawtx == nil || rawtx.Data == nil {
return nil, errors.New("Bad Transaction or Data") return nil, errors.New("Bad transaction data")
} }
// Construct raw JSON-RPC params // Construct raw JSON-RPC params
@ -562,6 +555,13 @@ func (s *lwdStreamer) GetTaddressBalanceStream(addresses walletrpc.CompactTxStre
return nil return nil
} }
func (s *lwdStreamer) GetMempoolStream(_empty *walletrpc.Empty, resp walletrpc.CompactTxStreamer_GetMempoolStreamServer) error {
err := common.GetMempool(func(tx *walletrpc.RawTransaction) error {
return resp.Send(tx)
})
return err
}
// Key is 32-byte txid (as a 64-character string), data is pointer to compact tx. // Key is 32-byte txid (as a 64-character string), data is pointer to compact tx.
var mempoolMap *map[string]*walletrpc.CompactTx var mempoolMap *map[string]*walletrpc.CompactTx
var mempoolList []string var mempoolList []string
@ -622,7 +622,7 @@ func (s *lwdStreamer) GetMempoolTx(exclude *walletrpc.Exclude, resp walletrpc.Co
return errors.New("extra data deserializing transaction") return errors.New("extra data deserializing transaction")
} }
newmempoolMap[txidstr] = &walletrpc.CompactTx{} newmempoolMap[txidstr] = &walletrpc.CompactTx{}
if tx.HasSaplingElements() { if tx.HasShieldedElements() {
newmempoolMap[txidstr] = tx.ToCompact( /* height */ 0) newmempoolMap[txidstr] = tx.ToCompact( /* height */ 0)
} }
} }
@ -644,27 +644,6 @@ func (s *lwdStreamer) GetMempoolTx(exclude *walletrpc.Exclude, resp walletrpc.Co
return nil return nil
} }
func (s *lwdStreamer) GetMempoolStream(_empty *walletrpc.Empty, resp walletrpc.CompactTxStreamer_GetMempoolStreamServer) error {
ch := make(chan *walletrpc.RawTransaction, 200)
go common.AddNewClient(ch)
for {
select {
case rtx, more := <-ch:
if !more || rtx == nil {
return nil
}
if resp.Send(rtx) != nil {
return nil
}
// Timeout after 5 mins
case <-time.After(5 * time.Minute):
return nil
}
}
}
// Return the subset of items that aren't excluded, but // Return the subset of items that aren't excluded, but
// if more than one item matches an exclude entry, return // if more than one item matches an exclude entry, return
// all those items. // all those items.
@ -730,7 +709,7 @@ func getAddressUtxos(arg *walletrpc.GetAddressUtxosArg, f func(*walletrpc.GetAdd
if rpcErr != nil { if rpcErr != nil {
return rpcErr return rpcErr
} }
var utxosReply common.ZcashdRpcReplyGetaddressutxos var utxosReply []common.ZcashdRpcReplyGetaddressutxos
err = json.Unmarshal(result, &utxosReply) err = json.Unmarshal(result, &utxosReply)
if err != nil { if err != nil {
return err return err
@ -909,3 +888,23 @@ func (s *DarksideStreamer) ClearIncomingTransactions(ctx context.Context, e *wal
common.DarksideClearIncomingTransactions() common.DarksideClearIncomingTransactions()
return &walletrpc.Empty{}, nil return &walletrpc.Empty{}, nil
} }
// AddAddressUtxo adds a UTXO which will be returned by GetAddressUtxos() (above)
func (s *DarksideStreamer) AddAddressUtxo(ctx context.Context, arg *walletrpc.GetAddressUtxosReply) (*walletrpc.Empty, error) {
utxosReply := common.ZcashdRpcReplyGetaddressutxos{
Address: arg.Address,
Txid: hex.EncodeToString(parser.Reverse(arg.Txid)),
OutputIndex: int64(arg.Index),
Script: hex.EncodeToString(arg.Script),
Satoshis: uint64(arg.ValueZat),
Height: int(arg.Height),
}
err := common.DarksideAddAddressUtxo(utxosReply)
return &walletrpc.Empty{}, err
}
// ClearAddressUtxo removes the list of cached utxo entries
func (s *DarksideStreamer) ClearAddressUtxo(ctx context.Context, arg *walletrpc.Empty) (*walletrpc.Empty, error) {
err := common.DarksideClearAddressUtxos()
return &walletrpc.Empty{}, err
}

18
go.mod
View File

@ -5,27 +5,15 @@ go 1.12
require ( require (
github.com/btcsuite/btcd v0.20.1-beta github.com/btcsuite/btcd v0.20.1-beta
github.com/golang/protobuf v1.5.2 github.com/golang/protobuf v1.5.2
github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.5.1 github.com/prometheus/client_golang v1.5.1
github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus v1.4.2
github.com/smartystreets/assertions v1.0.1 // indirect
github.com/spf13/afero v1.5.1 // indirect
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0
github.com/spf13/viper v1.6.2 github.com/spf13/viper v1.6.2
github.com/stretchr/testify v1.6.1 // indirect github.com/zcash/lightwalletd v0.4.12
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect google.golang.org/grpc v1.44.0
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect google.golang.org/protobuf v1.27.1
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46 // indirect
google.golang.org/grpc v1.37.0
google.golang.org/protobuf v1.26.0
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.51.0 gopkg.in/ini.v1 v1.51.0
gopkg.in/yaml.v3 v3.0.0-20210105161348-2e78108cf5f8 // indirect
) )

321
go.sum
View File

@ -1,18 +1,36 @@
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@ -26,77 +44,74 @@ github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/fullstorydev/grpcurl v1.8.6/go.mod h1:WhP7fRQdhxz2TkL97u+TCb505sxfH78W1usyoB3tepw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@ -104,10 +119,11 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -116,57 +132,58 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de h1:F7WD09S8QB4LrkEpka0dFPLSotH11HRpCsLIbIcJ7sU= github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de h1:F7WD09S8QB4LrkEpka0dFPLSotH11HRpCsLIbIcJ7sU=
github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jhump/protoreflect v1.10.3/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0 h1:ZqfnKyx9KGpRcW04j5nnPDgRgoXUeLh2YFBeFzphcA0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -176,24 +193,18 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 h1:F9x/1yl3T2AeKLr2AMdilSD8+f9bvMnNN8VS5iDtovc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@ -201,7 +212,6 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -225,13 +235,11 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af h1:gu+uRPtBe88sKxUCEXRoeCvVG90TJmwhiqRpvdhQFng=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
@ -241,16 +249,13 @@ github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHei
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg=
github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
@ -262,75 +267,116 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= github.com/zcash/lightwalletd v0.4.12 h1:PAPB3GpHw3LCf30SskHw1sXKcRZq5bjmKH1Awkm9U+I=
github.com/zcash/lightwalletd v0.4.12/go.mod h1:KsNsRWUATRvWuhsW/h0thygNtT7JIEJQFNW0r2wXIuA=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4 h1:c2HOrn5iMezYjSlGPncknSEr/8x5LELb/ilJbXi9DEA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -338,10 +384,25 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -351,47 +412,110 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46 h1:f4STrQZf8jaowsiUitigvrqMCCM4QJH1A2JCSI7U1ow= google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46 h1:f4STrQZf8jaowsiUitigvrqMCCM4QJH1A2JCSI7U1ow=
google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -401,27 +525,27 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -429,5 +553,12 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210105161348-2e78108cf5f8 h1:tH9C0MON9YI3/KuD+u5+tQrQQ8px0MrcJ/avzeALw7o= gopkg.in/yaml.v3 v3.0.0-20210105161348-2e78108cf5f8 h1:tH9C0MON9YI3/KuD+u5+tQrQQ8px0MrcJ/avzeALw7o=
gopkg.in/yaml.v3 v3.0.0-20210105161348-2e78108cf5f8/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210105161348-2e78108cf5f8/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@ -62,7 +62,7 @@ func (b *Block) GetDisplayPrevHash() []byte {
// HasSaplingTransactions indicates if the block contains any Sapling tx. // HasSaplingTransactions indicates if the block contains any Sapling tx.
func (b *Block) HasSaplingTransactions() bool { func (b *Block) HasSaplingTransactions() bool {
for _, tx := range b.vtx { for _, tx := range b.vtx {
if tx.HasSaplingElements() { if tx.HasShieldedElements() {
return true return true
} }
} }
@ -118,7 +118,7 @@ func (b *Block) ToCompact() *walletrpc.CompactBlock {
// Only Sapling transactions have a meaningful compact encoding // Only Sapling transactions have a meaningful compact encoding
saplingTxns := make([]*walletrpc.CompactTx, 0, len(b.vtx)) saplingTxns := make([]*walletrpc.CompactTx, 0, len(b.vtx))
for idx, tx := range b.vtx { for idx, tx := range b.vtx {
if tx.HasSaplingElements() { if tx.HasShieldedElements() {
saplingTxns = append(saplingTxns, tx.ToCompact(idx)) saplingTxns = append(saplingTxns, tx.ToCompact(idx))
} }
} }

View File

@ -134,7 +134,7 @@ func TestBlockHeader(t *testing.T) {
} }
// This is not necessarily true for anything but our current test cases. // This is not necessarily true for anything but our current test cases.
for _, b := range hash[:4] { for _, b := range hash[:1] {
if b != 0 { if b != 0 {
t.Errorf("Hash lacked leading zeros: %x", hash) t.Errorf("Hash lacked leading zeros: %x", hash)
} }

View File

@ -4,13 +4,11 @@
package parser package parser
import ( import (
"bufio"
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"testing" "testing"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -18,200 +16,6 @@ import (
protobuf "github.com/golang/protobuf/proto" protobuf "github.com/golang/protobuf/proto"
) )
func TestBlockParser(t *testing.T) {
// These (valid on testnet) correspond to the transactions in testdata/blocks;
// for each block, the hashes for the tx within that block.
var txhashes = [][]string{
{
"81096ff101a4f01d25ffd34a446bee4368bd46c233a59ac0faf101e1861c6b22",
}, {
"921dc41bef3a0d887c615abac60a29979efc8b4bbd3d887caeb6bb93501bde8e",
}, {
"d8e4c336ffa69dacaa4e0b4eaf8e3ae46897f1930a573c10b53837a03318c980",
"4d5ccbfc6984680c481ff5ce145b8a93d59dfea90c150dfa45c938ab076ee5b2",
}, {
"df2b03619d441ce3d347e9278d87618e975079d0e235dfb3b3d8271510f707aa",
"8d2593edfc328fa637b4ac91c7d569ee922bb9a6fda7cea230e92deb3ae4b634",
},
}
testBlocks, err := os.Open("../testdata/blocks")
if err != nil {
t.Fatal(err)
}
defer testBlocks.Close()
scan := bufio.NewScanner(testBlocks)
for blockindex := 0; scan.Scan(); blockindex++ {
blockDataHex := scan.Text()
blockData, err := hex.DecodeString(blockDataHex)
if err != nil {
t.Error(err)
continue
}
// This is just a sanity check of the test:
if int(blockData[1487]) != len(txhashes[blockindex]) {
t.Error("wrong number of transactions, test broken?")
}
// Make a copy of just the transactions alone, which,
// for these blocks, start just beyond the header and
// the one-byte nTx value, which is offset 1488.
transactions := make([]byte, len(blockData[1488:]))
copy(transactions, blockData[1488:])
// Each iteration of this loop appends the block's original
// transactions, so we build an ever-larger block. The loop
// limit is arbitrary, but make sure we get into double-digit
// transaction counts (compact integer).
for i := 0; i < 264; i++ {
b := blockData
block := NewBlock()
b, err = block.ParseFromSlice(b)
if err != nil {
t.Error(errors.Wrap(err, fmt.Sprintf("parsing block %d", i)))
continue
}
if len(b) > 0 {
t.Error("Extra data remaining")
}
// Some basic sanity checks
if block.hdr.Version != 4 {
t.Error("Read wrong version in a test block.")
break
}
if block.GetVersion() != 4 {
t.Error("Read wrong version in a test block.")
break
}
if block.GetTxCount() < 1 {
t.Error("No transactions in block")
break
}
if len(block.Transactions()) != block.GetTxCount() {
t.Error("Number of transactions mismatch")
break
}
if block.GetTxCount() != len(txhashes[blockindex])*(i+1) {
t.Error("Unexpected number of transactions")
}
if block.HasSaplingTransactions() {
t.Error("Unexpected Sapling tx")
break
}
for txindex, tx := range block.Transactions() {
if tx.HasSaplingElements() {
t.Error("Unexpected Sapling tx")
break
}
expectedHash := txhashes[blockindex][txindex%len(txhashes[blockindex])]
if hex.EncodeToString(tx.GetDisplayHash()) != expectedHash {
t.Error("incorrect tx hash")
}
}
// Keep appending the original transactions, which is unrealistic
// because the coinbase is being replicated, but it works; first do
// some surgery to the transaction count (see DarksideApplyStaged()).
for j := 0; j < len(txhashes[blockindex]); j++ {
nTxFirstByte := blockData[1487]
switch {
case nTxFirstByte < 252:
blockData[1487]++
case nTxFirstByte == 252:
// incrementing to 253, requires "253" followed by 2-byte length,
// extend the block by two bytes, shift existing transaction bytes
blockData = append(blockData, 0, 0)
copy(blockData[1490:], blockData[1488:len(blockData)-2])
blockData[1487] = 253
blockData[1488] = 253
blockData[1489] = 0
case nTxFirstByte == 253:
blockData[1488]++
if blockData[1488] == 0 {
// wrapped around
blockData[1489]++
}
}
}
blockData = append(blockData, transactions...)
}
}
}
func TestBlockParserFail(t *testing.T) {
testBlocks, err := os.Open("../testdata/badblocks")
if err != nil {
t.Fatal(err)
}
defer testBlocks.Close()
scan := bufio.NewScanner(testBlocks)
// the first "block" contains an illegal hex character
{
scan.Scan()
blockDataHex := scan.Text()
_, err := hex.DecodeString(blockDataHex)
if err == nil {
t.Error("unexpected success parsing illegal hex bad block")
}
}
for i := 0; scan.Scan(); i++ {
blockDataHex := scan.Text()
blockData, err := hex.DecodeString(blockDataHex)
if err != nil {
t.Error(err)
continue
}
block := NewBlock()
blockData, err = block.ParseFromSlice(blockData)
if err == nil {
t.Error("unexpected success parsing bad block")
}
}
}
// Checks on the first 20 blocks from mainnet genesis.
func TestGenesisBlockParser(t *testing.T) {
blockFile, err := os.Open("../testdata/mainnet_genesis")
if err != nil {
t.Fatal(err)
}
defer blockFile.Close()
scan := bufio.NewScanner(blockFile)
for i := 0; scan.Scan(); i++ {
blockDataHex := scan.Text()
blockData, err := hex.DecodeString(blockDataHex)
if err != nil {
t.Error(err)
continue
}
block := NewBlock()
blockData, err = block.ParseFromSlice(blockData)
if err != nil {
t.Error(err)
continue
}
if len(blockData) > 0 {
t.Error("Extra data remaining")
}
// Some basic sanity checks
if block.hdr.Version != 4 {
t.Error("Read wrong version in genesis block.")
break
}
if block.GetHeight() != i {
t.Errorf("Got wrong height for block %d: %d", i, block.GetHeight())
}
}
}
func TestCompactBlocks(t *testing.T) { func TestCompactBlocks(t *testing.T) {
type compactTest struct { type compactTest struct {
BlockHeight int `json:"block"` BlockHeight int `json:"block"`

View File

@ -154,6 +154,16 @@ func (s *String) ReadCompactLengthPrefixed(out *String) bool {
return true return true
} }
// SkipCompactLengthPrefixed skips a CompactSize-encoded
// length field.
func (s *String) SkipCompactLengthPrefixed() bool {
var length int
if !s.ReadCompactSize(&length) {
return false
}
return s.Skip(length)
}
// ReadInt32 decodes a little-endian 32-bit value into out, treating it as // ReadInt32 decodes a little-endian 32-bit value into out, treating it as
// signed, and advances over it. It reports whether the read was successful. // signed, and advances over it. It reports whether the read was successful.
func (s *String) ReadInt32(out *int32) bool { func (s *String) ReadInt32(out *int32) bool {

View File

@ -261,6 +261,38 @@ func TestString_ReadCompactLengthPrefixed(t *testing.T) {
} }
} }
func TestString_SkipCompactLengthPrefixed(t *testing.T) {
// a stream of 3 bytes followed by 2 bytes into the value variable, v
s := String{3, 55, 66, 77, 2, 88, 99}
// read the 3 and thus the following 3 bytes
if !s.SkipCompactLengthPrefixed() {
t.Fatalf("SkipCompactLengthPrefix failed")
}
if len(s) != 3 {
t.Fatalf("SkipCompactLengthPrefix incorrect remaining length")
}
// read the 2 and then two bytes
if !s.SkipCompactLengthPrefixed() {
t.Fatalf("SkipCompactLengthPrefix failed")
}
if len(s) != 0 {
t.Fatalf("SkipCompactLengthPrefix incorrect remaining length")
}
// at the end of the String, another read should return false
if s.SkipCompactLengthPrefixed() {
t.Fatalf("SkipCompactLengthPrefix unexpected success")
}
// this string is too short (less than 2 bytes of data)
s = String{3, 55, 66}
if s.SkipCompactLengthPrefixed() {
t.Fatalf("SkipdCompactLengthPrefix unexpected success")
}
}
var readInt32Tests = []struct { var readInt32Tests = []struct {
s String s String
expected int32 expected int32

View File

@ -6,7 +6,7 @@
package parser package parser
import ( import (
"crypto/sha256" "fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/adityapk00/lightwalletd/parser/internal/bytestring" "github.com/adityapk00/lightwalletd/parser/internal/bytestring"
@ -17,51 +17,53 @@ type rawTransaction struct {
fOverwintered bool fOverwintered bool
version uint32 version uint32
nVersionGroupID uint32 nVersionGroupID uint32
transparentInputs []*txIn consensusBranchID uint32
transparentOutputs []*txOut transparentInputs []txIn
nLockTime uint32 transparentOutputs []txOut
nExpiryHeight uint32 //nLockTime uint32
valueBalance int64 //nExpiryHeight uint32
shieldedSpends []*spend //valueBalanceSapling int64
shieldedOutputs []*output shieldedSpends []spend
joinSplits []*joinSplit shieldedOutputs []output
joinSplitPubKey []byte joinSplits []joinSplit
joinSplitSig []byte //joinSplitPubKey []byte
bindingSig []byte //joinSplitSig []byte
//bindingSigSapling []byte
orchardActions []action
} }
// Txin format as described in https://en.bitcoin.it/wiki/Transaction // Txin format as described in https://en.bitcoin.it/wiki/Transaction
type txIn struct { type txIn struct {
// SHA256d of a previous (to-be-used) transaction // SHA256d of a previous (to-be-used) transaction
PrevTxHash []byte //PrevTxHash []byte
// Index of the to-be-used output in the previous tx // Index of the to-be-used output in the previous tx
PrevTxOutIndex uint32 //PrevTxOutIndex uint32
// CompactSize-prefixed, could be a pubkey or a script // CompactSize-prefixed, could be a pubkey or a script
ScriptSig []byte ScriptSig []byte
// Bitcoin: "normally 0xFFFFFFFF; irrelevant unless transaction's lock_time > 0" // Bitcoin: "normally 0xFFFFFFFF; irrelevant unless transaction's lock_time > 0"
SequenceNumber uint32 //SequenceNumber uint32
} }
func (tx *txIn) ParseFromSlice(data []byte) ([]byte, error) { func (tx *txIn) ParseFromSlice(data []byte) ([]byte, error) {
s := bytestring.String(data) s := bytestring.String(data)
if !s.ReadBytes(&tx.PrevTxHash, 32) { if !s.Skip(32) {
return nil, errors.New("could not read PrevTxHash") return nil, errors.New("could not skip PrevTxHash")
} }
if !s.ReadUint32(&tx.PrevTxOutIndex) { if !s.Skip(4) {
return nil, errors.New("could not read PrevTxOutIndex") return nil, errors.New("could not skip PrevTxOutIndex")
} }
if !s.ReadCompactLengthPrefixed((*bytestring.String)(&tx.ScriptSig)) { if !s.ReadCompactLengthPrefixed((*bytestring.String)(&tx.ScriptSig)) {
return nil, errors.New("could not read ScriptSig") return nil, errors.New("could not read ScriptSig")
} }
if !s.ReadUint32(&tx.SequenceNumber) { if !s.Skip(4) {
return nil, errors.New("could not read SequenceNumber") return nil, errors.New("could not skip SequenceNumber")
} }
return []byte(s), nil return []byte(s), nil
@ -73,86 +75,118 @@ type txOut struct {
Value uint64 Value uint64
// Script. CompactSize-prefixed. // Script. CompactSize-prefixed.
Script []byte //Script []byte
} }
func (tx *txOut) ParseFromSlice(data []byte) ([]byte, error) { func (tx *txOut) ParseFromSlice(data []byte) ([]byte, error) {
s := bytestring.String(data) s := bytestring.String(data)
if !s.ReadUint64(&tx.Value) { if !s.Skip(8) {
return nil, errors.New("could not read txOut value") return nil, errors.New("could not skip txOut value")
} }
if !s.ReadCompactLengthPrefixed((*bytestring.String)(&tx.Script)) { if !s.SkipCompactLengthPrefixed() {
return nil, errors.New("could not read txOut script") return nil, errors.New("could not skip txOut script")
} }
return []byte(s), nil return []byte(s), nil
} }
// spend is a Sapling Spend Description as described in 7.3 of the Zcash // parse the transparent parts of the transaction
// protocol spec. Total size is 384 bytes. func (tx *Transaction) ParseTransparent(data []byte) ([]byte, error) {
type spend struct {
cv []byte // 32
anchor []byte // 32
nullifier []byte // 32
rk []byte // 32
zkproof []byte // 192
spendAuthSig []byte // 64
}
func (p *spend) ParseFromSlice(data []byte) ([]byte, error) {
s := bytestring.String(data) s := bytestring.String(data)
var txInCount int
if !s.ReadBytes(&p.cv, 32) { if !s.ReadCompactSize(&txInCount) {
return nil, errors.New("could not read cv") return nil, errors.New("could not read tx_in_count")
}
var err error
tx.transparentInputs = make([]txIn, txInCount)
for i := 0; i < txInCount; i++ {
ti := &tx.transparentInputs[i]
s, err = ti.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing transparent input")
}
} }
if !s.ReadBytes(&p.anchor, 32) { var txOutCount int
return nil, errors.New("could not read anchor") if !s.ReadCompactSize(&txOutCount) {
return nil, errors.New("could not read tx_out_count")
}
tx.transparentOutputs = make([]txOut, txOutCount)
for i := 0; i < txOutCount; i++ {
to := &tx.transparentOutputs[i]
s, err = to.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing transparent output")
}
}
return []byte(s), nil
}
// spend is a Sapling Spend Description as described in 7.3 of the Zcash
// protocol specification.
type spend struct {
//cv []byte // 32
//anchor []byte // 32
nullifier []byte // 32
//rk []byte // 32
//zkproof []byte // 192
//spendAuthSig []byte // 64
}
func (p *spend) ParseFromSlice(data []byte, version uint32) ([]byte, error) {
s := bytestring.String(data)
if !s.Skip(32) {
return nil, errors.New("could not skip cv")
}
if version <= 4 && !s.Skip(32) {
return nil, errors.New("could not skip anchor")
} }
if !s.ReadBytes(&p.nullifier, 32) { if !s.ReadBytes(&p.nullifier, 32) {
return nil, errors.New("could not read nullifier") return nil, errors.New("could not read nullifier")
} }
if !s.ReadBytes(&p.rk, 32) { if !s.Skip(32) {
return nil, errors.New("could not read rk") return nil, errors.New("could not skip rk")
} }
if !s.ReadBytes(&p.zkproof, 192) { if version <= 4 && !s.Skip(192) {
return nil, errors.New("could not read zkproof") return nil, errors.New("could not skip zkproof")
} }
if !s.ReadBytes(&p.spendAuthSig, 64) { if version <= 4 && !s.Skip(64) {
return nil, errors.New("could not read spendAuthSig") return nil, errors.New("could not skip spendAuthSig")
} }
return []byte(s), nil return []byte(s), nil
} }
func (p *spend) ToCompact() *walletrpc.CompactSpend { func (p *spend) ToCompact() *walletrpc.CompactSaplingSpend {
return &walletrpc.CompactSpend{ return &walletrpc.CompactSaplingSpend{
Nf: p.nullifier, Nf: p.nullifier,
} }
} }
// output is a Sapling Output Description as described in section 7.4 of the // output is a Sapling Output Description as described in section 7.4 of the
// Zcash protocol spec. Total size is 948. // Zcash protocol spec.
type output struct { type output struct {
cv []byte // 32 //cv []byte // 32
cmu []byte // 32 cmu []byte // 32
ephemeralKey []byte // 32 ephemeralKey []byte // 32
encCiphertext []byte // 580 encCiphertext []byte // 580
outCiphertext []byte // 80 //outCiphertext []byte // 80
zkproof []byte // 192 //zkproof []byte // 192
} }
func (p *output) ParseFromSlice(data []byte) ([]byte, error) { func (p *output) ParseFromSlice(data []byte, version uint32) ([]byte, error) {
s := bytestring.String(data) s := bytestring.String(data)
if !s.ReadBytes(&p.cv, 32) { if !s.Skip(32) {
return nil, errors.New("could not read cv") return nil, errors.New("could not skip cv")
} }
if !s.ReadBytes(&p.cmu, 32) { if !s.ReadBytes(&p.cmu, 32) {
@ -167,19 +201,19 @@ func (p *output) ParseFromSlice(data []byte) ([]byte, error) {
return nil, errors.New("could not read encCiphertext") return nil, errors.New("could not read encCiphertext")
} }
if !s.ReadBytes(&p.outCiphertext, 80) { if !s.Skip(80) {
return nil, errors.New("could not read outCiphertext") return nil, errors.New("could not skip outCiphertext")
} }
if !s.ReadBytes(&p.zkproof, 192) { if version <= 4 && !s.Skip(192) {
return nil, errors.New("could not read zkproof") return nil, errors.New("could not skip zkproof")
} }
return []byte(s), nil return []byte(s), nil
} }
func (p *output) ToCompact() *walletrpc.CompactOutput { func (p *output) ToCompact() *walletrpc.CompactSaplingOutput {
return &walletrpc.CompactOutput{ return &walletrpc.CompactSaplingOutput{
Cmu: p.cmu, Cmu: p.cmu,
Epk: p.ephemeralKey, Epk: p.ephemeralKey,
Ciphertext: p.encCiphertext[:52], Ciphertext: p.encCiphertext[:52],
@ -188,112 +222,139 @@ func (p *output) ToCompact() *walletrpc.CompactOutput {
// joinSplit is a JoinSplit description as described in 7.2 of the Zcash // joinSplit is a JoinSplit description as described in 7.2 of the Zcash
// protocol spec. Its exact contents differ by transaction version and network // protocol spec. Its exact contents differ by transaction version and network
// upgrade level. // upgrade level. Only version 4 is supported, no need for proofPHGR13.
type joinSplit struct { type joinSplit struct {
vpubOld uint64 //vpubOld uint64
vpubNew uint64 //vpubNew uint64
anchor []byte // 32 //anchor []byte // 32
nullifiers [2][]byte // 64 [N_old][32]byte //nullifiers [2][]byte // 64 [N_old][32]byte
commitments [2][]byte // 64 [N_new][32]byte //commitments [2][]byte // 64 [N_new][32]byte
ephemeralKey []byte // 32 //ephemeralKey []byte // 32
randomSeed []byte // 32 //randomSeed []byte // 32
vmacs [2][]byte // 64 [N_old][32]byte //vmacs [2][]byte // 64 [N_old][32]byte
proofPHGR13 []byte // 296 //proofGroth16 []byte // 192 (version 4 only)
proofGroth16 []byte // 192 //encCiphertexts [2][]byte // 1202 [N_new][601]byte
encCiphertexts [2][]byte // 1202 [N_new][601]byte
// not actually in the format, but needed for parsing
version uint32
} }
func (p *joinSplit) ParseFromSlice(data []byte) ([]byte, error) { func (p *joinSplit) ParseFromSlice(data []byte) ([]byte, error) {
s := bytestring.String(data) s := bytestring.String(data)
if !s.ReadUint64(&p.vpubOld) { if !s.Skip(8) {
return nil, errors.New("could not read vpubOld") return nil, errors.New("could not skip vpubOld")
} }
if !s.ReadUint64(&p.vpubNew) { if !s.Skip(8) {
return nil, errors.New("could not read vpubNew") return nil, errors.New("could not skip vpubNew")
} }
if !s.ReadBytes(&p.anchor, 32) { if !s.Skip(32) {
return nil, errors.New("could not read anchor") return nil, errors.New("could not skip anchor")
} }
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
if !s.ReadBytes(&p.nullifiers[i], 32) { if !s.Skip(32) {
return nil, errors.New("could not read a nullifier") return nil, errors.New("could not skip a nullifier")
} }
} }
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
if !s.ReadBytes(&p.commitments[i], 32) { if !s.Skip(32) {
return nil, errors.New("could not read a commitment") return nil, errors.New("could not skip a commitment")
} }
} }
if !s.ReadBytes(&p.ephemeralKey, 32) { if !s.Skip(32) {
return nil, errors.New("could not read ephemeralKey") return nil, errors.New("could not skip ephemeralKey")
} }
if !s.ReadBytes(&p.randomSeed, 32) { if !s.Skip(32) {
return nil, errors.New("could not read randomSeed") return nil, errors.New("could not skip randomSeed")
} }
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
if !s.ReadBytes(&p.vmacs[i], 32) { if !s.Skip(32) {
return nil, errors.New("could not read a vmac") return nil, errors.New("could not skip a vmac")
} }
} }
if p.version == 2 || p.version == 3 { if !s.Skip(192) {
if !s.ReadBytes(&p.proofPHGR13, 296) { return nil, errors.New("could not skip Groth16 proof")
return nil, errors.New("could not read PHGR13 proof")
}
} else if p.version >= 4 {
if !s.ReadBytes(&p.proofGroth16, 192) {
return nil, errors.New("could not read Groth16 proof")
}
} else {
return nil, errors.New("unexpected transaction version")
} }
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
if !s.ReadBytes(&p.encCiphertexts[i], 601) { if !s.Skip(601) {
return nil, errors.New("could not read an encCiphertext") return nil, errors.New("could not skip an encCiphertext")
} }
} }
return []byte(s), nil return []byte(s), nil
} }
type action struct {
//cv []byte // 32
nullifier []byte // 32
//rk []byte // 32
cmx []byte // 32
ephemeralKey []byte // 32
encCiphertext []byte // 580
//outCiphertext []byte // 80
}
func (a *action) ParseFromSlice(data []byte) ([]byte, error) {
s := bytestring.String(data)
if !s.Skip(32) {
return nil, errors.New("could not read action cv")
}
if !s.ReadBytes(&a.nullifier, 32) {
return nil, errors.New("could not read action nullifier")
}
if !s.Skip(32) {
return nil, errors.New("could not read action rk")
}
if !s.ReadBytes(&a.cmx, 32) {
return nil, errors.New("could not read action cmx")
}
if !s.ReadBytes(&a.ephemeralKey, 32) {
return nil, errors.New("could not read action ephemeralKey")
}
if !s.ReadBytes(&a.encCiphertext, 580) {
return nil, errors.New("could not read action encCiphertext")
}
if !s.Skip(80) {
return nil, errors.New("could not read action outCiphertext")
}
return []byte(s), nil
}
func (p *action) ToCompact() *walletrpc.CompactOrchardAction {
return &walletrpc.CompactOrchardAction{
Nullifier: p.nullifier,
Cmx: p.cmx,
EphemeralKey: p.ephemeralKey,
Ciphertext: p.encCiphertext[:52],
}
}
// Transaction encodes a full (zcashd) transaction. // Transaction encodes a full (zcashd) transaction.
type Transaction struct { type Transaction struct {
*rawTransaction *rawTransaction
rawBytes []byte rawBytes []byte
cachedTxID []byte // cached for performance txID []byte // from getblock verbose=1
}
func (tx *Transaction) SetTxID(txid []byte) {
tx.txID = txid
} }
// GetDisplayHash returns the transaction hash in big-endian display order. // GetDisplayHash returns the transaction hash in big-endian display order.
func (tx *Transaction) GetDisplayHash() []byte { func (tx *Transaction) GetDisplayHash() []byte {
if tx.cachedTxID != nil {
return tx.cachedTxID
}
// SHA256d
digest := sha256.Sum256(tx.rawBytes)
digest = sha256.Sum256(digest[:])
// Convert to big-endian // Convert to big-endian
tx.cachedTxID = Reverse(digest[:]) return Reverse(tx.txID[:])
return tx.cachedTxID
} }
// GetEncodableHash returns the transaction hash in little-endian wire format order. // GetEncodableHash returns the transaction hash in little-endian wire format order.
func (tx *Transaction) GetEncodableHash() []byte { func (tx *Transaction) GetEncodableHash() []byte {
digest := sha256.Sum256(tx.rawBytes) return tx.txID
digest = sha256.Sum256(digest[:])
return digest[:]
} }
// Bytes returns a full transaction's raw bytes. // Bytes returns a full transaction's raw bytes.
@ -301,10 +362,11 @@ func (tx *Transaction) Bytes() []byte {
return tx.rawBytes return tx.rawBytes
} }
// HasSaplingElements indicates whether a transaction has // HasShieldedElements indicates whether a transaction has
// at least one shielded input or output. // at least one shielded input or output.
func (tx *Transaction) HasSaplingElements() bool { func (tx *Transaction) HasShieldedElements() bool {
return tx.version >= 4 && (len(tx.shieldedSpends)+len(tx.shieldedOutputs)) > 0 nshielded := len(tx.shieldedSpends) + len(tx.shieldedOutputs) + len(tx.orchardActions)
return tx.version >= 4 && nshielded > 0
} }
// ToCompact converts the given (full) transaction to compact format. // ToCompact converts the given (full) transaction to compact format.
@ -313,8 +375,9 @@ func (tx *Transaction) ToCompact(index int) *walletrpc.CompactTx {
Index: uint64(index), // index is contextual Index: uint64(index), // index is contextual
Hash: tx.GetEncodableHash(), Hash: tx.GetEncodableHash(),
//Fee: 0, // TODO: calculate fees //Fee: 0, // TODO: calculate fees
Spends: make([]*walletrpc.CompactSpend, len(tx.shieldedSpends)), Spends: make([]*walletrpc.CompactSaplingSpend, len(tx.shieldedSpends)),
Outputs: make([]*walletrpc.CompactOutput, len(tx.shieldedOutputs)), Outputs: make([]*walletrpc.CompactSaplingOutput, len(tx.shieldedOutputs)),
Actions: make([]*walletrpc.CompactOrchardAction, len(tx.orchardActions)),
} }
for i, spend := range tx.shieldedSpends { for i, spend := range tx.shieldedSpends {
ctx.Spends[i] = spend.ToCompact() ctx.Spends[i] = spend.ToCompact()
@ -322,9 +385,197 @@ func (tx *Transaction) ToCompact(index int) *walletrpc.CompactTx {
for i, output := range tx.shieldedOutputs { for i, output := range tx.shieldedOutputs {
ctx.Outputs[i] = output.ToCompact() ctx.Outputs[i] = output.ToCompact()
} }
for i, a := range tx.orchardActions {
ctx.Actions[i] = a.ToCompact()
}
return ctx return ctx
} }
// parse version 4 transaction data after the nVersionGroupId field.
func (tx *Transaction) parseV4(data []byte) ([]byte, error) {
s := bytestring.String(data)
var err error
if tx.nVersionGroupID != 0x892F2085 {
return nil, errors.New(fmt.Sprintf("version group ID %x must be 0x892F2085", tx.nVersionGroupID))
}
s, err = tx.ParseTransparent([]byte(s))
if err != nil {
return nil, err
}
if !s.Skip(4) {
return nil, errors.New("could not skip nLockTime")
}
if !s.Skip(4) {
return nil, errors.New("could not skip nExpiryHeight")
}
var spendCount, outputCount int
if !s.Skip(8) {
return nil, errors.New("could not skip valueBalance")
}
if !s.ReadCompactSize(&spendCount) {
return nil, errors.New("could not read nShieldedSpend")
}
tx.shieldedSpends = make([]spend, spendCount)
for i := 0; i < spendCount; i++ {
newSpend := &tx.shieldedSpends[i]
s, err = newSpend.ParseFromSlice([]byte(s), 4)
if err != nil {
return nil, errors.Wrap(err, "while parsing shielded Spend")
}
}
if !s.ReadCompactSize(&outputCount) {
return nil, errors.New("could not read nShieldedOutput")
}
tx.shieldedOutputs = make([]output, outputCount)
for i := 0; i < outputCount; i++ {
newOutput := &tx.shieldedOutputs[i]
s, err = newOutput.ParseFromSlice([]byte(s), 4)
if err != nil {
return nil, errors.Wrap(err, "while parsing shielded Output")
}
}
var joinSplitCount int
if !s.ReadCompactSize(&joinSplitCount) {
return nil, errors.New("could not read nJoinSplit")
}
tx.joinSplits = make([]joinSplit, joinSplitCount)
if joinSplitCount > 0 {
for i := 0; i < joinSplitCount; i++ {
js := &tx.joinSplits[i]
s, err = js.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing JoinSplit")
}
}
if !s.Skip(32) {
return nil, errors.New("could not skip joinSplitPubKey")
}
if !s.Skip(64) {
return nil, errors.New("could not skip joinSplitSig")
}
}
if spendCount+outputCount > 0 && !s.Skip(64) {
return nil, errors.New("could not skip bindingSigSapling")
}
return s, nil
}
// parse version 5 transaction data after the nVersionGroupId field.
func (tx *Transaction) parseV5(data []byte) ([]byte, error) {
s := bytestring.String(data)
var err error
if !s.ReadUint32(&tx.consensusBranchID) {
return nil, errors.New("could not read nVersionGroupId")
}
if tx.nVersionGroupID != 0x26A7270A {
return nil, errors.New(fmt.Sprintf("version group ID %d must be 0x26A7270A", tx.nVersionGroupID))
}
if !s.Skip(4) {
return nil, errors.New("could not skip nLockTime")
}
if !s.Skip(4) {
return nil, errors.New("could not skip nExpiryHeight")
}
s, err = tx.ParseTransparent([]byte(s))
if err != nil {
return nil, err
}
var spendCount, outputCount int
if !s.ReadCompactSize(&spendCount) {
return nil, errors.New("could not read nShieldedSpend")
}
if spendCount >= (1 << 16) {
return nil, errors.New(fmt.Sprintf("spentCount (%d) must be less than 2^16", spendCount))
}
tx.shieldedSpends = make([]spend, spendCount)
for i := 0; i < spendCount; i++ {
newSpend := &tx.shieldedSpends[i]
s, err = newSpend.ParseFromSlice([]byte(s), tx.version)
if err != nil {
return nil, errors.Wrap(err, "while parsing shielded Spend")
}
}
if !s.ReadCompactSize(&outputCount) {
return nil, errors.New("could not read nShieldedOutput")
}
if outputCount >= (1 << 16) {
return nil, errors.New(fmt.Sprintf("outputCount (%d) must be less than 2^16", outputCount))
}
tx.shieldedOutputs = make([]output, outputCount)
for i := 0; i < outputCount; i++ {
newOutput := &tx.shieldedOutputs[i]
s, err = newOutput.ParseFromSlice([]byte(s), tx.version)
if err != nil {
return nil, errors.Wrap(err, "while parsing shielded Output")
}
}
if spendCount+outputCount > 0 && !s.Skip(8) {
return nil, errors.New("could not read valueBalance")
}
if spendCount > 0 && !s.Skip(32) {
return nil, errors.New("could not skip anchorSapling")
}
if !s.Skip(192 * spendCount) {
return nil, errors.New("could not skip vSpendProofsSapling")
}
if !s.Skip(64 * spendCount) {
return nil, errors.New("could not skip vSpendAuthSigsSapling")
}
if !s.Skip(192 * outputCount) {
return nil, errors.New("could not skip vOutputProofsSapling")
}
if spendCount+outputCount > 0 && !s.Skip(64) {
return nil, errors.New("could not skip bindingSigSapling")
}
var actionsCount int
if !s.ReadCompactSize(&actionsCount) {
return nil, errors.New("could not read nActionsOrchard")
}
if actionsCount >= (1 << 16) {
return nil, errors.New(fmt.Sprintf("actionsCount (%d) must be less than 2^16", actionsCount))
}
tx.orchardActions = make([]action, actionsCount)
for i := 0; i < actionsCount; i++ {
a := &tx.orchardActions[i]
s, err = a.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing orchard action")
}
}
if actionsCount > 0 {
if !s.Skip(1) {
return nil, errors.New("could not skip flagsOrchard")
}
if !s.Skip(8) {
return nil, errors.New("could not skip valueBalanceOrchard")
}
if !s.Skip(32) {
return nil, errors.New("could not skip anchorOrchard")
}
var proofsCount int
if !s.ReadCompactSize(&proofsCount) {
return nil, errors.New("could not read sizeProofsOrchard")
}
if !s.Skip(proofsCount) {
return nil, errors.New("could not skip proofsOrchard")
}
if !s.Skip(64 * actionsCount) {
return nil, errors.New("could not skip vSpendAuthSigsOrchard")
}
if !s.Skip(64) {
return nil, errors.New("could not skip bindingSigOrchard")
}
}
return s, nil
}
// ParseFromSlice deserializes a single transaction from the given data. // ParseFromSlice deserializes a single transaction from the given data.
func (tx *Transaction) ParseFromSlice(data []byte) ([]byte, error) { func (tx *Transaction) ParseFromSlice(data []byte) ([]byte, error) {
s := bytestring.String(data) s := bytestring.String(data)
@ -338,135 +589,26 @@ func (tx *Transaction) ParseFromSlice(data []byte) ([]byte, error) {
} }
tx.fOverwintered = (header >> 31) == 1 tx.fOverwintered = (header >> 31) == 1
if !tx.fOverwintered {
return nil, errors.New("fOverwinter flag must be set")
}
tx.version = header & 0x7FFFFFFF tx.version = header & 0x7FFFFFFF
if tx.version < 4 {
if tx.version >= 3 { return nil, errors.New(fmt.Sprintf("version number %d must be greater or equal to 4", tx.version))
if !s.ReadUint32(&tx.nVersionGroupID) {
return nil, errors.New("could not read nVersionGroupId")
}
} }
var txInCount int if !s.ReadUint32(&tx.nVersionGroupID) {
if !s.ReadCompactSize(&txInCount) { return nil, errors.New("could not read nVersionGroupId")
return nil, errors.New("could not read tx_in_count")
} }
// parse the main part of the transaction
// TODO: Duplicate/otherwise-too-many transactions are a possible DoS if tx.version <= 4 {
// TODO: vector. At the moment we're assuming trusted input. s, err = tx.parseV4([]byte(s))
// See https://nvd.nist.gov/vuln/detail/CVE-2018-17144 for an example. } else {
s, err = tx.parseV5([]byte(s))
if txInCount > 0 {
tx.transparentInputs = make([]*txIn, txInCount)
for i := 0; i < txInCount; i++ {
ti := &txIn{}
s, err = ti.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing transparent input")
}
tx.transparentInputs[i] = ti
}
} }
if err != nil {
var txOutCount int return nil, err
if !s.ReadCompactSize(&txOutCount) {
return nil, errors.New("could not read tx_out_count")
} }
if txOutCount > 0 {
tx.transparentOutputs = make([]*txOut, txOutCount)
for i := 0; i < txOutCount; i++ {
to := &txOut{}
s, err = to.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing transparent output")
}
tx.transparentOutputs[i] = to
}
}
if !s.ReadUint32(&tx.nLockTime) {
return nil, errors.New("could not read nLockTime")
}
if tx.fOverwintered {
if !s.ReadUint32(&tx.nExpiryHeight) {
return nil, errors.New("could not read nExpiryHeight")
}
}
var spendCount, outputCount int
if tx.version >= 4 {
if !s.ReadInt64(&tx.valueBalance) {
return nil, errors.New("could not read valueBalance")
}
if !s.ReadCompactSize(&spendCount) {
return nil, errors.New("could not read nShieldedSpend")
}
if spendCount > 0 {
tx.shieldedSpends = make([]*spend, spendCount)
for i := 0; i < spendCount; i++ {
newSpend := &spend{}
s, err = newSpend.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing shielded Spend")
}
tx.shieldedSpends[i] = newSpend
}
}
if !s.ReadCompactSize(&outputCount) {
return nil, errors.New("could not read nShieldedOutput")
}
if outputCount > 0 {
tx.shieldedOutputs = make([]*output, outputCount)
for i := 0; i < outputCount; i++ {
newOutput := &output{}
s, err = newOutput.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing shielded Output")
}
tx.shieldedOutputs[i] = newOutput
}
}
}
if tx.version >= 2 {
var joinSplitCount int
if !s.ReadCompactSize(&joinSplitCount) {
return nil, errors.New("could not read nJoinSplit")
}
if joinSplitCount > 0 {
tx.joinSplits = make([]*joinSplit, joinSplitCount)
for i := 0; i < joinSplitCount; i++ {
js := &joinSplit{version: tx.version}
s, err = js.ParseFromSlice([]byte(s))
if err != nil {
return nil, errors.Wrap(err, "while parsing JoinSplit")
}
tx.joinSplits[i] = js
}
if !s.ReadBytes(&tx.joinSplitPubKey, 32) {
return nil, errors.New("could not read joinSplitPubKey")
}
if !s.ReadBytes(&tx.joinSplitSig, 64) {
return nil, errors.New("could not read joinSplitSig")
}
}
}
if tx.version >= 4 && (spendCount+outputCount > 0) {
if !s.ReadBytes(&tx.bindingSig, 64) {
return nil, errors.New("could not read bindingSig")
}
}
// TODO: implement rawBytes with MarshalBinary() instead // TODO: implement rawBytes with MarshalBinary() instead
txLen := len(data) - len(s) txLen := len(data) - len(s)
tx.rawBytes = data[:txLen] tx.rawBytes = data[:txLen]

View File

@ -4,880 +4,112 @@
package parser package parser
import ( import (
"bufio"
"bytes"
"encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json"
"os" "os"
"strings"
"testing" "testing"
"github.com/adityapk00/lightwalletd/parser/internal/bytestring"
) )
// "Human-readable" version of joinSplit struct defined in transaction.go. // Some of these values may be "null" (which translates to nil in Go) in
// Remember to update this if the format ever changes. // the test data, so we have *_set variables to indicate if the corresponding
type joinSplitTestVector struct { // variable is non-null. (There is an "optional" package we could use for
vpubOld uint64 // these but it doesn't seem worth pulling it in.)
vpubNew uint64 type TxTestData struct {
anchor string // 32 Tx string
nullifiers []string // 64 [N_old][32]byte Txid string
commitments []string // 64 [N_new][32]byte Version int
ephemeralKey string // 32 NVersionGroupId int
randomSeed string // 32 NConsensusBranchId int
vmacs []string // 64 [N_old][32]byte Tx_in_count int
proofPHGR13 string // 296 Tx_out_count int
proofGroth16 string // 192 NSpendsSapling int
encCiphertexts []string // 1202 [N_new][601]byte NoutputsSapling int
NActionsOrchard int
} }
type spendTestVector struct { // https://jhall.io/posts/go-json-tricks-array-as-structs/
cv string // 32 func (r *TxTestData) UnmarshalJSON(p []byte) error {
anchor string // 32 var t []interface{}
nullifier string // 32 if err := json.Unmarshal(p, &t); err != nil {
rk string // 32 return err
zkproof string // 192 }
spendAuthSig string // 64 r.Tx = t[0].(string)
r.Txid = t[1].(string)
r.Version = int(t[2].(float64))
r.NVersionGroupId = int(t[3].(float64))
r.NConsensusBranchId = int(t[4].(float64))
r.Tx_in_count = int(t[7].(float64))
r.Tx_out_count = int(t[8].(float64))
r.NSpendsSapling = int(t[9].(float64))
r.NoutputsSapling = int(t[10].(float64))
r.NActionsOrchard = int(t[14].(float64))
return nil
} }
type outputTestVector struct { func TestV5TransactionParser(t *testing.T) {
cv string // 32
cmu string // 32
ephemeralKey string // 32
encCiphertext string // 580
outCiphertext string // 80
zkproof string // 192
}
type txTestVector struct {
// Sprout and Sapling
txid, header, nVersionGroupID, nLockTime, nExpiryHeight string
vin, vout [][]string
vJoinSplits []joinSplitTestVector
joinSplitPubKey, joinSplitSig string
// Sapling-only
valueBalance string // encoded int64
spends []spendTestVector
outputs []outputTestVector
bindingSig string
}
// https://github.com/zcash/zips/blob/master/zip-0143.rst
var zip143tests = []txTestVector{
{
// Test vector 1
txid: "f0b22277ac851b5f4df590fe6a128aad9d0ce8063235eb2b328c2dc6a23c1ec5",
header: "03000080",
nVersionGroupID: "7082c403",
nLockTime: "481cdd86",
nExpiryHeight: "b3cc4318",
vin: nil,
vout: [][]string{
{"8f739811893e0000", "095200ac6551ac636565"},
{"b1a45a0805750200", "025151"},
},
},
{
// Test vector 2
//raw: "we have some raw data for this tx, which this comment is too small to contain",
txid: "39fe585a56b005f568c3171d22afa916e946e2a8aff5971d58ee8a6fc1482059",
header: "03000080",
nVersionGroupID: "7082c403",
nLockTime: "97b0e4e4",
nExpiryHeight: "c705fc05",
vin: [][]string{
{"4201cfb1cd8dbf69b8250c18ef41294ca97993db546c1fe01f7e9c8e36d6a5e2", "9d4e30a7", "03ac6a00", "98421c69"},
{"378af1e40f64e125946f62c2fa7b2fecbcb64b6968912a6381ce3dc166d56a1d", "62f5a8d7", "056363635353", "e8c7203d"},
},
vout: [][]string{
{"6af786387ae60100", "080063656a63ac5200"},
{"23752997f4ff0400", "0751510053536565"},
},
vJoinSplits: []joinSplitTestVector{
{
vpubOld: uint64(0),
vpubNew: uint64(0),
anchor: "76495c222f7fba1e31defa3d5a57efc2e1e9b01a035587d5fb1a38e01d94903d",
nullifiers: []string{
"3c3e0ad3360c1d3710acd20b183e31d49f25c9a138f49b1a537edcf04be34a98",
"51a7af9db6990ed83dd64af3597c04323ea51b0052ad8084a8b9da948d320dad",
},
commitments: []string{
"d64f5431e61ddf658d24ae67c22c8d1309131fc00fe7f235734276d38d47f1e1",
"91e00c7a1d48af046827591e9733a97fa6b679f3dc601d008285edcbdae69ce8",
},
ephemeralKey: "fc1be4aac00ff2711ebd931de518856878f73476f21a482ec9378365c8f7393c",
randomSeed: "94e2885315eb4671098b79535e790fe53e29fef2b3766697ac32b4f473f468a0",
vmacs: []string{
"08e72389fc03880d780cb07fcfaabe3f1a84b27db59a4a153d882d2b21035965",
"55ed9494c6ac893c49723833ec8926c1039586a7afcf4a0d9c731e985d99589c",
},
proofPHGR13: "03b838e8aaf745533ed9e8ae3a1cd074a51a20da8aba18d1dbebbc862ded42435e02476930d069896cff30eb414f727b89e001afa2fb8dc3436d75a4a6f26572504b0b2232ecb9f0c02411e52596bc5e90457e745939ffedbd12863ce71a02af117d417adb3d15cc54dcb1fce467500c6b8fb86b12b56da9c382857deecc40a98d5f2903395ee4762dd21afdbb5d47fa9a6dd984d567db2857b927b7fae2db587105415d0242789d38f50b8dbcc129cab3d17d19f3355bcf73cecb8cb8a5da01307152f13902a270572670dc82d39026c6cb4cd4b0f7f5aa2a4f5a5341ec5dd715406f2fdd2a02733f5f641c8c21862a1bafce2609d9eecfa158cfb5cd79f88008e315dc7d8388036c1782fd2795d18a763624c25fa959cc97489ce75745824b77868c53239cfbdf",
encCiphertexts: []string{
"73caec65604037314faaceb56218c6bd30f8374ac13386793f21a9fb80ad03bc0cda4a44946c00e1b1a1df0e5b87b5bece477a709649e950060591394812951e1fe3895b8cc3d14d2cf6556df6ed4b4ddd3d9a69f53357d7767f4f5ccbdbc596631277f8fecd08cb056b95e3025b9792fff7f244fc716269b926d62e9596fa825c6bf21aff9e68625a192440ea06828123d97884806f15fa08da52754a1095e3ff1abd5ce4fddfccfc3a6128aef784a64610a89d1a7099216d0814d3a2d452431c32d411ac1cce82ad0229407bbc48985675e3f874a4533f1d63a84dfa3e0f460fe2f57e34fbc75423c3737f5b2a0615f5722db041a3ef66fa483afd3c2e19e59444a64add6df1d963f5dd5b5010d3d025f0287c4cf19c75f33d51ddddba5d657b43ee8da645443814cc7329f3e9b4e54c236c29af3923101756d9fa4bd0f7d2ddaacb6b0f86a2658e0a07a05ac5b950051cd24c47a88d13d659ba2a46ca1830816d09cd7646f76f716abec5de07fe9b523410806ea6f288f8736c23357c85f45791e1708029d9824d90704607f387a03e49bf9836574431345a7877efaa8a08e73081ef8d62cb780ab6883a50a0d470190dfba10a857f82842d3825b3d6da0573d316eb160dc0b716c48fbd467f75b780149ae8808f4e68f50c0536acddf6f1aeab016b6bc1ec144b4e553acfd670f77e755fc88e0677e31ba459b44e307768958fe3789d41c2b1ff434cb30e15914f01bc6bc2307b488d2556d7b7380ea4ffd712f6b02fe806b94569cd4059f396bf29b99d0a40e5e1711ca944f72d436a102fca4b97693da0b086fe9d2e7162470d02e0f05d4bec9512bf",
"b3f38327296efaa74328b118c27402c70c3a90b49ad4bbc68e37c0aa7d9b3fe17799d73b841e751713a02943905aae0803fd69442eb7681ec2a05600054e92eed555028f21b6a155268a2dd6640a69301a52a38d4d9f9f957ae35af7167118141ce4c9be0a6a492fe79f1581a155fa3a2b9dafd82e650b386ad3a08cb6b83131ac300b0846354a7eef9c410e4b62c47c5426907dfc6685c5c99b7141ac626ab4761fd3f41e728e1a28f89db89ffdeca364dd2f0f0739f0534556483199c71f189341ac9b78a269164206a0ea1ce73bfb2a942e7370b247c046f8e75ef8e3f8bd821cf577491864e20e6d08fd2e32b555c92c661f19588b72a89599710a88061253ca285b6304b37da2b5294f5cb354a894322848ccbdc7c2545b7da568afac87ffa005c312241c2d57f4b45d6419f0d2e2c5af33ae243785b325cdab95404fc7aed70525cddb41872cfcc214b13232edc78609753dbff930eb0dc156612b9cb434bc4b693392deb87c530435312edcedc6a961133338d786c4a3e103f60110a16b1337129704bf4754ff6ba9fbe65951e610620f71cda8fc877625f2c5bb04cbe1228b1e886f4050afd8fe94e97d2e9e85c6bb748c0042d3249abb1342bb0eebf62058bf3de080d94611a3750915b5dc6c0b3899d41222bace760ee9c8818ded599e34c56d7372af1eb86852f2a732104bdb750739de6c2c6e0f9eb7cb17f1942bfc9f4fd6ebb6b4cdd4da2bca26fac4578e9f543405acc7d86ff59158bd0cba3aef6f4a8472d144d99f8b8d1dedaa9077d4f01d4bb27bbe31d88fbefac3dcd4797563a26b1d61fcd9a464ab21ed550fe6fa09695ba0b2f10e",
},
},
{
vpubOld: uint64(0),
vpubNew: uint64(0),
anchor: "ea6468cc6e20a66f826e3d14c5006f0563887f5e1289be1b2004caca8d3f34d6",
nullifiers: []string{
"e84bf59c1e04619a7c23a996941d889e4622a9b9b1d59d5e319094318cd405ba",
"27b7e2c084762d31453ec4549a4d97729d033460fcf89d6494f2ffd789e98082",
},
commitments: []string{
"ea5ce9534b3acd60fe49e37e4f666931677319ed89f85588741b3128901a93bd",
"78e4be0225a9e2692c77c969ed0176bdf9555948cbd5a332d045de6ba6bf4490",
},
ephemeralKey: "adfe7444cd467a09075417fcc0062e49f008c51ad4227439c1b4476ccd8e9786",
randomSeed: "2dab7be1e8d399c05ef27c6e22ee273e15786e394c8f1be31682a30147963ac8",
vmacs: []string{
"da8d41d804258426a3f70289b8ad19d8de13be4eebe3bd4c8a6f55d6e0c373d4",
"56851879f5fbc282db9e134806bff71e11bc33ab75dd6ca067fb73a043b646a7",
},
proofPHGR13: "0339cab4928386786d2f24141ee120fdc34d6764eafc66880ee0204f53cc1167ed02b43a52dea3ca7cff8ef35cd8e6d7c111a68ef44bcd0c1513ad47ca61c659cc5d0a5b440f6b9f59aff66879bb6688fd2859362b182f207b3175961f6411a493bffd048e7d0d87d82fe6f990a2b0a25f5aa0111a6e68f37bf6f3ac2d26b84686e569038d99c1383597fad81193c4c1b16e6a90e2d507cdfe6fbdaa86163e9cf5de310003ca7e8da047b090db9f37952fbfee76af61668190bd52ed490e677b515d0143840307219c7c0ee7fc7bfc79f325644e4df4c0d7db08e9f0bd024943c705abff899403a605cfbc7ed746a7d3f7c37d9e8bdc433b7d79e08a12f738a8f0dbddfef2f26502f3e47d1b0fd11e6a13311fb799c79c641d9da43b33e7ad012e28255398789262",
encCiphertexts: []string{
"275f1175be8462c01491c4d842406d0ec4282c9526174a09878fe8fdde33a29604e5e5e7b2a025d6650b97dbb52befb59b1d30a57433b0a351474444099daa371046613260cf3354cfcdada663ece824ffd7e44393886a86165ddddf2b4c41773554c86995269408b11e6737a4c447586f69173446d8e48bf84cbc000a807899973eb93c5e819aad669413f8387933ad1584aa35e43f4ecd1e2d0407c0b1b89920ffdfdb9bea51ac95b557af71b89f903f5d9848f14fcbeb1837570f544d6359eb23faf38a0822da36ce426c4a2fbeffeb0a8a2e297a9d19ba15024590e3329d9fa9261f9938a4032dd34606c9cf9f3dd33e576f05cd1dd6811c6298757d77d9e810abdb226afcaa4346a6560f8932b3181fd355d5d391976183f8d99388839632d6354f666d09d3e5629ea19737388613d38a34fd0f6e50ee5a0cc9677177f50028c141378187bd2819403fc534f80076e9380cb4964d3b6b45819d3b8e9caf54f051852d671bf8c1ffde2d1510756418cb4810936aa57e6965d6fb656a760b7f19adf96c173488552193b147ee58858033dac7cd0eb204c06490bbdedf5f7571acb2ebe76acef3f2a01ee987486dfe6c3f0a5e234c127258f97a28fb5d164a8176be946b8097d0e317287f33bf9c16f9a545409ce29b1f4273725fc0df02a04ebae178b3414fb0a82d50deb09fcf4e6ee9d180ff4f56ff3bc1d3601fc2dc90d814c3256f4967d3a8d64c83fea339c51f5a8e5801fbb97835581b602465dee04b5922c2761b54245bec0c9eef2db97d22b2b3556cc969fbb13d06509765a52b3fac54b93f421bf08e18d52ddd52cc1c8ca8adfaccab7e5cc2",
"f4573fbbf8239bb0b8aedbf8dad16282da5c9125dba1c059d0df8abf621078f02d6c4bc86d40845ac1d59710c45f07d585eb48b32fc0167ba256e73ca3b9311c62d109497957d8dbe10aa3e866b40c0baa2bc492c19ad1e6372d9622bf163fbffeaeee796a3cd9b6fbbfa4d792f34d7fd6e763cd5859dd26833d21d9bc5452bd19515dff9f4995b35bc0c1f876e6ad11f2452dc9ae85aec01fc56f8cbfda75a7727b75ebbd6bbffb43b63a3b1b671e40feb0db002974a3c3b1a788567231bf6399ff89236981149d423802d2341a3bedb9ddcbac1fe7b6435e1479c72e7089d029e7fbbaf3cf37e9b9a6b776791e4c5e6fda57e8d5f14c8c35a2d270846b9dbe005cda16af4408f3ab06a916eeeb9c9594b70424a4c1d171295b6763b22f47f80b53ccbb904bd68fd65fbd3fbdea1035e98c21a7dbc91a9b5bc7690f05ec317c97f8764eb48e911d428ec8d861b708e8298acb62155145155ae95f0a1d1501034753146e22d05f586d7f6b4fe12dad9a17f5db70b1db96b8d9a83edadc966c8a5466b61fc998c31f1070d9a5c9a6d268d304fe6b8fd3b4010348611abdcbd49fe4f85b623c7828c71382e1034ea67bc8ae97404b0c50b2a04f559e49950afcb0ef462a2ae024b0f0224dfd73684b88c7fbe92d02b68f759c4752663cd7b97a14943649305521326bde085630864629291bae25ff8822a14c4b666a9259ad0dc42a8290ac7bc7f53a16f379f758e5de750f04fd7cad47701c8597f97888bea6fa0bf2999956fbfd0ee68ec36e4688809ae231eb8bc4369f5fe1573f57e099d9c09901bf39caac48dc11956a8ae905ead86954547c448ae43d31",
},
},
},
joinSplitPubKey: "5e669c4242da565938f417bf43ce7b2b30b1cd4018388e1a910f0fc41fb0877a",
// This joinSplitSig is (intentionally) invalid random data.
joinSplitSig: "5925e466819d375b0a912d4fe843b76ef6f223f0f7c894f38f7ab780dfd75f669c8c06cffa43eb47565a50e3b1fa45ad61ce9a1c4727b7aaa53562f523e73952",
},
}
func TestSproutTransactionParser(t *testing.T) {
// The raw data are stored in a separate file because they're large enough // The raw data are stored in a separate file because they're large enough
// to make the test table difficult to scroll through. They are in the same // to make the test table difficult to scroll through. They are in the same
// order as the test table above. If you update the test table without // order as the test table above. If you update the test table without
// adding a line to the raw file, this test will panic due to index // adding a line to the raw file, this test will panic due to index
// misalignment. // misalignment.
testData, err := os.Open("../testdata/zip143_raw_tx") s, err := os.ReadFile("../testdata/tx_v5.json")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer testData.Close()
// Parse the raw transactions file var testdata []json.RawMessage
rawTxData := [][]byte{} err = json.Unmarshal(s, &testdata)
scan := bufio.NewScanner(testData)
for scan.Scan() {
dataLine := scan.Text()
// Skip the comments
if strings.HasPrefix(dataLine, "#") {
continue
}
txData, err := hex.DecodeString(dataLine)
if err != nil {
t.Fatal(err)
}
rawTxData = append(rawTxData, txData)
}
for i, tt := range zip143tests {
tx := NewTransaction()
rest, err := tx.ParseFromSlice(rawTxData[i])
if err != nil {
t.Errorf("Test %d: %v", i, err)
continue
}
if len(rest) != 0 {
t.Errorf("Test %d: did not consume entire buffer", i)
continue
}
// Transaction metadata
if !subTestCommonBlockMeta(&tt, tx, t, i) {
continue
}
// Transparent inputs and outputs
if !subTestTransparentInputs(tt.vin, tx.transparentInputs, t, i) {
continue
}
if !subTestTransparentOutputs(tt.vout, tx.transparentOutputs, t, i) {
continue
}
// JoinSplits
if !subTestJoinSplits(tt.vJoinSplits, tx.joinSplits, t, i) {
continue
}
testJSPubKey, _ := hex.DecodeString(tt.joinSplitPubKey)
if !bytes.Equal(testJSPubKey, tx.joinSplitPubKey) {
t.Errorf("Test %d: jsPubKey mismatch %x %x", i, testJSPubKey, tx.joinSplitPubKey)
continue
}
testJSSig, _ := hex.DecodeString(tt.joinSplitSig)
if !bytes.Equal(testJSSig, tx.joinSplitSig) {
t.Errorf("Test %d: jsSig mismatch %x %x", i, testJSSig, tx.joinSplitSig)
continue
}
if hex.EncodeToString(tx.GetDisplayHash()) != tt.txid {
t.Errorf("Test %d: incorrect txid", i)
}
}
}
func subTestCommonBlockMeta(tt *txTestVector, tx *Transaction, t *testing.T, caseNum int) bool {
headerBytes, _ := hex.DecodeString(tt.header)
header := binary.LittleEndian.Uint32(headerBytes)
if (header >> 31) == 1 != tx.fOverwintered {
t.Errorf("Test %d: unexpected fOverwintered", caseNum)
return false
}
if (header & 0x7FFFFFFF) != tx.version {
t.Errorf("Test %d: unexpected tx version", caseNum)
return false
}
versionGroupBytes, _ := hex.DecodeString(tt.nVersionGroupID)
versionGroup := binary.LittleEndian.Uint32(versionGroupBytes)
if versionGroup != tx.nVersionGroupID {
t.Errorf("Test %d: unexpected versionGroupId", caseNum)
return false
}
lockTimeBytes, _ := hex.DecodeString(tt.nLockTime)
lockTime := binary.LittleEndian.Uint32(lockTimeBytes)
if lockTime != tx.nLockTime {
t.Errorf("Test %d: unexpected nLockTime", caseNum)
return false
}
expiryHeightBytes, _ := hex.DecodeString(tt.nExpiryHeight)
expiryHeight := binary.LittleEndian.Uint32(expiryHeightBytes)
if expiryHeight != tx.nExpiryHeight {
t.Errorf("Test %d: unexpected nExpiryHeight", caseNum)
return false
}
return true
}
func subTestJoinSplits(testJoinSplits []joinSplitTestVector, txJoinSplits []*joinSplit, t *testing.T, caseNum int) bool {
if testJoinSplits == nil && txJoinSplits != nil {
t.Errorf("Test %d: non-zero joinSplits when expected empty vector", caseNum)
return false
}
if len(testJoinSplits) != len(txJoinSplits) {
t.Errorf("Test %d: joinSplit vector lengths mismatch", caseNum)
return false
}
success := true
JoinSplitLoop:
for idx, test := range testJoinSplits {
tx := txJoinSplits[idx]
if test.vpubOld != tx.vpubOld {
t.Errorf("Test %d js %d: vpubOld %d %d", caseNum, idx, test.vpubOld, tx.vpubOld)
success = false
continue
}
if test.vpubNew != tx.vpubNew {
t.Errorf("Test %d js %d: vpubNew %d %d", caseNum, idx, test.vpubNew, tx.vpubNew)
success = false
continue
}
anchor, _ := hex.DecodeString(test.anchor)
if !bytes.Equal(anchor, tx.anchor) {
t.Errorf("Test %d js %d: anchor %x %x", caseNum, idx, anchor, tx.anchor)
success = false
continue
}
if len(test.nullifiers) != len(tx.nullifiers) {
t.Errorf("Test %d js %d: nf len mismatch %d %d", caseNum, idx, len(test.nullifiers), len(tx.nullifiers))
success = false
continue
}
for j := 0; j < len(test.nullifiers); j++ {
nf, _ := hex.DecodeString(test.nullifiers[j])
if !bytes.Equal(nf, tx.nullifiers[j]) {
t.Errorf("Test %d js %d: nf mismatch %x %x", caseNum, idx, nf, tx.nullifiers[j])
success = false
continue JoinSplitLoop
}
}
if len(test.commitments) != len(tx.commitments) {
t.Errorf("Test %d js %d: cm len mismatch %d %d", caseNum, idx, len(test.commitments), len(tx.commitments))
success = false
continue
}
for j := 0; j < len(test.commitments); j++ {
cm, _ := hex.DecodeString(test.commitments[j])
if !bytes.Equal(cm, tx.commitments[j]) {
t.Errorf("Test %d js %d: commit mismatch %x %x", caseNum, idx, cm, tx.commitments[j])
success = false
continue JoinSplitLoop
}
}
ephemeralKey, _ := hex.DecodeString(test.ephemeralKey)
if !bytes.Equal(ephemeralKey, tx.ephemeralKey) {
t.Errorf("Test %d js %d: ephemeralKey %x %x", caseNum, idx, ephemeralKey, tx.ephemeralKey)
success = false
continue
}
randomSeed, _ := hex.DecodeString(test.randomSeed)
if !bytes.Equal(randomSeed, tx.randomSeed) {
t.Errorf("Test %d js %d: randomSeed %x %x", caseNum, idx, randomSeed, tx.randomSeed)
success = false
continue
}
if len(test.vmacs) != len(tx.vmacs) {
t.Errorf("Test %d js %d: mac len mismatch %d %d", caseNum, idx, len(test.vmacs), len(tx.vmacs))
success = false
continue
}
for j := 0; j < len(test.vmacs); j++ {
mac, _ := hex.DecodeString(test.vmacs[j])
if !bytes.Equal(mac, tx.vmacs[j]) {
t.Errorf("Test %d js %d: mac mismatch %x %x", caseNum, idx, mac, tx.vmacs[j])
success = false
continue JoinSplitLoop
}
}
// This should not be possible.
if tx.proofPHGR13 != nil && tx.proofGroth16 != nil {
t.Errorf("Test %d js %d: parsed tx had both PHGR and Groth proofs defined", caseNum, idx)
success = false
continue
}
if test.proofPHGR13 != "" {
zkproof, _ := hex.DecodeString(test.proofPHGR13)
if !bytes.Equal(zkproof, tx.proofPHGR13) {
t.Errorf("Test %d js %d: zkproof %x %x", caseNum, idx, zkproof, tx.proofPHGR13)
success = false
continue
}
}
if test.proofGroth16 != "" {
zkproof, _ := hex.DecodeString(test.proofGroth16)
if !bytes.Equal(zkproof, tx.proofGroth16) {
t.Errorf("Test %d js %d: zkproof %x %x", caseNum, idx, zkproof, tx.proofGroth16)
success = false
continue
}
}
if len(test.encCiphertexts) != len(tx.encCiphertexts) {
t.Errorf("Test %d js %d: enc len mismatch %d %d", caseNum, idx, len(test.encCiphertexts), len(tx.encCiphertexts))
success = false
continue
}
for j := 0; j < len(test.encCiphertexts); j++ {
ct, _ := hex.DecodeString(test.encCiphertexts[j])
if !bytes.Equal(ct, tx.encCiphertexts[j]) {
t.Errorf("Test %d js %d: ct mismatch %x %x", caseNum, idx, ct, tx.encCiphertexts[j])
success = false
continue JoinSplitLoop
}
}
}
return success
}
func subTestTransparentInputs(testInputs [][]string, txInputs []*txIn, t *testing.T, caseNum int) bool {
if testInputs == nil && txInputs != nil {
t.Errorf("Test %d: non-zero vin when expected zero", caseNum)
return false
}
if len(testInputs) != len(txInputs) {
t.Errorf("Test %d: vins have mismatched lengths", caseNum)
return false
}
success := true
le := binary.LittleEndian
// 4201cfb1cd8dbf69b8250c18ef41294ca97993db546c1fe01f7e9c8e36d6a5e2 9d4e30a7 03ac6a00 98421c69
for idx, ti := range testInputs {
txInput := txInputs[idx]
testPrevTxHash, _ := hex.DecodeString(ti[0])
if eq := bytes.Equal(testPrevTxHash, txInput.PrevTxHash); !eq {
t.Errorf("Test %d tin %d: prevhash mismatch %x %x", caseNum, idx, testPrevTxHash, txInput.PrevTxHash)
success = false
continue
}
testPrevTxOutIndexBytes, _ := hex.DecodeString(ti[1])
testPrevTxOutIndex := le.Uint32(testPrevTxOutIndexBytes)
if testPrevTxOutIndex != txInput.PrevTxOutIndex {
t.Errorf("Test %d tin %d: prevout index mismatch %d %d", caseNum, idx, testPrevTxOutIndex, txInput.PrevTxOutIndex)
success = false
continue
}
// Decode scriptSig and correctly consume own CompactSize field
testScriptSig, _ := hex.DecodeString(ti[2])
ok := (*bytestring.String)(&testScriptSig).ReadCompactLengthPrefixed((*bytestring.String)(&testScriptSig))
if !ok {
t.Errorf("Test %d, tin %d: couldn't strip size from script", caseNum, idx)
success = false
continue
}
if eq := bytes.Equal(testScriptSig, txInput.ScriptSig); !eq {
t.Errorf("Test %d tin %d: scriptsig mismatch %x %x", caseNum, idx, testScriptSig, txInput.ScriptSig)
success = false
continue
}
testSeqNumBytes, _ := hex.DecodeString(ti[3])
testSeqNum := le.Uint32(testSeqNumBytes)
if testSeqNum != txInput.SequenceNumber {
t.Errorf("Test %d tin %d: seq mismatch %d %d", caseNum, idx, testSeqNum, txInput.SequenceNumber)
success = false
continue
}
}
return success
}
func subTestTransparentOutputs(testOutputs [][]string, txOutputs []*txOut, t *testing.T, caseNum int) bool {
if testOutputs == nil && txOutputs != nil {
t.Errorf("Test %d: non-zero vout when expected zero", caseNum)
return false
}
if len(testOutputs) != len(txOutputs) {
t.Errorf("Test %d: vout have mismatched lengths", caseNum)
return false
}
success := true
le := binary.LittleEndian
for idx, testOutput := range testOutputs {
txOutput := txOutputs[idx]
// Parse tx out value from test
testValueBytes, _ := hex.DecodeString(testOutput[0])
testValue := le.Uint64(testValueBytes)
if testValue != txOutput.Value {
t.Errorf("Test %d, tout %d: value mismatch %d %d", caseNum, idx, testValue, txOutput.Value)
success = false
continue
}
// Parse script from test
testScript, _ := hex.DecodeString(testOutput[1])
// Correctly consume own CompactSize field
ok := (*bytestring.String)(&testScript).ReadCompactLengthPrefixed((*bytestring.String)(&testScript))
if !ok {
t.Errorf("Test %d, tout %d: couldn't strip size from script", caseNum, idx)
success = false
continue
}
if !bytes.Equal(testScript, txOutput.Script) {
t.Errorf("Test %d, tout %d: script mismatch %x %x", caseNum, idx, testScript, txOutput.Script)
success = false
continue
}
}
return success
}
// https://github.com/zcash/zips/blob/master/zip-0243.rst
var zip243tests = []txTestVector{
// Test vector 1
{
txid: "5fc4867a1b8bd5ab709799adf322a85d10607e053726d5f5ab4b1c9ab897e6bc",
header: "04000080",
nVersionGroupID: "85202f89",
vin: nil,
vout: [][]string{
{"e7719811893e0000", "095200ac6551ac636565"},
{"b2835a0805750200", "025151"},
},
nLockTime: "481cdd86",
nExpiryHeight: "b3cc4318",
valueBalance: "442117623ceb0500",
spends: []spendTestVector{
{
cv: "1b3d1a027c2c40590958b7eb13d742a997738c46a458965baf276ba92f272c72",
anchor: "1fe01f7e9c8e36d6a5e29d4e30a73594bf5098421c69378af1e40f64e125946f",
nullifier: "62c2fa7b2fecbcb64b6968912a6381ce3dc166d56a1d62f5a8d7551db5fd9313",
rk: "e8c7203d996af7d477083756d59af80d06a745f44ab023752cb5b406ed8985e1",
zkproof: "8130ab33362697b0e4e4c763ccb8f676495c222f7fba1e31defa3d5a57efc2e1e9b01a035587d5fb1a38e01d94903d3c3e0ad3360c1d3710acd20b183e31d49f25c9a138f49b1a537edcf04be34a9851a7af9db6990ed83dd64af3597c04323ea51b0052ad8084a8b9da948d320dadd64f5431e61ddf658d24ae67c22c8d1309131fc00fe7f235734276d38d47f1e191e00c7a1d48af046827591e9733a97fa6b679f3dc601d008285edcbdae69ce8fc1be4aac00ff2711ebd931de518856878",
spendAuthSig: "f73476f21a482ec9378365c8f7393c94e2885315eb4671098b79535e790fe53e29fef2b3766697ac32b4f473f468a008e72389fc03880d780cb07fcfaabe3f1a",
},
{
cv: "15825b7acb4d6b57a61bc68f242b52e4fbf85cf1a09cc45b6d6bb3a391578f49",
anchor: "9486a7afd04a0d9c74c2995d96b4de37b36046a1ef6d190b916b1111c9288731",
nullifier: "1a20da8aba18d1dbebbc862ded42435e92476930d069896cff30eb414f727b89",
rk: "e001afa2fb8dc3436d75a4a6f26572504b192232ecb9f0c02411e52596bc5e90",
zkproof: "457e745939ffedbd12863ce71a02af117d417adb3d15cc54dcb1fce467500c6b8fb86b12b56da9c382857deecc40a98d5f2935395ee4762dd21afdbb5d47fa9a6dd984d567db2857b927b7fae2db587105415d4642789d38f50b8dbcc129cab3d17d19f3355bcf73cecb8cb8a5da01307152f13936a270572670dc82d39026c6cb4cd4b0f7f5aa2a4f5a5341ec5dd715406f2fdd2afa733f5f641c8c21862a1bafce2609d9eecfa158cfb5cd79f88008e315dc7d8388e76c1782fd2795d18a76",
spendAuthSig: "3624c25fa959cc97489ce75745824b77868c53239cfbdf73caec65604037314faaceb56218c6bd30f8374ac13386793f21a9fb80ad03bc0cda4a44946c00e1b1",
},
{
cv: "02c78f11876b7065212183199fb5979ca77d2c24c738fe5145f02602053bb4c2",
anchor: "f6556df6ed4b4ddd3d9a69f53357d7767f4f5ccbdbc596631277f8fecd08cb05",
nullifier: "6b95e3025b9792fff7f244fc716269b926d62e9596fa825c6bf21aff9e68625a",
rk: "192440ea06828123d97884806f15fa08da52754a1095e3ff1abd5ce4fddfccfc",
zkproof: "3a6128aef784a64610a89d1a7099216d0814d3a2d452431c32d411ac1cce82ad0229407bbc48985675e3f874a4533f1d63a84dfa3e0f460fe2f57e34fbc75423c3737f5b2a0615f5722db041a3ef66fa483afd3c2e19e59444a64add6df1d963f5dd5b5010d3d025f0287c4cf19c75f33d51ddddba5d657b43ee8da645443814cc7329f3e9b4e54c236c29af3923101756d9fa4bd0f7d2ddaacb6b0f86a2658e0a07a05ac5b950051cd24c47a88d13d659ba2a46ca1830816d09cd7646f76f71",
spendAuthSig: "6abec5de07fe9b523410806ea6f288f8736c23357c85f45791e1708029d9824d90704607f387a03e49bf9836574431345a7877efaa8a08e73081ef8d62cb780a",
},
},
outputs: []outputTestVector{
{
cv: "0fa3207ee2f0408097d563da1b2146819edf88d33e7753664fb71d122a6e3699",
cmu: "8fbd467f75b780149ae8808f4e68f50c0536acddf6f1aeab016b6bc1ec144b4e",
ephemeralKey: "59aeb77eef49d00e5fbb67101cdd41e6bc9cf641a52fca98be915f8440a410d7",
encCiphertext: "4cb30e15914f01bc6bc2307b488d2556d7b7380ea4ffd712f6b02fe806b94569cd4059f396bf29b99d0a40e5e1711ca944f72d436a102fca4b97693da0b086fe9d2e7162470d02e0f05d4bec9512bfb3f38327296efaa74328b118c27402c70c3a90b49ad4bbc68e37c0aa7d9b3fe17799d73b841e751713a02943905aae0803fd69442eb7681ec2a05600054e92eed555028f21b6a155268a2dd6640a69301a52a38d4d9f9f957ae35af7167118141ce4c9be0a6a492fe79f1581a155fa3a2b9dafd82e650b386ad3a08cb6b83131ac300b0846354a7eef9c410e4b62c47c5426907dfc6685c5c99b7141ac626ab4761fd3f41e728e1a28f89db89ffdeca364dd2f0f0739f0534556483199c71f189341ac9b78a269164206a0ea1ce73bfb2a942e7370b247c046f8e75ef8e3f8bd821cf577491864e20e6d08fd2e32b555c92c661f19588b72a89599710a88061253ca285b6304b37da2b5294f5cb354a894322848ccbdc7c2545b7da568afac87ffa005c312241c2d57f4b45d6419f0d2e2c5af33ae243785b325cdab95404fc7aed70525cddb41872cfcc214b13232edc78609753dbff930eb0dc156612b9cb434bc4b693392deb87c530435312edcedc6a961133338d786c4a3e103f60110a16b1337129704bf4754ff6ba9fbe65951e610620f71cda8fc877625f2c5bb04cbe1228b1e886f4050afd8fe94e97d2e9e85c6bb748c0042d3249abb1342bb0eebf62058bf3de080d94611a3750915b5dc6c0b3899d41222bace760ee9c8818ded599e34c56d7372af1eb86852f2a732104bdb750739",
outCiphertext: "de6c2c6e0f9eb7cb17f1942bfc9f4fd6ebb6b4cdd4da2bca26fac4578e9f543405acc7d86ff59158bd0cba3aef6f4a8472d144d99f8b8d1dedaa9077d4f01d4bb27bbe31d88fbefac3dcd4797563a26b",
zkproof: "1d61fcd9a464ab21ed550fe6fa09695ba0b2f10eea6468cc6e20a66f826e3d14c5006f0563887f5e1289be1b2004caca8d3f34d6e84bf59c1e04619a7c23a996941d889e4622a9b9b1d59d5e319094318cd405ba27b7e2c084762d31453ec4549a4d97729d033460fcf89d6494f2ffd789e98082ea5ce9534b3acd60fe49e37e4f666931677319ed89f85588741b3128901a93bd78e4be0225a9e2692c77c969ed0176bdf9555948cbd5a332d045de6ba6bf4490adfe7444cd467a09075417fc",
},
},
vJoinSplits: []joinSplitTestVector{
{
vpubOld: uint64(0),
vpubNew: uint64(0),
anchor: "062e49f008c51ad4227439c1b4476ccd8e97862dab7be1e8d399c05ef27c6e22",
nullifiers: []string{
"ee273e15786e394c8f1be31682a30147963ac8da8d41d804258426a3f70289b8",
"ad19d8de13be4eebe3bd4c8a6f55d6e0c373d456851879f5fbc282db9e134806",
},
commitments: []string{
"bff71e11bc33ab75dd6ca067fb73a043b646a7cf39cab4928386786d2f24141e",
"e120fdc34d6764eafc66880ee0204f53cc1167ed20b43a52dea3ca7cff8ef35c",
},
ephemeralKey: "d8e6d7c111a68ef44bcd0c1513ad47ca61c659cc5d325b440f6b9f59aff66879",
randomSeed: "bb6688fd2859362b182f207b3175961f6411a493bffd048e7d0d87d82fe6f990",
vmacs: []string{
"a2b0a25f5aa0111a6e68f37bf6f3ac2d26b84686e569d58d99c1383597fad811",
"93c4c1b16e6a90e2d507cdfe6fbdaa86163e9cf5de3100fbca7e8da047b090db",
},
proofGroth16: "9f37952fbfee76af61668190bd52ed490e677b515d014384af07219c7c0ee7fc7bfc79f325644e4df4c0d7db08e9f0bd024943c705abff8994bfa605cfbc7ed746a7d3f7c37d9e8bdc433b7d79e08a12f738a8f0dbddfef2f2657ef3e47d1b0fd11e6a13311fb799c79c641d9da43b33e7ad012e28255398789262275f1175be8462c01491c4d842406d0ec4282c9526174a09878fe8fdde33a29604e5e5e7b2a025d6650b97dbb52befb59b1d30a57433b0a351474444099daa371046613260",
encCiphertexts: []string{
"cf3354cfcdada663ece824ffd7e44393886a86165ddddf2b4c41773554c86995269408b11e6737a4c447586f69173446d8e48bf84cbc000a807899973eb93c5e819aad669413f8387933ad1584aa35e43f4ecd1e2d0407c0b1b89920ffdfdb9bea51ac95b557af71b89f903f5d9848f14fcbeb1837570f544d6359eb23faf38a0822da36ce426c4a2fbeffeb0a8a2e297a9d19ba15024590e3329d9fa9261f9938a4032dd34606c9cf9f3dd33e576f05cd1dd6811c6298757d77d9e810abdb226afcaa4346a6560f8932b3181fd355d5d391976183f8d99388839632d6354f666d09d3e5629ea19737388613d38a34fd0f6e50ee5a0cc9677177f50028c141378187bd2819403fc534f80076e9380cb4964d3b6b45819d3b8e9caf54f051852d671bf8c1ffde2d1510756418cb4810936aa57e6965d6fb656a760b7f19adf96c173488552193b147ee58858033dac7cd0eb204c06490bbdedf5f7571acb2ebe76acef3f2a01ee987486dfe6c3f0a5e234c127258f97a28fb5d164a8176be946b8097d0e317287f33bf9c16f9a545409ce29b1f4273725fc0df02a04ebae178b3414fb0a82d50deb09fcf4e6ee9d180ff4f56ff3bc1d3601fc2dc90d814c3256f4967d3a8d64c83fea339c51f5a8e5801fbb97835581b602465dee04b5922c2761b54245bec0c9eef2db97d22b2b3556cc969fbb13d06509765a52b3fac54b93f421bf08e18d52ddd52cc1c8ca8adfaccab7e5cc2f4573fbbf8239bb0b8aedbf8dad16282da5c9125dba1c059d0df8abf621078f02d6c4bc86d40845ac1d59710c45f07d585eb48b32fc0167ba256e73ca3b9311c62d1094979",
"57d8dbe10aa3e866b40c0baa2bc492c19ad1e6372d9622bf163fbffeaeee796a3cd9b6fbbfa4d792f34d7fd6e763cd5859dd26833d21d9bc5452bd19515dff9f4995b35bc0c1f876e6ad11f2452dc9ae85aec01fc56f8cbfda75a7727b75ebbd6bbffb43b63a3b1b671e40feb0db002974a3c3b1a788567231bf6399ff89236981149d423802d2341a3bedb9ddcbac1fe7b6435e1479c72e7089d029e7fbbaf3cf37e9b9a6b776791e4c5e6fda57e8d5f14c8c35a2d270846b9dbe005cda16af4408f3ab06a916eeeb9c9594b70424a4c1d171295b6763b22f47f80b53ccbb904bd68fd65fbd3fbdea1035e98c21a7dbc91a9b5bc7690f05ec317c97f8764eb48e911d428ec8d861b708e8298acb62155145155ae95f0a1d1501034753146e22d05f586d7f6b4fe12dad9a17f5db70b1db96b8d9a83edadc966c8a5466b61fc998c31f1070d9a5c9a6d268d304fe6b8fd3b4010348611abdcbd49fe4f85b623c7828c71382e1034ea67bc8ae97404b0c50b2a04f559e49950afcb0ef462a2ae024b0f0224dfd73684b88c7fbe92d02b68f759c4752663cd7b97a14943649305521326bde085630864629291bae25ff8822a14c4b666a9259ad0dc42a8290ac7bc7f53a16f379f758e5de750f04fd7cad47701c8597f97888bea6fa0bf2999956fbfd0ee68ec36e4688809ae231eb8bc4369f5fe1573f57e099d9c09901bf39caac48dc11956a8ae905ead86954547c448ae43d315e669c4242da565938f417bf43ce7b2b30b1cd4018388e1a910f0fc41fb0877a5925e466819d375b0a912d4fe843b76ef6f223f0f7c894f38f7ab780dfd75f669c8c06cffa",
},
},
{
vpubOld: uint64(0),
vpubNew: uint64(0),
anchor: "43eb47565a50e3b1fa45ad61ce9a1c4727b7aaa53562f523e73952bbf33d8a41",
nullifiers: []string{
"04078ade3eaaa49699a69fdf1c5ac7732146ee5e1d6b6ca9b9180f964cc9d087",
"8ae1373524d7d510e58227df6de9d30d271867640177b0f1856e28d5c8afb095",
},
commitments: []string{
"ef6184fed651589022eeaea4c0ce1fa6f085092b04979489172b3ef8194a798d",
"f5724d6b05f1ae000013a08d612bca8a8c31443c10346dbf61de8475c0bbec51",
},
ephemeralKey: "04b47556af3d514458e2321d146071789d2335934a680614e83562f82dfd405b",
randomSeed: "54a45eb32c165448d4d5d61ca2859585369f53f1a137e9e82b67b8fdaf01bda5",
vmacs: []string{
"4a317311896ae10280a032440c420a421e944d1e952b70d5826cd3b08b7db963",
"0fe4fd5f22125de840fcc40b98038af11d55be25432597b4b65b9ec1c7a8bbfd",
},
proofGroth16: "052cbf7e1c1785314934b262d5853754f1f17771cfb7503072655753fa3f54ecc587e9f83b581916092df26e63e18994cb0db91a0bbdc7b6119b32222adf5e61d8d8ae89dae4954b54813bb33f08d562ba513fee1b09c0fcd516055419474dd7fda038a89c84ea7b9468287f0eb0c10c4b132520194d3d8d5351fc10d09c15c8cc101aa1663bbf17b84111f38bb439f07353bdea3596d15e713e1e2e7d3f1c383135b47fa7f81f46df7a902a404699ec912f5656c35b85763e4de583aecaa1df",
encCiphertexts: []string{
"d5d2677d9c8ffee877f63f40a5ca0d67f6e554124739f805af876aeede53aa8b0f8e5604a73c30cbd09dad963d6f8a5dcc40def40797342113ba206fae8ebe4f3bc3caf69259e462eff9ba8b3f4bfaa1300c26925a8729cd32915bfc966086f0d5560bbe32a598c22adfb48cef72ba5d4287c0cefbacfd8ce195b4963c34a94bba7a175dae4bbe3ef4863d53708915090f47a068e227433f9e49d3aa09e356d8d66d0c0121e91a3c4aa3f27fa1b63396e2b41db908fdab8b18cc7304e94e970568f9421c0dbbbaf84598d972b0534f48a5e52670436aaa776ed2482ad703430201e53443c36dcfd34a0cb6637876105e79bf3bd58ec148cb64970e3223a91f71dfcfd5a04b667fbaf3d4b3b908b9828820dfecdd753750b5f9d2216e56c615272f854464c0ca4b1e85aedd038292c4e1a57744ebba010b9ebfbb011bd6f0b78805025d27f3c17746bae116c15d9f471f0f6288a150647b2afe9df7cccf01f5cde5f04680bbfed87f6cf429fb27ad6babe791766611cf5bc20e48bef119259b9b8a0e39c3df28cb9582ea338601cdc481b32fb82adeebb3dade25d1a3df20c37e712506b5d996c49a9f0f30ddcb91fe9004e1e83294a6c9203d94e8dc2cbb449de4155032604e47997016b304fd437d8235045e255a19b743a0a9f2e336b44cae307bb3987bd3e4e777fbb34c0ab8cc3d67466c0a88dd4ccad18a07a8d1068df5b629e5718d0f6df5c957cf71bb00a5178f175caca944e635c5159f738e2402a2d21aa081e10e456afb00b9f62416c8b9c0f7228f510729e0be3f305313d77f7379dc2af24869c6c74ee4471498861d192f0ff0f508285dab6b",
"6a36ccf7d12256cc76b95503720ac672d08268d2cf7773b6ba2a5f664847bf707f2fc10c98f2f006ec22ccb5a8c8b7c40c7c2d49a6639b9f2ce33c25c04bc461e744dfa536b00d94baddf4f4d14044c695a33881477df124f0fcf206a9fb2e65e304cdbf0c4d2390170c130ab849c2f22b5cdd3921640c8cf1976ae1010b0dfd9cb2543e45f99749cc4d61f2e8aabfe98bd905fa39951b33ea769c45ab9531c57209862ad12fd76ba4807e65417b6cd12fa8ec916f013ebb8706a96effeda06c4be24b04846392e9d1e6930eae01fa21fbd700583fb598b92c8f4eb8a61aa6235db60f2841cf3a1c6ab54c67066844711d091eb931a1bd6281aedf2a0e8fab18817202a9be06402ed9cc720c16bfe881e4df4255e87afb7fc62f38116bbe03cd8a3cb11a27d568414782f47b1a44c97c680467694bc9709d32916c97e8006cbb07ba0e4180a3738038c374c4cce8f32959afb25f303f5815c4533124acf9d18940e77522ac5dc4b9570aae8f47b7f57fd8767bea1a24ae7bed65b4afdc8f1278c30e2db98fd172730ac6bbed4f1127cd32b04a95b205526cfcb4c4e1cc955175b3e8de1f5d81b18669692350aaa1a1d797617582e54d7a5b57a683b32fb1098062dad7b0c2eb518f6862e83db25e3dbaf7aed504de932acb99d735992ce62bae9ef893ff6acc0ffcf8e3483e146b9d49dd8c7835f43a37dca0787e3ec9f6605223d5ba7ae0ab9025b73bc03f7fac36c009a56d4d95d1e81d3b3ebca7e54cc1a12d127b57c8138976e791013b015f06a624f521b6ee04ec980893c7e5e01a336203594094f82833d7445fe2d09130f63511da54832de9136b39",
},
},
},
joinSplitPubKey: "f4599f5aa5dfbb45da60cdceab7eefde89be63f3f7c0d2324847cce1405def7c",
joinSplitSig: "469b0e272494e5df54f568656cb9c8818d92b72b8bc34db7bb3112487e746eefe4e808bbb287d99bf07d00dabededc5e5f074ffeae0cba7da3a516c173be1c51",
bindingSig: "3323e119f635e8209a074b216b7023fadc2d25949c90037e71e3e550726d210a2c688342e52440635e9cc14afe10102621a9c9accb782e9e4a5fa87f0a956f5b",
},
// Test vector 2
{
txid: "6732cf8d67aac5b82a2a0f0217a7d4aa245b2adb0b97fd2d923dfc674415e221",
header: "04000080",
nVersionGroupID: "85202f89",
vin: [][]string{
{"56e551406a7ee8355656a21e43e38ce129fdadb759eddfa08f00fc8e567cef93", "c6792d01", "0763656300ac63ac", "8df04245"},
{"1a33590d3e8cf49b2627218f0c292fa66ada945fa55bb23548e33a83a562957a", "3149a993", "086a5352516a65006a", "78d97ce4"},
},
vout: [][]string{
{"e91cb65a63b70100", "09516a6a656aac636565"},
{"5cc7c9aae5bd0300", "02636a"},
},
nLockTime: "675cb83e",
nExpiryHeight: "43e29c17",
valueBalance: "44b8b5b99ce30500",
spends: []spendTestVector{
{
cv: "b0f5b874a6ecabe6c56ee58b67d02f5d47db8cc3458435d5088d69b2240c28f3",
anchor: "71c012c415d2382a6eebc8b3db07ea1cbf28288daaa91538de4552eeeef72c24",
nullifier: "c85d83db20efad48be8996fb1bff591efff360fe1199056c56e5feec61a7b8b9",
rk: "f699d6012c2849232f329fef95c7af370098ffe4918e0ca1df47f275867b739e",
zkproof: "0a514d3209325e217045927b479c1ce2e5d54f25488cad1513e3f44a21266cfd841633327dee6cf810fbf7393e317d9e53d1be1d5ae7839b66b943b9ed18f2c530e975422332c3439cce49a29f2a336a4851263c5e9bd13d731109e844b7f8c392a5c1dcaa2ae5f50ff63fab9765e016702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76c0fbf1ef963ea80e3223de3277bc559251725829ec03f213ba8955cab2822ff21a9b0a4904d668fcd77224bde3dd01f6",
spendAuthSig: "ffc4828f6b64230b35c6a049873494276ea1d7ed5e92cb4f90ba83a9e49601b194042f2900d99d312d7b70508cf176066d154dbe96ef9d4367e4c840e4a17b5e",
},
{
cv: "26bca7fdd7cc43201c56f468fadc42cff0d81a966417ad8f097ebf3b25879e55",
anchor: "c23e34da91c816d8d1790dfe34bdce040db1727af24d59ef78d3f4aac2b59822",
nullifier: "d6f12f24fd364496b3be0871ca3dd9625348a614b59bde45885649bae36de34d",
rk: "ef8fcec85343475d976ae1e9b27829ce2ac5efd0b399a8b448be6504294ee6b3",
zkproof: "c1c6a5342d7c01ae9d8ad3070c2b1a91573af5e0c5e4cbbf4acdc6b54c9272200d9970250c17c1036f06085c41858ed3a0c48150bc697e4a695fef335f7ad07e1a46dc767ff822db70e6669080b9816b2232c81a4c66cc586abfe1eaa8ca6cf41fc3c3e6c7b886fb6dac9f4822b4fc6fff9d0513d61a21c80a377671d135a668a0ae2bb934c82c4142da69d12ca7de9a7df706400ec79878d868e17e8f71ea31495af819a016cc419e07c501aa8309b2e6c85b79b2763733a37bbc0420d42537",
spendAuthSig: "b871b4294a65d3e055ff718dd9dc8c75e7e5b2efe442637371b7c48f6ee99e3ea38a4b0f2f67fc2b908cda657eae754e037e262e9a9f9bd7ec4267ed8e96930e",
},
{
cv: "eb89a85980f97d7faaed78d8f38beb624b774c73a46ced614be219b3d94873b6",
anchor: "0df7fc90b579abf62037975edd6aacc442190a0ba55b15f81f86bade794ace2a",
nullifier: "9d9a816baf728a955b960b7701fa626687dc3c9cba646337b53e29816e9482dd",
rk: "f5578a8768aae477fce410ac2d5de6095861c111d7feb3e6bb4fbb5a54955495",
zkproof: "972798350a253f05f66c2ecfcbc0ed43f5ec2e6d8dba15a51254d97b1821107c07dd9a16ef8406f943e282b95d4b362530c913d6ba421df6027de5af1e4745d5868106954be6c1962780a2941072e95131b1679df0637625042c37d48ffb152e5ebc185c8a2b7d4385f1c95af937df78dfd8757fab434968b0b57c66574468f160b447ac8221e5060676a842a1c6b7172dd3340f764070ab1fe091c5c74c95a5dc043390723a4c127da14cdde1dc2675a62340b3e6afd0522a31de26e7d1ec3a",
spendAuthSig: "9c8a091ffdc75b7ecfdc7c12995a5e37ce3488bd29f8629d68f696492448dd526697476dc061346ebe3f677217ff9c60efce943af28dfd3f9e59692598a6047c",
},
},
outputs: nil,
vJoinSplits: nil,
joinSplitPubKey: "",
joinSplitSig: "",
bindingSig: "c01400f1ab5730eac0ae8d5843d5051c376240172af218d7a1ecfe65b4f75100638983c14de4974755dade8018c9b8f4543fb095961513e67c61dbc59c607f9b",
},
}
func TestSaplingTransactionParser(t *testing.T) {
testData, err := os.Open("../testdata/zip243_raw_tx")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer testData.Close() if len(testdata) < 3 {
t.Fatal("tx_vt.json has too few lines")
}
testdata = testdata[2:]
for _, onetx := range testdata {
var txtestdata TxTestData
// Parse the raw transactions file err = json.Unmarshal(onetx, &txtestdata)
rawTxData := [][]byte{}
scan := bufio.NewScanner(testData)
for scan.Scan() {
dataLine := scan.Text()
// Skip the comments
if strings.HasPrefix(dataLine, "#") {
continue
}
txData, err := hex.DecodeString(dataLine)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
rawTxData = append(rawTxData, txData) t.Logf("txid %s", txtestdata.Txid)
} rawTxData, _ := hex.DecodeString(txtestdata.Tx)
for i, tt := range zip243tests {
tx := NewTransaction() tx := NewTransaction()
rest, err := tx.ParseFromSlice(rawTxData)
rest, err := tx.ParseFromSlice(rawTxData[i])
if err != nil { if err != nil {
t.Errorf("Test %d: %v", i, err) t.Fatalf("%v", err)
continue
} }
if len(rest) != 0 { if len(rest) != 0 {
t.Errorf("Test %d: did not consume entire buffer", i) t.Fatalf("Test did not consume entire buffer, %d remaining", len(rest))
continue
} }
// Currently, we can't check the txid because we get that from
// If the transaction is shorter than it should be, parsing // zcashd (getblock rpc) rather than computing it ourselves.
// should fail gracefully // https://github.com/zcash/lightwalletd/issues/392
for j := 0; j < len(rawTxData[i]); j++ { if tx.version != uint32(txtestdata.Version) {
_, err := tx.ParseFromSlice(rawTxData[i][0:j]) t.Fatal("version miscompare")
if err == nil {
t.Errorf("Test %d: Parsing transaction unexpected succeeded", i)
break
}
if len(rest) > 0 {
t.Errorf("Test %d: Parsing transaction unexpected rest", i)
break
}
} }
if tx.nVersionGroupID != uint32(txtestdata.NVersionGroupId) {
// Transaction metadata t.Fatal("nVersionGroupId miscompare")
if !subTestCommonBlockMeta(&tt, tx, t, i) {
continue
} }
if tx.consensusBranchID != uint32(txtestdata.NConsensusBranchId) {
// Transparent inputs and outputs t.Fatal("consensusBranchID miscompare")
if !subTestTransparentInputs(tt.vin, tx.transparentInputs, t, i) {
continue
} }
if !subTestTransparentOutputs(tt.vout, tx.transparentOutputs, t, i) { if len(tx.transparentInputs) != int(txtestdata.Tx_in_count) {
continue t.Fatal("tx_in_count miscompare")
} }
if len(tx.transparentOutputs) != int(txtestdata.Tx_out_count) {
// JoinSplits t.Fatal("tx_out_count miscompare")
if !subTestJoinSplits(tt.vJoinSplits, tx.joinSplits, t, i) {
continue
} }
if len(tx.shieldedSpends) != int(txtestdata.NSpendsSapling) {
testJSPubKey, _ := hex.DecodeString(tt.joinSplitPubKey) t.Fatal("NSpendsSapling miscompare")
if !bytes.Equal(testJSPubKey, tx.joinSplitPubKey) {
t.Errorf("Test %d: jsPubKey mismatch %x %x", i, testJSPubKey, tx.joinSplitPubKey)
continue
} }
if len(tx.shieldedOutputs) != int(txtestdata.NoutputsSapling) {
testJSSig, _ := hex.DecodeString(tt.joinSplitSig) t.Fatal("NOutputsSapling miscompare")
if !bytes.Equal(testJSSig, tx.joinSplitSig) {
t.Errorf("Test %d: jsSig mismatch %x %x", i, testJSSig, tx.joinSplitSig)
continue
} }
if len(tx.orchardActions) != int(txtestdata.NActionsOrchard) {
// Begin Sapling-specific tests t.Fatal("NActionsOrchard miscompare")
testValueBalanceBytes, _ := hex.DecodeString(tt.valueBalance)
testValueBalance := int64(binary.LittleEndian.Uint64(testValueBalanceBytes))
if testValueBalance != tx.valueBalance {
t.Errorf("Test %d: valueBalance mismatch %d %d", i, testValueBalance, tx.valueBalance)
continue
}
if !subTestShieldedSpends(tt.spends, tx.shieldedSpends, t, i) {
continue
}
if !subTestShieldedOutputs(tt.outputs, tx.shieldedOutputs, t, i) {
continue
}
testBinding, _ := hex.DecodeString(tt.bindingSig)
if !bytes.Equal(testBinding, tx.bindingSig) {
t.Errorf("Test %d: bindingSig %x %x", i, testBinding, tx.bindingSig)
continue
}
if hex.EncodeToString(tx.GetDisplayHash()) != tt.txid {
t.Errorf("Test %d: incorrect txid", i)
}
// test caching
if hex.EncodeToString(tx.GetDisplayHash()) != tt.txid {
t.Errorf("Test %d: incorrect cached txid", i)
} }
} }
} }
func subTestShieldedSpends(testSpends []spendTestVector, txSpends []*spend, t *testing.T, caseNum int) bool {
if testSpends == nil && txSpends != nil {
t.Errorf("Test %d: non-zero Spends when expected empty vector", caseNum)
return false
}
if len(testSpends) != len(txSpends) {
t.Errorf("Test %d: Spend vector lengths mismatch", caseNum)
return false
}
success := true
for j, tt := range testSpends {
tx := txSpends[j]
testCV, _ := hex.DecodeString(tt.cv)
if !bytes.Equal(testCV, tx.cv) {
t.Errorf("Test %d spend %d: cv %x %x", caseNum, j, testCV, tx.cv)
success = false
continue
}
testAnchor, _ := hex.DecodeString(tt.anchor)
if !bytes.Equal(testAnchor, tx.anchor) {
t.Errorf("Test %d spend %d: anchor %x %x", caseNum, j, testAnchor, tx.anchor)
success = false
continue
}
testNullifier, _ := hex.DecodeString(tt.nullifier)
if !bytes.Equal(testNullifier, tx.nullifier) {
t.Errorf("Test %d spend %d: nullifier %x %x", caseNum, j, testNullifier, tx.nullifier)
success = false
continue
}
testrk, _ := hex.DecodeString(tt.rk)
if !bytes.Equal(testrk, tx.rk) {
t.Errorf("Test %d spend %d: rk %x %x", caseNum, j, testrk, tx.rk)
success = false
continue
}
testzkproof, _ := hex.DecodeString(tt.zkproof)
if !bytes.Equal(testzkproof, tx.zkproof) {
t.Errorf("Test %d spend %d: zkproof %x %x", caseNum, j, testzkproof, tx.zkproof)
success = false
continue
}
testspendAuthSig, _ := hex.DecodeString(tt.spendAuthSig)
if !bytes.Equal(testspendAuthSig, tx.spendAuthSig) {
t.Errorf("Test %d spend %d: spendAuthSig %x %x", caseNum, j, testspendAuthSig, tx.spendAuthSig)
success = false
continue
}
}
return success
}
func subTestShieldedOutputs(testOutputs []outputTestVector, txOutputs []*output, t *testing.T, caseNum int) bool {
if testOutputs == nil && txOutputs != nil {
t.Errorf("Test %d: non-zero Outputs when expected empty vector", caseNum)
return false
}
if len(testOutputs) != len(txOutputs) {
t.Errorf("Test %d: Output vector lengths mismatch", caseNum)
return false
}
success := true
for j, tt := range testOutputs {
tx := txOutputs[j]
testCV, _ := hex.DecodeString(tt.cv)
if !bytes.Equal(testCV, tx.cv) {
t.Errorf("Test %d output %d: cv %x %x", caseNum, j, testCV, tx.cv)
success = false
continue
}
testcmu, _ := hex.DecodeString(tt.cmu)
if !bytes.Equal(testcmu, tx.cmu) {
t.Errorf("Test %d output %d: cmu %x %x", caseNum, j, testcmu, tx.cmu)
success = false
continue
}
testEphemeralKey, _ := hex.DecodeString(tt.ephemeralKey)
if !bytes.Equal(testEphemeralKey, tx.ephemeralKey) {
t.Errorf("Test %d output %d: ephemeralKey %x %x", caseNum, j, testEphemeralKey, tx.ephemeralKey)
success = false
continue
}
testencCiphertext, _ := hex.DecodeString(tt.encCiphertext)
if !bytes.Equal(testencCiphertext, tx.encCiphertext) {
t.Errorf("Test %d output %d: encCiphertext %x %x", caseNum, j, testencCiphertext, tx.encCiphertext)
success = false
continue
}
testzkproof, _ := hex.DecodeString(tt.zkproof)
if !bytes.Equal(testzkproof, tx.zkproof) {
t.Errorf("Test %d output %d: zkproof %x %x", caseNum, j, testzkproof, tx.zkproof)
success = false
continue
}
}
return success
}

8
testdata/blocks vendored
View File

@ -1,4 +1,4 @@
040000008a024cebb99e30ff83d5b9f50cc5303351923da95a8dc7fda3e0160900000000226b1c86e101f1fac09aa533c246bd6843ee6b444ad3ff251df0a401f16f0981000000000000000000000000000000000000000000000000000000000000000069cb7d5b0f1d0a1c0000000000000000004d6cdd939a4900000000000000000000000000310c50b3fd4005008f78a11b4b81126dec31cba6ede2e131ab376a8611237b04d20cd8bb4253f1e8721e0941970e0f58c206f09c8c86c70b2f73b3b5994571c389a90fadf6b812cebba5afe622b3e4aab20a88c805e1f3925e31300df11c09e3d4b7acebbfb156b75e213e36f65d88f023feae5d37ab2f13a1215299155b7d9a1f4cbb333212e8ef9959785adfcd2506d33ac1021207fc32584022080f4a7ba67157ea99f6fc645737a2a5c6f5d99700ff0c1a92f2845dba3b022d24de26691c0b56977b13e94d5f93ebe423d3d422a478f2e6d9f0b113b3fa0434fe432c173013b1a641e884f74922a3e6fc6cde4dedcd8c2458be13fb91f5285ffbf8a5dd207dad3b011b832444a85e27da43c1f94864ad7b066559d5210bf495565005f9297f6204ad7b4c395d5faa19c2530427ad4889555aefd272185f825564525f6d3e0bb62b18cce8ca120a6f636ee36f18612fede045bae81403752f8154e7c3bf4fef7134591379389155360cd15328c731c1ed3b57f439994b0350799e91f91f53e30ce9bed6ea9ce01b3f74f6041b739d85965d789b9c43ba65cf4f99808ef03c2ac46461ba0eedc05e77400815af9d8049027bb7fef6646142d86ef35adcca060e8a656c6c6cc811f65231b4ac531fa2083ddffbab26d19409cc357b89ed7da3d25476cb9d9a9c939c343d23fa35a09c52d593fb03f609dafcc28579fdd35e044168e33e747757bfdf5123080b6799d2527368f90de7f126304610765670214b6e9b6f497a491650db139129da19964461c368e2524aa1524248ed92561b3e94aec38d5ff4adcab5f73565dc7626477b1d56620ad1bb49000d1cd915a260c0913960c493edb9770d2fefae76dae63963e147331a51b1c66d5ff3ecf87f141306d575e60ca3b34fd26cb0b1d735dbbb1977db519a7a9d345ccc77121b688c7470975ee9dbfc489800f25a41d406ccbcbe1f01c629dfcbd59ea5dcd00334cc6af8718e08631c3a83d5e6395b4acc3afab48b145b73a064904176c30c2cd9a876ebab5f333b6ebd17c10e31ce6f009daad792c31fce13dd6d401120eb08d66348c13735ffc667e653ccf80bda54d0773473177433406a0c2001ec9f534c54e667c5a3cff3bca72625b5fee94a51dfc2b5b3fc73353b2b2f3a9e708932003e771dd21441e9cd075765e33ab5fe0db05b4b087bb04608d5fe5bd32f8272752cb1e59f856eab0e366a935a9651be4584f8886649c66bb6bff29ac82e0bf749c94e46cc6a42988196c15d3b2a6376185b990e653cbc8a77e56fd3e74378bcd54f4540afdf39650950fd18192198bd743708fcd948ec57aab07d71211157758ca83509cbc0094158b75bd840810fb266f91565df4f4013aaa4e414b3a56bf8442938189441ae24f8e2417b7bb729f9cf27a2ee5da291fed793afcf09a1c63f14af0dab7aa6b34b1be3d545356653f14a2d31173cf50fa6aed549933a5743cd46809bf6e64824111cb5032130536943f359ffe5cc7ad5b4dcce3f2d078f7ca751fb08f8a5d9ac3970cb9f2cf31ed1a713cec3e8bac8586ce10c74e215c3d691c58e176b39382da1fe4ff0edc7f23373f594ab00c987c772f92317575d4d199e79f5b95fe1986ff0dd4d4a339a797b3b366e737bf8befbf80fe58f0d5b6f35c831d00ebd0c47ddcec914cf879ca685c0724b9036f98abacd96102657148a55e6e7896f33d51daa97190a233a4d68278b51c2bd26dd23916c54e605b6578a8e3657359c36a9ee2e4c0f650a95a3f4b61c4133ddaa901154d20c807a6ab85211bda537f26a4fe4b53a4a64f5522d13eb75cd2bab7669ef47d1c7fd43416182bcde9370105383fa2c0c574d4895d2fea59889068e66f83c8f15118c7ce7adb41fd8de61c2afd7277d6ac31346aa01030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff0503e0ce0500ffffffff0200ca9a3b000000001976a914361683f47d7dfc6a8d17f8f7b9413ff1a27ec62988ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000 0400000006785624481f381e68b4506ba5d6cc53ddd6dc876cbc97e45e3c7c4a626a19008c450aa9112b2e900eba30c2e3b8428c23fb2a30bb7fa34a853c97f02fb1a2200d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5aecdc295c172c191f870000790c975f8c9f0a77f12ef1e021c6045c3c9acb7c432c2aa7ed42ad0000fd4005005db35c547608bbf32bd1b90369e6e0bc1e275a0d064f092b235835cb6dfc9158c6146a0e5cfbdf2d2f04f71478f7d9212bdeeb938029a5cc217ebf1f517711dbc7cb35d084328b8f7613e878f69e27b2b40e8103292cb87845006943b761bbbe43d94cfbf971011617965a7de1e846a586ad81f2ad138eb0fd74729efc04720badc95a1f1383cc70e890db91c143591ab96526263ec6b8a6186568dda29b9015078d19e87cbb2c00b26edee3e4b227ad6fa090db2d290191ef1043e2037fc0bd225e6a1364d16223b0234311e8c5ff455a0cc2e0c1f84944dfab49864f57e5ec2a2b5e91df5229449ee399b4c721abab63c534602abdf64d37f60905bea71cd59be759bae5967f6f3e1bf732753d4d9c1c11dcb5b6949bc4f63a06a3b0db5c2deebab040c70fc55fc648bb2559fe2da2b4a4bd53ccbca7aaf03262cdf31c5bab90cdc151b686d3e5f8a29103b9346602b5394b245dc9655116d33c2ed9d31563bb74950d0927895a024c119d30d4f2c760c346b11108ab29db2931123aa36937cbd152756758e3d341ec40db1d1b539fcbefa2e76af9827f575025c58569fbec1f806607e03a6eabc228a900a18144e310ab608a930ee6a10d5e6fc7ecc9934fb42b51f0a6552e2a1ba1d627b51df2d27889e14b87f093452b79bce3e2a74398f4b748eda48495b30437bef13527a231ce724f24d5bcf4040cc77f56dab50ff30ce12039ca968eef3c5ab44b2cdd8f7fecb36ed39bc624807a4da49d5b2f53abeb1a027676fb500fb89d7092eef849f254dfd3a7325e4b810687b8567d7db8e796480836bbeab2efff44bb0421f4e3d5d1493bedc2c331f75b7ba931e93495dc379fa22404a2e60919fb2644ee4e5c3bc2025fb17540dce5dede2fdc4fc6b87494ae26ae89bbe954ee8458740601a665126129c9962052683661efcfffce8303211fe3bf0adac14936927ce2f4b30a22227c39b4128616dfbfcaeae8f4a3b30255d215d1b9ccd9bff2173b5a94ffa5473bc49097030e782d81c1dc4f8c4a25803c6dd9a9e775646084ed2bbbf7457386ece058032128bc87c7b7772be513f79176241de701580b5c04f88ee81e231583528b514f0c478382e60d5741bd0b5582c2ece2767931f538d050498886814c5b27541764bda9734d5c46f2b3c80f2649d40374e45c053c050e33e83ed578f6d5c19435b7f495261e7e522d5225eaead374497fed7c30e322d6acbf512751b58417120bf8d97fcfdaa5e3be842fc7beab85235ff7e9ee459b03ef2ae01ceff42e0621ddce403e65521505ed0b25fca1a0747263e44c72c5e1e95d85119a7956852c629fcb903b9589e768a6bcbec5358a5332368a6913ffb9b9880e8d3701c6a366bec102bab8c6d9e57b2287ede4774d69fe81af83dbd423c905f666170bfc03f360314edf3098fe2036634ad90f326a71faa5b70f245acbdf8f7d4481283819d8dae7823ac31bafef129b94822a4d94b8ea5773b7477269be9dbe3bc8c11886a2d2a8176658fe30e1ba1bdcf320873d1d2325096223af6e142818a2c370b8447db8e6e865fef2074596bc9e679b8c37c51e99c4f35ac8431303fac507193d1d162d309a3d8d6e57cf4cd429b34ce69f69ef2f1e728d7b9347051b46d4ba5a7e7f9d43963e960d0bbaf63eeb69396dc75b325f08e9243db0c678aa192eb3db32d9cf65a0a38bd5726e31380f2de23ea9a019d8496ab511df2d955978fcee6e331aeea5df0a1826639323180b87bbbf6a039e34f482a5e4eabc6d9a139c40e2840b40eb53dea3d549b54405ba7e1b392f308df2abfd6e97a3eb44f540b272a6d97c085be2142445ea27349bc7a5493397ceee4c8016a38457480f4de263cd2c2416296a2d86c19ded93cf431bfdd1e3010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e0ce050103ffffffff0200ca9a3b000000001976a914f4fbba801ad64c6539e64a1478392c57c9a5e7a688ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f570880148700000000000000000000000000000000000000
0400000015bea7ff6272a28e0dd187b5160d8fae6f2ad6316d652fdd26b92204000000008ede1b5093bbb6ae7c883dbd4b8bfc9e97290ac6ba5a617c880d3aef1bc41d9200000000000000000000000000000000000000000000000000000000000000009bcb7d5ba51e0a1c0000000000000000002c476f1d2c08000000000000000000000000002c27173bfd4005001a40fe9c1795f9617212aa1ade76cd93f85db2e5254a8ffd5aab68218adb36065f6947477a423c26c719803ba9c01555a1d81ef1cbd4ab0e7a7c9c7aeba622c7c1614f16409f5b0f757a93d12923027fbe875e01d4003525150ba313f43148bf39e7836a3d5fae611de2de0eebd8a3d1b163e4ad7b3ad0bbc00a3f4b8d029ee0e23f6354cbc381711eec9df770f31149ac1e0eb55229d10d7ba106edb12834296cfd241f5a62a6014ac0726dc4543f05a88138ad2d7654b707aa799115886e467957d5f195fda7a0a0d7908e084b974a1e0565e222acc9670f4f7191b4052f84595457315647468f532773a0755b0b3c7649aad0ce1e9da9597819022f7c951ddf47978c5985bb3f4350b1b91f2eff7f149ba3992316712d0bb2a3b6fbb3dee54b516d22b21f60c23f87e3513d2ae3447191b55b17f3671f9e3629da0eb3b8261cb7eccc675761f95452435bf6b6f800a4e5a2deeee86b8ae3d026a11eaed463373c378b079a68b51eed25b596fd519a2530f9414684d71dfa427c461ab170137fcd343af2fef3122bb037df784e647b6386823340abffa60668eb7a5729fdda35d42602729b2fa822d11da41c304ce27530bc17e717fdd10a2f221cf793e4db842ee2f6f04b2a74d3945214ec0d1819005f0e42f68c8183e9a0a87011180ed87eb3205e7f01d7a760d95b874ae2d17e915b267cbd0e4e06e99982744e7473f74af2ff766730ee01f7528478116633f7d2eebd87d8e134429e4d29b92144fd0ffb1628add40f98c4df2856632055a3d2c70a2abf69851929b6aa5a9de2af2148ea564a7520f6d95e5724b40c2a3c9d39c995b2f3e131795f2299029c215b07cd14bce9e10fd05296a8a646302ff4c45e85a4bc3bec12fedc1d1f60da8f6aac22f746d43a11bd08be8e52153c60ab71061d35284872c427e3aaff0d8a3a82af016db8d42937f04be1ccb021e7152aa82a068b0a1b04cbe51b904ffc00f3bd46cedc3c58ba378355360e11982c9981c6a5ae7c6d21fa3b2e54b8e01d49a0f618df191ffbd3274b7ac3c5f066623a15c1e07eb64e1db18f37cf4d4452c441c63b8075ca220d0131a2d022da9305700b8e0d236ab4dfd17c2f453c3f17fd722925de3cdfac190bdec92340db74ad46ff693f79c92bad961d021e3a01dcf16445d66713e53bc37b89720c887088d26831e5a4a7011366eb3b6920df10a3316eb41dfbe9ef6f697bfb673be8bce2a64c16baa1ed1cce0a0bc32595bbc22f42ba8d2dbdba3f6097cf7b27cf4717d7187bab684e364a17c69e29c49ff3aab10d8f9d3002149c72d90cf115723ca3aee3c8b8014918896bf63a2746d7a486a496b274b21765dcdeb83b387252b876129b65ce91e613783f55aa1ca85c07a448b4eb36d95681c1851f7532a47e8056eacbd8c45d01b61dda489c744f267111294fef34a98c5391d6ff31491f974fdcbee1cfcd740c714abd9a616878d604076dc376afd53826da95c4b81ad0f991642a6bd3d518feec5a021e20a73be5924147203586c75b3fa9c51111119bd39061fdeedbc1a1a92aeafe834dff67071438f21b247a5713e66bf156ab70f04995ba70f4f0129da42ee3d5ca8da38c35c2b8d33d19e79618a0061ac8fdae6a58250725ab51dbda4a6541d7fe1cd31403ad8d6cfde6badbb85ff162bc1f08b109866f8aaa1688b2de068fa272a3a6371f3876101a37191dc9c308eff5bbe41512b7a749668f2a35f43e2dc67c91ed13e39bc4ce5783b795d1a16ba03886ca053dbd6a4006e0f5091e6955d7abdc154373d10d4d60ecee597c0a8d71dfbb2e3b4fa83554d459c0a68d655c9b28ff0cdd2ace655bdd8dc2322394a34255b1d5373dc39c310244fa0fa1c557d7caa3d029ad36966d0d7606e301030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff0503e1ce0500ffffffff0200ca9a3b000000001976a9146d17c0ca63e020d639f5fba181ca4f5da48b8f7088ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000 04000000913b07faeb835a29bd3a1727876fe1c65aaeb10c7cde36ccd038b2b3445e0a001e1ecc75a33e350c7763ccf055402a3082f28209c643810a2ef17df4b14486cb0d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5a15dd295c21c8181f15000813d02ae5e889354eb9b7b62cca4f139ca6364fb63646ff32f2b4700000fd400500356a828c88fb46eaaa21d759e99109375d79b61557348f830c71fd4dabb126ae794d403af814bfd3fc01b76c2fc110525507f6728bec686ea9a432eda0ef1c8fc97d912923a9ab0d06f8aeef2ba272a3b7125e0e5079f131e4706d59c4f34a2775cfed3fca2cba4a23795351a38abfacf67ae7772e6fd14326efde46192105f2c3b0989a15aedfd22063529005723c8c8ea756ea876e0ae7846d4556e57fdb4b7ae1d2125456130653604eff1a6e632e20350a88b0fece49fa57079818d28c0064764979ed2e75766767a7ddce8578a23712274fac056571619b9ef4371f6924068fd5dcf25112da1ffe4255fe60b851e50b704eef0577967a867a0fbd7ed06f0d93f0f0ae31830ab5eaee5b20757e96233c21f96d6eb8f5b5ff03e88d7a31ced8037a52d94ce82fb719764841c06016ba82e29acb9d521cf9d74e1a1a90175c19ff365b763db1d3fbb6332499a5f90903d26af753812bca3eb2b142992bbd87140c3a0c29732d648c650e6bdfda63a56c6184570bf2bb4d700ba30d7800cecac92f67647bbb282d85228fedbdae1e1e3d56e9cb7743a58f02df45f658cb3b627f6bb311618d1697a217ede3f763d8fbf1fba96f697a62b321d397d492594b477029b23565f8ee80e3df1a74d81be2eaf203e3c9215c72c5fa6ec5f0d20cff3f151d7131ff6a3021f489f87819245d6af34f12dc5d1bd70d2a692be0da4827ed3f81a4b63ee58223bcb53474471a4bfcab99ca08d7dfc6c1cefda57f836d1e58731b4eccbea60c0606dc42945b26b17a3599be385b0b64519f6160adb65fd1da795cf27ea25e9884783834130be24ec10d549eb21ca32188f4221d3ee358f2894099930d165ca4d78985e6c13ceb9ea340ad5c116118c6a2d7851781e554a0e1b968540151e3715513f5476ff6618a5de0498e4f5632a6d5ffea8579ddd0be010b10204499c82540d521397b9a39a079acccaaae32add4d7991db22dcfcb04f86730cbef5b8abb0fa31137abab148457325eb161fd0ebe033094c324f6da261fc31476619753fe95c63a326fd14dbe6e7f83c501b77d4ce5602877b5164973dd55c04f7a891e6f3b423ee425b992d73bdf7e2735e4f52cbedceed9afde086f923208dc1abf1ddce86f9e7c467a8b0b79740510900bef0351faffdda005bd35e5a819b96c1622ca06399cc62f01d08d64c4236970e6c119380df5c48d11d57a8908e76b6d8ac3517f459ec83af139986abf135ea4be1886054eeb0087996aff4ace796b765175166f46af49d6ba10f8b5a455f7bc04ad82a53ac8d71529a6d0dd138642b68a518b61be13761b33bf60133cf97c9c2a0fab6cbfaf3601c0642b6d918b142caf1da2da75d52523739a62984f34f3016ed17cfe03522e71e332079920eb33c0b41de3c3f41e92c0382f7804195e251c0db4d2b6db83566cb4a767a9a85d4d674b226732bbe298ab5df3d5fe2239b82dca3fef254d1a7e3fa9c3545a23eb49136fcd21308280715c7d26601eb40fc49e025b33a6f676b16ae215bce5d6281e0bee2d779549ca7fe32811335e404c10e142ec50c5442afbb03ce0f179848765998ef1a3b60062fd187733919a34999d8bc5724d354421e699e25c39d416c74eb3e2c79229656b54af9a3cb0e71a52e8a9fefd08043f69ad8a8e536b0728e2a039ee80c999d4bd86340c97dea3cb2be33ff333e11dddf0ddd482d99844df08f7bc2ac351987b71e802aec4266b372f2a1e86780b89be04b444801e52c2a4cbf0cc2049e2b3d2c6180e7a28ba0e459de1ddbd016e0c3538f137dc98e2ee1729d5d5b0879073eb421183da7b55866ba8b79c911792a4a6b80b9ed15dfc4249d4c88cf229bc16491f5b8f1afcf272622bf782396aa55fe527a5a67d6327010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e1ce050103ffffffff0200ca9a3b000000001976a91403e105ea5dbb243cddada1ec31cebd92266cd22588ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f570880148700000000000000000000000000000000000000
040000003723935953489b860d1de1b8fc8240ced04625f0ffd23f16519b8e0700000000f066ce1a8f2b97d05dc15ee51e1eedac93ba6057a953eb81d3f856e9f4b7ae270000000000000000000000000000000000000000000000000000000000000000c8cb7d5b13520a1c00000000020ff5b32c230200000000000000000000000000000000000d5e39cefd4005003eed282b472cfdcb0540b4f4245ed479c5357ff11989ef70be9700eff5987318f727dafa0b467302aa016e5e956c5a5d23f0f9e4a5623b9dda30e0f1b3c47e8c3d151e686cabd4ac89fc627e5cded736d707780c3dc341370bf7af4cb291878a1c4236cc207f39f081ef26b50fe099bdb90c8a9462663d1aaf079fefa010c2a8c29211f08b8debf2f90e4afade29bc53d74253c3fbdf265759fee75e1ab46adc90f38bba5f73e80e518def9b61e8b714d6e6a1dd585539ebd1f5f2040e8e73498455bec4fd333747f96823c66fb859177d13f3ba05868918255bb022cc32dd0a099438fdb1b31b15e2de9acc341066d6b20e4c1d18f56397dfe97919a2eb988e114e3cc015c1c209d906e494c46b9dac34a99ad0595868b4f84a1474ff532202149ef12acc1db1f9307213f49efcb0a408fcc1cc6124e637adb22ee4368da8d0a78b696956e7e4c9feea5d2e198f0e00bdd16ca49956c32ff793e3ff6e635efe57788fbf11a8b2a771d1981aeed6462fdd74a6a9f5d813d86616923f5add19a41d507ba22b69a0caf4a608f8b7673bd605d7f2b022b3d8436448aeb34e491c12addc3911564ecf5de8b1355f1762dc402e37915c35cb69de2a9d575a765737ff92c653eed1eb871270589c2dff15f827ba45b19ab3d25da28fe3176895a8cc32a943391276625d991492ed315ab22a7192fbcc5f5eb01611640c96585ac4db590777a87444c3dadc653bc2bb279474ad76ac00d5972b92e026d45fdd0ed84b099a13d08c00eea952c5a2a78218e06ff989f85b52801d203f82d395310f67e80f4646f3f29c5b0c2f9c3ce31530b766c12f3253a6f3e2aed5b66efd9dcdb6f1de1e601a36b00fa2b7c4d6241e46afc746cfb73f1b2f19c60f81472bd15bdaff21afb0c44514915bfbdb5a20172209c4c9c281ba14950b07b22d097bc0cce5fa017ef344aec83bca60db20f4241ab3e1d29f7f200a24b801aa1e2c638d77ac13c0732da3561e3e1bcc6f2ac78fcf21e7f113b56d83c0343a1cb6d8b69eb12975891c1bb27885f1efc8c97a0af71176f716fe36b61262e23b48e7266f6551821948e4c44d48153df60a1a921faa5766e4a99239c2f36231bdadc93e749db715ff7e8ced9ef6cb28e7a5a8aa7603de56e73ea5fd1d79be8974a4c071ed1b969382da51d68b11f4722303d74f82849cb05d07c0c313d9a0d5eccbb853f85f0c7002c67eeb93737060180a3f557582d3849b73bf13807ff3f4065faacd7562487fc96a20fcf2cc892e16ad74b813caed4f72f11293243912c976a9f2035b099b9b9debc968aec54031bb9f4eb7815ddb3bffc128d6be34814fbec58b17c6dfab6c812a5eb3fd15d60fe3fa55128466cb80bae5579b71025e6a9c34b7f818eb11cdb029eff94fa465e419b9aef2e8679f12ce02b780aba2c17313bb375033beda50e90be5fd949002fbb85634d42598b62d21e346d13c99e4b6364354136f828f972a7b2fd8c4464defb82629ffdddea6355afcf76a5b6a1f797b2a46b51cee7f95f812d926d00436f98711c6f6a1e374a5f8a6f73f39b70150ae7315988b1a2c88174e9bad58c2e0f82476bb1c9ebd03079970441810e5c7c1b8d3a5b8eb21750f29eb92f348d5ccd2dd13fc68b063c754564f490e33ba1bc71b111eb14500d1dfcd883be26a8952aed912f4a999831b80a94d1f994c69558334e165513fbe129a9348922d6205d0bdb3fed3d0fec41a8f7dac2a46f2f9bdd837d6fa791bd25ea3bedf454b7fcf8907000a78d4e911bc798c6d261817400572cea0a26e9e2f5b16cd7129e92738be52b4832c2a072e2c7db3c2b889fa089b1284a3ae2ec654da817e15e0b26856be1caa1c7c0b3446158365a0992bc01fc67c19d5444ad8c6be044902030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff4903e2ce050004c8cb7d5b598c2ba5c7f0b4587e7d60e62e08985aee803a179dda187d2f0c5284df7da7482f4f76657277696e7465722f5361706c696e672f706f6f6c696e2e636f6d2fffffffff02d0eb9a3b000000001976a914de2757e612dee78a681ace9b8e623570dce776f588ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000030000807082c403012263eb14eca399ec05b64be85325e2c5ab93e5d70d7dc49b4e8b8dcb52ff0f7b680200006a47304402207ade36a404000f4d5cebed5c28e28c57a539b7985b66aa4c014e0c59a43fde3a02201bd61f0a998301241d83fc9370654e0acda7cc6602258b954af6bf06605dffaf0121026e88bf2ad6aa4fdc21b2636583184a589fcddb3c1ed40b4e3613cf61601fad54feffffff01bc131600000000001976a9142f592f81575c361e91397dccc60772b9335f432588accfce0500f4ce050000 040000003893091e180992ed3ddbdca17b69bb32636fa24e139463cc3fcc390f72f00100152337b21d88dbabe7993aeda34e575edc0a10d8425ebf675ebc4a83b3ebc20c0d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5a39dd295c4699181f1e007d867f82f93d39b4107a1265900058b7565dd1b2945241a4ef63bc690000fd4005004b556303cc38ed6fccb33b93a81c0f8f05dd0e8006d64e34868ac9fe5c22863eff3928f6f2831b502400bed03b98c17215ca8a50612273461d43f857d192154f4ad5db69f067aa48d19503523a2f0602fbccbc01bceeeeb256d5690efa33a583efbf397481afaa5745976f397bd7c0cd270674f2de48ded99778fb0da11068c770ac303637c1ecb1b53e6f1be4f89130a7b45a49edcf081959f37121190d42d668b6bd5c1d353609479c1a598c2c43dd0661c9d51222bda25437f3fd1e952aea271a02c0f19a92f4a11faa20ccef67046f1a4036f38b299e73692e61aa67d526f1b7251da0914ac33d1cddd7a4bfeefada21c8f38ceedc1557d0710bbba0f4932c839177bac34abcf402e168303ed8021dc449b3ca0940448bff3217c0bc2730b19190c6811c420629a1878f6e7021171e9359002e4bc636a5322b8056733e3299bdf0c0f4545aba5372ca4a5b337300f3e8c43e89819a563df0e385229405479e1c12a50b57cc1b8e8e2f8b1db9b3aeca20724244f21c2997270e316e37528f7f302d95d9a2b71d7f0319fb4afc4cb25ea17f1a6fc3b7fbf68d71b65139fbee9997c404c2c76611cbb97750d7e5aae23d2ac26de83ec81d2774caf7279e40737f7b1502a4e8ad15f88a7bcc660a148b1c8c68fe4d891514a7a0d7b6b9e9e4561cf510a9c10bdd586fa57a9683afc9db809d93777c435e0780404f5e05a91ab84d6a63abd77e33e1881f2e341c6a7cae0b8d0507dd6bab56ba688cef5910ff18a816a3bb38fa5c6307eea5221569cdc90cde855083b12e189c39cc9052c328d1e654a3ea11371a6f5ad6ad07d396227464e23b4ae1e1aa1956567e000558473a29f34c53dcd8d4b8d3df0410d8af663de3f177565409f30a2ee236d6edbffc355609b4a60643f6f7db0b30a111d9269d6df96d1d487a6ae2d672ce37fbe0ef02ef64ea5793778f67af238fe45ff15ad1609bdead8fe39d445b2644254cf0acc5effc84ff8786fcbd041b7d3a42085d5c2f1cea86f2817d9b1e21c252e6f02404c7699ed8c6c14b979371d1a726451599fe312b10653fa69fc6c132e30bc299af2e92f9fb4495229f1e49ce927fadcbb19ebee2cb5ceae56981201d7b73168997bde9b287abb25d86d43562839a0b30be80f02c4ee3d2021afb990364264e78cf5b07097dfe860a047191ece343378f63d88136a6509c511f4b785b48187e1bde4f8fcabec22451c19eb9af4a6b743c289426cbc2b508bd4bf9ebb382fe131928292ed0d5113f3e86c3dd8656638f4c0ee5b500ef57d19aaa4e00ab17dcf7950954d017f648aa09bbd5a87aab8c9f42a01c810bc93790ed6791d3a2462a571320bae636632b2d3d77611c6cdff96afff421a534df351910f3ffe92eaae18fc6d4a50908be160ffc5dca626d2777625205d07f18eae60d9fe1b9e32f56fd3e92f98a1aa5c728130249a24cb47556d2c40f2029b17217807e3b3a11afbf8d981df73122d61199854f2414b9ec3f687a2a021fec118b38e6756e67aec56eb726fcab9b69ae09d77d3b55559c10d8afd242836bab39f8a93d1a5f16ba0e0c76565a2731a467af0a490a8e3baa3b3bcd36fba75c7d5c3985355dc38f2ff73f9728903f02274126e39301b1ee8599ccb9fd9955696f08f79a035f09d9ac570225ad05666a2900b56c97cfaa985f3a5814c46ad2a5d998c7f18be2dc1e23c540cd208b3a11124de8965dd8b645746cf351544d0371cc798ec6552d329980050c2a04812f66219677507591470d9a5d103d011b901f2a234395f363a59cc8d18561f7807f1d26e0fe5d2bd38365c174b2886758eeccb73f958c1550df9016863c87aa5a94daabb03dc34208bd682854ebaebe90954ddfc2a4974a02566c15fc5976d38c010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e2ce050101ffffffff0200ca9a3b000000001976a9141fb09ecb821dd7ce9cc8ee1ed54df0d1863f824188ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f570880148700000000000000000000000000000000000000
04000000c848f5a041f4406004243ecf645ef91f303f6766f5615e4cd2c7ab08000000002c46ffced042e210ec98759ee1bf5792b62c3a3c56f24667422350dcf3c84e070000000000000000000000000000000000000000000000000000000000000000d4cb7d5b7beb091cf18a4fa59e6d1400000000000000000000000000000000000000000038d0a613fd400500572cbab31dea47dc52529819b5b80cce7fa6ff4f0c1e8f09d50bee7b5012813826948828c3d5e6f14505a4f7ab54884cb7b8f1a49675b99f820d219567d72695fc14f74a26554ad3c346123852669bd29e50eb056cda5e176bd065ccbbf2663f3a12a11f7773a0847c09059fddb09a37908e1a8240f29dd6eaec78f92b1f67e2a1cd27c2b1d6f9c5c7d0c8545dedb6f949c93507838d4525606b73d176ed8ddfa2a20d93ba4d4303512f8fa4c96efcc084329bad15f9997edef03fc90edcd1e7f943c95b5c7123d66a4d0ec9012ab2578e1d9bbcb47bdf56e9eb72e3c82dcfb14ed9785c860522791bb3bde200f76db5e907555c27ef91489cc4410b4129e4aa08b800c00952b451cf3640c326b690e719d92cd2a87799d1dd63b36984c30a6582bdb1fc6d16b323c2ef33b23deaf2325763f8b1fe7b21dd7c801ffc7df2c4d68511aff3b2059e681bb1afaa19090d03592df27c452350d040718758902afcaee5fa48a00e9fffbd3ec4222973c2686fb3e7beee6c5ebe0ecc130b8981d00adfcd464832b625d7cd82adb99e02f71c4b3d9ec6ce5812cb5075cd70cffd967e73b9f08c04c97c728e02efa88b18f318423ce212fca69c05b743289eb18912bdbcde1bc5fb507286baccb1b8937438092c5418a86fe56bdf441637ac4a49e172f491f743a694bc0516e02ebb1e36ec3b4a460e5f45bf6d2c055924c396c9546f9839b696785fdc09f99ddc7e701a3f0f61b7cb90d6de292400b8423f45bdb6d11d921711cc0a5316d200c220f70e80cda935f6b911e34d1aed9769d40ab973a6aaf1bbbc33ecf57f60d93a490d5835583ca4b70de9218510784caaf2d28c1b3dfe1af1e47ea3c96ddd46e27343ea5b80d175c3ef69b5387d2bfae8d026c765d2f5ec7ec7dacdca63dfbae85974e5a57e636edd68754664b56b9421a009ed09d7007b72db75980945b9f8e0da56d03cdcd8cdb9ce8a6d21336a8ab946fdeb59472585584a85e59e31152f0a9e03da924877854e93d5f6fbcff21a4165bbc4b60c8a195bd46761499fe1a28eb464c0957203d337cd0781d1e385308017999260c8da0933ee3b751d3ce92015b3e67393dc98d883d70113d24f72c4b73a885f1cea47062e88aba3983f192c69dc10db68b95fb3e021363ba87ad938bf97077263a7aeca4f769dfd54370194582d31d7c632c60833fa9346814b26ce1d7c451d6fbd6c309de603780185f499b963a7310abc42450445a2f2840f25350d38f2140b3904fd636ff5016334e2c234d72eff0d8096588c71ffdcde3569b3914f02acbe1938957135acc6d10f2d5bf56885c177e6ca778f7ce431225fd535a15949fdfd2e8ab0c47fd8251e294c02cf98d91340afb5812950c46d9b8dadba902fc70ea73c2c26b5a4d0d59410da46018486d9ec5a0a9b89422190afb7e72b7150f97b359d70841170ae23bacf915f10a019c601f48017472dd2b7c7b89bf0128dfd4a01e450adf17071ded02a3ae13eb7f8fec54510955a305256b2be2d97994140f36222d5ba55ec0ea35749fc894289af4454e944c1dbb1d7d40f1e72276651c4e3542bfd9f145500d9295eab83c6fc92362875620cd0159b7b53ff530d66b25adde2187438045c5fc4b8bdaff93dfb65b85c71753846bfa91f6ac60c9db561423b6109feef932486ece2cdc3c539112318c79ecc7e08ddda73ce663c3d4e9b9a7c743955330f1ca702b8a5673f82328b5f637dfa3743bcbe07583bfecf731cab93abc8d4a5dbfcdbf3536db25f1fff0d71175b744d561eecd1a89fe0484d466d2c5a68d61abba2dd9e8786211482b2b50218eec505f94c67971242a67a93872681ac81e1f541ecbf95a8bd7f5d8c1e60d95a76138bab40da3455b5a36549920d7f4d0102030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff1a03e3ce05152f5669614254432f48656c6c6f20776f726c64212fffffffff0288f19a3b000000001976a914fb8a6a4c11cb216ce21f9f371dfc9271a469bd6d88ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000030000807082c403016f4029430669c709d041c579c8e9469446f1159064613e6cd47514691b93b8ff000000006a47304402204ff60fca23a36026d374850bc018e7c714de78d8560d4188fa247b1a4ee4dcee02206538b475265173915662465b4a8554a111003701371d553134047bf185c98ba20121029ba2dc5033c7c17f06274b85c0f8e51ad518f34235713ffee4705867162819fafeffffff0208672302000000001976a9140ed9a32475fa7214939a6705fd790a74976bab0388ac3e926c01000000001976a914d752bedc09529fb3719004407dd6b5f29000e3e688acd7ce0500f6ce050000 04000000d91995f491c208a7a8c1d358417120e91451158db34ab4ef30a1c026e2d6070094eda3d052afd42b6d45e541a1d97184636bb767ccbb7d8f91584693a80233250d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5ab4dd295ca942181f1a0006ea1556b0c6c73177cd09700bb72e6b2457fed3174f1d69d4e6e3190000fd4005002f434e5adb994d86d3d45d4fc9584f3d70dba6ee34005bbd47169aa751d4c4d06bf9476a26cfb2fdc905c663c77186e370765413a5d0d25be15e4d50746c232c0fde2d09e01c5cf1e53b70db14c9d889fcd1ad128add562edc91339d81d1a4a78e3eed31d4d16d5b3209ae0571569d590114f68e85fd37b26b0c7724531d14a72bbacd02a309cf039521ce4d5537069326fd1fec07eda692ff09f941a8f8c0f543372ec8fa85c20416161dd719e3f4d3f0e663eeefc4da0feb31eace0e54f9df1fd5714aebb4d306636d0b61357e343e9c04c7f60402a9066bdf11b6817ced3f39e539ff98e4282b63ead466a6e15d5c85b76affa63a4e8e935f060a074f30cf9bcc89ef3872f80268ffb4cdc5aa67fb10b745e3b856fbb4b95d439fe8c8933b50eb5dc0091ec9c41c5ddc998b477c5302c0aede64eecf70b35c1f7d7983e1e052039dea18529752ea7e5ae67f4f51009908fd530968726e0fc9dd79d71022d2eb5749f1055e96fa98b35b79e7e32a92de750036c29bbaf38c0d30587b1f87653bcbb979142b658396d4cb7c2496566154d160ba44dbe97165f909c0c5c2e99077bb71041313603d852e22f0c560ab1f0738ddf74f105aa13e26ad8baa139f98f29ed71b85c80085f324f7db0b0a6e9e1d4584af6c592483254378654903adf6b4b70b77be24e817b053ac55016f29ac78a218095509e902936166f7923ceaabda692442ce1da6fd8e3a6b860cf8ecf7770ad2d77afbb0d15de5fc6084ff491a370baeb547171415e1be7f38e5edcc1283bc573f5522286f3d92208d568896dcf51c1566cdb583f1f0d87902e8fc27c6d1c43b1b3bb051cf568e426b551608cc1d27aa72fc9ff34f2479e609a8fc68a6899598f2d713065789f95983f78a3b746798bb19a989381ae0a531178d735c11e1cfa856b40d05b1f959115608e66800e95c067be6ebbd6ac008193ced38e24bc6db67a210d9a6ed0eddbbcdfb0f8439ab66cd4e27ca32f01a095212f36cd6b1c13c17c4ad3327c255b770dc66e03c797b1d39177365c08af59e723825596f024c7dba0a6a71657f84ab7ef5b345c11ad19191bd25d725cd1660d4e0e793c453bf9aac0494f4942f75481f577d0fe5860ffe6c776fbbb801bc6794c11c9d81ec91d32a2e162c69651c8deb52d2bd4bcdf9e0f18254549c041230266cadaf43cb09f113967492286faa3ce2c50a261ec8e847956ddce763e1df446b4164f2594bc40a1c6a756a451022381fd618bb432b9dbfbcb92d79865e3e9beee8a7277359188b6ef0956b59b47e023c06cd3f99c002fed0fb9a7cb63578a4ab4be39d24981caf13d1d4d580e4d48183aca7ae8a3230011b83d1097b33d5b7a3cf89f61d6702f5ec79e66fcd93e5bd4a5183189fae5123cb56791bcf64b9425e473cfdd2073b30e551703823d848e4adcf32673270b7d4b91511b38efd3a60937f2b90c7accaf7102e0b3c5e12c907b62acf098fe2abe7d073f4a4ba248623757adcd12f27ec2cedb749c7e280452b7f2cc085beceb495040cdb00ef434bc9ab78f8b0f79e8bb90cfaf7f8577743dd5a96c8264aa9b19ca5b7e46ed1a74b3d3fa1f02eb0164b62297b61e6bd951bea4562fdf8b3355ea95ad9a72ad0a35affe08f683bf77f781212cb53f9130b672e7e6a5ed3b31bf0a1089f2e694ed7875b9b5d11bc2c6ce1db7dc770d3b6a4e872a572285bfaff5c1f7a2202d8891b3ee2f6bbe4bd633ab700815c6ed9229e19b49856d72da66f865b9bcda32e5af81fd54c122c79ca1fd7a666ea4ef38b5a668b9532e675d8c0561aeba9c5f29a8f9cfc66918bda81e63ecf792705298699e526a10d4bdcc293e93b21513b8cb7dd486030145c81942a84038001873665f93d8ef80bf942f0020400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e3ce050104ffffffff0208d99a3b000000001976a9142943b34e1bbdefc6f6a5c501264404eac228ba5b88ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f5708801487000000000000000000000000000000000000000400008085202f8901bd114c7474dc9bddc943f99e3cd8af97332b4c899fbdebc44f105fe6b760bf41010000006b483045022100b73c1baacf61e8b4bd915ee1c007a51366a7cc718c5469de9f035aec7f92fdda0220595ad4cadd2617be7ce65ca5aa10b6d86ae27fb86c960686d7e1c668469afe12012103f9e72f0713a4d4a980309a14a2ba563e0b1125ad067818e77553a1eefbfc5be7ffffffff02f0ba0400000000001976a914d78f41784821c3d9929fa56e85267eae0bb09ffd88ac486e1500000000001976a9144faeeb51bcd0b49f238b323e5f1c6c8bf11ae02a88ac00000000e6ce05000000000000000000000000

14
testdata/tx_v5.json vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -744,9 +744,6 @@ func (d decoder) skipValue() error {
// Skip items. This will not validate whether skipped values are // Skip items. This will not validate whether skipped values are
// of the same type or not, same behavior as C++ // of the same type or not, same behavior as C++
// TextFormat::Parser::AllowUnknownField(true) version 3.8.0. // TextFormat::Parser::AllowUnknownField(true) version 3.8.0.
if err := d.skipValue(); err != nil {
return err
}
} }
} }
} }

View File

@ -263,3 +263,8 @@ func (e *Encoder) Snapshot() encoderState {
func (e *Encoder) Reset(es encoderState) { func (e *Encoder) Reset(es encoderState) {
e.encoderState = es e.encoderState = es
} }
// AppendString appends the escaped form of the input string to b.
func AppendString(b []byte, s string) []byte {
return appendString(b, s, false)
}

View File

@ -440,6 +440,13 @@ func legacyMerge(in piface.MergeInput) piface.MergeOutput {
if !ok { if !ok {
return piface.MergeOutput{} return piface.MergeOutput{}
} }
if !in.Source.IsValid() {
// Legacy Marshal methods may not function on nil messages.
// Check for a typed nil source only after we confirm that
// legacy Marshal/Unmarshal methods are present, for
// consistency.
return piface.MergeOutput{Flags: piface.MergeComplete}
}
b, err := marshaler.Marshal() b, err := marshaler.Marshal()
if err != nil { if err != nil {
return piface.MergeOutput{} return piface.MergeOutput{}

View File

@ -52,8 +52,8 @@ import (
// 10. Send out the CL for review and submit it. // 10. Send out the CL for review and submit it.
const ( const (
Major = 1 Major = 1
Minor = 26 Minor = 27
Patch = 0 Patch = 1
PreRelease = "" PreRelease = ""
) )

View File

@ -94,7 +94,8 @@ type Files struct {
// Note that enum values are in the top-level since that are in the same // Note that enum values are in the top-level since that are in the same
// scope as the parent enum. // scope as the parent enum.
descsByName map[protoreflect.FullName]interface{} descsByName map[protoreflect.FullName]interface{}
filesByPath map[string]protoreflect.FileDescriptor filesByPath map[string][]protoreflect.FileDescriptor
numFiles int
} }
type packageDescriptor struct { type packageDescriptor struct {
@ -117,17 +118,16 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
r.descsByName = map[protoreflect.FullName]interface{}{ r.descsByName = map[protoreflect.FullName]interface{}{
"": &packageDescriptor{}, "": &packageDescriptor{},
} }
r.filesByPath = make(map[string]protoreflect.FileDescriptor) r.filesByPath = make(map[string][]protoreflect.FileDescriptor)
} }
path := file.Path() path := file.Path()
if prev := r.filesByPath[path]; prev != nil { if prev := r.filesByPath[path]; len(prev) > 0 {
r.checkGenProtoConflict(path) r.checkGenProtoConflict(path)
err := errors.New("file %q is already registered", file.Path()) err := errors.New("file %q is already registered", file.Path())
err = amendErrorWithCaller(err, prev, file) err = amendErrorWithCaller(err, prev[0], file)
if r == GlobalFiles && ignoreConflict(file, err) { if !(r == GlobalFiles && ignoreConflict(file, err)) {
err = nil return err
} }
return err
} }
for name := file.Package(); name != ""; name = name.Parent() { for name := file.Package(); name != ""; name = name.Parent() {
@ -168,7 +168,8 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
rangeTopLevelDescriptors(file, func(d protoreflect.Descriptor) { rangeTopLevelDescriptors(file, func(d protoreflect.Descriptor) {
r.descsByName[d.FullName()] = d r.descsByName[d.FullName()] = d
}) })
r.filesByPath[path] = file r.filesByPath[path] = append(r.filesByPath[path], file)
r.numFiles++
return nil return nil
} }
@ -308,6 +309,7 @@ func (s *nameSuffix) Pop() (name protoreflect.Name) {
// FindFileByPath looks up a file by the path. // FindFileByPath looks up a file by the path.
// //
// This returns (nil, NotFound) if not found. // This returns (nil, NotFound) if not found.
// This returns an error if multiple files have the same path.
func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error) { func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {
if r == nil { if r == nil {
return nil, NotFound return nil, NotFound
@ -316,13 +318,19 @@ func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error)
globalMutex.RLock() globalMutex.RLock()
defer globalMutex.RUnlock() defer globalMutex.RUnlock()
} }
if fd, ok := r.filesByPath[path]; ok { fds := r.filesByPath[path]
return fd, nil switch len(fds) {
case 0:
return nil, NotFound
case 1:
return fds[0], nil
default:
return nil, errors.New("multiple files named %q", path)
} }
return nil, NotFound
} }
// NumFiles reports the number of registered files. // NumFiles reports the number of registered files,
// including duplicate files with the same name.
func (r *Files) NumFiles() int { func (r *Files) NumFiles() int {
if r == nil { if r == nil {
return 0 return 0
@ -331,10 +339,11 @@ func (r *Files) NumFiles() int {
globalMutex.RLock() globalMutex.RLock()
defer globalMutex.RUnlock() defer globalMutex.RUnlock()
} }
return len(r.filesByPath) return r.numFiles
} }
// RangeFiles iterates over all registered files while f returns true. // RangeFiles iterates over all registered files while f returns true.
// If multiple files have the same name, RangeFiles iterates over all of them.
// The iteration order is undefined. // The iteration order is undefined.
func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) { func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
if r == nil { if r == nil {
@ -344,9 +353,11 @@ func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
globalMutex.RLock() globalMutex.RLock()
defer globalMutex.RUnlock() defer globalMutex.RUnlock()
} }
for _, file := range r.filesByPath { for _, files := range r.filesByPath {
if !f(file) { for _, file := range files {
return if !f(file) {
return
}
} }
} }
} }

View File

@ -43,7 +43,6 @@ package descriptorpb
import ( import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoiface "google.golang.org/protobuf/runtime/protoiface"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect" reflect "reflect"
sync "sync" sync "sync"
@ -829,15 +828,6 @@ func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{3} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{3}
} }
var extRange_ExtensionRangeOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use ExtensionRangeOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*ExtensionRangeOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_ExtensionRangeOptions
}
func (x *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption { func (x *ExtensionRangeOptions) GetUninterpretedOption() []*UninterpretedOption {
if x != nil { if x != nil {
return x.UninterpretedOption return x.UninterpretedOption
@ -1520,15 +1510,6 @@ func (*FileOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{10} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{10}
} }
var extRange_FileOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use FileOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*FileOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_FileOptions
}
func (x *FileOptions) GetJavaPackage() string { func (x *FileOptions) GetJavaPackage() string {
if x != nil && x.JavaPackage != nil { if x != nil && x.JavaPackage != nil {
return *x.JavaPackage return *x.JavaPackage
@ -1776,15 +1757,6 @@ func (*MessageOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{11} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{11}
} }
var extRange_MessageOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use MessageOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*MessageOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_MessageOptions
}
func (x *MessageOptions) GetMessageSetWireFormat() bool { func (x *MessageOptions) GetMessageSetWireFormat() bool {
if x != nil && x.MessageSetWireFormat != nil { if x != nil && x.MessageSetWireFormat != nil {
return *x.MessageSetWireFormat return *x.MessageSetWireFormat
@ -1930,15 +1902,6 @@ func (*FieldOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{12} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{12}
} }
var extRange_FieldOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use FieldOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*FieldOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_FieldOptions
}
func (x *FieldOptions) GetCtype() FieldOptions_CType { func (x *FieldOptions) GetCtype() FieldOptions_CType {
if x != nil && x.Ctype != nil { if x != nil && x.Ctype != nil {
return *x.Ctype return *x.Ctype
@ -2030,15 +1993,6 @@ func (*OneofOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{13} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{13}
} }
var extRange_OneofOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use OneofOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*OneofOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_OneofOptions
}
func (x *OneofOptions) GetUninterpretedOption() []*UninterpretedOption { func (x *OneofOptions) GetUninterpretedOption() []*UninterpretedOption {
if x != nil { if x != nil {
return x.UninterpretedOption return x.UninterpretedOption
@ -2101,15 +2055,6 @@ func (*EnumOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{14} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{14}
} }
var extRange_EnumOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use EnumOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*EnumOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_EnumOptions
}
func (x *EnumOptions) GetAllowAlias() bool { func (x *EnumOptions) GetAllowAlias() bool {
if x != nil && x.AllowAlias != nil { if x != nil && x.AllowAlias != nil {
return *x.AllowAlias return *x.AllowAlias
@ -2183,15 +2128,6 @@ func (*EnumValueOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{15} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{15}
} }
var extRange_EnumValueOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use EnumValueOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*EnumValueOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_EnumValueOptions
}
func (x *EnumValueOptions) GetDeprecated() bool { func (x *EnumValueOptions) GetDeprecated() bool {
if x != nil && x.Deprecated != nil { if x != nil && x.Deprecated != nil {
return *x.Deprecated return *x.Deprecated
@ -2258,15 +2194,6 @@ func (*ServiceOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{16} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{16}
} }
var extRange_ServiceOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use ServiceOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*ServiceOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_ServiceOptions
}
func (x *ServiceOptions) GetDeprecated() bool { func (x *ServiceOptions) GetDeprecated() bool {
if x != nil && x.Deprecated != nil { if x != nil && x.Deprecated != nil {
return *x.Deprecated return *x.Deprecated
@ -2335,15 +2262,6 @@ func (*MethodOptions) Descriptor() ([]byte, []int) {
return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{17} return file_google_protobuf_descriptor_proto_rawDescGZIP(), []int{17}
} }
var extRange_MethodOptions = []protoiface.ExtensionRangeV1{
{Start: 1000, End: 536870911},
}
// Deprecated: Use MethodOptions.ProtoReflect.Descriptor.ExtensionRanges instead.
func (*MethodOptions) ExtensionRangeArray() []protoiface.ExtensionRangeV1 {
return extRange_MethodOptions
}
func (x *MethodOptions) GetDeprecated() bool { func (x *MethodOptions) GetDeprecated() bool {
if x != nil && x.Deprecated != nil { if x != nil && x.Deprecated != nil {
return *x.Deprecated return *x.Deprecated

2
vendor/modules.txt vendored
View File

@ -156,7 +156,7 @@ google.golang.org/grpc/serviceconfig
google.golang.org/grpc/stats google.golang.org/grpc/stats
google.golang.org/grpc/status google.golang.org/grpc/status
google.golang.org/grpc/tap google.golang.org/grpc/tap
# google.golang.org/protobuf v1.26.0 # google.golang.org/protobuf v1.27.1
google.golang.org/protobuf/encoding/prototext google.golang.org/protobuf/encoding/prototext
google.golang.org/protobuf/encoding/protowire google.golang.org/protobuf/encoding/protowire
google.golang.org/protobuf/internal/descfmt google.golang.org/protobuf/internal/descfmt

View File

@ -4,7 +4,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.26.0 // protoc-gen-go v1.28.0
// protoc v3.6.1 // protoc v3.6.1
// source: compact_formats.proto // source: compact_formats.proto
@ -138,9 +138,10 @@ type CompactTx struct {
// unset because the calculation requires reference to prior transactions. // unset because the calculation requires reference to prior transactions.
// in a pure-Sapling context, the fee will be calculable as: // in a pure-Sapling context, the fee will be calculable as:
// valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut)) // valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut))
Fee uint32 `protobuf:"varint,3,opt,name=fee,proto3" json:"fee,omitempty"` Fee uint32 `protobuf:"varint,3,opt,name=fee,proto3" json:"fee,omitempty"`
Spends []*CompactSpend `protobuf:"bytes,4,rep,name=spends,proto3" json:"spends,omitempty"` // inputs Spends []*CompactSaplingSpend `protobuf:"bytes,4,rep,name=spends,proto3" json:"spends,omitempty"` // inputs
Outputs []*CompactOutput `protobuf:"bytes,5,rep,name=outputs,proto3" json:"outputs,omitempty"` // outputs Outputs []*CompactSaplingOutput `protobuf:"bytes,5,rep,name=outputs,proto3" json:"outputs,omitempty"` // outputs
Actions []*CompactOrchardAction `protobuf:"bytes,6,rep,name=actions,proto3" json:"actions,omitempty"`
} }
func (x *CompactTx) Reset() { func (x *CompactTx) Reset() {
@ -196,23 +197,30 @@ func (x *CompactTx) GetFee() uint32 {
return 0 return 0
} }
func (x *CompactTx) GetSpends() []*CompactSpend { func (x *CompactTx) GetSpends() []*CompactSaplingSpend {
if x != nil { if x != nil {
return x.Spends return x.Spends
} }
return nil return nil
} }
func (x *CompactTx) GetOutputs() []*CompactOutput { func (x *CompactTx) GetOutputs() []*CompactSaplingOutput {
if x != nil { if x != nil {
return x.Outputs return x.Outputs
} }
return nil return nil
} }
// CompactSpend is a Sapling Spend Description as described in 7.3 of the Zcash func (x *CompactTx) GetActions() []*CompactOrchardAction {
if x != nil {
return x.Actions
}
return nil
}
// CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash
// protocol specification. // protocol specification.
type CompactSpend struct { type CompactSaplingSpend struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
@ -220,8 +228,8 @@ type CompactSpend struct {
Nf []byte `protobuf:"bytes,1,opt,name=nf,proto3" json:"nf,omitempty"` // nullifier (see the Zcash protocol specification) Nf []byte `protobuf:"bytes,1,opt,name=nf,proto3" json:"nf,omitempty"` // nullifier (see the Zcash protocol specification)
} }
func (x *CompactSpend) Reset() { func (x *CompactSaplingSpend) Reset() {
*x = CompactSpend{} *x = CompactSaplingSpend{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_compact_formats_proto_msgTypes[2] mi := &file_compact_formats_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -229,13 +237,13 @@ func (x *CompactSpend) Reset() {
} }
} }
func (x *CompactSpend) String() string { func (x *CompactSaplingSpend) String() string {
return protoimpl.X.MessageStringOf(x) return protoimpl.X.MessageStringOf(x)
} }
func (*CompactSpend) ProtoMessage() {} func (*CompactSaplingSpend) ProtoMessage() {}
func (x *CompactSpend) ProtoReflect() protoreflect.Message { func (x *CompactSaplingSpend) ProtoReflect() protoreflect.Message {
mi := &file_compact_formats_proto_msgTypes[2] mi := &file_compact_formats_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -247,12 +255,12 @@ func (x *CompactSpend) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x) return mi.MessageOf(x)
} }
// Deprecated: Use CompactSpend.ProtoReflect.Descriptor instead. // Deprecated: Use CompactSaplingSpend.ProtoReflect.Descriptor instead.
func (*CompactSpend) Descriptor() ([]byte, []int) { func (*CompactSaplingSpend) Descriptor() ([]byte, []int) {
return file_compact_formats_proto_rawDescGZIP(), []int{2} return file_compact_formats_proto_rawDescGZIP(), []int{2}
} }
func (x *CompactSpend) GetNf() []byte { func (x *CompactSaplingSpend) GetNf() []byte {
if x != nil { if x != nil {
return x.Nf return x.Nf
} }
@ -261,18 +269,18 @@ func (x *CompactSpend) GetNf() []byte {
// output is a Sapling Output Description as described in section 7.4 of the // output is a Sapling Output Description as described in section 7.4 of the
// Zcash protocol spec. Total size is 948. // Zcash protocol spec. Total size is 948.
type CompactOutput struct { type CompactSaplingOutput struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Cmu []byte `protobuf:"bytes,1,opt,name=cmu,proto3" json:"cmu,omitempty"` // note commitment u-coordinate Cmu []byte `protobuf:"bytes,1,opt,name=cmu,proto3" json:"cmu,omitempty"` // note commitment u-coordinate
Epk []byte `protobuf:"bytes,2,opt,name=epk,proto3" json:"epk,omitempty"` // ephemeral public key Epk []byte `protobuf:"bytes,2,opt,name=epk,proto3" json:"epk,omitempty"` // ephemeral public key
Ciphertext []byte `protobuf:"bytes,3,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` // ciphertext and zkproof Ciphertext []byte `protobuf:"bytes,3,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` // first 52 bytes of ciphertext
} }
func (x *CompactOutput) Reset() { func (x *CompactSaplingOutput) Reset() {
*x = CompactOutput{} *x = CompactSaplingOutput{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_compact_formats_proto_msgTypes[3] mi := &file_compact_formats_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -280,13 +288,13 @@ func (x *CompactOutput) Reset() {
} }
} }
func (x *CompactOutput) String() string { func (x *CompactSaplingOutput) String() string {
return protoimpl.X.MessageStringOf(x) return protoimpl.X.MessageStringOf(x)
} }
func (*CompactOutput) ProtoMessage() {} func (*CompactSaplingOutput) ProtoMessage() {}
func (x *CompactOutput) ProtoReflect() protoreflect.Message { func (x *CompactSaplingOutput) ProtoReflect() protoreflect.Message {
mi := &file_compact_formats_proto_msgTypes[3] mi := &file_compact_formats_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -298,26 +306,99 @@ func (x *CompactOutput) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x) return mi.MessageOf(x)
} }
// Deprecated: Use CompactOutput.ProtoReflect.Descriptor instead. // Deprecated: Use CompactSaplingOutput.ProtoReflect.Descriptor instead.
func (*CompactOutput) Descriptor() ([]byte, []int) { func (*CompactSaplingOutput) Descriptor() ([]byte, []int) {
return file_compact_formats_proto_rawDescGZIP(), []int{3} return file_compact_formats_proto_rawDescGZIP(), []int{3}
} }
func (x *CompactOutput) GetCmu() []byte { func (x *CompactSaplingOutput) GetCmu() []byte {
if x != nil { if x != nil {
return x.Cmu return x.Cmu
} }
return nil return nil
} }
func (x *CompactOutput) GetEpk() []byte { func (x *CompactSaplingOutput) GetEpk() []byte {
if x != nil { if x != nil {
return x.Epk return x.Epk
} }
return nil return nil
} }
func (x *CompactOutput) GetCiphertext() []byte { func (x *CompactSaplingOutput) GetCiphertext() []byte {
if x != nil {
return x.Ciphertext
}
return nil
}
// https://github.com/zcash/zips/blob/main/zip-0225.rst#orchard-action-description-orchardaction
// (but not all fields are needed)
type CompactOrchardAction struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Nullifier []byte `protobuf:"bytes,1,opt,name=nullifier,proto3" json:"nullifier,omitempty"` // [32] The nullifier of the input note
Cmx []byte `protobuf:"bytes,2,opt,name=cmx,proto3" json:"cmx,omitempty"` // [32] The x-coordinate of the note commitment for the output note
EphemeralKey []byte `protobuf:"bytes,3,opt,name=ephemeralKey,proto3" json:"ephemeralKey,omitempty"` // [32] An encoding of an ephemeral Pallas public key
Ciphertext []byte `protobuf:"bytes,4,opt,name=ciphertext,proto3" json:"ciphertext,omitempty"` // [52] The note plaintext component of the encCiphertext field
}
func (x *CompactOrchardAction) Reset() {
*x = CompactOrchardAction{}
if protoimpl.UnsafeEnabled {
mi := &file_compact_formats_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CompactOrchardAction) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CompactOrchardAction) ProtoMessage() {}
func (x *CompactOrchardAction) ProtoReflect() protoreflect.Message {
mi := &file_compact_formats_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CompactOrchardAction.ProtoReflect.Descriptor instead.
func (*CompactOrchardAction) Descriptor() ([]byte, []int) {
return file_compact_formats_proto_rawDescGZIP(), []int{4}
}
func (x *CompactOrchardAction) GetNullifier() []byte {
if x != nil {
return x.Nullifier
}
return nil
}
func (x *CompactOrchardAction) GetCmx() []byte {
if x != nil {
return x.Cmx
}
return nil
}
func (x *CompactOrchardAction) GetEphemeralKey() []byte {
if x != nil {
return x.EphemeralKey
}
return nil
}
func (x *CompactOrchardAction) GetCiphertext() []byte {
if x != nil { if x != nil {
return x.Ciphertext return x.Ciphertext
} }
@ -343,26 +424,41 @@ var file_compact_formats_proto_rawDesc = []byte{
0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x03, 0x76, 0x74, 0x78, 0x18, 0x07, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x03, 0x76, 0x74, 0x78, 0x18, 0x07,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61,
0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d,
0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x52, 0x03, 0x76, 0x74, 0x78, 0x22, 0xc4, 0x01, 0x0a, 0x09, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x52, 0x03, 0x76, 0x74, 0x78, 0x22, 0x99, 0x02, 0x0a, 0x09,
0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12,
0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68,
0x61, 0x73, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x61, 0x73, 0x68, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x18, 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x18,
0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f,
0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x52, 0x06, 0x73, 0x70, 0x65, 0x6e, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x6e,
0x64, 0x73, 0x12, 0x3e, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x05, 0x20, 0x64, 0x52, 0x06, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x45, 0x0a, 0x07, 0x6f, 0x75, 0x74,
0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x70, 0x75, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x61, 0x73,
0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72,
0x61, 0x63, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x61, 0x70, 0x6c, 0x69, 0x6e,
0x74, 0x73, 0x22, 0x1e, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x70, 0x65, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73,
0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x6e, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x12, 0x45, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28,
0x6e, 0x66, 0x22, 0x53, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x4f, 0x75, 0x74, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65,
0x70, 0x75, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63,
0x52, 0x03, 0x63, 0x6d, 0x75, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x70, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x74, 0x4f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07,
0x28, 0x0c, 0x52, 0x03, 0x65, 0x70, 0x6b, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x25, 0x0a, 0x13, 0x43, 0x6f, 0x6d, 0x70, 0x61,
0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x69, 0x70, 0x63, 0x74, 0x53, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x0e,
0x0a, 0x02, 0x6e, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x6e, 0x66, 0x22, 0x5a,
0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67,
0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x75, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x03, 0x63, 0x6d, 0x75, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x70, 0x6b, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x65, 0x70, 0x6b, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x69,
0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a,
0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x22, 0x8a, 0x01, 0x0a, 0x14, 0x43,
0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x4f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x75, 0x6c, 0x6c, 0x69, 0x66, 0x69, 0x65, 0x72,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6e, 0x75, 0x6c, 0x6c, 0x69, 0x66, 0x69, 0x65,
0x72, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x6d, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03,
0x63, 0x6d, 0x78, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c,
0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x70, 0x68, 0x65, 0x6d,
0x65, 0x72, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x69, 0x70, 0x68, 0x65,
0x72, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x69, 0x70,
0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x42, 0x1b, 0x5a, 0x16, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x68, 0x65, 0x72, 0x74, 0x65, 0x78, 0x74, 0x42, 0x1b, 0x5a, 0x16, 0x6c, 0x69, 0x67, 0x68, 0x74,
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70,
0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
@ -380,22 +476,24 @@ func file_compact_formats_proto_rawDescGZIP() []byte {
return file_compact_formats_proto_rawDescData return file_compact_formats_proto_rawDescData
} }
var file_compact_formats_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_compact_formats_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_compact_formats_proto_goTypes = []interface{}{ var file_compact_formats_proto_goTypes = []interface{}{
(*CompactBlock)(nil), // 0: cash.z.wallet.sdk.rpc.CompactBlock (*CompactBlock)(nil), // 0: cash.z.wallet.sdk.rpc.CompactBlock
(*CompactTx)(nil), // 1: cash.z.wallet.sdk.rpc.CompactTx (*CompactTx)(nil), // 1: cash.z.wallet.sdk.rpc.CompactTx
(*CompactSpend)(nil), // 2: cash.z.wallet.sdk.rpc.CompactSpend (*CompactSaplingSpend)(nil), // 2: cash.z.wallet.sdk.rpc.CompactSaplingSpend
(*CompactOutput)(nil), // 3: cash.z.wallet.sdk.rpc.CompactOutput (*CompactSaplingOutput)(nil), // 3: cash.z.wallet.sdk.rpc.CompactSaplingOutput
(*CompactOrchardAction)(nil), // 4: cash.z.wallet.sdk.rpc.CompactOrchardAction
} }
var file_compact_formats_proto_depIdxs = []int32{ var file_compact_formats_proto_depIdxs = []int32{
1, // 0: cash.z.wallet.sdk.rpc.CompactBlock.vtx:type_name -> cash.z.wallet.sdk.rpc.CompactTx 1, // 0: cash.z.wallet.sdk.rpc.CompactBlock.vtx:type_name -> cash.z.wallet.sdk.rpc.CompactTx
2, // 1: cash.z.wallet.sdk.rpc.CompactTx.spends:type_name -> cash.z.wallet.sdk.rpc.CompactSpend 2, // 1: cash.z.wallet.sdk.rpc.CompactTx.spends:type_name -> cash.z.wallet.sdk.rpc.CompactSaplingSpend
3, // 2: cash.z.wallet.sdk.rpc.CompactTx.outputs:type_name -> cash.z.wallet.sdk.rpc.CompactOutput 3, // 2: cash.z.wallet.sdk.rpc.CompactTx.outputs:type_name -> cash.z.wallet.sdk.rpc.CompactSaplingOutput
3, // [3:3] is the sub-list for method output_type 4, // 3: cash.z.wallet.sdk.rpc.CompactTx.actions:type_name -> cash.z.wallet.sdk.rpc.CompactOrchardAction
3, // [3:3] is the sub-list for method input_type 4, // [4:4] is the sub-list for method output_type
3, // [3:3] is the sub-list for extension type_name 4, // [4:4] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension extendee 4, // [4:4] is the sub-list for extension type_name
0, // [0:3] is the sub-list for field type_name 4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
} }
func init() { file_compact_formats_proto_init() } func init() { file_compact_formats_proto_init() }
@ -429,7 +527,7 @@ func file_compact_formats_proto_init() {
} }
} }
file_compact_formats_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { file_compact_formats_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CompactSpend); i { switch v := v.(*CompactSaplingSpend); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -441,7 +539,19 @@ func file_compact_formats_proto_init() {
} }
} }
file_compact_formats_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { file_compact_formats_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CompactOutput); i { switch v := v.(*CompactSaplingOutput); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_compact_formats_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CompactOrchardAction); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -459,7 +569,7 @@ func file_compact_formats_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_compact_formats_proto_rawDesc, RawDescriptor: file_compact_formats_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 4, NumMessages: 5,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@ -37,20 +37,30 @@ message CompactTx {
// valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut)) // valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut))
uint32 fee = 3; uint32 fee = 3;
repeated CompactSpend spends = 4; // inputs repeated CompactSaplingSpend spends = 4; // inputs
repeated CompactOutput outputs = 5; // outputs repeated CompactSaplingOutput outputs = 5; // outputs
repeated CompactOrchardAction actions = 6;
} }
// CompactSpend is a Sapling Spend Description as described in 7.3 of the Zcash // CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash
// protocol specification. // protocol specification.
message CompactSpend { message CompactSaplingSpend {
bytes nf = 1; // nullifier (see the Zcash protocol specification) bytes nf = 1; // nullifier (see the Zcash protocol specification)
} }
// output is a Sapling Output Description as described in section 7.4 of the // output is a Sapling Output Description as described in section 7.4 of the
// Zcash protocol spec. Total size is 948. // Zcash protocol spec. Total size is 948.
message CompactOutput { message CompactSaplingOutput {
bytes cmu = 1; // note commitment u-coordinate bytes cmu = 1; // note commitment u-coordinate
bytes epk = 2; // ephemeral public key bytes epk = 2; // ephemeral public key
bytes ciphertext = 3; // ciphertext and zkproof bytes ciphertext = 3; // first 52 bytes of ciphertext
}
// https://github.com/zcash/zips/blob/main/zip-0225.rst#orchard-action-description-orchardaction
// (but not all fields are needed)
message CompactOrchardAction {
bytes nullifier = 1; // [32] The nullifier of the input note
bytes cmx = 2; // [32] The x-coordinate of the note commitment for the output note
bytes ephemeralKey = 3; // [32] An encoding of an ephemeral Pallas public key
bytes ciphertext = 4; // [52] The note plaintext component of the encCiphertext field
} }

View File

@ -4,8 +4,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.26.0 // protoc-gen-go v1.27.1
// protoc v3.15.7 // protoc v3.19.4
// source: darkside.proto // source: darkside.proto
package walletrpc package walletrpc
@ -383,7 +383,7 @@ var file_darkside_proto_rawDesc = []byte{
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05,
0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03,
0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0xda, 0x06, 0x0a, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x8b, 0x08, 0x0a, 0x10,
0x44, 0x61, 0x72, 0x6b, 0x73, 0x69, 0x64, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x44, 0x61, 0x72, 0x6b, 0x73, 0x69, 0x64, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72,
0x12, 0x51, 0x0a, 0x05, 0x52, 0x65, 0x73, 0x65, 0x74, 0x12, 0x28, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x12, 0x51, 0x0a, 0x05, 0x52, 0x65, 0x73, 0x65, 0x74, 0x12, 0x28, 0x2e, 0x63, 0x61, 0x73, 0x68,
0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70,
@ -437,9 +437,20 @@ var file_darkside_proto_rawDesc = []byte{
0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72,
0x70, 0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x70, 0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e,
0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63,
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x1b, 0x5a, 0x16, 0x6c, 0x69, 0x67, 0x68, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x41,
0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x12, 0x2b, 0x2e, 0x63, 0x61, 0x73,
0x70, 0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72,
0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78,
0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x1a, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a,
0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x10, 0x43, 0x6c, 0x65, 0x61, 0x72,
0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x12, 0x1c, 0x2e, 0x63, 0x61,
0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e,
0x72, 0x70, 0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68,
0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70,
0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x1b, 0x5a, 0x16, 0x6c, 0x69, 0x67,
0x68, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
0x72, 0x70, 0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -464,31 +475,36 @@ var file_darkside_proto_goTypes = []interface{}{
(*DarksideEmptyBlocks)(nil), // 5: cash.z.wallet.sdk.rpc.DarksideEmptyBlocks (*DarksideEmptyBlocks)(nil), // 5: cash.z.wallet.sdk.rpc.DarksideEmptyBlocks
(*RawTransaction)(nil), // 6: cash.z.wallet.sdk.rpc.RawTransaction (*RawTransaction)(nil), // 6: cash.z.wallet.sdk.rpc.RawTransaction
(*Empty)(nil), // 7: cash.z.wallet.sdk.rpc.Empty (*Empty)(nil), // 7: cash.z.wallet.sdk.rpc.Empty
(*GetAddressUtxosReply)(nil), // 8: cash.z.wallet.sdk.rpc.GetAddressUtxosReply
} }
var file_darkside_proto_depIdxs = []int32{ var file_darkside_proto_depIdxs = []int32{
0, // 0: cash.z.wallet.sdk.rpc.DarksideStreamer.Reset:input_type -> cash.z.wallet.sdk.rpc.DarksideMetaState 0, // 0: cash.z.wallet.sdk.rpc.DarksideStreamer.Reset:input_type -> cash.z.wallet.sdk.rpc.DarksideMetaState
1, // 1: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksStream:input_type -> cash.z.wallet.sdk.rpc.DarksideBlock 1, // 1: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksStream:input_type -> cash.z.wallet.sdk.rpc.DarksideBlock
2, // 2: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocks:input_type -> cash.z.wallet.sdk.rpc.DarksideBlocksURL 2, // 2: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocks:input_type -> cash.z.wallet.sdk.rpc.DarksideBlocksURL
5, // 3: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksCreate:input_type -> cash.z.wallet.sdk.rpc.DarksideEmptyBlocks 5, // 3: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksCreate:input_type -> cash.z.wallet.sdk.rpc.DarksideEmptyBlocks
6, // 4: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactionsStream:input_type -> cash.z.wallet.sdk.rpc.RawTransaction 6, // 4: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactionsStream:input_type -> cash.z.wallet.sdk.rpc.RawTransaction
3, // 5: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactions:input_type -> cash.z.wallet.sdk.rpc.DarksideTransactionsURL 3, // 5: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactions:input_type -> cash.z.wallet.sdk.rpc.DarksideTransactionsURL
4, // 6: cash.z.wallet.sdk.rpc.DarksideStreamer.ApplyStaged:input_type -> cash.z.wallet.sdk.rpc.DarksideHeight 4, // 6: cash.z.wallet.sdk.rpc.DarksideStreamer.ApplyStaged:input_type -> cash.z.wallet.sdk.rpc.DarksideHeight
7, // 7: cash.z.wallet.sdk.rpc.DarksideStreamer.GetIncomingTransactions:input_type -> cash.z.wallet.sdk.rpc.Empty 7, // 7: cash.z.wallet.sdk.rpc.DarksideStreamer.GetIncomingTransactions:input_type -> cash.z.wallet.sdk.rpc.Empty
7, // 8: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearIncomingTransactions:input_type -> cash.z.wallet.sdk.rpc.Empty 7, // 8: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearIncomingTransactions:input_type -> cash.z.wallet.sdk.rpc.Empty
7, // 9: cash.z.wallet.sdk.rpc.DarksideStreamer.Reset:output_type -> cash.z.wallet.sdk.rpc.Empty 8, // 9: cash.z.wallet.sdk.rpc.DarksideStreamer.AddAddressUtxo:input_type -> cash.z.wallet.sdk.rpc.GetAddressUtxosReply
7, // 10: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksStream:output_type -> cash.z.wallet.sdk.rpc.Empty 7, // 10: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearAddressUtxo:input_type -> cash.z.wallet.sdk.rpc.Empty
7, // 11: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocks:output_type -> cash.z.wallet.sdk.rpc.Empty 7, // 11: cash.z.wallet.sdk.rpc.DarksideStreamer.Reset:output_type -> cash.z.wallet.sdk.rpc.Empty
7, // 12: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksCreate:output_type -> cash.z.wallet.sdk.rpc.Empty 7, // 12: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksStream:output_type -> cash.z.wallet.sdk.rpc.Empty
7, // 13: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactionsStream:output_type -> cash.z.wallet.sdk.rpc.Empty 7, // 13: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocks:output_type -> cash.z.wallet.sdk.rpc.Empty
7, // 14: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactions:output_type -> cash.z.wallet.sdk.rpc.Empty 7, // 14: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksCreate:output_type -> cash.z.wallet.sdk.rpc.Empty
7, // 15: cash.z.wallet.sdk.rpc.DarksideStreamer.ApplyStaged:output_type -> cash.z.wallet.sdk.rpc.Empty 7, // 15: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactionsStream:output_type -> cash.z.wallet.sdk.rpc.Empty
6, // 16: cash.z.wallet.sdk.rpc.DarksideStreamer.GetIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.RawTransaction 7, // 16: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactions:output_type -> cash.z.wallet.sdk.rpc.Empty
7, // 17: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.Empty 7, // 17: cash.z.wallet.sdk.rpc.DarksideStreamer.ApplyStaged:output_type -> cash.z.wallet.sdk.rpc.Empty
9, // [9:18] is the sub-list for method output_type 6, // 18: cash.z.wallet.sdk.rpc.DarksideStreamer.GetIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.RawTransaction
0, // [0:9] is the sub-list for method input_type 7, // 19: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.Empty
0, // [0:0] is the sub-list for extension type_name 7, // 20: cash.z.wallet.sdk.rpc.DarksideStreamer.AddAddressUtxo:output_type -> cash.z.wallet.sdk.rpc.Empty
0, // [0:0] is the sub-list for extension extendee 7, // 21: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearAddressUtxo:output_type -> cash.z.wallet.sdk.rpc.Empty
0, // [0:0] is the sub-list for field type_name 11, // [11:22] is the sub-list for method output_type
0, // [0:11] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
} }
func init() { file_darkside_proto_init() } func init() { file_darkside_proto_init() }

View File

@ -114,4 +114,11 @@ service DarksideStreamer {
// Clear the incoming transaction pool. // Clear the incoming transaction pool.
rpc ClearIncomingTransactions(Empty) returns (Empty) {} rpc ClearIncomingTransactions(Empty) returns (Empty) {}
// Add a GetAddressUtxosReply entry to be returned by GetAddressUtxos().
// There is no staging or applying for these, very simple.
rpc AddAddressUtxo(GetAddressUtxosReply) returns (Empty) {}
// Clear the list of GetAddressUtxos entries (can't fail)
rpc ClearAddressUtxo(Empty) returns (Empty) {}
} }

View File

@ -1,4 +1,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.19.4
// source: darkside.proto
package walletrpc package walletrpc
@ -76,6 +80,11 @@ type DarksideStreamerClient interface {
GetIncomingTransactions(ctx context.Context, in *Empty, opts ...grpc.CallOption) (DarksideStreamer_GetIncomingTransactionsClient, error) GetIncomingTransactions(ctx context.Context, in *Empty, opts ...grpc.CallOption) (DarksideStreamer_GetIncomingTransactionsClient, error)
// Clear the incoming transaction pool. // Clear the incoming transaction pool.
ClearIncomingTransactions(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) ClearIncomingTransactions(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
// Add a GetAddressUtxosReply entry to be returned by GetAddressUtxos().
// There is no staging or applying for these, very simple.
AddAddressUtxo(ctx context.Context, in *GetAddressUtxosReply, opts ...grpc.CallOption) (*Empty, error)
// Clear the list of GetAddressUtxos entries (can't fail)
ClearAddressUtxo(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
} }
type darksideStreamerClient struct { type darksideStreamerClient struct {
@ -240,6 +249,24 @@ func (c *darksideStreamerClient) ClearIncomingTransactions(ctx context.Context,
return out, nil return out, nil
} }
func (c *darksideStreamerClient) AddAddressUtxo(ctx context.Context, in *GetAddressUtxosReply, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty)
err := c.cc.Invoke(ctx, "/cash.z.wallet.sdk.rpc.DarksideStreamer/AddAddressUtxo", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *darksideStreamerClient) ClearAddressUtxo(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty)
err := c.cc.Invoke(ctx, "/cash.z.wallet.sdk.rpc.DarksideStreamer/ClearAddressUtxo", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DarksideStreamerServer is the server API for DarksideStreamer service. // DarksideStreamerServer is the server API for DarksideStreamer service.
// All implementations must embed UnimplementedDarksideStreamerServer // All implementations must embed UnimplementedDarksideStreamerServer
// for forward compatibility // for forward compatibility
@ -302,6 +329,11 @@ type DarksideStreamerServer interface {
GetIncomingTransactions(*Empty, DarksideStreamer_GetIncomingTransactionsServer) error GetIncomingTransactions(*Empty, DarksideStreamer_GetIncomingTransactionsServer) error
// Clear the incoming transaction pool. // Clear the incoming transaction pool.
ClearIncomingTransactions(context.Context, *Empty) (*Empty, error) ClearIncomingTransactions(context.Context, *Empty) (*Empty, error)
// Add a GetAddressUtxosReply entry to be returned by GetAddressUtxos().
// There is no staging or applying for these, very simple.
AddAddressUtxo(context.Context, *GetAddressUtxosReply) (*Empty, error)
// Clear the list of GetAddressUtxos entries (can't fail)
ClearAddressUtxo(context.Context, *Empty) (*Empty, error)
mustEmbedUnimplementedDarksideStreamerServer() mustEmbedUnimplementedDarksideStreamerServer()
} }
@ -336,6 +368,12 @@ func (UnimplementedDarksideStreamerServer) GetIncomingTransactions(*Empty, Darks
func (UnimplementedDarksideStreamerServer) ClearIncomingTransactions(context.Context, *Empty) (*Empty, error) { func (UnimplementedDarksideStreamerServer) ClearIncomingTransactions(context.Context, *Empty) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method ClearIncomingTransactions not implemented") return nil, status.Errorf(codes.Unimplemented, "method ClearIncomingTransactions not implemented")
} }
func (UnimplementedDarksideStreamerServer) AddAddressUtxo(context.Context, *GetAddressUtxosReply) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddAddressUtxo not implemented")
}
func (UnimplementedDarksideStreamerServer) ClearAddressUtxo(context.Context, *Empty) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method ClearAddressUtxo not implemented")
}
func (UnimplementedDarksideStreamerServer) mustEmbedUnimplementedDarksideStreamerServer() {} func (UnimplementedDarksideStreamerServer) mustEmbedUnimplementedDarksideStreamerServer() {}
// UnsafeDarksideStreamerServer may be embedded to opt out of forward compatibility for this service. // UnsafeDarksideStreamerServer may be embedded to opt out of forward compatibility for this service.
@ -530,6 +568,42 @@ func _DarksideStreamer_ClearIncomingTransactions_Handler(srv interface{}, ctx co
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _DarksideStreamer_AddAddressUtxo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetAddressUtxosReply)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DarksideStreamerServer).AddAddressUtxo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cash.z.wallet.sdk.rpc.DarksideStreamer/AddAddressUtxo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DarksideStreamerServer).AddAddressUtxo(ctx, req.(*GetAddressUtxosReply))
}
return interceptor(ctx, in, info, handler)
}
func _DarksideStreamer_ClearAddressUtxo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DarksideStreamerServer).ClearAddressUtxo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cash.z.wallet.sdk.rpc.DarksideStreamer/ClearAddressUtxo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DarksideStreamerServer).ClearAddressUtxo(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
// DarksideStreamer_ServiceDesc is the grpc.ServiceDesc for DarksideStreamer service. // DarksideStreamer_ServiceDesc is the grpc.ServiceDesc for DarksideStreamer service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@ -561,6 +635,14 @@ var DarksideStreamer_ServiceDesc = grpc.ServiceDesc{
MethodName: "ClearIncomingTransactions", MethodName: "ClearIncomingTransactions",
Handler: _DarksideStreamer_ClearIncomingTransactions_Handler, Handler: _DarksideStreamer_ClearIncomingTransactions_Handler,
}, },
{
MethodName: "AddAddressUtxo",
Handler: _DarksideStreamer_AddAddressUtxo_Handler,
},
{
MethodName: "ClearAddressUtxo",
Handler: _DarksideStreamer_ClearAddressUtxo_Handler,
},
}, },
Streams: []grpc.StreamDesc{ Streams: []grpc.StreamDesc{
{ {

View File

@ -4,7 +4,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.26.0 // protoc-gen-go v1.28.0
// protoc v3.6.1 // protoc v3.6.1
// source: service.proto // source: service.proto
@ -205,7 +205,8 @@ func (x *TxFilter) GetHash() []byte {
} }
// RawTransaction contains the complete transaction data. It also optionally includes // RawTransaction contains the complete transaction data. It also optionally includes
// the block height in which the transaction was included. // the block height in which the transaction was included, or, when returned
// by GetMempoolStream(), the latest block height.
type RawTransaction struct { type RawTransaction struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -909,11 +910,12 @@ type TreeState struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` // "main" or "test" Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` // "main" or "test"
Height uint64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` Height uint64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` // block height
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` // block id Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"` // block id
Time uint32 `protobuf:"varint,4,opt,name=time,proto3" json:"time,omitempty"` // Unix epoch time when the block was mined Time uint32 `protobuf:"varint,4,opt,name=time,proto3" json:"time,omitempty"` // Unix epoch time when the block was mined
Tree string `protobuf:"bytes,5,opt,name=tree,proto3" json:"tree,omitempty"` // sapling commitment tree state SaplingTree string `protobuf:"bytes,5,opt,name=saplingTree,proto3" json:"saplingTree,omitempty"` // sapling commitment tree state
OrchardTree string `protobuf:"bytes,6,opt,name=orchardTree,proto3" json:"orchardTree,omitempty"` // orchard commitment tree state
} }
func (x *TreeState) Reset() { func (x *TreeState) Reset() {
@ -976,9 +978,16 @@ func (x *TreeState) GetTime() uint32 {
return 0 return 0
} }
func (x *TreeState) GetTree() string { func (x *TreeState) GetSaplingTree() string {
if x != nil { if x != nil {
return x.Tree return x.SaplingTree
}
return ""
}
func (x *TreeState) GetOrchardTree() string {
if x != nil {
return x.OrchardTree
} }
return "" return ""
} }
@ -1395,153 +1404,156 @@ var file_service_proto_rawDesc = []byte{
0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x22, 0x1d, 0x0a, 0x07, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x22, 0x1d, 0x0a, 0x07, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52,
0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0x79, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0xa9, 0x01, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74,
0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01,
0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x16, 0x0a,
0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68,
0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20,
0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a,
0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x72, 0x65, 0x65, 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01,
0x22, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x65, 0x65, 0x12,
0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x20, 0x0a, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x54, 0x72, 0x65, 0x65, 0x18, 0x06,
0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x54, 0x72, 0x65,
0x73, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x69, 0x65, 0x22, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55,
0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65,
0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, 0x74, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72,
0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65,
0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x64, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x72,
0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e,
0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78,
0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79,
0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28,
0x64, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x03, 0x20, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78,
0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x14,
0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69,
0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x03,
0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08,
0x6b, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08,
0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0c, 0x61, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74,
0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x22, 0x6b, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74,
0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0c,
0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x52, 0x0c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x48, 0x0a, 0x0c, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x52,
0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x0c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x48, 0x0a,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x0c, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5f, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63,
0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5f, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x63, 0x65,
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d,
0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x32, 0xd0, 0x0c, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x61, 0x63, 0x74, 0x54, 0x78, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x63, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x01, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x32, 0xd0, 0x0c, 0x0a, 0x11, 0x43, 0x6f, 0x6d,
0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x70, 0x65, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x12, 0x54,
0x63, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x12, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
0x44, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x70,
0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x65, 0x63, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x49, 0x44, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44,
0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74,
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c,
0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e,
0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63,
0x00, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x5a, 0x45, 0x43, 0x50, 0x72, 0x69, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x63, 0x61,
0x63, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e,
0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x22, 0x00, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x5a, 0x45, 0x43, 0x50, 0x72,
0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x69, 0x63, 0x65, 0x12, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c,
0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
0x5a, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5a, 0x45, 0x43,
0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x6d,
0x70, 0x74, 0x79, 0x1a, 0x24, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x69, 0x63, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x69, 0x63,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0e, 0x47, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e,
0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63,
0x2e, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x5a, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5a, 0x45,
0x43, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e,
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x1a, 0x24, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61,
0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x69,
0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0e,
0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f,
0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73,
0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x78, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a,
0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e,
0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x63, 0x61,
0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e,
0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x10, 0x47, 0x65, 0x74,
0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x78, 0x69, 0x64, 0x73, 0x12, 0x34, 0x2e,
0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64,
0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x78, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a, 0x25, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e,
0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x69, 0x6c,
0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x74, 0x65, 0x72, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54,
0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x5a,
0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x61, 0x6c,
0x61, 0x6e, 0x63, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61,
0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e,
0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63,
0x2e, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x18, 0x47, 0x65,
0x74, 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e,
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x41,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e,
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42,
0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x54, 0x0a, 0x0c, 0x47, 0x65,
0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73,
0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72,
0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x1a, 0x20, 0x2e, 0x63, 0x61, 0x73,
0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72,
0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x22, 0x00, 0x30, 0x01,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x54, 0x12, 0x5b, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x74,
0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x54, 0x78, 0x69, 0x64, 0x73, 0x12, 0x34, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61,
0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x6d, 0x70,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x74, 0x79, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x74,
0x65, 0x72, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a,
0x12, 0x47, 0x65, 0x74, 0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x61, 0x6c, 0x61, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x2e,
0x6e, 0x63, 0x65, 0x12, 0x22, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64,
0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x20, 0x2e,
0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64,
0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22,
0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x00, 0x12, 0x6f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55,
0x54, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x1a,
0x64, 0x72, 0x65, 0x73, 0x73, 0x1a, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x2f, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x61, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65,
0x6c, 0x61, 0x6e, 0x63, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x54, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74,
0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x54, 0x78, 0x12, 0x1e, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x29, 0x2e, 0x63, 0x61,
0x63, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x1a, 0x20, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e,
0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74,
0x63, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x22, 0x00, 0x30, 0x01, 0x12, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x1a, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e,
0x5b, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x74, 0x72, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47,
0x65, 0x61, 0x6d, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65,
0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x69,
0x79, 0x1a, 0x25, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x67, 0x68, 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e,
0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x77, 0x54, 0x72, 0x61, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63,
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0c, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e,
0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x2e, 0x63, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c,
0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x69, 0x67, 0x68, 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x04, 0x50,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x20, 0x2e, 0x63, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c,
0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x75, 0x72, 0x61,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61,
0x12, 0x6f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x69, 0x6e,
0x78, 0x6f, 0x73, 0x12, 0x29, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x1b, 0x5a, 0x16, 0x6c,
0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x69, 0x67, 0x68, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, 0x6c,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x1a, 0x2f, 0x65, 0x74, 0x72, 0x70, 0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73,
0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x22,
0x00, 0x12, 0x73, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55,
0x74, 0x78, 0x6f, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x29, 0x2e, 0x63, 0x61, 0x73,
0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72,
0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78,
0x6f, 0x73, 0x41, 0x72, 0x67, 0x1a, 0x2b, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65,
0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x67,
0x68, 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a,
0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77,
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69,
0x67, 0x68, 0x74, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x04, 0x50, 0x69,
0x6e, 0x67, 0x12, 0x1f, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c,
0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x1a, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c,
0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x69, 0x6e, 0x67,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x1b, 0x5a, 0x16, 0x6c, 0x69,
0x67, 0x68, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2f, 0x77, 0x61, 0x6c, 0x6c, 0x65,
0x74, 0x72, 0x70, 0x63, 0xba, 0x02, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View File

@ -32,7 +32,8 @@ message TxFilter {
} }
// RawTransaction contains the complete transaction data. It also optionally includes // RawTransaction contains the complete transaction data. It also optionally includes
// the block height in which the transaction was included. // the block height in which the transaction was included, or, when returned
// by GetMempoolStream(), the latest block height.
message RawTransaction { message RawTransaction {
bytes data = 1; // exact data returned by Zcash 'getrawtransaction' bytes data = 1; // exact data returned by Zcash 'getrawtransaction'
uint64 height = 2; // height that the transaction was mined (or -1) uint64 height = 2; // height that the transaction was mined (or -1)
@ -109,11 +110,12 @@ message Exclude {
// The TreeState is derived from the Zcash z_gettreestate rpc. // The TreeState is derived from the Zcash z_gettreestate rpc.
message TreeState { message TreeState {
string network = 1; // "main" or "test" string network = 1; // "main" or "test"
uint64 height = 2; uint64 height = 2; // block height
string hash = 3; // block id string hash = 3; // block id
uint32 time = 4; // Unix epoch time when the block was mined uint32 time = 4; // Unix epoch time when the block was mined
string tree = 5; // sapling commitment tree state string saplingTree = 5; // sapling commitment tree state
string orchardTree = 6; // orchard commitment tree state
} }
// Results are sorted by height, which makes it easy to issue another // Results are sorted by height, which makes it easy to issue another

View File

@ -1,4 +1,8 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT. // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.6.1
// source: service.proto
package walletrpc package walletrpc
@ -45,6 +49,8 @@ type CompactTxStreamerClient interface {
// match a shortened txid, they are all sent (none is excluded). Transactions // match a shortened txid, they are all sent (none is excluded). Transactions
// in the exclude list that don't exist in the mempool are ignored. // in the exclude list that don't exist in the mempool are ignored.
GetMempoolTx(ctx context.Context, in *Exclude, opts ...grpc.CallOption) (CompactTxStreamer_GetMempoolTxClient, error) GetMempoolTx(ctx context.Context, in *Exclude, opts ...grpc.CallOption) (CompactTxStreamer_GetMempoolTxClient, error)
// Return a stream of current Mempool transactions. This will keep the output stream open while
// there are mempool transactions. It will close the returned stream when a new block is mined.
GetMempoolStream(ctx context.Context, in *Empty, opts ...grpc.CallOption) (CompactTxStreamer_GetMempoolStreamClient, error) GetMempoolStream(ctx context.Context, in *Empty, opts ...grpc.CallOption) (CompactTxStreamer_GetMempoolStreamClient, error)
// GetTreeState returns the note commitment tree state corresponding to the given block. // GetTreeState returns the note commitment tree state corresponding to the given block.
// See section 3.7 of the Zcash protocol specification. It returns several other useful // See section 3.7 of the Zcash protocol specification. It returns several other useful
@ -391,6 +397,8 @@ type CompactTxStreamerServer interface {
// match a shortened txid, they are all sent (none is excluded). Transactions // match a shortened txid, they are all sent (none is excluded). Transactions
// in the exclude list that don't exist in the mempool are ignored. // in the exclude list that don't exist in the mempool are ignored.
GetMempoolTx(*Exclude, CompactTxStreamer_GetMempoolTxServer) error GetMempoolTx(*Exclude, CompactTxStreamer_GetMempoolTxServer) error
// Return a stream of current Mempool transactions. This will keep the output stream open while
// there are mempool transactions. It will close the returned stream when a new block is mined.
GetMempoolStream(*Empty, CompactTxStreamer_GetMempoolStreamServer) error GetMempoolStream(*Empty, CompactTxStreamer_GetMempoolStreamServer) error
// GetTreeState returns the note commitment tree state corresponding to the given block. // GetTreeState returns the note commitment tree state corresponding to the given block.
// See section 3.7 of the Zcash protocol specification. It returns several other useful // See section 3.7 of the Zcash protocol specification. It returns several other useful