diff --git a/.gitignore b/.gitignore index 060c36b..99ac34e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ lwd-api.html *.orig __debug_bin .vscode +frontend/unittestcache/ diff --git a/cmd/root.go b/cmd/root.go index 70387a2..8d5c7cf 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -60,6 +60,7 @@ var rootCmd = &cobra.Command{ GenCertVeryInsecure: viper.GetBool("gen-cert-very-insecure"), DataDir: viper.GetString("data-dir"), Redownload: viper.GetBool("redownload"), + SyncFromHeight: viper.GetInt("sync-from-height"), PingEnable: viper.GetBool("ping-very-insecure"), Darkside: viper.GetBool("darkside-very-insecure"), 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.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 { go common.BlockIngestor(cache, 0 /*loop forever*/) } else { @@ -286,10 +291,6 @@ func startServer(opts *common.Options) error { // Initialize price fetcher common.StartPriceFetcher(dbPath, chainName) - // Initialize mempool monitor - exitMempool := make(chan bool) - common.StartMempoolMonitor(cache, exitMempool) - // Start listening listener, err := net.Listen("tcp", opts.GRPCBindAddr) if err != nil { @@ -309,7 +310,6 @@ func startServer(opts *common.Options) error { "signal": s.String(), }).Info("caught signal, stopping gRPC server") - exitMempool <- true 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("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().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().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)") @@ -381,6 +382,8 @@ func init() { viper.SetDefault("gen-cert-very-insecure", false) viper.BindPFlag("redownload", rootCmd.Flags().Lookup("redownload")) 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.SetDefault("data-dir", "/var/lib/lightwalletd") viper.BindPFlag("ping-very-insecure", rootCmd.Flags().Lookup("ping-very-insecure")) @@ -409,8 +412,9 @@ func init() { logrus.RegisterExitHandler(onexit) - // Indirect function for test mocking (so unit tests can talk to stub functions) - common.Sleep = time.Sleep + // Indirect functions for test mocking (so unit tests can talk to stub functions) + common.Time.Sleep = time.Sleep + common.Time.Now = time.Now } // initConfig reads in config file and ENV variables if set. @@ -421,7 +425,7 @@ func initConfig() { } else { // Look in the current directory for a configuration file viper.AddConfigPath(".") - // Viper auto appends extention to this config name + // Viper auto appends extension to this config name // For example, lightwalletd.yml viper.SetConfigName("lightwalletd") } diff --git a/common/cache.go b/common/cache.go index 4ee85f6..3bc749b 100644 --- a/common/cache.go +++ b/common/cache.go @@ -51,12 +51,12 @@ func (c *BlockCache) GetLatestHash() []byte { 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. -func (c *BlockCache) HashMismatch(prevhash []byte) bool { +func (c *BlockCache) HashMatch(prevhash []byte) bool { c.mutex.RLock() 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. @@ -191,7 +191,8 @@ func (c *BlockCache) Reset(startHeight int) { // NewBlockCache returns an instance of a block cache object. // (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.firstBlock = startHeight c.nextBlock = startHeight @@ -208,18 +209,20 @@ func NewBlockCache(dbPath string, chainName string, startHeight int, redownload if err != nil { 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) if err != nil { 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. var offset int64 diff --git a/common/cache_test.go b/common/cache_test.go index dce9543..80f8bf5 100644 --- a/common/cache_test.go +++ b/common/cache_test.go @@ -58,7 +58,7 @@ func TestCache(t *testing.T) { // Pretend Sapling starts at 289460. os.RemoveAll(unitTestPath) - cache = NewBlockCache(unitTestPath, unitTestChain, 289460, true) + cache = NewBlockCache(unitTestPath, unitTestChain, 289460, 0) // Initially cache is empty. if cache.GetLatestHeight() != -1 { @@ -75,7 +75,7 @@ func TestCache(t *testing.T) { fillCache(t) // 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. if cache.nextBlock != 289466 { diff --git a/common/common.go b/common/common.go index d07ad9b..c76e783 100644 --- a/common/common.go +++ b/common/common.go @@ -42,6 +42,7 @@ type Options struct { NoTLSVeryInsecure bool `json:"no_tls_very_insecure,omitempty"` GenCertVeryInsecure bool `json:"gen_cert_very_insecure,omitempty"` Redownload bool `json:"redownload"` + SyncFromHeight int `json:"sync_from_height"` DataDir string `json:"data_dir"` PingEnable bool `json:"ping_enable"` Darkside bool `json:"darkside"` @@ -53,10 +54,16 @@ type Options struct { // in unit tests it points to a function to mock RPCs to zcashd. var RawRequest func(method string, params []json.RawMessage) (json.RawMessage, error) -// Sleep allows a request to time.Sleep() to be mocked for testing; -// in production, it points to the standard library time.Sleep(); -// in unit tests it points to a mock function. -var Sleep func(d time.Duration) +// Time allows time-related functions to be mocked for testing, +// so that tests can be deterministic and so they don't require +// real time to elapse. In production, these point to the standard +// 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 var Log *logrus.Entry @@ -109,9 +116,16 @@ type ( } 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 { Hex string Height int @@ -129,7 +143,7 @@ type ( ZcashdRpcRequestGetaddressutxos struct { Addresses []string `json:"addresses"` } - ZcashdRpcReplyGetaddressutxos []struct { + ZcashdRpcReplyGetaddressutxos struct { Address string Txid string OutputIndex int64 @@ -137,6 +151,11 @@ type ( Satoshis uint64 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 @@ -166,7 +185,7 @@ func FirstRPC() { "error": rpcErr.Error(), "retry": retryCount, }).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) heightJSON, err := json.Marshal(strconv.Itoa(height)) if err != nil { - return nil, errors.Wrap(err, "error marshaling height") + Log.Fatal("getBlockFromRPC bad height argument", height, err) } params[0] = heightJSON 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") } + // `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 } @@ -303,11 +347,8 @@ func stopIngestor() { // 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. func BlockIngestor(c *BlockCache, rep int) { - lastLog := time.Now() - reorgCount := 0 + lastLog := Time.Now() lastHeightLogged := 0 - retryCount := 0 - wait := true // Start listening for new blocks for i := 0; rep == 0 || i < rep; i++ { @@ -318,110 +359,60 @@ func BlockIngestor(c *BlockCache, rep int) { default: } - height := c.GetNextHeight() - block, err := getBlockFromRPC(height) + result, err := RawRequest("getbestblockhash", []json.RawMessage{}) if err != nil { Log.WithFields(logrus.Fields{ - "height": height, - "error": err, - }).Warn("error zcashd getblock rpc") - retryCount++ - if retryCount > 10 { - Log.WithFields(logrus.Fields{ - "timeouts": retryCount, - }).Fatal("unable to issue RPC call to zcashd node") - } - // Delay then retry the same height. + "error": err, + }).Fatal("error zcashd getbestblockhash rpc") + } + var hashHex string + err = json.Unmarshal(result, &hashHex) + if err != nil { + Log.Fatal("bad getbestblockhash return:", err, result) + } + lastBestBlockHash := []byte{} + 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() - Sleep(10 * time.Second) - wait = true + if lastHeightLogged != height-1 { + lastHeightLogged = height - 1 + Log.Info("Waiting for block: ", height) + } + Time.Sleep(2 * time.Second) + lastLog = Time.Now() continue } - retryCount = 0 - if block == nil { - // No block at this height. - if height == c.GetFirstHeight() { - 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 - } + var block *walletrpc.CompactBlock + block, err = getBlockFromRPC(height) + if err != nil { + Log.Fatal("getblock failed, will retry", err) } - if block == nil || c.HashMismatch(block.PrevHash) { - // This may not be a reorg; it may be we're at the tip - // and there's no new block yet, but we want to back up - // 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!") + if block != nil && c.HashMatch(block.PrevHash) { + if err = c.Add(height, block); err != nil { + Log.Fatal("Cache add failed:", err) } - // Print the hash of the block that is getting reorg-ed away - // as 'phash', not the prevhash of the block we just received. - if block != nil { - Log.WithFields(logrus.Fields{ - "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") + // Don't log these too often. + if DarksideEnabled || Time.Now().Sub(lastLog).Seconds() >= 4 { + lastLog = Time.Now() + Log.Info("Adding block to cache ", height, " ", displayHash(block.Hash)) } - // Try backing up - c.Reorg(height - 1) continue } - // We have a valid block to add. - wait = true - reorgCount = 0 - if err := c.Add(height, block); err != nil { - Log.Fatal("Cache add failed:", err) - } - // 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) + if height == c.GetFirstHeight() { + c.Sync() + Log.Info("Waiting for zcashd height to reach Sapling activation height ", + "(", c.GetFirstHeight(), ")...") + Time.Sleep(20 * time.Second) + return } + Log.Info("REORG: dropping block ", height-1, " ", displayHash(c.GetLatestHash())) + c.Reorg(height - 1) } } diff --git a/common/common_test.go b/common/common_test.go index 58d4f6c..2b3ddf0 100644 --- a/common/common_test.go +++ b/common/common_test.go @@ -5,6 +5,7 @@ package common import ( "bufio" + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -33,6 +34,8 @@ var ( logger = logrus.New() blocks [][]byte // four test blocks + + testcache *BlockCache ) // TestMain does common setup that's shared across multiple tests @@ -59,6 +62,7 @@ func TestMain(m *testing.M) { blockJSON, _ := json.Marshal(scan.Text()) blocks = append(blocks, blockJSON) } + testcache = NewBlockCache(unitTestPath, unitTestChain, 380640, 0) // Setup is done; run all tests. exitcode := m.Run() @@ -77,6 +81,10 @@ func sleepStub(d time.Duration) { sleepCount++ sleepDuration += d } +func nowStub() time.Time { + start := time.Time{} + return start.Add(sleepDuration) +} // ------------------------------------------ GetLightdInfo() @@ -110,7 +118,7 @@ func getLightdInfoStub(method string, params []json.RawMessage) (json.RawMessage func TestGetLightdInfo(t *testing.T) { testT = t RawRequest = getLightdInfoStub - Sleep = sleepStub + Time.Sleep = sleepStub // This calls the getblockchaininfo rpc just to establish connectivity with zcashd FirstRPC() @@ -155,8 +163,217 @@ func TestGetLightdInfo(t *testing.T) { // ------------------------------------------ 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 +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) { + if method != "getblock" { + testT.Error("unexpected method") + } var height string err := json.Unmarshal(params[0], &height) if err != nil { @@ -267,27 +484,11 @@ func getblockStub(method string, params []json.RawMessage) (json.RawMessage, err 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) { testT = t RawRequest = getblockStub os.RemoveAll(unitTestPath) - testcache := NewBlockCache(unitTestPath, unitTestChain, 380640, true) + testcache = NewBlockCache(unitTestPath, unitTestChain, 380640, 0) blockChan := make(chan *walletrpc.CompactBlock) errChan := make(chan error) go GetBlockRange(testcache, blockChan, errChan, 380640, 380642) @@ -366,7 +567,7 @@ func TestGetBlockRangeReverse(t *testing.T) { testT = t RawRequest = getblockStubReverse os.RemoveAll(unitTestPath) - testcache := NewBlockCache(unitTestPath, unitTestChain, 380640, true) + testcache = NewBlockCache(unitTestPath, unitTestChain, 380640, 0) blockChan := make(chan *walletrpc.CompactBlock) errChan := make(chan error) @@ -414,3 +615,158 @@ func TestGenerateCerts(t *testing.T) { 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 +} diff --git a/common/darkside.go b/common/darkside.go index cd929ac..5236278 100644 --- a/common/darkside.go +++ b/common/darkside.go @@ -46,6 +46,9 @@ type darksideState struct { // These transactions come from StageTransactions(); they will be merged into // activeBlocks by ApplyStaged() (and this list then cleared). stagedTransactions []stagedTx + + // Unordered list of replies + getAddressUtxos []ZcashdRpcReplyGetaddressutxos } var state darksideState @@ -74,7 +77,7 @@ func DarksideInit(c *BlockCache, timeout int) { // DarksideReset allows the wallet test code to specify values // that are returned by GetLightdInfo(). func DarksideReset(sa int, bi, cn string) error { - Log.Info("Reset(saplingActivation=", sa, ")") + Log.Info("DarksideReset(saplingActivation=", sa, ")") stopIngestor() state = darksideState{ resetted: true, @@ -135,7 +138,7 @@ func setPrevhash() { copy(blockBytes[4:4+32], prevhash) } prevhash = block.GetEncodableHash() - Log.Info("active block height ", block.GetHeight(), " hash ", + Log.Info("Darkside active block height ", block.GetHeight(), " hash ", hex.EncodeToString(block.GetDisplayHash()), " txcount ", block.GetTxCount()) } @@ -150,7 +153,7 @@ func DarksideApplyStaged(height int) error { if !state.resetted { return errors.New("please call Reset first") } - Log.Info("ApplyStaged(height=", height, ")") + Log.Info("DarksideApplyStaged(height=", height, ")") if height < state.startHeight { return errors.New(fmt.Sprint("height ", height, " is less than sapling activation height ", state.startHeight)) @@ -209,9 +212,13 @@ func DarksideApplyStaged(height int) error { block = append(block, tx.bytes...) state.activeBlocks[tx.height-state.startHeight] = block } + maxHeight := state.startHeight + len(state.activeBlocks) - 1 + if height > maxHeight { + height = maxHeight + } setPrevhash() 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, ", latest presented height ", state.latestHeight) @@ -241,7 +248,7 @@ func darksideStageBlock(caller string, b []byte) error { if len(rest) != 0 { 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 { return errors.New(fmt.Sprint("block height ", block.GetHeight(), " is less than sapling activation height ", state.startHeight)) @@ -256,7 +263,7 @@ func DarksideStageBlocks(url string) error { if !state.resetted { return errors.New("please call Reset first") } - Log.Info("StageBlocks(url=", url, ")") + Log.Info("DarksideStageBlocks(url=", url, ")") resp, err := http.Get(url) if err != nil { return err @@ -289,7 +296,7 @@ func DarksideStageBlockStream(blockHex string) error { if !state.resetted { return errors.New("please call Reset first") } - Log.Info("StageBlocksStream()") + Log.Info("DarksideStageBlocksStream()") blockBytes, err := hex.DecodeString(blockHex) if err != nil { return err @@ -305,7 +312,7 @@ func DarksideStageBlocksCreate(height int32, nonce int32, count int32) error { if !state.resetted { 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++ { fakeCoinbase := "0400008085202f890100000000000000000000000000000000000000000000000000" + @@ -410,6 +417,18 @@ func darksideRawRequest(method string, params []json.RawMessage) (json.RawMessag } 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": // Not required for minimal reorg testing. return nil, errors.New("not implemented yet") @@ -459,6 +478,23 @@ func darksideRawRequest(method string, params []json.RawMessage) (json.RawMessag } 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: 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 { 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) if err != nil { return err @@ -585,3 +621,13 @@ func DarksideStageTransactionsURL(height int, url string) error { return scan.Err() } + +func DarksideAddAddressUtxo(arg ZcashdRpcReplyGetaddressutxos) error { + state.getAddressUtxos = append(state.getAddressUtxos, arg) + return nil +} + +func DarksideClearAddressUtxos() error { + state.getAddressUtxos = nil + return nil +} diff --git a/common/mempool.go b/common/mempool.go index 7c0c9b5..76314fe 100644 --- a/common/mempool.go +++ b/common/mempool.go @@ -1,183 +1,156 @@ package common import ( - "bytes" "encoding/hex" "encoding/json" "sync" - "sync/atomic" "time" "github.com/adityapk00/lightwalletd/walletrpc" ) +type txid string + var ( - // List of all mempool transactions - txns map[string]*walletrpc.RawTransaction = make(map[string]*walletrpc.RawTransaction) + // Set of mempool txids that have been seen during the current block interval. + // 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 - clients []chan<- *walletrpc.RawTransaction + // List of transactions during current block interval, in order received. Each + // 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 - lastHash []byte + // The most recent absolute time that we fetched the mempool and the latest + // (tip) block hash (so we know when a new block has been mined). + g_lastTime time.Time - // A pointer to the blockcache - blockcache *BlockCache + // The most recent zcashd getblockchaininfo reply, for height and best block + // hash (tip) which is used to detect when a new block arrives. + g_lastBlockChainInfo *ZcashdRpcReplyGetblockchaininfo = &ZcashdRpcReplyGetblockchaininfo{} - // Mutex to lock the above 2 structs - lock sync.Mutex - - // Since the mutex doesn't have a "try_lock" method, we'll have to improvize with this - refreshing int32 = 0 + // Mutex to protect the above variables. + g_lock sync.Mutex ) -// AddNewClient adds a new client to the list of clients to notify for mempool txns -func AddNewClient(client chan<- *walletrpc.RawTransaction) { +func GetMempool(sendToClient func(*walletrpc.RawTransaction) error) error { + 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") - - // Copy map locally - lock.Lock() - localmap := make(map[string]*walletrpc.RawTransaction) - - for k, rtx := range txns { - localmap[k] = rtx - } - lock.Unlock() - - // Also send all pending mempool txns - for _, rtx := range localmap { - if client != nil { - client <- rtx + // Wait for more transactions to be added to the list + for { + // Don't fetch the mempool more often than every 2 seconds. + now := Time.Now() + if now.After(g_lastTime.Add(2 * time.Second)) { + blockChainInfo, err := getLatestBlockChainInfo() + if err != nil { + g_lock.Unlock() + return err + } + if g_lastBlockChainInfo.BestBlockHash != blockChainInfo.BestBlockHash { + // A new block has arrived + g_lastBlockChainInfo = blockChainInfo + Log.Infoln("Latest Block changed, clearing everything") + // 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 } } - - lock.Lock() - if client != nil { - clients = append(clients, client) - } - lock.Unlock() + g_lock.Unlock() + return nil } // RefreshMempoolTxns gets all new mempool txns and sends any new ones to waiting clients func refreshMempoolTxns() error { - // First check if another refresh is running, if it is, just return - if !atomic.CompareAndSwapInt32(&refreshing, 0, 1) { - Log.Warnln("Another refresh in progress, returning") - return nil - } + Log.Infoln("Refreshing mempool") - // Set refreshing to 0 when we exit - 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) + params := []json.RawMessage{} result, rpcErr := RawRequest("getrawmempool", params) if rpcErr != nil { return rpcErr } + var mempoolList []string err := json.Unmarshal(result, &mempoolList) if err != nil { return err } - //println("getrawmempool size ", len(mempoolList)) - // Fetch all new mempool txns and add them into `newTxns` for _, txidstr := range mempoolList { - if _, ok := txns[txidstr]; !ok { - 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 - } - - // 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 + if _, ok := g_txidSeen[txid(txidstr)]; ok { + // We've already fetched this transaction + continue } + 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 } -// StartMempoolMonitor starts monitoring the mempool -func StartMempoolMonitor(cache *BlockCache, done <-chan bool) { - go func() { - ticker := time.NewTicker(5 * time.Second) - blockcache = cache - lastHash = blockcache.GetLatestHash() - - for { - select { - case <-ticker.C: - go func() { - //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 - } - } - }() +func getLatestBlockChainInfo() (*ZcashdRpcReplyGetblockchaininfo, error) { + result, rpcErr := RawRequest("getblockchaininfo", []json.RawMessage{}) + if rpcErr != nil { + return nil, rpcErr + } + var getblockchaininfoReply ZcashdRpcReplyGetblockchaininfo + err := json.Unmarshal(result, &getblockchaininfoReply) + if err != nil { + return nil, err + } + return &getblockchaininfoReply, nil } diff --git a/docs/darksidewalletd.md b/docs/darksidewalletd.md index 42eedb8..da2c528 100644 --- a/docs/darksidewalletd.md +++ b/docs/darksidewalletd.md @@ -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 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 If you haven't already started darksidewalletd, please start it: diff --git a/docs/docker-compose-setup.md b/docs/docker-compose-setup.md index a58c2a0..4592041 100644 --- a/docs/docker-compose-setup.md +++ b/docs/docker-compose-setup.md @@ -10,16 +10,17 @@ docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all ## 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 | | ------------- |:-------------:| | `GF_SECURITY_ADMIN_USER` | Grafana admin user name | | `ZCASHD_RPCUSER` | zcashd rpc user | +| `ZCASHD_RPCPASSWORD` | zcashd rpc password | | `ZCASHD_RPCPORT` | zcashd rpc port | -|`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_PARMDIR`| local location of zcasd data directory. `uid` 2001 needs read access| +|`ZCASHD_ALLOWIP`| zcashd rpc allowed IPs (don't change unless you know what you're doing)| +|`ZCASHD_DATADIR`| local location of zcashd data directory. `uid` 2001 needs write access| +|`ZCASHD_PARMDIR`| local location of zcashd data directory. `uid` 2001 needs read access| |`ZCASHD_NETWORK`| zcashd network to use, `testnet` or `mainnet`| |`ZCASHD_GEN`| should zcashd mine? `0` or `1` |`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 ``` +## 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 `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 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 @@ -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) 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. diff --git a/docs/rtd/index.html b/docs/rtd/index.html index 6070357..18fa4fc 100644 --- a/docs/rtd/index.html +++ b/docs/rtd/index.html @@ -183,11 +183,15 @@
  • - MCompactOutput + MCompactOrchardAction
  • - MCompactSpend + MCompactSaplingOutput +
  • + +
  • + MCompactSaplingSpend
  • @@ -408,7 +412,52 @@ -

    CompactOutput

    +

    CompactOrchardAction

    +

    https://github.com/zcash/zips/blob/main/zip-0225.rst#orchard-action-description-orchardaction

    (but not all fields are needed)

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldTypeLabelDescription
    nullifierbytes

    [32] The nullifier of the input note

    cmxbytes

    [32] The x-coordinate of the note commitment for the output note

    ephemeralKeybytes

    [32] An encoding of an ephemeral Pallas public key

    ciphertextbytes

    [52] The note plaintext component of the encCiphertext field

    + + + + + +

    CompactSaplingOutput

    output is a Sapling Output Description as described in section 7.4 of the

    Zcash protocol spec. Total size is 948.

    @@ -436,7 +485,7 @@ ciphertext bytes -

    ciphertext and zkproof

    +

    first 52 bytes of ciphertext

    @@ -446,8 +495,8 @@ -

    CompactSpend

    -

    CompactSpend is a Sapling Spend Description as described in 7.3 of the Zcash

    protocol specification.

    +

    CompactSaplingSpend

    +

    CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash

    protocol specification.

    @@ -507,18 +556,25 @@ in a pure-Sapling context, the fee will be calculable as: - + - + + + + + + + +
    spendsCompactSpendCompactSaplingSpend repeated

    inputs

    outputsCompactOutputCompactSaplingOutput repeated

    outputs

    actionsCompactOrchardActionrepeated

    @@ -836,6 +892,21 @@ into a specified block on the next ApplyStaged().

    Clear the incoming transaction pool.

    + + AddAddressUtxo + GetAddressUtxosReply + Empty +

    Add a GetAddressUtxosReply entry to be returned by GetAddressUtxos(). +There is no staging or applying for these, very simple.

    + + + + ClearAddressUtxo + Empty + Empty +

    Clear the list of GetAddressUtxos entries (can't fail)

    + + @@ -1045,7 +1116,7 @@ into a specified block on the next ApplyStaged().

    GetAddressUtxosArg

    -

    +

    Results are sorted by height, which makes it easy to issue another

    request that picks up from where the previous left off.

    @@ -1055,9 +1126,9 @@ into a specified block on the next ApplyStaged().

    - + - + @@ -1092,6 +1163,13 @@ into a specified block on the next ApplyStaged().

    + + + + + + + @@ -1305,7 +1383,7 @@ into a specified block on the next ApplyStaged().

    RawTransaction

    -

    RawTransaction contains the complete transaction data. It also optionally includes

    the block height in which the transaction was included.

    +

    RawTransaction contains the complete transaction data. It also optionally includes

    the block height in which the transaction was included, or, when returned

    by GetMempoolStream(), the latest block height.

    addressaddresses stringrepeated

    addressstring

    txid bytes
    @@ -1418,7 +1496,7 @@ into a specified block on the next ApplyStaged().

    - + @@ -1436,12 +1514,19 @@ into a specified block on the next ApplyStaged().

    - + + + + + + + +
    height uint64

    block height

    treesaplingTree string

    sapling commitment tree state

    orchardTreestring

    orchard commitment tree state

    @@ -1572,6 +1657,14 @@ 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.

    + + GetMempoolStream + Empty + RawTransaction stream +

    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.

    + + GetTreeState BlockID @@ -1607,7 +1700,7 @@ The block can be specified by either height or hash.

    Ping Duration PingResponse -

    Testing-only

    +

    Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production)

    diff --git a/frontend/frontend_test.go b/frontend/frontend_test.go index 7a30ee0..4e5e64f 100644 --- a/frontend/frontend_test.go +++ b/frontend/frontend_test.go @@ -36,7 +36,7 @@ const ( func testsetup() (walletrpc.CompactTxStreamerServer, *common.BlockCache) { os.RemoveAll(unitTestPath) - cache := common.NewBlockCache(unitTestPath, unitTestChain, 380640, true) + cache := common.NewBlockCache(unitTestPath, unitTestChain, 380640, 0) lwd, err := NewLwdStreamer(cache, "main", false /* enablePing */) if err != nil { os.Stderr.WriteString(fmt.Sprint("NewLwdStreamer failed:", err)) @@ -191,6 +191,9 @@ func TestGetLatestBlock(t *testing.T) { if blockID.Height != 380640 { t.Fatal("unexpected blockID.height") } + if string(blockID.Hash) != string(block.Hash) { + t.Fatal("unexpected blockID.hash") + } step = 0 } diff --git a/frontend/service.go b/frontend/service.go index 8eebebc..5e55ece 100644 --- a/frontend/service.go +++ b/frontend/service.go @@ -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. func (s *lwdStreamer) GetLatestBlock(ctx context.Context, placeholder *walletrpc.ChainSpec) (*walletrpc.BlockID, error) { - result, rpcErr := common.RawRequest("getblockchaininfo", []json.RawMessage{}) - if rpcErr != nil { - return nil, rpcErr - } - var getblockchaininfoReply common.ZcashdRpcReplyGetblockchaininfo - err := json.Unmarshal(result, &getblockchaininfoReply) - if err != nil { - return nil, err + latestBlock := s.cache.GetLatestHeight() + latestHash := s.cache.GetLatestHash() + + if latestBlock == -1 { + return nil, errors.New("Cache is empty. Server is probably not yet ready") } - hash, err := hex.DecodeString(getblockchaininfoReply.BestBlockHash) - if err != nil { - return nil, err - } - - common.Metrics.LatestBlockCounter.Inc() - return &walletrpc.BlockID{Height: uint64(getblockchaininfoReply.Blocks), Hash: parser.Reverse(hash)}, nil + return &walletrpc.BlockID{Height: uint64(latestBlock), Hash: latestHash}, nil } // 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 &walletrpc.TreeState{ - Network: s.chainName, - Height: uint64(gettreestateReply.Height), - Hash: gettreestateReply.Hash, - Time: gettreestateReply.Time, - Tree: gettreestateReply.Sapling.Commitments.FinalState, + Network: s.chainName, + Height: uint64(gettreestateReply.Height), + Hash: gettreestateReply.Hash, + Time: gettreestateReply.Time, + SaplingTree: gettreestateReply.Sapling.Commitments.FinalState, + OrchardTree: gettreestateReply.Orchard.Commitments.FinalState, }, nil } @@ -463,8 +455,9 @@ func (s *lwdStreamer) SendTransaction(ctx context.Context, rawtx *walletrpc.RawT // Result: // "hex" (string) The transaction hash in hex + // Verify rawtx 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 @@ -562,6 +555,13 @@ func (s *lwdStreamer) GetTaddressBalanceStream(addresses walletrpc.CompactTxStre 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. var mempoolMap *map[string]*walletrpc.CompactTx var mempoolList []string @@ -622,7 +622,7 @@ func (s *lwdStreamer) GetMempoolTx(exclude *walletrpc.Exclude, resp walletrpc.Co return errors.New("extra data deserializing transaction") } newmempoolMap[txidstr] = &walletrpc.CompactTx{} - if tx.HasSaplingElements() { + if tx.HasShieldedElements() { newmempoolMap[txidstr] = tx.ToCompact( /* height */ 0) } } @@ -644,27 +644,6 @@ func (s *lwdStreamer) GetMempoolTx(exclude *walletrpc.Exclude, resp walletrpc.Co 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 // if more than one item matches an exclude entry, return // all those items. @@ -730,7 +709,7 @@ func getAddressUtxos(arg *walletrpc.GetAddressUtxosArg, f func(*walletrpc.GetAdd if rpcErr != nil { return rpcErr } - var utxosReply common.ZcashdRpcReplyGetaddressutxos + var utxosReply []common.ZcashdRpcReplyGetaddressutxos err = json.Unmarshal(result, &utxosReply) if err != nil { return err @@ -909,3 +888,23 @@ func (s *DarksideStreamer) ClearIncomingTransactions(ctx context.Context, e *wal common.DarksideClearIncomingTransactions() 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 +} diff --git a/go.mod b/go.mod index 7005fe7..3d8c3af 100644 --- a/go.mod +++ b/go.mod @@ -5,27 +5,15 @@ go 1.12 require ( github.com/btcsuite/btcd v0.20.1-beta 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-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/prometheus/client_golang v1.5.1 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/viper v1.6.2 - github.com/stretchr/testify v1.6.1 // indirect - golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect - 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 + github.com/zcash/lightwalletd v0.4.12 + google.golang.org/grpc v1.44.0 + google.golang.org/protobuf v1.27.1 gopkg.in/ini.v1 v1.51.0 - gopkg.in/yaml.v3 v3.0.0-20210105161348-2e78108cf5f8 // indirect ) diff --git a/go.sum b/go.sum index 1332056..59f9d55 100644 --- a/go.sum +++ b/go.sum @@ -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.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/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/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= 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-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 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-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= 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/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= @@ -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/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/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/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/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/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= 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/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 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/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/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/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/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= 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-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/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/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/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= 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 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/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/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/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.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.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00= -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/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 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/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/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.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= 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.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= 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/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/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/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/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.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.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.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.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 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.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 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/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/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-20191106031601-ce3c9ade29de h1:F7WD09S8QB4LrkEpka0dFPLSotH11HRpCsLIbIcJ7sU= 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/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-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/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.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/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/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/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/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/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= 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.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 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/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/kisielk/errcheck v1.1.0 h1:ZqfnKyx9KGpRcW04j5nnPDgRgoXUeLh2YFBeFzphcA0= 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/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/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/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/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/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/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/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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/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/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/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= 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-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 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 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 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/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/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/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= 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/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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= 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/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/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/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/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 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/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 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/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/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/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= 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/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= 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/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/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= 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/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.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.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +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/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/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= 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/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/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= -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.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/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= 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= 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-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-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-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= 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-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-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-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/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.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/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-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-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-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-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-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-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-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/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-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-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-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-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/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= @@ -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-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-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-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-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-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-20201119102817-f84b799fce68/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/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-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= 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.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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +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-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-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-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-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-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-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-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.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/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-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/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.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.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-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-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-20210406143921-e86de6bf7a46 h1:f4STrQZf8jaowsiUitigvrqMCCM4QJH1A2JCSI7U1ow= 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.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.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 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.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.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.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg= +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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 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.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.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 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= 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/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-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/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/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= 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/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/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.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.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= 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/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-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.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= diff --git a/parser/block.go b/parser/block.go index a82a422..3162d07 100644 --- a/parser/block.go +++ b/parser/block.go @@ -62,7 +62,7 @@ func (b *Block) GetDisplayPrevHash() []byte { // HasSaplingTransactions indicates if the block contains any Sapling tx. func (b *Block) HasSaplingTransactions() bool { for _, tx := range b.vtx { - if tx.HasSaplingElements() { + if tx.HasShieldedElements() { return true } } @@ -118,7 +118,7 @@ func (b *Block) ToCompact() *walletrpc.CompactBlock { // Only Sapling transactions have a meaningful compact encoding saplingTxns := make([]*walletrpc.CompactTx, 0, len(b.vtx)) for idx, tx := range b.vtx { - if tx.HasSaplingElements() { + if tx.HasShieldedElements() { saplingTxns = append(saplingTxns, tx.ToCompact(idx)) } } diff --git a/parser/block_header_test.go b/parser/block_header_test.go index 0909da3..e0dbfc6 100644 --- a/parser/block_header_test.go +++ b/parser/block_header_test.go @@ -134,7 +134,7 @@ func TestBlockHeader(t *testing.T) { } // 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 { t.Errorf("Hash lacked leading zeros: %x", hash) } diff --git a/parser/block_test.go b/parser/block_test.go index 99f6338..affb8c6 100644 --- a/parser/block_test.go +++ b/parser/block_test.go @@ -4,13 +4,11 @@ package parser import ( - "bufio" "bytes" "encoding/hex" "encoding/json" "fmt" "io/ioutil" - "os" "testing" "github.com/pkg/errors" @@ -18,200 +16,6 @@ import ( 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) { type compactTest struct { BlockHeight int `json:"block"` diff --git a/parser/internal/bytestring/bytestring.go b/parser/internal/bytestring/bytestring.go index 98f75c1..0c980f9 100644 --- a/parser/internal/bytestring/bytestring.go +++ b/parser/internal/bytestring/bytestring.go @@ -154,6 +154,16 @@ func (s *String) ReadCompactLengthPrefixed(out *String) bool { 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 // signed, and advances over it. It reports whether the read was successful. func (s *String) ReadInt32(out *int32) bool { diff --git a/parser/internal/bytestring/bytestring_test.go b/parser/internal/bytestring/bytestring_test.go index 1de8117..97e957e 100644 --- a/parser/internal/bytestring/bytestring_test.go +++ b/parser/internal/bytestring/bytestring_test.go @@ -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 { s String expected int32 diff --git a/parser/transaction.go b/parser/transaction.go index b350eca..9aeb2ff 100644 --- a/parser/transaction.go +++ b/parser/transaction.go @@ -6,7 +6,7 @@ package parser import ( - "crypto/sha256" + "fmt" "github.com/pkg/errors" "github.com/adityapk00/lightwalletd/parser/internal/bytestring" @@ -17,51 +17,53 @@ type rawTransaction struct { fOverwintered bool version uint32 nVersionGroupID uint32 - transparentInputs []*txIn - transparentOutputs []*txOut - nLockTime uint32 - nExpiryHeight uint32 - valueBalance int64 - shieldedSpends []*spend - shieldedOutputs []*output - joinSplits []*joinSplit - joinSplitPubKey []byte - joinSplitSig []byte - bindingSig []byte + consensusBranchID uint32 + transparentInputs []txIn + transparentOutputs []txOut + //nLockTime uint32 + //nExpiryHeight uint32 + //valueBalanceSapling int64 + shieldedSpends []spend + shieldedOutputs []output + joinSplits []joinSplit + //joinSplitPubKey []byte + //joinSplitSig []byte + //bindingSigSapling []byte + orchardActions []action } // Txin format as described in https://en.bitcoin.it/wiki/Transaction type txIn struct { // SHA256d of a previous (to-be-used) transaction - PrevTxHash []byte + //PrevTxHash []byte // Index of the to-be-used output in the previous tx - PrevTxOutIndex uint32 + //PrevTxOutIndex uint32 // CompactSize-prefixed, could be a pubkey or a script ScriptSig []byte // Bitcoin: "normally 0xFFFFFFFF; irrelevant unless transaction's lock_time > 0" - SequenceNumber uint32 + //SequenceNumber uint32 } func (tx *txIn) ParseFromSlice(data []byte) ([]byte, error) { s := bytestring.String(data) - if !s.ReadBytes(&tx.PrevTxHash, 32) { - return nil, errors.New("could not read PrevTxHash") + if !s.Skip(32) { + return nil, errors.New("could not skip PrevTxHash") } - if !s.ReadUint32(&tx.PrevTxOutIndex) { - return nil, errors.New("could not read PrevTxOutIndex") + if !s.Skip(4) { + return nil, errors.New("could not skip PrevTxOutIndex") } if !s.ReadCompactLengthPrefixed((*bytestring.String)(&tx.ScriptSig)) { return nil, errors.New("could not read ScriptSig") } - if !s.ReadUint32(&tx.SequenceNumber) { - return nil, errors.New("could not read SequenceNumber") + if !s.Skip(4) { + return nil, errors.New("could not skip SequenceNumber") } return []byte(s), nil @@ -73,86 +75,118 @@ type txOut struct { Value uint64 // Script. CompactSize-prefixed. - Script []byte + //Script []byte } func (tx *txOut) ParseFromSlice(data []byte) ([]byte, error) { s := bytestring.String(data) - if !s.ReadUint64(&tx.Value) { - return nil, errors.New("could not read txOut value") + if !s.Skip(8) { + return nil, errors.New("could not skip txOut value") } - if !s.ReadCompactLengthPrefixed((*bytestring.String)(&tx.Script)) { - return nil, errors.New("could not read txOut script") + if !s.SkipCompactLengthPrefixed() { + return nil, errors.New("could not skip txOut script") } return []byte(s), nil } -// spend is a Sapling Spend Description as described in 7.3 of the Zcash -// protocol spec. Total size is 384 bytes. -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) { +// parse the transparent parts of the transaction +func (tx *Transaction) ParseTransparent(data []byte) ([]byte, error) { s := bytestring.String(data) - - if !s.ReadBytes(&p.cv, 32) { - return nil, errors.New("could not read cv") + var txInCount int + if !s.ReadCompactSize(&txInCount) { + 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) { - return nil, errors.New("could not read anchor") + var txOutCount int + 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) { return nil, errors.New("could not read nullifier") } - if !s.ReadBytes(&p.rk, 32) { - return nil, errors.New("could not read rk") + if !s.Skip(32) { + return nil, errors.New("could not skip rk") } - if !s.ReadBytes(&p.zkproof, 192) { - return nil, errors.New("could not read zkproof") + if version <= 4 && !s.Skip(192) { + return nil, errors.New("could not skip zkproof") } - if !s.ReadBytes(&p.spendAuthSig, 64) { - return nil, errors.New("could not read spendAuthSig") + if version <= 4 && !s.Skip(64) { + return nil, errors.New("could not skip spendAuthSig") } return []byte(s), nil } -func (p *spend) ToCompact() *walletrpc.CompactSpend { - return &walletrpc.CompactSpend{ +func (p *spend) ToCompact() *walletrpc.CompactSaplingSpend { + return &walletrpc.CompactSaplingSpend{ Nf: p.nullifier, } } // 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 { - cv []byte // 32 + //cv []byte // 32 cmu []byte // 32 ephemeralKey []byte // 32 encCiphertext []byte // 580 - outCiphertext []byte // 80 - zkproof []byte // 192 + //outCiphertext []byte // 80 + //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) - if !s.ReadBytes(&p.cv, 32) { - return nil, errors.New("could not read cv") + if !s.Skip(32) { + return nil, errors.New("could not skip cv") } 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") } - if !s.ReadBytes(&p.outCiphertext, 80) { - return nil, errors.New("could not read outCiphertext") + if !s.Skip(80) { + return nil, errors.New("could not skip outCiphertext") } - if !s.ReadBytes(&p.zkproof, 192) { - return nil, errors.New("could not read zkproof") + if version <= 4 && !s.Skip(192) { + return nil, errors.New("could not skip zkproof") } return []byte(s), nil } -func (p *output) ToCompact() *walletrpc.CompactOutput { - return &walletrpc.CompactOutput{ +func (p *output) ToCompact() *walletrpc.CompactSaplingOutput { + return &walletrpc.CompactSaplingOutput{ Cmu: p.cmu, Epk: p.ephemeralKey, 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 // 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 { - vpubOld uint64 - vpubNew uint64 - anchor []byte // 32 - nullifiers [2][]byte // 64 [N_old][32]byte - commitments [2][]byte // 64 [N_new][32]byte - ephemeralKey []byte // 32 - randomSeed []byte // 32 - vmacs [2][]byte // 64 [N_old][32]byte - proofPHGR13 []byte // 296 - proofGroth16 []byte // 192 - encCiphertexts [2][]byte // 1202 [N_new][601]byte - - // not actually in the format, but needed for parsing - version uint32 + //vpubOld uint64 + //vpubNew uint64 + //anchor []byte // 32 + //nullifiers [2][]byte // 64 [N_old][32]byte + //commitments [2][]byte // 64 [N_new][32]byte + //ephemeralKey []byte // 32 + //randomSeed []byte // 32 + //vmacs [2][]byte // 64 [N_old][32]byte + //proofGroth16 []byte // 192 (version 4 only) + //encCiphertexts [2][]byte // 1202 [N_new][601]byte } func (p *joinSplit) ParseFromSlice(data []byte) ([]byte, error) { s := bytestring.String(data) - if !s.ReadUint64(&p.vpubOld) { - return nil, errors.New("could not read vpubOld") + if !s.Skip(8) { + return nil, errors.New("could not skip vpubOld") } - if !s.ReadUint64(&p.vpubNew) { - return nil, errors.New("could not read vpubNew") + if !s.Skip(8) { + return nil, errors.New("could not skip vpubNew") } - if !s.ReadBytes(&p.anchor, 32) { - return nil, errors.New("could not read anchor") + if !s.Skip(32) { + return nil, errors.New("could not skip anchor") } for i := 0; i < 2; i++ { - if !s.ReadBytes(&p.nullifiers[i], 32) { - return nil, errors.New("could not read a nullifier") + if !s.Skip(32) { + return nil, errors.New("could not skip a nullifier") } } for i := 0; i < 2; i++ { - if !s.ReadBytes(&p.commitments[i], 32) { - return nil, errors.New("could not read a commitment") + if !s.Skip(32) { + return nil, errors.New("could not skip a commitment") } } - if !s.ReadBytes(&p.ephemeralKey, 32) { - return nil, errors.New("could not read ephemeralKey") + if !s.Skip(32) { + return nil, errors.New("could not skip ephemeralKey") } - if !s.ReadBytes(&p.randomSeed, 32) { - return nil, errors.New("could not read randomSeed") + if !s.Skip(32) { + return nil, errors.New("could not skip randomSeed") } for i := 0; i < 2; i++ { - if !s.ReadBytes(&p.vmacs[i], 32) { - return nil, errors.New("could not read a vmac") + if !s.Skip(32) { + return nil, errors.New("could not skip a vmac") } } - if p.version == 2 || p.version == 3 { - if !s.ReadBytes(&p.proofPHGR13, 296) { - 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") + if !s.Skip(192) { + return nil, errors.New("could not skip Groth16 proof") } for i := 0; i < 2; i++ { - if !s.ReadBytes(&p.encCiphertexts[i], 601) { - return nil, errors.New("could not read an encCiphertext") + if !s.Skip(601) { + return nil, errors.New("could not skip an encCiphertext") } } 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. type Transaction struct { *rawTransaction - rawBytes []byte - cachedTxID []byte // cached for performance + rawBytes []byte + 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. 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 - tx.cachedTxID = Reverse(digest[:]) - return tx.cachedTxID + return Reverse(tx.txID[:]) } // GetEncodableHash returns the transaction hash in little-endian wire format order. func (tx *Transaction) GetEncodableHash() []byte { - digest := sha256.Sum256(tx.rawBytes) - digest = sha256.Sum256(digest[:]) - return digest[:] + return tx.txID } // Bytes returns a full transaction's raw bytes. @@ -301,10 +362,11 @@ func (tx *Transaction) Bytes() []byte { return tx.rawBytes } -// HasSaplingElements indicates whether a transaction has +// HasShieldedElements indicates whether a transaction has // at least one shielded input or output. -func (tx *Transaction) HasSaplingElements() bool { - return tx.version >= 4 && (len(tx.shieldedSpends)+len(tx.shieldedOutputs)) > 0 +func (tx *Transaction) HasShieldedElements() bool { + 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. @@ -313,8 +375,9 @@ func (tx *Transaction) ToCompact(index int) *walletrpc.CompactTx { Index: uint64(index), // index is contextual Hash: tx.GetEncodableHash(), //Fee: 0, // TODO: calculate fees - Spends: make([]*walletrpc.CompactSpend, len(tx.shieldedSpends)), - Outputs: make([]*walletrpc.CompactOutput, len(tx.shieldedOutputs)), + Spends: make([]*walletrpc.CompactSaplingSpend, len(tx.shieldedSpends)), + Outputs: make([]*walletrpc.CompactSaplingOutput, len(tx.shieldedOutputs)), + Actions: make([]*walletrpc.CompactOrchardAction, len(tx.orchardActions)), } for i, spend := range tx.shieldedSpends { ctx.Spends[i] = spend.ToCompact() @@ -322,9 +385,197 @@ func (tx *Transaction) ToCompact(index int) *walletrpc.CompactTx { for i, output := range tx.shieldedOutputs { ctx.Outputs[i] = output.ToCompact() } + for i, a := range tx.orchardActions { + ctx.Actions[i] = a.ToCompact() + } 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. func (tx *Transaction) ParseFromSlice(data []byte) ([]byte, error) { s := bytestring.String(data) @@ -338,135 +589,26 @@ func (tx *Transaction) ParseFromSlice(data []byte) ([]byte, error) { } tx.fOverwintered = (header >> 31) == 1 + if !tx.fOverwintered { + return nil, errors.New("fOverwinter flag must be set") + } tx.version = header & 0x7FFFFFFF - - if tx.version >= 3 { - if !s.ReadUint32(&tx.nVersionGroupID) { - return nil, errors.New("could not read nVersionGroupId") - } + if tx.version < 4 { + return nil, errors.New(fmt.Sprintf("version number %d must be greater or equal to 4", tx.version)) } - var txInCount int - if !s.ReadCompactSize(&txInCount) { - return nil, errors.New("could not read tx_in_count") + if !s.ReadUint32(&tx.nVersionGroupID) { + return nil, errors.New("could not read nVersionGroupId") } - - // TODO: Duplicate/otherwise-too-many transactions are a possible DoS - // TODO: vector. At the moment we're assuming trusted input. - // See https://nvd.nist.gov/vuln/detail/CVE-2018-17144 for an example. - - 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 - } + // parse the main part of the transaction + if tx.version <= 4 { + s, err = tx.parseV4([]byte(s)) + } else { + s, err = tx.parseV5([]byte(s)) } - - var txOutCount int - if !s.ReadCompactSize(&txOutCount) { - return nil, errors.New("could not read tx_out_count") + if err != nil { + return nil, err } - - 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 txLen := len(data) - len(s) tx.rawBytes = data[:txLen] diff --git a/parser/transaction_test.go b/parser/transaction_test.go index b753e05..018cd89 100644 --- a/parser/transaction_test.go +++ b/parser/transaction_test.go @@ -4,880 +4,112 @@ package parser import ( - "bufio" - "bytes" - "encoding/binary" "encoding/hex" + "encoding/json" "os" - "strings" "testing" - - "github.com/adityapk00/lightwalletd/parser/internal/bytestring" ) -// "Human-readable" version of joinSplit struct defined in transaction.go. -// Remember to update this if the format ever changes. -type joinSplitTestVector struct { - vpubOld uint64 - vpubNew uint64 - anchor string // 32 - nullifiers []string // 64 [N_old][32]byte - commitments []string // 64 [N_new][32]byte - ephemeralKey string // 32 - randomSeed string // 32 - vmacs []string // 64 [N_old][32]byte - proofPHGR13 string // 296 - proofGroth16 string // 192 - encCiphertexts []string // 1202 [N_new][601]byte +// Some of these values may be "null" (which translates to nil in Go) in +// the test data, so we have *_set variables to indicate if the corresponding +// variable is non-null. (There is an "optional" package we could use for +// these but it doesn't seem worth pulling it in.) +type TxTestData struct { + Tx string + Txid string + Version int + NVersionGroupId int + NConsensusBranchId int + Tx_in_count int + Tx_out_count int + NSpendsSapling int + NoutputsSapling int + NActionsOrchard int } -type spendTestVector struct { - cv string // 32 - anchor string // 32 - nullifier string // 32 - rk string // 32 - zkproof string // 192 - spendAuthSig string // 64 +// https://jhall.io/posts/go-json-tricks-array-as-structs/ +func (r *TxTestData) UnmarshalJSON(p []byte) error { + var t []interface{} + if err := json.Unmarshal(p, &t); err != nil { + return err + } + 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 { - 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) { +func TestV5TransactionParser(t *testing.T) { // 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 // 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 // misalignment. - testData, err := os.Open("../testdata/zip143_raw_tx") + s, err := os.ReadFile("../testdata/tx_v5.json") if err != nil { t.Fatal(err) } - defer testData.Close() - // Parse the raw transactions file - 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 { - 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") + var testdata []json.RawMessage + err = json.Unmarshal(s, &testdata) if err != nil { 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 - 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) + err = json.Unmarshal(onetx, &txtestdata) if err != nil { 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() - - rest, err := tx.ParseFromSlice(rawTxData[i]) + rest, err := tx.ParseFromSlice(rawTxData) if err != nil { - t.Errorf("Test %d: %v", i, err) - continue + t.Fatalf("%v", err) } - if len(rest) != 0 { - t.Errorf("Test %d: did not consume entire buffer", i) - continue + t.Fatalf("Test did not consume entire buffer, %d remaining", len(rest)) } - - // If the transaction is shorter than it should be, parsing - // should fail gracefully - for j := 0; j < len(rawTxData[i]); j++ { - _, err := tx.ParseFromSlice(rawTxData[i][0:j]) - 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 - } + // Currently, we can't check the txid because we get that from + // zcashd (getblock rpc) rather than computing it ourselves. + // https://github.com/zcash/lightwalletd/issues/392 + if tx.version != uint32(txtestdata.Version) { + t.Fatal("version miscompare") } - - // Transaction metadata - if !subTestCommonBlockMeta(&tt, tx, t, i) { - continue + if tx.nVersionGroupID != uint32(txtestdata.NVersionGroupId) { + t.Fatal("nVersionGroupId miscompare") } - - // Transparent inputs and outputs - if !subTestTransparentInputs(tt.vin, tx.transparentInputs, t, i) { - continue + if tx.consensusBranchID != uint32(txtestdata.NConsensusBranchId) { + t.Fatal("consensusBranchID miscompare") } - if !subTestTransparentOutputs(tt.vout, tx.transparentOutputs, t, i) { - continue + if len(tx.transparentInputs) != int(txtestdata.Tx_in_count) { + t.Fatal("tx_in_count miscompare") } - - // JoinSplits - if !subTestJoinSplits(tt.vJoinSplits, tx.joinSplits, t, i) { - continue + if len(tx.transparentOutputs) != int(txtestdata.Tx_out_count) { + t.Fatal("tx_out_count miscompare") } - - testJSPubKey, _ := hex.DecodeString(tt.joinSplitPubKey) - if !bytes.Equal(testJSPubKey, tx.joinSplitPubKey) { - t.Errorf("Test %d: jsPubKey mismatch %x %x", i, testJSPubKey, tx.joinSplitPubKey) - continue + if len(tx.shieldedSpends) != int(txtestdata.NSpendsSapling) { + t.Fatal("NSpendsSapling miscompare") } - - 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 len(tx.shieldedOutputs) != int(txtestdata.NoutputsSapling) { + t.Fatal("NOutputsSapling miscompare") } - - // Begin Sapling-specific tests - 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) + if len(tx.orchardActions) != int(txtestdata.NActionsOrchard) { + t.Fatal("NActionsOrchard miscompare") } } } - -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 -} diff --git a/testdata/blocks b/testdata/blocks index e3af9b8..4c8f068 100644 --- a/testdata/blocks +++ b/testdata/blocks @@ -1,4 +1,4 @@ -040000008a024cebb99e30ff83d5b9f50cc5303351923da95a8dc7fda3e0160900000000226b1c86e101f1fac09aa533c246bd6843ee6b444ad3ff251df0a401f16f0981000000000000000000000000000000000000000000000000000000000000000069cb7d5b0f1d0a1c0000000000000000004d6cdd939a4900000000000000000000000000310c50b3fd4005008f78a11b4b81126dec31cba6ede2e131ab376a8611237b04d20cd8bb4253f1e8721e0941970e0f58c206f09c8c86c70b2f73b3b5994571c389a90fadf6b812cebba5afe622b3e4aab20a88c805e1f3925e31300df11c09e3d4b7acebbfb156b75e213e36f65d88f023feae5d37ab2f13a1215299155b7d9a1f4cbb333212e8ef9959785adfcd2506d33ac1021207fc32584022080f4a7ba67157ea99f6fc645737a2a5c6f5d99700ff0c1a92f2845dba3b022d24de26691c0b56977b13e94d5f93ebe423d3d422a478f2e6d9f0b113b3fa0434fe432c173013b1a641e884f74922a3e6fc6cde4dedcd8c2458be13fb91f5285ffbf8a5dd207dad3b011b832444a85e27da43c1f94864ad7b066559d5210bf495565005f9297f6204ad7b4c395d5faa19c2530427ad4889555aefd272185f825564525f6d3e0bb62b18cce8ca120a6f636ee36f18612fede045bae81403752f8154e7c3bf4fef7134591379389155360cd15328c731c1ed3b57f439994b0350799e91f91f53e30ce9bed6ea9ce01b3f74f6041b739d85965d789b9c43ba65cf4f99808ef03c2ac46461ba0eedc05e77400815af9d8049027bb7fef6646142d86ef35adcca060e8a656c6c6cc811f65231b4ac531fa2083ddffbab26d19409cc357b89ed7da3d25476cb9d9a9c939c343d23fa35a09c52d593fb03f609dafcc28579fdd35e044168e33e747757bfdf5123080b6799d2527368f90de7f126304610765670214b6e9b6f497a491650db139129da19964461c368e2524aa1524248ed92561b3e94aec38d5ff4adcab5f73565dc7626477b1d56620ad1bb49000d1cd915a260c0913960c493edb9770d2fefae76dae63963e147331a51b1c66d5ff3ecf87f141306d575e60ca3b34fd26cb0b1d735dbbb1977db519a7a9d345ccc77121b688c7470975ee9dbfc489800f25a41d406ccbcbe1f01c629dfcbd59ea5dcd00334cc6af8718e08631c3a83d5e6395b4acc3afab48b145b73a064904176c30c2cd9a876ebab5f333b6ebd17c10e31ce6f009daad792c31fce13dd6d401120eb08d66348c13735ffc667e653ccf80bda54d0773473177433406a0c2001ec9f534c54e667c5a3cff3bca72625b5fee94a51dfc2b5b3fc73353b2b2f3a9e708932003e771dd21441e9cd075765e33ab5fe0db05b4b087bb04608d5fe5bd32f8272752cb1e59f856eab0e366a935a9651be4584f8886649c66bb6bff29ac82e0bf749c94e46cc6a42988196c15d3b2a6376185b990e653cbc8a77e56fd3e74378bcd54f4540afdf39650950fd18192198bd743708fcd948ec57aab07d71211157758ca83509cbc0094158b75bd840810fb266f91565df4f4013aaa4e414b3a56bf8442938189441ae24f8e2417b7bb729f9cf27a2ee5da291fed793afcf09a1c63f14af0dab7aa6b34b1be3d545356653f14a2d31173cf50fa6aed549933a5743cd46809bf6e64824111cb5032130536943f359ffe5cc7ad5b4dcce3f2d078f7ca751fb08f8a5d9ac3970cb9f2cf31ed1a713cec3e8bac8586ce10c74e215c3d691c58e176b39382da1fe4ff0edc7f23373f594ab00c987c772f92317575d4d199e79f5b95fe1986ff0dd4d4a339a797b3b366e737bf8befbf80fe58f0d5b6f35c831d00ebd0c47ddcec914cf879ca685c0724b9036f98abacd96102657148a55e6e7896f33d51daa97190a233a4d68278b51c2bd26dd23916c54e605b6578a8e3657359c36a9ee2e4c0f650a95a3f4b61c4133ddaa901154d20c807a6ab85211bda537f26a4fe4b53a4a64f5522d13eb75cd2bab7669ef47d1c7fd43416182bcde9370105383fa2c0c574d4895d2fea59889068e66f83c8f15118c7ce7adb41fd8de61c2afd7277d6ac31346aa01030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff0503e0ce0500ffffffff0200ca9a3b000000001976a914361683f47d7dfc6a8d17f8f7b9413ff1a27ec62988ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000 -0400000015bea7ff6272a28e0dd187b5160d8fae6f2ad6316d652fdd26b92204000000008ede1b5093bbb6ae7c883dbd4b8bfc9e97290ac6ba5a617c880d3aef1bc41d9200000000000000000000000000000000000000000000000000000000000000009bcb7d5ba51e0a1c0000000000000000002c476f1d2c08000000000000000000000000002c27173bfd4005001a40fe9c1795f9617212aa1ade76cd93f85db2e5254a8ffd5aab68218adb36065f6947477a423c26c719803ba9c01555a1d81ef1cbd4ab0e7a7c9c7aeba622c7c1614f16409f5b0f757a93d12923027fbe875e01d4003525150ba313f43148bf39e7836a3d5fae611de2de0eebd8a3d1b163e4ad7b3ad0bbc00a3f4b8d029ee0e23f6354cbc381711eec9df770f31149ac1e0eb55229d10d7ba106edb12834296cfd241f5a62a6014ac0726dc4543f05a88138ad2d7654b707aa799115886e467957d5f195fda7a0a0d7908e084b974a1e0565e222acc9670f4f7191b4052f84595457315647468f532773a0755b0b3c7649aad0ce1e9da9597819022f7c951ddf47978c5985bb3f4350b1b91f2eff7f149ba3992316712d0bb2a3b6fbb3dee54b516d22b21f60c23f87e3513d2ae3447191b55b17f3671f9e3629da0eb3b8261cb7eccc675761f95452435bf6b6f800a4e5a2deeee86b8ae3d026a11eaed463373c378b079a68b51eed25b596fd519a2530f9414684d71dfa427c461ab170137fcd343af2fef3122bb037df784e647b6386823340abffa60668eb7a5729fdda35d42602729b2fa822d11da41c304ce27530bc17e717fdd10a2f221cf793e4db842ee2f6f04b2a74d3945214ec0d1819005f0e42f68c8183e9a0a87011180ed87eb3205e7f01d7a760d95b874ae2d17e915b267cbd0e4e06e99982744e7473f74af2ff766730ee01f7528478116633f7d2eebd87d8e134429e4d29b92144fd0ffb1628add40f98c4df2856632055a3d2c70a2abf69851929b6aa5a9de2af2148ea564a7520f6d95e5724b40c2a3c9d39c995b2f3e131795f2299029c215b07cd14bce9e10fd05296a8a646302ff4c45e85a4bc3bec12fedc1d1f60da8f6aac22f746d43a11bd08be8e52153c60ab71061d35284872c427e3aaff0d8a3a82af016db8d42937f04be1ccb021e7152aa82a068b0a1b04cbe51b904ffc00f3bd46cedc3c58ba378355360e11982c9981c6a5ae7c6d21fa3b2e54b8e01d49a0f618df191ffbd3274b7ac3c5f066623a15c1e07eb64e1db18f37cf4d4452c441c63b8075ca220d0131a2d022da9305700b8e0d236ab4dfd17c2f453c3f17fd722925de3cdfac190bdec92340db74ad46ff693f79c92bad961d021e3a01dcf16445d66713e53bc37b89720c887088d26831e5a4a7011366eb3b6920df10a3316eb41dfbe9ef6f697bfb673be8bce2a64c16baa1ed1cce0a0bc32595bbc22f42ba8d2dbdba3f6097cf7b27cf4717d7187bab684e364a17c69e29c49ff3aab10d8f9d3002149c72d90cf115723ca3aee3c8b8014918896bf63a2746d7a486a496b274b21765dcdeb83b387252b876129b65ce91e613783f55aa1ca85c07a448b4eb36d95681c1851f7532a47e8056eacbd8c45d01b61dda489c744f267111294fef34a98c5391d6ff31491f974fdcbee1cfcd740c714abd9a616878d604076dc376afd53826da95c4b81ad0f991642a6bd3d518feec5a021e20a73be5924147203586c75b3fa9c51111119bd39061fdeedbc1a1a92aeafe834dff67071438f21b247a5713e66bf156ab70f04995ba70f4f0129da42ee3d5ca8da38c35c2b8d33d19e79618a0061ac8fdae6a58250725ab51dbda4a6541d7fe1cd31403ad8d6cfde6badbb85ff162bc1f08b109866f8aaa1688b2de068fa272a3a6371f3876101a37191dc9c308eff5bbe41512b7a749668f2a35f43e2dc67c91ed13e39bc4ce5783b795d1a16ba03886ca053dbd6a4006e0f5091e6955d7abdc154373d10d4d60ecee597c0a8d71dfbb2e3b4fa83554d459c0a68d655c9b28ff0cdd2ace655bdd8dc2322394a34255b1d5373dc39c310244fa0fa1c557d7caa3d029ad36966d0d7606e301030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff0503e1ce0500ffffffff0200ca9a3b000000001976a9146d17c0ca63e020d639f5fba181ca4f5da48b8f7088ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000 -040000003723935953489b860d1de1b8fc8240ced04625f0ffd23f16519b8e0700000000f066ce1a8f2b97d05dc15ee51e1eedac93ba6057a953eb81d3f856e9f4b7ae270000000000000000000000000000000000000000000000000000000000000000c8cb7d5b13520a1c00000000020ff5b32c230200000000000000000000000000000000000d5e39cefd4005003eed282b472cfdcb0540b4f4245ed479c5357ff11989ef70be9700eff5987318f727dafa0b467302aa016e5e956c5a5d23f0f9e4a5623b9dda30e0f1b3c47e8c3d151e686cabd4ac89fc627e5cded736d707780c3dc341370bf7af4cb291878a1c4236cc207f39f081ef26b50fe099bdb90c8a9462663d1aaf079fefa010c2a8c29211f08b8debf2f90e4afade29bc53d74253c3fbdf265759fee75e1ab46adc90f38bba5f73e80e518def9b61e8b714d6e6a1dd585539ebd1f5f2040e8e73498455bec4fd333747f96823c66fb859177d13f3ba05868918255bb022cc32dd0a099438fdb1b31b15e2de9acc341066d6b20e4c1d18f56397dfe97919a2eb988e114e3cc015c1c209d906e494c46b9dac34a99ad0595868b4f84a1474ff532202149ef12acc1db1f9307213f49efcb0a408fcc1cc6124e637adb22ee4368da8d0a78b696956e7e4c9feea5d2e198f0e00bdd16ca49956c32ff793e3ff6e635efe57788fbf11a8b2a771d1981aeed6462fdd74a6a9f5d813d86616923f5add19a41d507ba22b69a0caf4a608f8b7673bd605d7f2b022b3d8436448aeb34e491c12addc3911564ecf5de8b1355f1762dc402e37915c35cb69de2a9d575a765737ff92c653eed1eb871270589c2dff15f827ba45b19ab3d25da28fe3176895a8cc32a943391276625d991492ed315ab22a7192fbcc5f5eb01611640c96585ac4db590777a87444c3dadc653bc2bb279474ad76ac00d5972b92e026d45fdd0ed84b099a13d08c00eea952c5a2a78218e06ff989f85b52801d203f82d395310f67e80f4646f3f29c5b0c2f9c3ce31530b766c12f3253a6f3e2aed5b66efd9dcdb6f1de1e601a36b00fa2b7c4d6241e46afc746cfb73f1b2f19c60f81472bd15bdaff21afb0c44514915bfbdb5a20172209c4c9c281ba14950b07b22d097bc0cce5fa017ef344aec83bca60db20f4241ab3e1d29f7f200a24b801aa1e2c638d77ac13c0732da3561e3e1bcc6f2ac78fcf21e7f113b56d83c0343a1cb6d8b69eb12975891c1bb27885f1efc8c97a0af71176f716fe36b61262e23b48e7266f6551821948e4c44d48153df60a1a921faa5766e4a99239c2f36231bdadc93e749db715ff7e8ced9ef6cb28e7a5a8aa7603de56e73ea5fd1d79be8974a4c071ed1b969382da51d68b11f4722303d74f82849cb05d07c0c313d9a0d5eccbb853f85f0c7002c67eeb93737060180a3f557582d3849b73bf13807ff3f4065faacd7562487fc96a20fcf2cc892e16ad74b813caed4f72f11293243912c976a9f2035b099b9b9debc968aec54031bb9f4eb7815ddb3bffc128d6be34814fbec58b17c6dfab6c812a5eb3fd15d60fe3fa55128466cb80bae5579b71025e6a9c34b7f818eb11cdb029eff94fa465e419b9aef2e8679f12ce02b780aba2c17313bb375033beda50e90be5fd949002fbb85634d42598b62d21e346d13c99e4b6364354136f828f972a7b2fd8c4464defb82629ffdddea6355afcf76a5b6a1f797b2a46b51cee7f95f812d926d00436f98711c6f6a1e374a5f8a6f73f39b70150ae7315988b1a2c88174e9bad58c2e0f82476bb1c9ebd03079970441810e5c7c1b8d3a5b8eb21750f29eb92f348d5ccd2dd13fc68b063c754564f490e33ba1bc71b111eb14500d1dfcd883be26a8952aed912f4a999831b80a94d1f994c69558334e165513fbe129a9348922d6205d0bdb3fed3d0fec41a8f7dac2a46f2f9bdd837d6fa791bd25ea3bedf454b7fcf8907000a78d4e911bc798c6d261817400572cea0a26e9e2f5b16cd7129e92738be52b4832c2a072e2c7db3c2b889fa089b1284a3ae2ec654da817e15e0b26856be1caa1c7c0b3446158365a0992bc01fc67c19d5444ad8c6be044902030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff4903e2ce050004c8cb7d5b598c2ba5c7f0b4587e7d60e62e08985aee803a179dda187d2f0c5284df7da7482f4f76657277696e7465722f5361706c696e672f706f6f6c696e2e636f6d2fffffffff02d0eb9a3b000000001976a914de2757e612dee78a681ace9b8e623570dce776f588ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000030000807082c403012263eb14eca399ec05b64be85325e2c5ab93e5d70d7dc49b4e8b8dcb52ff0f7b680200006a47304402207ade36a404000f4d5cebed5c28e28c57a539b7985b66aa4c014e0c59a43fde3a02201bd61f0a998301241d83fc9370654e0acda7cc6602258b954af6bf06605dffaf0121026e88bf2ad6aa4fdc21b2636583184a589fcddb3c1ed40b4e3613cf61601fad54feffffff01bc131600000000001976a9142f592f81575c361e91397dccc60772b9335f432588accfce0500f4ce050000 -04000000c848f5a041f4406004243ecf645ef91f303f6766f5615e4cd2c7ab08000000002c46ffced042e210ec98759ee1bf5792b62c3a3c56f24667422350dcf3c84e070000000000000000000000000000000000000000000000000000000000000000d4cb7d5b7beb091cf18a4fa59e6d1400000000000000000000000000000000000000000038d0a613fd400500572cbab31dea47dc52529819b5b80cce7fa6ff4f0c1e8f09d50bee7b5012813826948828c3d5e6f14505a4f7ab54884cb7b8f1a49675b99f820d219567d72695fc14f74a26554ad3c346123852669bd29e50eb056cda5e176bd065ccbbf2663f3a12a11f7773a0847c09059fddb09a37908e1a8240f29dd6eaec78f92b1f67e2a1cd27c2b1d6f9c5c7d0c8545dedb6f949c93507838d4525606b73d176ed8ddfa2a20d93ba4d4303512f8fa4c96efcc084329bad15f9997edef03fc90edcd1e7f943c95b5c7123d66a4d0ec9012ab2578e1d9bbcb47bdf56e9eb72e3c82dcfb14ed9785c860522791bb3bde200f76db5e907555c27ef91489cc4410b4129e4aa08b800c00952b451cf3640c326b690e719d92cd2a87799d1dd63b36984c30a6582bdb1fc6d16b323c2ef33b23deaf2325763f8b1fe7b21dd7c801ffc7df2c4d68511aff3b2059e681bb1afaa19090d03592df27c452350d040718758902afcaee5fa48a00e9fffbd3ec4222973c2686fb3e7beee6c5ebe0ecc130b8981d00adfcd464832b625d7cd82adb99e02f71c4b3d9ec6ce5812cb5075cd70cffd967e73b9f08c04c97c728e02efa88b18f318423ce212fca69c05b743289eb18912bdbcde1bc5fb507286baccb1b8937438092c5418a86fe56bdf441637ac4a49e172f491f743a694bc0516e02ebb1e36ec3b4a460e5f45bf6d2c055924c396c9546f9839b696785fdc09f99ddc7e701a3f0f61b7cb90d6de292400b8423f45bdb6d11d921711cc0a5316d200c220f70e80cda935f6b911e34d1aed9769d40ab973a6aaf1bbbc33ecf57f60d93a490d5835583ca4b70de9218510784caaf2d28c1b3dfe1af1e47ea3c96ddd46e27343ea5b80d175c3ef69b5387d2bfae8d026c765d2f5ec7ec7dacdca63dfbae85974e5a57e636edd68754664b56b9421a009ed09d7007b72db75980945b9f8e0da56d03cdcd8cdb9ce8a6d21336a8ab946fdeb59472585584a85e59e31152f0a9e03da924877854e93d5f6fbcff21a4165bbc4b60c8a195bd46761499fe1a28eb464c0957203d337cd0781d1e385308017999260c8da0933ee3b751d3ce92015b3e67393dc98d883d70113d24f72c4b73a885f1cea47062e88aba3983f192c69dc10db68b95fb3e021363ba87ad938bf97077263a7aeca4f769dfd54370194582d31d7c632c60833fa9346814b26ce1d7c451d6fbd6c309de603780185f499b963a7310abc42450445a2f2840f25350d38f2140b3904fd636ff5016334e2c234d72eff0d8096588c71ffdcde3569b3914f02acbe1938957135acc6d10f2d5bf56885c177e6ca778f7ce431225fd535a15949fdfd2e8ab0c47fd8251e294c02cf98d91340afb5812950c46d9b8dadba902fc70ea73c2c26b5a4d0d59410da46018486d9ec5a0a9b89422190afb7e72b7150f97b359d70841170ae23bacf915f10a019c601f48017472dd2b7c7b89bf0128dfd4a01e450adf17071ded02a3ae13eb7f8fec54510955a305256b2be2d97994140f36222d5ba55ec0ea35749fc894289af4454e944c1dbb1d7d40f1e72276651c4e3542bfd9f145500d9295eab83c6fc92362875620cd0159b7b53ff530d66b25adde2187438045c5fc4b8bdaff93dfb65b85c71753846bfa91f6ac60c9db561423b6109feef932486ece2cdc3c539112318c79ecc7e08ddda73ce663c3d4e9b9a7c743955330f1ca702b8a5673f82328b5f637dfa3743bcbe07583bfecf731cab93abc8d4a5dbfcdbf3536db25f1fff0d71175b744d561eecd1a89fe0484d466d2c5a68d61abba2dd9e8786211482b2b50218eec505f94c67971242a67a93872681ac81e1f541ecbf95a8bd7f5d8c1e60d95a76138bab40da3455b5a36549920d7f4d0102030000807082c403010000000000000000000000000000000000000000000000000000000000000000ffffffff1a03e3ce05152f5669614254432f48656c6c6f20776f726c64212fffffffff0288f19a3b000000001976a914fb8a6a4c11cb216ce21f9f371dfc9271a469bd6d88ac80b2e60e0000000017a91414c884180589f6d0fdc7c400181afb1bb10c9fe487000000000000000000030000807082c403016f4029430669c709d041c579c8e9469446f1159064613e6cd47514691b93b8ff000000006a47304402204ff60fca23a36026d374850bc018e7c714de78d8560d4188fa247b1a4ee4dcee02206538b475265173915662465b4a8554a111003701371d553134047bf185c98ba20121029ba2dc5033c7c17f06274b85c0f8e51ad518f34235713ffee4705867162819fafeffffff0208672302000000001976a9140ed9a32475fa7214939a6705fd790a74976bab0388ac3e926c01000000001976a914d752bedc09529fb3719004407dd6b5f29000e3e688acd7ce0500f6ce050000 +0400000006785624481f381e68b4506ba5d6cc53ddd6dc876cbc97e45e3c7c4a626a19008c450aa9112b2e900eba30c2e3b8428c23fb2a30bb7fa34a853c97f02fb1a2200d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5aecdc295c172c191f870000790c975f8c9f0a77f12ef1e021c6045c3c9acb7c432c2aa7ed42ad0000fd4005005db35c547608bbf32bd1b90369e6e0bc1e275a0d064f092b235835cb6dfc9158c6146a0e5cfbdf2d2f04f71478f7d9212bdeeb938029a5cc217ebf1f517711dbc7cb35d084328b8f7613e878f69e27b2b40e8103292cb87845006943b761bbbe43d94cfbf971011617965a7de1e846a586ad81f2ad138eb0fd74729efc04720badc95a1f1383cc70e890db91c143591ab96526263ec6b8a6186568dda29b9015078d19e87cbb2c00b26edee3e4b227ad6fa090db2d290191ef1043e2037fc0bd225e6a1364d16223b0234311e8c5ff455a0cc2e0c1f84944dfab49864f57e5ec2a2b5e91df5229449ee399b4c721abab63c534602abdf64d37f60905bea71cd59be759bae5967f6f3e1bf732753d4d9c1c11dcb5b6949bc4f63a06a3b0db5c2deebab040c70fc55fc648bb2559fe2da2b4a4bd53ccbca7aaf03262cdf31c5bab90cdc151b686d3e5f8a29103b9346602b5394b245dc9655116d33c2ed9d31563bb74950d0927895a024c119d30d4f2c760c346b11108ab29db2931123aa36937cbd152756758e3d341ec40db1d1b539fcbefa2e76af9827f575025c58569fbec1f806607e03a6eabc228a900a18144e310ab608a930ee6a10d5e6fc7ecc9934fb42b51f0a6552e2a1ba1d627b51df2d27889e14b87f093452b79bce3e2a74398f4b748eda48495b30437bef13527a231ce724f24d5bcf4040cc77f56dab50ff30ce12039ca968eef3c5ab44b2cdd8f7fecb36ed39bc624807a4da49d5b2f53abeb1a027676fb500fb89d7092eef849f254dfd3a7325e4b810687b8567d7db8e796480836bbeab2efff44bb0421f4e3d5d1493bedc2c331f75b7ba931e93495dc379fa22404a2e60919fb2644ee4e5c3bc2025fb17540dce5dede2fdc4fc6b87494ae26ae89bbe954ee8458740601a665126129c9962052683661efcfffce8303211fe3bf0adac14936927ce2f4b30a22227c39b4128616dfbfcaeae8f4a3b30255d215d1b9ccd9bff2173b5a94ffa5473bc49097030e782d81c1dc4f8c4a25803c6dd9a9e775646084ed2bbbf7457386ece058032128bc87c7b7772be513f79176241de701580b5c04f88ee81e231583528b514f0c478382e60d5741bd0b5582c2ece2767931f538d050498886814c5b27541764bda9734d5c46f2b3c80f2649d40374e45c053c050e33e83ed578f6d5c19435b7f495261e7e522d5225eaead374497fed7c30e322d6acbf512751b58417120bf8d97fcfdaa5e3be842fc7beab85235ff7e9ee459b03ef2ae01ceff42e0621ddce403e65521505ed0b25fca1a0747263e44c72c5e1e95d85119a7956852c629fcb903b9589e768a6bcbec5358a5332368a6913ffb9b9880e8d3701c6a366bec102bab8c6d9e57b2287ede4774d69fe81af83dbd423c905f666170bfc03f360314edf3098fe2036634ad90f326a71faa5b70f245acbdf8f7d4481283819d8dae7823ac31bafef129b94822a4d94b8ea5773b7477269be9dbe3bc8c11886a2d2a8176658fe30e1ba1bdcf320873d1d2325096223af6e142818a2c370b8447db8e6e865fef2074596bc9e679b8c37c51e99c4f35ac8431303fac507193d1d162d309a3d8d6e57cf4cd429b34ce69f69ef2f1e728d7b9347051b46d4ba5a7e7f9d43963e960d0bbaf63eeb69396dc75b325f08e9243db0c678aa192eb3db32d9cf65a0a38bd5726e31380f2de23ea9a019d8496ab511df2d955978fcee6e331aeea5df0a1826639323180b87bbbf6a039e34f482a5e4eabc6d9a139c40e2840b40eb53dea3d549b54405ba7e1b392f308df2abfd6e97a3eb44f540b272a6d97c085be2142445ea27349bc7a5493397ceee4c8016a38457480f4de263cd2c2416296a2d86c19ded93cf431bfdd1e3010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e0ce050103ffffffff0200ca9a3b000000001976a914f4fbba801ad64c6539e64a1478392c57c9a5e7a688ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f570880148700000000000000000000000000000000000000 +04000000913b07faeb835a29bd3a1727876fe1c65aaeb10c7cde36ccd038b2b3445e0a001e1ecc75a33e350c7763ccf055402a3082f28209c643810a2ef17df4b14486cb0d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5a15dd295c21c8181f15000813d02ae5e889354eb9b7b62cca4f139ca6364fb63646ff32f2b4700000fd400500356a828c88fb46eaaa21d759e99109375d79b61557348f830c71fd4dabb126ae794d403af814bfd3fc01b76c2fc110525507f6728bec686ea9a432eda0ef1c8fc97d912923a9ab0d06f8aeef2ba272a3b7125e0e5079f131e4706d59c4f34a2775cfed3fca2cba4a23795351a38abfacf67ae7772e6fd14326efde46192105f2c3b0989a15aedfd22063529005723c8c8ea756ea876e0ae7846d4556e57fdb4b7ae1d2125456130653604eff1a6e632e20350a88b0fece49fa57079818d28c0064764979ed2e75766767a7ddce8578a23712274fac056571619b9ef4371f6924068fd5dcf25112da1ffe4255fe60b851e50b704eef0577967a867a0fbd7ed06f0d93f0f0ae31830ab5eaee5b20757e96233c21f96d6eb8f5b5ff03e88d7a31ced8037a52d94ce82fb719764841c06016ba82e29acb9d521cf9d74e1a1a90175c19ff365b763db1d3fbb6332499a5f90903d26af753812bca3eb2b142992bbd87140c3a0c29732d648c650e6bdfda63a56c6184570bf2bb4d700ba30d7800cecac92f67647bbb282d85228fedbdae1e1e3d56e9cb7743a58f02df45f658cb3b627f6bb311618d1697a217ede3f763d8fbf1fba96f697a62b321d397d492594b477029b23565f8ee80e3df1a74d81be2eaf203e3c9215c72c5fa6ec5f0d20cff3f151d7131ff6a3021f489f87819245d6af34f12dc5d1bd70d2a692be0da4827ed3f81a4b63ee58223bcb53474471a4bfcab99ca08d7dfc6c1cefda57f836d1e58731b4eccbea60c0606dc42945b26b17a3599be385b0b64519f6160adb65fd1da795cf27ea25e9884783834130be24ec10d549eb21ca32188f4221d3ee358f2894099930d165ca4d78985e6c13ceb9ea340ad5c116118c6a2d7851781e554a0e1b968540151e3715513f5476ff6618a5de0498e4f5632a6d5ffea8579ddd0be010b10204499c82540d521397b9a39a079acccaaae32add4d7991db22dcfcb04f86730cbef5b8abb0fa31137abab148457325eb161fd0ebe033094c324f6da261fc31476619753fe95c63a326fd14dbe6e7f83c501b77d4ce5602877b5164973dd55c04f7a891e6f3b423ee425b992d73bdf7e2735e4f52cbedceed9afde086f923208dc1abf1ddce86f9e7c467a8b0b79740510900bef0351faffdda005bd35e5a819b96c1622ca06399cc62f01d08d64c4236970e6c119380df5c48d11d57a8908e76b6d8ac3517f459ec83af139986abf135ea4be1886054eeb0087996aff4ace796b765175166f46af49d6ba10f8b5a455f7bc04ad82a53ac8d71529a6d0dd138642b68a518b61be13761b33bf60133cf97c9c2a0fab6cbfaf3601c0642b6d918b142caf1da2da75d52523739a62984f34f3016ed17cfe03522e71e332079920eb33c0b41de3c3f41e92c0382f7804195e251c0db4d2b6db83566cb4a767a9a85d4d674b226732bbe298ab5df3d5fe2239b82dca3fef254d1a7e3fa9c3545a23eb49136fcd21308280715c7d26601eb40fc49e025b33a6f676b16ae215bce5d6281e0bee2d779549ca7fe32811335e404c10e142ec50c5442afbb03ce0f179848765998ef1a3b60062fd187733919a34999d8bc5724d354421e699e25c39d416c74eb3e2c79229656b54af9a3cb0e71a52e8a9fefd08043f69ad8a8e536b0728e2a039ee80c999d4bd86340c97dea3cb2be33ff333e11dddf0ddd482d99844df08f7bc2ac351987b71e802aec4266b372f2a1e86780b89be04b444801e52c2a4cbf0cc2049e2b3d2c6180e7a28ba0e459de1ddbd016e0c3538f137dc98e2ee1729d5d5b0879073eb421183da7b55866ba8b79c911792a4a6b80b9ed15dfc4249d4c88cf229bc16491f5b8f1afcf272622bf782396aa55fe527a5a67d6327010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e1ce050103ffffffff0200ca9a3b000000001976a91403e105ea5dbb243cddada1ec31cebd92266cd22588ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f570880148700000000000000000000000000000000000000 +040000003893091e180992ed3ddbdca17b69bb32636fa24e139463cc3fcc390f72f00100152337b21d88dbabe7993aeda34e575edc0a10d8425ebf675ebc4a83b3ebc20c0d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5a39dd295c4699181f1e007d867f82f93d39b4107a1265900058b7565dd1b2945241a4ef63bc690000fd4005004b556303cc38ed6fccb33b93a81c0f8f05dd0e8006d64e34868ac9fe5c22863eff3928f6f2831b502400bed03b98c17215ca8a50612273461d43f857d192154f4ad5db69f067aa48d19503523a2f0602fbccbc01bceeeeb256d5690efa33a583efbf397481afaa5745976f397bd7c0cd270674f2de48ded99778fb0da11068c770ac303637c1ecb1b53e6f1be4f89130a7b45a49edcf081959f37121190d42d668b6bd5c1d353609479c1a598c2c43dd0661c9d51222bda25437f3fd1e952aea271a02c0f19a92f4a11faa20ccef67046f1a4036f38b299e73692e61aa67d526f1b7251da0914ac33d1cddd7a4bfeefada21c8f38ceedc1557d0710bbba0f4932c839177bac34abcf402e168303ed8021dc449b3ca0940448bff3217c0bc2730b19190c6811c420629a1878f6e7021171e9359002e4bc636a5322b8056733e3299bdf0c0f4545aba5372ca4a5b337300f3e8c43e89819a563df0e385229405479e1c12a50b57cc1b8e8e2f8b1db9b3aeca20724244f21c2997270e316e37528f7f302d95d9a2b71d7f0319fb4afc4cb25ea17f1a6fc3b7fbf68d71b65139fbee9997c404c2c76611cbb97750d7e5aae23d2ac26de83ec81d2774caf7279e40737f7b1502a4e8ad15f88a7bcc660a148b1c8c68fe4d891514a7a0d7b6b9e9e4561cf510a9c10bdd586fa57a9683afc9db809d93777c435e0780404f5e05a91ab84d6a63abd77e33e1881f2e341c6a7cae0b8d0507dd6bab56ba688cef5910ff18a816a3bb38fa5c6307eea5221569cdc90cde855083b12e189c39cc9052c328d1e654a3ea11371a6f5ad6ad07d396227464e23b4ae1e1aa1956567e000558473a29f34c53dcd8d4b8d3df0410d8af663de3f177565409f30a2ee236d6edbffc355609b4a60643f6f7db0b30a111d9269d6df96d1d487a6ae2d672ce37fbe0ef02ef64ea5793778f67af238fe45ff15ad1609bdead8fe39d445b2644254cf0acc5effc84ff8786fcbd041b7d3a42085d5c2f1cea86f2817d9b1e21c252e6f02404c7699ed8c6c14b979371d1a726451599fe312b10653fa69fc6c132e30bc299af2e92f9fb4495229f1e49ce927fadcbb19ebee2cb5ceae56981201d7b73168997bde9b287abb25d86d43562839a0b30be80f02c4ee3d2021afb990364264e78cf5b07097dfe860a047191ece343378f63d88136a6509c511f4b785b48187e1bde4f8fcabec22451c19eb9af4a6b743c289426cbc2b508bd4bf9ebb382fe131928292ed0d5113f3e86c3dd8656638f4c0ee5b500ef57d19aaa4e00ab17dcf7950954d017f648aa09bbd5a87aab8c9f42a01c810bc93790ed6791d3a2462a571320bae636632b2d3d77611c6cdff96afff421a534df351910f3ffe92eaae18fc6d4a50908be160ffc5dca626d2777625205d07f18eae60d9fe1b9e32f56fd3e92f98a1aa5c728130249a24cb47556d2c40f2029b17217807e3b3a11afbf8d981df73122d61199854f2414b9ec3f687a2a021fec118b38e6756e67aec56eb726fcab9b69ae09d77d3b55559c10d8afd242836bab39f8a93d1a5f16ba0e0c76565a2731a467af0a490a8e3baa3b3bcd36fba75c7d5c3985355dc38f2ff73f9728903f02274126e39301b1ee8599ccb9fd9955696f08f79a035f09d9ac570225ad05666a2900b56c97cfaa985f3a5814c46ad2a5d998c7f18be2dc1e23c540cd208b3a11124de8965dd8b645746cf351544d0371cc798ec6552d329980050c2a04812f66219677507591470d9a5d103d011b901f2a234395f363a59cc8d18561f7807f1d26e0fe5d2bd38365c174b2886758eeccb73f958c1550df9016863c87aa5a94daabb03dc34208bd682854ebaebe90954ddfc2a4974a02566c15fc5976d38c010400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e2ce050101ffffffff0200ca9a3b000000001976a9141fb09ecb821dd7ce9cc8ee1ed54df0d1863f824188ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f570880148700000000000000000000000000000000000000 +04000000d91995f491c208a7a8c1d358417120e91451158db34ab4ef30a1c026e2d6070094eda3d052afd42b6d45e541a1d97184636bb767ccbb7d8f91584693a80233250d86a7943df2dc92fb8b131b0698db24dd01a12d19696c20443f5f639df3ab5ab4dd295ca942181f1a0006ea1556b0c6c73177cd09700bb72e6b2457fed3174f1d69d4e6e3190000fd4005002f434e5adb994d86d3d45d4fc9584f3d70dba6ee34005bbd47169aa751d4c4d06bf9476a26cfb2fdc905c663c77186e370765413a5d0d25be15e4d50746c232c0fde2d09e01c5cf1e53b70db14c9d889fcd1ad128add562edc91339d81d1a4a78e3eed31d4d16d5b3209ae0571569d590114f68e85fd37b26b0c7724531d14a72bbacd02a309cf039521ce4d5537069326fd1fec07eda692ff09f941a8f8c0f543372ec8fa85c20416161dd719e3f4d3f0e663eeefc4da0feb31eace0e54f9df1fd5714aebb4d306636d0b61357e343e9c04c7f60402a9066bdf11b6817ced3f39e539ff98e4282b63ead466a6e15d5c85b76affa63a4e8e935f060a074f30cf9bcc89ef3872f80268ffb4cdc5aa67fb10b745e3b856fbb4b95d439fe8c8933b50eb5dc0091ec9c41c5ddc998b477c5302c0aede64eecf70b35c1f7d7983e1e052039dea18529752ea7e5ae67f4f51009908fd530968726e0fc9dd79d71022d2eb5749f1055e96fa98b35b79e7e32a92de750036c29bbaf38c0d30587b1f87653bcbb979142b658396d4cb7c2496566154d160ba44dbe97165f909c0c5c2e99077bb71041313603d852e22f0c560ab1f0738ddf74f105aa13e26ad8baa139f98f29ed71b85c80085f324f7db0b0a6e9e1d4584af6c592483254378654903adf6b4b70b77be24e817b053ac55016f29ac78a218095509e902936166f7923ceaabda692442ce1da6fd8e3a6b860cf8ecf7770ad2d77afbb0d15de5fc6084ff491a370baeb547171415e1be7f38e5edcc1283bc573f5522286f3d92208d568896dcf51c1566cdb583f1f0d87902e8fc27c6d1c43b1b3bb051cf568e426b551608cc1d27aa72fc9ff34f2479e609a8fc68a6899598f2d713065789f95983f78a3b746798bb19a989381ae0a531178d735c11e1cfa856b40d05b1f959115608e66800e95c067be6ebbd6ac008193ced38e24bc6db67a210d9a6ed0eddbbcdfb0f8439ab66cd4e27ca32f01a095212f36cd6b1c13c17c4ad3327c255b770dc66e03c797b1d39177365c08af59e723825596f024c7dba0a6a71657f84ab7ef5b345c11ad19191bd25d725cd1660d4e0e793c453bf9aac0494f4942f75481f577d0fe5860ffe6c776fbbb801bc6794c11c9d81ec91d32a2e162c69651c8deb52d2bd4bcdf9e0f18254549c041230266cadaf43cb09f113967492286faa3ce2c50a261ec8e847956ddce763e1df446b4164f2594bc40a1c6a756a451022381fd618bb432b9dbfbcb92d79865e3e9beee8a7277359188b6ef0956b59b47e023c06cd3f99c002fed0fb9a7cb63578a4ab4be39d24981caf13d1d4d580e4d48183aca7ae8a3230011b83d1097b33d5b7a3cf89f61d6702f5ec79e66fcd93e5bd4a5183189fae5123cb56791bcf64b9425e473cfdd2073b30e551703823d848e4adcf32673270b7d4b91511b38efd3a60937f2b90c7accaf7102e0b3c5e12c907b62acf098fe2abe7d073f4a4ba248623757adcd12f27ec2cedb749c7e280452b7f2cc085beceb495040cdb00ef434bc9ab78f8b0f79e8bb90cfaf7f8577743dd5a96c8264aa9b19ca5b7e46ed1a74b3d3fa1f02eb0164b62297b61e6bd951bea4562fdf8b3355ea95ad9a72ad0a35affe08f683bf77f781212cb53f9130b672e7e6a5ed3b31bf0a1089f2e694ed7875b9b5d11bc2c6ce1db7dc770d3b6a4e872a572285bfaff5c1f7a2202d8891b3ee2f6bbe4bd633ab700815c6ed9229e19b49856d72da66f865b9bcda32e5af81fd54c122c79ca1fd7a666ea4ef38b5a668b9532e675d8c0561aeba9c5f29a8f9cfc66918bda81e63ecf792705298699e526a10d4bdcc293e93b21513b8cb7dd486030145c81942a84038001873665f93d8ef80bf942f0020400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff0603e3ce050104ffffffff0208d99a3b000000001976a9142943b34e1bbdefc6f6a5c501264404eac228ba5b88ac80b2e60e0000000017a91466a04fe5f6f1b5bb1149e6cd0079167f5708801487000000000000000000000000000000000000000400008085202f8901bd114c7474dc9bddc943f99e3cd8af97332b4c899fbdebc44f105fe6b760bf41010000006b483045022100b73c1baacf61e8b4bd915ee1c007a51366a7cc718c5469de9f035aec7f92fdda0220595ad4cadd2617be7ce65ca5aa10b6d86ae27fb86c960686d7e1c668469afe12012103f9e72f0713a4d4a980309a14a2ba563e0b1125ad067818e77553a1eefbfc5be7ffffffff02f0ba0400000000001976a914d78f41784821c3d9929fa56e85267eae0bb09ffd88ac486e1500000000001976a9144faeeb51bcd0b49f238b323e5f1c6c8bf11ae02a88ac00000000e6ce05000000000000000000000000 diff --git a/testdata/tx_v5.json b/testdata/tx_v5.json new file mode 100644 index 0000000..9b0ed18 --- /dev/null +++ b/testdata/tx_v5.json @@ -0,0 +1,14 @@ +[ + ["From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/transaction_v5.py"], + ["tx, txid, version, nVersionGroupId, nConsensusBranchId, lock_time, nExpiryHeight, tx_in_count, tx_out_count, nSpendsSapling, nOutputsSapling, valueBalanceSapling, anchorSapling, bindingSigSapling, nActionsOrchard, flagsOrchard, valueBalanceOrchard, anchorOrchard, proofsOrchard, bindingSigOrchard"], + ["050000800a27a7265d7a8f732d9e945b0ce84f13010000000000000000000000000000000000000000000000000000000000000000ffffffff06040ce84f1300ffffffff021f5c73459faf0000016304311792382f000008636553ac530051510000040aec52303bb9bfb5651cd7f15b1c95e618d4cc05f74f837d61144f8fb58f33b1a67993db8dd99714cd92b572420bd27b9d4e30a73594bf5098421c69378af124fc87ca5388f256cca20b2b6e65f3536731185a7d55172d086db8ebf19f2fcf9d531db5fdb9b18d95e94aff57ffa2eac33656d59af80d06a745f44ab023752c35eb40f19c4b1ad1aa3f7239c4fe0fc2cf39fcada75318bee7805fcfed8d7f2d1d3d5a57efc2e1e9b01a035587d5fb1a38e01d94903d3c3e0ad3360c1d3710acd20b183e31d49f25c9a138f49b1a537edcf04be34a9851a7af9db6990ed83dd64af3597c04323ea51b0052ad8084a8b9da948d320dadd64f5431e61ddf658d24ae67c22c8d1309131fc00fe7f235734276d38d47f1e191e00c7a1d48af046827591e9733a97fa6b679f3dc601d008285edcbdae69ce8fc1be4aac00ff2711ebd931de518856878f73476f21a482ec9378365c8f7393c94e2885315eb4671098b79535e790fe53e29fef2b3766697ac32b4f473f468a008e72389fc03880d780cb07fcfaabe3f1a84b27db59a4a153d882d2b2103596555ed9494c6ac893c49723833ec8926c1039586a7afcf4a0d9c731e985d99589c8bb838e8aaf745533ed9e8ae3a1cd074a51a20da8aba18d1dbebbc862ded42435e92476930d069896cff30eb414f727b89e001afa2fb8dc3436d75a4a6f26572504b192232ecb9f0c02411e52596bc5e90457e745939ffedbd12863ce71a02af117d417adb3d15cc54dcb1fce467500c6b8fb86b12b56da9c382857deecc40a98d5f2935395ee4762dd21afdbb5d47fa9a6dd984d567db2857b927b7fae2db587105415d4642789d38f50b8dbcc129cab3d17d19f3355bcf73cecb8cb8a5da01307152f13936a270572670dc82d39026c6cb4cd4b0f7f5aa2a4f5a5341ec5dd715406f2fdd2afa733f5f641c8c21862a1bafce2609d9eecfa158cfb5cd79f88008e315dc7d8388e76c1782fd2795d18a763624c25fa959cc97489ce75745824b77868c53239cfbdf73caec65604037314faaceb56218c6bd30f8374ac13386793f21a9fb80ad03bc0cda4a44946c00e1b1a1df0e5b87b5bece477a709649e950060591394812951e1fe3895b8cc3d14d2cf6556df6ed4b4ddd3d9a69f53357169bb2c92f3879947dbb05811548b937bc17345340deaa3cba669cdd9c34b7b6206d0814e671a7b92723e5ca1513d6ab82ad0229407bbc48985675e3f874a4139ec3c34ecf2b762f7fb006a613b8a136e7481f044efab0cb0e6cea0734a10faf64fa483a23dbd3e6ada2aa9352abe0acd963f5dd5b5010d3d025f0287c4cf11c00ed167ff3cfb0df35137fe56369599909e63c5d9b68e13cf329b23d3a8e61ac101756d9fa4bd0f7d2ddaacb6b0f86a2658e0a07a05ac5b950051cd24c47a88d13d659ba2a46ca1830816d09cd7646f76f716abec5de07fe9b523410806ea6f288f8736c23357c85f45791e1708029d9824d90704607f387a03e49bf9836574431345a7877efaa8a08e73081ef8d62cb780ab6883a50a0d470190dfba10a857f82842d3825b3d6da0573d316eb160dc0b716c48fbd467f75b780149ae8808f4e68f50c0536acddf6f1aeab016b6bc1ec144b4e553acfd670f77e755fc88e0677e31ba459b44e307768958fe3789d41c2b1ff434cb30e15914f01bc6bc2307b488d2556d7b7380ea4ffd712f6b02fe806b94569cd4059f396bf29b99d0a40e5e1711ca944f72d436a102fca4b97693da0b086fe9d2e7162470d02e0f05d4bec9512bfb3f38327296efaa74328b118c27402c70c3a90b49ad4bbc68e37c0aa7d9b3fe17799d73b841e751713a02943905aae0803fd69442eb7681ec2a05600054e92eed555028f21b6a155268a2dd6640a69301a52a38d4d9f9f957ae35af7167118141ce4c9be0a6a492fe79f1581a155fa3a2b9dafd82e650b386ad3a08cb6b83131ac300b0846354a7eef9c410e4b62c47c5426907dfc6685c5c99b7141ac626ab4761fd3f41e728e1a28f89db89ffdeca364dd2f0f0739f0534556483199c71f189341ac9b78a269164206a0ea1ce73bfb2a942e7370b247c046f8e75ef8e3f8bd821cf577491864e20e6d08fd2e32b555c92c661f19588b72a89599710a88061253ca285b6304b37da2b5294f5cb354a894322848ccbdc7c2545b7da568afac87ffa005c312241c2d57f4b45d6419f0d2e2c5af33ae243785b325cdab95404fc7aed70525cddb41872cfcc214b13232edc78609753dbff930eb0dc156612b9cb434bc4b693392deb87c530435312edcedc6a93237c8521aae7a1d481596abc73c4963a012089770eaf4107ef6bb934a6a76a93599d4125b2747abbbfde1659922863734c56d7372af1eb86852f2a732104b1b4ef573e186efd8ab0e444a7340ac451a311ffb7e4f4f36f97f2c5dd5317be1af9c543405e53451a4a2a671a118ef66886f4a8472d144d99f8b8d1dedaa90771469f4202c2851fe308cfeef1f70d2698056143aa55e15b3f83501c585906fab9009695ba0b2f10eea6468cc6e20a66f826e3d14c5006f0563887f5e1289be1b2004caca8d3f34d6e84bf59c1e04619a7c23a996941d889e4622a9b9b1d59d5e319094318cd405ba27b7e2c084762d31453ec4549a4d97729d033460fcf89d6494f2ffd789e98082ea5ce9534b3acd60fe49e37e4f666931677319ed89f85588741b3128901a93bd78e4be0225a9e2692c77c969ed0176bdf9555948cbd5a332d045de6ba6bf4490adfe7444cd467a09075417fcc0062e49f008c51ad4227439c1b4476ccd8e97862dab7be1e8d399c05ef27c6e22ee273e15786e394c8f1be31682a30147963ac8da8d41d804258426a3f70289b8ad19d8de13be4eebe3bd4c8a6f55d6e0c373d456851879f5fbc282db9e134806bff71e11bc33ab75dd6ca067fb73a043b646a7cf39cab4928386786d2f24141ee120fdc34d6764eafc66880ee0204f53cc1167ed20b43a52dea3ca7cff8ef35cd8e6d7c111a68ef44bcd0c1513ad47ca61c659cc5d325b440f6b9f59aff66879bb6688fd2859362b182f207b3175961f6411a493bffd048e7d0d87d82fe6f990a2b0a25f5aa0111a6e68f37bf6f3ac2d26b84686e569d58d99c1383597fad81193c4c1b16e6a90e2d507cdfe6fbdaa86163e9cf5de3100fbca7e8da047b090db9f37952fbfee76af61668190bd52ed490e677b515d014384af07219c7c0ee7fc7bfc79f325644e4df4c0d7db08e9f0bd024943c705abff8994bfa605cfbc7ed746a7d3f7c37d9e8bdc433b7d79e08a12f738a8f0dbddfef2f2657ef3e47d1b0fd11e6a13311fb799c79c641d9da43b33e7ad012e28255398789262275f1175be8462c01491c4d842406d0ec4282c9526174a09878fe8fdde33a29604e5e5e7b2a025d6650b97dbb52befb59b1d30a57433b0a351474444099daa371046613260dcaba6838db07787ea3d88b9e9e83b40ddb5430c60acdb32764bbba34a5e0f82e851ac95dbf5543f81adf62c6566bbac4fcbeb1837570f544d6359eb23faf30a94542176db1892be6253efcb6075f3e5af8be3bb0ad5bfaeaf7f8bf4b53bdf3238a4032dd34606c9cf9f3dd33e576f05cd1dd6811c6298757d77d9e810abdb22f02f0bcffd06f2ed2a2137f1f1f63b854d6338f7113ca98549d844985043ea0b6d09d3e5629ea19737388613d38a34fd0f6e50ee5a0cc9677177f50028c141378187bd2819403fc534f80076e9380cb4964d3b6b45819d3b8e9caf54f051852d671bf8c1ffde2d1510756418cb4810936aa57e6965d6fb656a760b7f19adf96c173488552193b147ee58858033dac7cd0eb204c06490bbdedf5f7571acb2ebe76acef3f2a01ee987486dfe6c3f0a5e234c127258f97a28fb5d164a8176be946b8097d0e317287f33bf9c16f9a545409ce29b1f4273725fc0df02a04ebae178b3414fb0a82d50deb09fcf4e6ee9d180ff4f56ff3bc1d3601fc2dc90d814c3256f4967d3a8d64c83fea339c51f5a8e5801fbb97835581b602465dee04b5922c2761b54245bec0c9eef2db97d22b2b3556cc969fbb13d06509765a52b3fac54b93f421bf08e18d52ddd52cc1c8ca8adfaccab7e5cc2f4573fbbf8239bb0b8aedbf8dad16282da5c9125dba1c059d0df8abf621078f02d6c4bc86d40845ac1d59710c45f07d585eb48b32fc0167ba256e73ca3b9311c62d109497957d8dbe10aa3e866b40c0baa2bc492c19ad1e6372d9622bf163fbffeaeee796a3cd9b6fbbfa4d792f34d7fd6e763cd5859dd26833d21d9bc5452bd19515dff9f4995b35bc0c1f876e6ad11f2452dc9ae85aec01fc56f8cbfda75a7727b75ebbd6bbffb43b63a3b1b671e40feb0db002974a3c3b1a788567231bf6399ff89236981149d423802d2341a3bedb9ddcbac1fe7b6435e1479c72e7089d029e7fbbaf3cf37e9b9a6b776791e4c5e6fda57e8d5f14c8c35a2d270846b9dbe005cda16af4408f3ab06a916eeeb9c9594b70424a4c1d171295b6763b22f47f80b53ccbb904bd68fd65fbd3fbdea1035e98c21a7dbc91a9b5bc7690f05ec317c97f8764eb48e911d428ec8d861b708e8298acb62155145155ae95f0a1d1501030052d92ecde9cd040082e1034ea67bc8ae97404b0c50b2a04f559e49950afcb0ef462a2ae024b0f0226dfd73684b88c7fbe92d02b68f759c4752663cd7b97a14943649305521326bde085630864629291bae25ff8822a14c4b666a9259ad0dc42a8290ac7bc7f53a16f379f758e5de750f04fd7cad47701c8597f97888bea6fa0bf2999956fbfd0ee68ec36e4688809ae231eb8bc4369f3901538a5d79cb93f48757a5b569027f0de993c6445427d8b6e0c9ad8ce6520969b926d62e9596fa825c6bf21aff9e68625a192440ea06828123d97884806f15657bcd1d9b57545b51146fb8658f2c7d5cc0e092d412b6442eff8b6d03a405b15f0f71cd453bb3d18cf7079f10000ebc8a1e886f4050afd8fe94e97d2e9e850674a261f6e7c22da542de35a59aa367676a3fb238a5c70aecddc3c0140882e1b6259408b1fd7bf017e79ec3656d7eed23d8e48bf84cbc000a807899973eb93c1e40bdc093f8cca0607d4d4580b85cda8f5047d6e8552aeca691e78db112e63c205266b61f87c23507551eb092d1744524d304fe6b8fd3b4010348611abdcbd41fbe7da2728cfe5bf7ec9a94a57942910d56b9654145a5c2e76eb7242cc6f97db73b315e665a6cb4c19b070fe11f8db6897b2b30b1cd4018388e1a910f0fc41f30", "bd4a365a38d72376e814e0b9321025d99a287a47e45d082c4cc03b417f50e967", 5, 648488714, 1938782813, 1536466477, 324003852, 1, 2, 0, 0, 0, null, null, 4, 0, 1352303960316242, "22f0b024e02a2a46efb0fc0a95499e554fa0b2500c4b4097aec87ba64e03e182", "fd73684b88c7fbe92d02b68f759c4752663cd7b97a14943649305521326bde085630864629291bae25ff8822a14c4b666a9259ad0dc42a8290ac7bc7f53a16f379f758e5de750f04fd7cad47701c8597f97888bea6fa0bf2999956fbfd0ee68ec36e4688809ae231eb8bc4369f", "be7da2728cfe5bf7ec9a94a57942910d56b9654145a5c2e76eb7242cc6f97db73b315e665a6cb4c19b070fe11f8db6897b2b30b1cd4018388e1a910f0fc41f30"], + ["050000800a27a726877a592566819d375ba5c30f000002f8453d9ff66f3b016d2f89fd9bfe11772ea294afedb9c401a3b64039caf3d81c9699a69fdf1c5ac7732146ee5e1d6b6ca9b9180f964cc9d0878ae1373524d7d510e58227df6de9d30d271867640177b0f1856e28d5c8afb095ef6184fed65158905f96ee25c806a48276f1a9d89a5e475ca3023d288608b2feaef46b4a0233f07b9468287f0eb0c10c4b132520194d3d8d5351fc10d09c15c8cc101aa1663bbfe877f63f40a5ca0d67f6e554124739f805af876aeede53aa8b0f8e5604a73c300043d0779a0d8afeff4fe843b76ef6f223f0f7c894f38f7ab780dfd75f669c8c06cffa43eb47565a509022eeaea4c0ce1fa6f085092b04979489172b3ef8194a798df5724d6b05f1ae000013a08d612bca8a8c31443c10346dbf61de8475c0bbec5104b47556af3d514458e2321d146071789d2335934a680614e83562f82dfd405b54a45eb32c165448d4d5d61ca2859585369f53f1a137e9e82b67b8fdaf01bda54a317311896ae10280a032440c420a421e944d1e952b70d5826cd3b08b7db9630fe4fd5f22125de840fcc40b98038af11d55be25432597b4b65b9ec1c7a8bbfd052cbf7e1c1785cbd09dad963d6f8a5dcc40def40797342113ba206fae8ebe4f3bc3caf69259e462eff9ba8b3f4bfaa1300c26925a8729cd32915bfc966086f0d5560bbe32a598c22adfb48cef72ba5d4287c0cefbacfd8ce195b4963c34a94bba7a175dae4bbe3ef4863d53708915090f47a068e227433f9e49d3aa09e356d8d66d0c0121e91a3c4aa3f27fa1b63396e2b41db908fdab8b18cc7304e94e970568f9421c0dbbbaf84598d972b0534f48a5e52670436aaa776ed2482ad703430201e53443c36dcfdb4e4dd1a51fce98c020f5d3f61b731bafaef0c9bc08316f762de247f5f7cec6f049858cbad3fa6378263db954c5ab47b0c3902618dcd61ec7fbd3ba61c9fb045276f9381617db3519cdbb1bf40c42cd7ea0ba537a5e06aa94bf4ee1e8ae786f27140181dfc0c56ffacdf6ecfad22e10b2d2cd1b692fc2f5d9c0824ad0375603180f2a988522d35ec9bf5f42f3b632c21460b245e319b6ea714085fd6e9e3d693276e9643dc6fd335fe85e00769b7ba7de670873b07569392968f1a115e7040c00", "44fc7cb148821cc205f50561cb5c97b7050dcae6b984de6ce6d93cb008548e08", 5, 648488714, 626621063, 933069158, 264480091, 0, 0, 2, 0, -411158922670013, "505a5647eb43facf068c9c665fd7df80b77a8ff394c8f7f023f2f66eb743e84f", "180f2a988522d35ec9bf5f42f3b632c21460b245e319b6ea714085fd6e9e3d693276e9643dc6fd335fe85e00769b7ba7de670873b07569392968f1a115e7040c", 0, null, 0, null, null, null], + ["050000800a27a726e7917666cf5bc20e48bef119029b9b8a0e39c3df28cb9582ea338601cdc481b32fb82adeebb3dade25d1a3df20c37e712506635165ac526a0f30ddcb91fe9004e1e83294a6c9203d94e8dc2cbb449de4155032604e47997016b304fd437d82350465635251b743a0a900000000", "34cb0d127ec0a4c67c3594d098b170708cad95e63e885de001c0e145ce033841", 5, 648488714, 1719046631, 247618511, 435273288, 2, 0, 0, 0, 0, null, null, 0, null, 0, null, null, null], + ["050000800a27a726f2e336b4ae307bb398b83514000002a95ec688aed0c93cfb8c6da9e14556f1de9b55677da307d859d6845c3be0e953fb00b9f62416c8b9c0f7228f510729e0be3f305313d77f7379dc2af24869c6c74ee4471498861d192f0ff0f508285dab6b6a36ccf7d12256cc76b95503720ac62e9a3415299a464121e09e4db8d4798576a033aa9467784ba15782b8093289967c680467694bc9709d32916c97e8006cbb07ba0e4180a3738038c374c4cce8f37fd8767bea1a24ae7bed65b4afdc8f1278c30e2db98fd172730ac6bbed4f112702fc82cc401c6a6233649f875a16306db092b22aabda93a3857a38922aa06b970b7da3a516c173be1c513323e119f635e8209a074b216b7023fadc2d25949c9003020dc5fc0884616b4393ea2dcc6e3c920aa4f46591e0a9131cc7bd95372979a79e4a5fa87f0a956f5b85509960285c22627c59483a5a4c28cce4b156e551406a7ee8355656a21e43e38ce129fdadb759eddfa08f00fc8e567cef93c6792d01df05e6d580f4d5d48df042451a33590d3e8cf49b2627218f0c292fa66ada945fa55bb23548e33a83a562957a3149a993cc472362298736a8b778d97ce423013d64b32cd172efa551bf7f368f04bdaec6091a3004a757598b801dcf675cb83e43a53ae8b254d333bcda20d4817d3477abfba25bb83df5949c126f149b1d99341e4e6f9120f4d41e629185002c72c012c414d2382a6d47c7b3deaba770c400ca96b2814f6b26c3ef17429f1a98c85d83db20efad48be8996fb1bff591efff360fe1199056c56e5feec61a7b8b9f699d6012c2849232f329fef95c7af370098ffe4918e0ca1df47f275867b739e0a514d3209325e217045927b479c1ce2e5d54f25488cad1513e3f44a21266cfd841633327dee6cf810fbf7393e317d9e53d1be1d5ae7839b66b943b9ed18f2c530e975422332c3439cce49a29f2a336a4851263c5e9bd13d731109e844b7f8c392a5c1dcaa2ae5f50ff63fab9765e016702c35a67cd7364d3fab552fb349e35c15c50250453fd18f7b855992632e2c76c0fbf1ef963ea80e3223de3277bc559251725829ec03f213ba8955cab2822ff21a9b0a4904d668fcd77224bde3dd01f6ffc4828f6b64230b35c6a049873494276ea1d7ed5e92cb4f90ba83a9e49601b194042f2900d99d312d7b70508cf176066d154dbe96ef9d4367e4c840e4a17b5e5122e8ebe2158a3c5f4cbae21ea3fa1ae6c25a9462ebcbb0fd5f14554bc97747c33e34da90c816d8d0d50bfe37618c5812891484fa259322c15092d4155d8696d6f12f24fd364496b3be0871ca3dd9625348a614b59bde45885649bae36de34def8fcec85343475d9734f2ed22512ac2d9a3514cadb37b17630cbd2d7dac18ba42158ec5d14429a585fe718dd9dd8c75e7e656f1e43fbfb51db2eced64e1c6047042ce710514553e1cbf7cd887d0c945a62dbc428da838ebed4ad70ea13232ba1e0f0c3db0a64c155bfd29f4cc477e66f130d630430dcc0104899b4f9f46eb090ef7fc90b479abf61f93955ee00e6a1848f1ab14ad334f2b68035808cdf1bb9e9d9a816baf728a955b960b7701fa626687dc3c9cba646337b53e29816e9482ddf5578a8768aae477fce410ac2d5de6095861c111d7feb3e6bb4fbb5a54955495972798350a253f05f66c2ecfcbc0ed43f5ec2e6d8dba15a51254d97b1821107c07dd9a16ef8406f943e282b95d4b362530c913d6ba421df6027de5af1e4745d5868106954be6c1962780a2941072e95131b1679df0637625042c37d48ffb152e5ebc185c8a2b7d4385f1c95af937df78dfd8757fab434968b0b57c66574468f160b447ac8221e5060676a842a1c6b7172dd3340f764070ab1fe091c5c74c95a5dc043390723a4c127da14cdde1dc2675a62340b3e6afd0522a31de26e7d1ec3a9c8a091ffdc75b7ecfdc7c12995a5e37ce3488bd29f8629d68f696492448dd526697476dc061346ebe3f677217ff9c60efce943af28dfd3f9e59692598a6047c23c4c01400f1ab5730eac0ae8d5843d5051c376240172af218d7a1ecfe65b4f75100638983c14de4974755dade8018c9b8f4543fb095961513e67c61dbc59c607f9b51f8d09bdcad28bcfb9e5d2744ea8848b2623ac07f8ef61a81a35910b8a1baf39a919a7b60bc604d63185f759221d847cc54a22765a4c33475b5791e9af3271fc8d9350667090d8184ec50522d804f23c4fb44ffa481bc92ae408d1b9f2b131904f9705c59e2f4bde7a3b2c085d93fd2abc5e14d163001a12f51938d021afa92239b873dc6c357eaa8af4ee6d00540657fe32914103b5d98f68bd3e2b5359f08ccd88d0c811e4c31fbb49f3a90bbd05dce62f344e7077593159ae35050b04c9e6b86bc432dc8b048c73c0018ca5b69411297732a4e1aa99a928c71155cdc9258d8faffe777fbb34c0ab8cc3d67466c0a88dd4ccad18a07a8d1068df5b629e5718d0f6d72d08268d2cf7773b6ba2a5f664847bf707f2fc10c98f2f006ec22ccb5a8c8b7c40c7c2d49a6639b9f2ce33c25c04bc461e744dfa536b00d94baddf4f4d14044c695a33881477df124f0fcf206a9fb2e65e304cdbf0c4d2390170c130ab849c2f22b5cdd3921640c8cf1976ae1010b0dfd9cb2543e45f99749cc4d61f2e8aabfe98bd905fa39951b33ea769c45ab9531c57209862ad12fd76ba4807e65417b6cd12fa8ec916f013ebb8706a96effeda06c4be24b04846392e9d1e6930eae01facd32b04a95b205526cfcb4c4e1cc955175b3e8de1f5d81b18669692350aaa1a1d797617582e54d7a5b57a683b32fb1098062dad7b0c2eb518f6862e83db25e3dbaf7aed504de932acb99d735992ce62bae9ef893ff6acc0ffcf8e3483e146b9d49dd8c7835f43a37dca0787e3ec9f6605223d5ba7ae0ab9025b73bc03f7fac36c009a56d4d95d1e81d3b3ebca7e54cc1a12d127b57c8138976e791013b015f06a624f521b6ee04ec980893c7e5e01a336203594094f82833d7445fe2d09130f61b8900e26b311a5f6154637a757441c460c8aa737bf345b67d9771a654e58b9a015296aecb4b30b435792d13ee040d450ed12eef980e93d99dde911f66c7e300fe7e3d3d350811b20f97cf1ced37de916df3671c02c69ee9c82b1f17c426e1ee87edba5cfb2695c54aa61d358d7fda20dde0ade55b662e663396ed6ed0fb28076ae1e9b27829ce2ac5efd0b399a8b448be6504294ee6b3c1c6a5342d7c01ae9d8ad3070c2b1a91573af5e0c5e4cbbf4acdc6b54c9272200d9970250c17c1036f06085c41858ed3a0c48150bc697e4a695fef335f7ad07e1a46dc767ff822db70e6669080b9816b2232c81a4c66cc586abfe1eaa8ca6cf41fc3c3e6c7b886fb6dac9f4822b4fc6fff9d0513d61a21c80a377671d135a668a0ae2bb934c82c4142da69d12ca7de9a7df706400ec79878d868e17e8f71ea31495af819a016cc419ee7a24fd277856aa42501e51b012aea9446a2104e93f815a0b3a29b458314f3d8be2b9823d342f46213e942a7e19a46e970b5c506708430317b1bb3b35df68ae33a4926a03e6bfeb5510416fcbb0524c9ca5074156cc5a5d6fe1c995edc60a2f550411aa41e3da3bdcf64bcf04a0510571b936d47e55cec0330ee8dfe73563404f047d7f3a8a3d7743bc554955210f1eb0d08599ea77d5f974d87176d37d98b9c0ad440407209ed6a9f08464d565593e1a63b938536b49244e97d880173b640f2a9d6b0e86578ce7e2ab01fbc42de44642410e4cd9429226fbe0f4608a4142290dc665ef0d6a1c9f02e96add140eca4c49f98c9629b4ee4832fa084c5b2548d0c0490340b8c1cdf0ab25a11469e8d61cb420ef13e8e75b808156b47566be3b9b3a15fc041526e0ac74a87f2456985c32e64768428b4c2b25e3745f009c5dce20b2920f2dbddee21b7836b6dfe41dbe145befddce5dc12ee383c8061e5b977f03d24c397fabaad64a383a86bec05c80e25d88b0e1c68a525d706d6604b2330b6b308138adc13c6c1dde1b21a2ebf4d4dc51e6576b0255d347fe1f229a539e06afdb28e66216286bafe47ff4dbcced51444480a9a5673ece7fac73a0ed41ab0051753a7caa89be3139afd9793b3e02f27f040046595acd47bf13fd0da27f09eda48036d3ee437f2ee8f8606ea97343c33584657f46dba99db5cfe6ca176fab7b0f3bfa0ab61e340c34eb9f17c7ec2be03b180f0bb6f434c2a6542e00e84373f4f4649cda32bf686666143f622aa480460b5afac518607cd9af8bcd6b58c30127316b25d5ea7bf6b0cab8542ff69d9b2f180be12ed75344a395aa10f852f083ad64ef40e9c0309e9bba54b8cb33c95498a69538d3ae5b25e247098306fa8c74a8ee5bca941531d61aac27aab3dc5617d5606c9577a2a8346e8d85b32b8505775108dc85e2ade2eac1e636e1af4054c8b6f57632df269c3723b320872e4c57b218358dc7e9905bb04edf92edf0df635f3bf361e57a13296e1447af5087872d636e27518a9876e15eb01f5e8ded81892511cc2851b00b832712a6d3ba5666517bcd3567621a7cf8445589653262020c33bf78031b8ee0707de072068c170570327e6d9f5c6ddc335402efc548862f5a07094fd428a7bbc15d7b38d05362c9ca985f58a76647d2be4c2cd6b3d17d6870971d7a098baf72c6f6f1214cf1faae488bd7de259d3415c2f0ddec7457004f35708d1eccccc0df65a04943ad5cbc13f295f000fe056c40b2d88f27dc34cfeb803be3483a9ebf9b5a9026057725d63ead2c0c0ff1fe26ac1e7bdfcd6fad875842d194f331750462c06b8d7982d67995ed5d3ae96a05ae0067f4eb1c7c93231bd39773cbe0a9d66b0c9aa8cff6a376e1f372eac6ac4e46cc0942245d4c2dcf02d7640ffcc5a6ac3a87f5c411551bcc2f26cb94961d53f95ddb19ae930c8d70f031b29a5df99ff36695e802cbcb6b58c1ba7ed5eacfa76414a41ad4a44f71f1b580d34c3a952920b254ab72e6a0d3cacb01d9419a86a1e9b3aacb8e7c68016066bd3ff51abb44cb8f0aad7fb8300139f372183a9ff5ca820b46c0f5ac9a8408e925b626bb21a471fe33e1e0a14d48e4436c734eb0137304243be251cf0cf571b6c8d8441f2ab7cab11bdde3eb54b24de62c4566085520d62a57cf53689c2b1a18eaf2d471d13c1ab39197a0f1e753a73290c7f9f096693a7bd3cce1246c20ef32d10ef9dad195227d7be8aa033b65e51c1a08b8a11d84d0409b734f452aaf0d6b18f50258683d3f9a76d399fd047eee288bb4585851dc93eccc62322924cd13b5dd4eed66ed8d9972d772629ea64742e54733981b006c062468e4bd8f7dd9af698f52ae814634e81d7f3e0c420317caca9ae4811c6af06fe80a8c02ab7a00e18e4a6aa1ea1b76945d2615d43ac118b56c2f2960fe93a025f13ec91ffc6d2c353699abb092dedc065db8fa214dbc46466f897b88c58b30152133aa3831af37c74d99e9e36ff7011d3238305691508a2c3a43e755dc081b511d6482a7db65fa9699ea87ff47099ed3637dbb0a3d0ef79796a8ef1e4d94d42b4bc2b4a038ae6e46b24cfc84153d31eaf895063a5ca959be63f37f2ba0d432366736d8632fce072b6ae5b6f3fd59d3faff638275a992fefc87e60d44c2cadc2b5c494e3e72eb4597c96b40167799a9001a2ed3676a8b403ae25ffd772f7081e9a32bcc1c5e2edd4e2a6576b783cce3aae11fa432262548856183ee682d5dc31beb38f061cbdeca7021a444e2dd417df26dcd220f2b731772b439e96d614e1facb486c7a7d5171b1de359f6ad3a96f649c969102a1964fb4b4a1a4279c68e6c372e42187d754e804a61653092069fb9b6d25266890808b015df28c801065da6febdc1a56bfd002625acfaa5373fde149c1cfc3649b4869696d44ecb12479c5ebef995f10029f8b530eeb3fdc2e50e8757fc0bb9e263023db82f878d9ac7ffb0bd4391df1d879899a3ef57bfd0d1f7755648edd85bb052a6edf71cd2628c987429f36dc505ccc43f30e7a869c9e255e2af9fcf30c121796d190000960cb6fe2f1bf246118b498f3247f9d484c73cf09393039e45326b8ffffb3e7e6159c46699f100792d4672950348a90552e45943beeacf03f3216f94e274d63d637d9f190e8a266cdeef153531bba208468306600446dfa578295a310f2d7bc5102040ebfba047be0f04c1e20e604a2807e46186fa5dd477bedeeed4b05e585fbebb48faf58f1b65dca2497204126daa907983d5065339131b57e693a8e1bbdcced799ee128f12543b6f5f407c84a108964e2de74b6ea55b4cb8f6f9bee98b10d415109455f48b776082dc30b1f9a0371e103ce82a937ccc717d3af2b3c47e0e0bba4e8618be2fc3ae82bff12f48b3f7bfefa31bcdc665c6d7123e95350811375947b055a43db07e03f33627df5c638bfad956ddc1ea7d7620a20f2792f63817a1cf32580d04274234af2a51b56bb68a29e43a954142ba4ca6823bde9053d72fdadbc61ad5936c53fdd7579446d11c44607f41630e4c08915e631771550e9ce1fca2c63fe06b7989d584fa7d782a88c1e7d64b6fbf55e3596af9bcb7585f8c7d3aa5c2082b265249df05701dab031c4bac1ea267a2996a2028d1e6a0f80a3847c531dba96ee65a24189bd2712e40e959664981e58b2a4f951ef8f497dfff2f2f271eab89c628e18b5fcb43882537eaf6ad2a6b1754633caa86bf2c76f3993154fc73e6fbba2210c2743f530a427849a301e00e01129f03a4607f87cbe0762c0b1c65855deba8422ca4b88abeea6a4382cf16ccd6dc7c37c44e549c4534819acd8bb0a02a5fa7a1c1d3806fbc3407fd7da93fd0de6400d3ab8977485cddfbed5932f507b79947adb2fad37615aa717db5f298099f20f263b359a1151a6b75c01365eb154ae42140d6e10342f14f34dc33e07ff0e4d1a6be375b32f84b92e5d81ebb639c4f27e715aa42cc75707d4ebd1bbfbe8f90fc7c953e7a9715e65af8267373d3451674ff084efd92ccf3bcc7aca1467b6327e4f9522b2cc579a7a8fff7ca7cf145dfc13eafc34153b2c3e8afbe53444d0c73b3bd5bc870b01cd457911e356313fd1dafb4c8151634a01aff7cf116d433c3d2b3adda9cebe18f7d172443e5e7b5ac9abe8db2256d7ebe2ff28020939503870597b9a955892c7389650a2d42ec92be723fedf2f2ede5a472aa1e74f33ad41901544edbbe3ac464cf439196015f4f22ac2b8fc01496beab4d45907f479812a259431a2cbc93d4f3b84e4dd366020273a6752e501af6ff1b78ddc817e6ea351d6006becf8d2ffb03990f67774a8137618c21494b0d45ed1920f0e6c4a9d77c1712ac61bd88a8f66e4888ead75163eaf1877138f55432c7ef3f14393909959fb358554e94c7e678ce01aebf94e11bfca88478a3142decaaeb9be86b37be1cb9802cd46d3a90bd7e0a686ac747f2c06b41f92f645ea7423b7b8f885c8827a2dbd0eedee871c1c0f48b8e9b8e4be3789bba5b4ad738e629325ec1bc676d37c716d4a735254381a1e790a38814b250ecac9aaa10c2e7de415edb0806c6da03020a134ca7ecdc8da1bd57a37f55a46940b45b241b1c16ee100927d1bd860d445a9de50d4c384d6e1d00108026c0ea5ebbf0b72fbf5c370bce18d3acbc46599099baae1d802f77333494a7ae130fe86e8f818f9261a2dadb4125229ba0ffc0e7090324430b521a90d224ab7a1024e1d893e7404fedb348e4d5e2235c59a7876a0fc60145c6a009687684460271ee133a437fe52fb6cfba97fcec161df515dde905a24da6d37bdc34044a955e682b47471ca1e8c78c51ed377cd4afa894bd9bd12e707156da0726f7cf5729fabe372160463fe0429244d067489ba5d09472ecd9bcdc4d5e4df101e189db8463eb538307b587deff78de9c73af28080b2fd05003e11d3e1b3299dc9521f8b513badb010e91bfeb91b0b2a6cb129c2e825a597b8fb75bc562d654d62104640dd74e56cd14baaba565b84b845e163d1caef2533c3981637204f96a59c8e8024d9041b2029e94c15245f1a958840ba3f380a4d20f1184e77827de3ff8f3d73459afe241f723c084823230e003d3d21e53501ec0499b083a7dad685c57127f4de64733a880c2db28fdaabf1b542d205f664a35135712711dcccd931a50b9c5661882360d4cac0047681bc2e2b3bf6c99760d7cfb4fa21394377a4551c76d1f75ac03c262054dffd79a9ded05e888958199eea4501e2990a53a5cd2a46a401576588fd7d058a26f28438e5782f45ac1d07f6f6f5ed73741d5785837a6b844b474775718c29dd99084e9f88ef153a8329f532a69017dc3a97ed754367723098e5765840b022897244745fbbbb30a7cb54fa0511166e9544122000610bd2aacbd82325a59b95154ecd82c88d23abd1e20770ffb8aabf83fc0734964ccd411d1c935714e24aab566f4f08424014c4eca91b590f082b473f361c87415d00fe08b49d923d000040cbd3f16f113fd5b757ffd15f41de81ae838860adc88aacc7bd6a00ae0c193f6533a485efde082b5f4d1f7a8ebe7ed82b7b05a8cfe1e373459f1bdcbf9525747e8c9508a555facb798740e0bdf994d9739bbe5538a0ae0f076c582c0f5ba878b99b8249db1d7e95056c98af083d98cb0ed9e3f7436e1c7643766f966b83e999206ebd1393b99f2fd8636242fdc102ffea86c76770dc1117571fd3d0743cfb7ede7404909d1fc519a4605f5826312b2eb37ab367e635e06faf7f3ceae7d3419b1fca265a5519775c53afdbd7501d2840d0b0eb97ee708d33a0315ee9d5c203536891e659a3207960c4879236dc9ae865e23a00a331588218b3add9c06893bd02db9b61191d3b6527a0513cf5337aad2b2b6528224fe8fd3b0a71889a87885e9ca7ce0d8a8738c0657eba5d7a2767bf8031135121b766aa51c143b0cb25b9142c61bd790a80177ff15884ed58dbe0f73dc9bb7a1a470cfaf0f2648bed701d8f7705588763a698a5555ac55b71f1d0251e59d2cb32c002041a089c283f19649968c2498cde5635f350a22b08f552e2ec715b9a6eed6b9aaf047a8ab7193ff5bfd24a89a215be8c9635c29827aad86726c9ade3b265b9086c8b5b75ef56fe4bd8b4d62893895b3f", "4b70db7a920aaac381297968f18912f652819dd70506fa943be6f57c200c4cff", 5, 648488714, 3023496178, 3011195054, 339064984, 0, 0, 2, 2, -1450974927627243, "6d0f8d71e529b6f58d06d1a8078ad1ca4cdd880a6c46673dccb80a4cb3fb77e7", "a9d6b0e86578ce7e2ab01fbc42de44642410e4cd9429226fbe0f4608a4142290dc665ef0d6a1c9f02e96add140eca4c49f98c9629b4ee4832fa084c5b2548d0c", 4, 0, 67699920341246, "3f190cae006abdc7ac8ac8ad608883ae81de415fd1ff57b7d53f116ff1d3cb40", "33a485efde082b5f4d1f7a8ebe7ed82b7b05a8cfe1e373459f1bdcbf9525747e8c9508a555facb798740e0bdf994d9739bbe5538a0ae0f076c582c0f5ba878b99b8249db1d7e95056c98af083d98cb0ed9e3f7436e1c7643766f966b83e999206ebd1393b9", "f350a22b08f552e2ec715b9a6eed6b9aaf047a8ab7193ff5bfd24a89a215be8c9635c29827aad86726c9ade3b265b9086c8b5b75ef56fe4bd8b4d62893895b3f"], + ["050000800a27a726d2734fda64156d7e5e5eae1c00000149a3e853e92a33cd1f43b55e4f72f3a3ca562e814f47bd93789101ca251752535e1aa2a452f3731c8cb65082a622a7c2e0013ea47d0bdd42d6990466649a905c32d58e6777765f22a4116344eeb65b2ec516393ab3751b5356d2b0c9500c0f3e0047de4944cd0501001c83b86f669637e3b2e6c2649397ce88efe2ad362d07c3273017bb5a24daa316469181035bc3660f0b8f9fbe6e40b5e89cb79b063714ca75e72e2e100a10d63bf784df0820ef25f8ef40fe5f05fb95683f9105ff3cb2d219ab76605a064f69219f1dc0d00b3b48642f970dc00cca4b8b43308be18286ec5a4288d600a3785cb622d468a4c6969b3792f2485027d0ad9aa4a9c2cc972f9ee5190a95b1eb058dddd8c08e7d753f5e011b2bcfee1d52c1c4f2cacda30bdb6930653c0cc4486e60e89fa849b32083ba9db453fb8df683cd68754c87daa731f570a7a4060af0ce700d6f7dc13ef1b6302a04bce22e12300fb14c9898938383040afc997925cd573090b7c6aa583669fd49169795447e355fa6965ab623939f0a883d75ef75274be8003e09bb11e98342d60aac922035358f6a1ad6481e52934375457e7fbf8a3b0a93969c224cb87d337886c0e29725918aa27f80b46e782a7fe7e4dc7ad975197e0200", "6191d6fee8bbf112b42cd7d163a3aecdfaeee307e520b8880e8a796235ff4f21", 5, 648488714, 3662640082, 2121078116, 481189470, 0, 0, 1, 0, 287854148836935, "16a3da245abb173027c3072d36ade2ef88ce979364c2e6b2e33796666fb8831c", "3e09bb11e98342d60aac922035358f6a1ad6481e52934375457e7fbf8a3b0a93969c224cb87d337886c0e29725918aa27f80b46e782a7fe7e4dc7ad975197e02", 0, null, 0, null, null, null], + ["050000800a27a726f683933071e348fc523dc91100000000013e3d2dd6f369981df1fb9924862f07fe3a17e3041b9f16aaae76e21ed358d884b8b195a433d454d18257e04f9d85f4e4f790789942f55c200b773ecdd7992c3f1c3b15e64835324463b7923d61886aa3696f0ae0d619304c861af905263b763b4bc5d601d42eef2100d128c2920b092283ac05160b7a84eaa7aab74009e57a0544114fbb7dabf8952314682af2e87cafc6b6fc6ec7cd426aaba543c4e25782118a4af6fa8381f0658819eab483f65b325d5aeda15232cfadec75ab1866e4c0155a9c74a7a57ccf34c483ac7da1588a1b6b9941f11040f94cf78fad89bf11fed69aa0d83105adacdd4e5f04a62424023c9b9e33c4fb7f12bdf21f07f265c537d51c6551f4617b915d21991839c3d0d36393d646e0a8a41509217d0e7d2ca1a0a0d677a3eaca23edeb07b74e652a0bc50c6c083a55d6c7306e74086f4768933aa24873681867a7893d77cb7f29b8c847c583f2d071a686616e206719f761ae39c110442e06163d2b84590360695d4e19849e634f24d9ad396c19ff83ce74f46e645f932e141a41195936c85d514414f112e60b1a2537c38d6dc6c4638305c9bd6c62e366bc63123e3e6dd36eedd3136fce8deeca2aa09a3298a39d83859efc9b2b69cf9a7dee08a98e4be558ac7912fdcb42209075420260f7cad0f2c01f2afe33073f26249d944f7a50dd84839bc3ea7fdee4ed71449cf07533d26e1e27a3efb032c3a3b34bd3092622d2062ae536ef5149c49b5bc9475eafab6e675761008b0daddeecaa604470bbe0fada255d290e92b190c2c2d8c2dee5455d1fa9a9f3db7779b584643464aa8014ba66994de25517f83980e66ee4f62314ae6dbef452d5d38b0a16f3991f36d8a8b39ddc0d5595eed98762878cdf3f4a2edc5cda77d5fe4faf63a15f568a540da57dd9beb6fb1a977ccb91b4d79cb39b28911a29e7bf028ac6103796dfb6b20967239ad373c38c53f6df1823d4950a0283e99b9c06ab2966667c9df677716b0caded818df9e449c072e22f9d98bb0f9b03bd5fd013fcef3ed6a49aeb98720254087ef728e31947ffe8f766e63ee46ff20816d5fa8ff55a26398961490ab9ae366fc5a2d1996ed693ccca82356f600ab099f6eca8bfe645270d3f95edba5b0de7a32819233bcc754a5ce2e5ea036400e1696ed1fcff8f2157fcbdb14f7aeec1285cb80de42146619af02456ae695962fe5e931a6335e79052ecd333e18412db91e15f7cbc70b4cd7e8e3c951f358572e37767e7d52704a6721b30efc41017ae4d231558c5c82cc7dd7e3356c09dc24906f0438dfcc300856ac2ced8f77fa8015736c661e80248aeeb774874aa79d290b8f5027a0a509537fc7c689b7ad86116cfec2647ccaae1c74b416f3e6ae8f7cc60eaaf7b6a590d51544138e1732945603a53462c60e1f6cb0c9ca0390c488224c313269fcd59fcb611fb2d9b4c8fa601bb1cb8d07d797bf5de52bceeb02301c8962ac1fc0491dc81affd6c1ebf89a13d6f290eda5d5cef382215c5e951d71305ef33d9737126d0e662905f12509212d6383e7758f9e8ac8bfd14faac138014ee7251ec1bc60ee960f04d180918a032094f6e108558fc1e78f78f388b6ee2d65fe7b4b365d094459250aaa55444098052ef0d6cfc70d7bc82538cac8cd898de00a7f8590fbf480b316116866ace8583438d8a67b2f8d1f0f931c941ceefcfa0f18e26f4fa45d1be8f3dc4a707133e", "133e20c18e7f8e5c48b54d56da9d6a403e3e03f3ea592dd9b109888358f9b5c4", 5, 648488714, 814973942, 4232635249, 298401106, 0, 0, 0, 0, 0, null, null, 1, 3, -895627753881500, "35631a935efe625969ae5624f09a614621e40db85c28c1ee7a4fb1bdfc57218f", "9052ecd333e18412db91e15f7cbc70b4cd7e8e3c951f358572e37767e7d52704a6721b30efc41017ae4d231558c5c82cc7dd7e3356c09dc24906f0438dfcc300856ac2ced8f77fa8015736c661e80248aeeb774874aa79d290b8f5027a0a509537fc7c689b7ad86116cfec2647ccaae1c74b416f3e6ae8f7cc60eaaf7b6a590d51544138e1732945603a53462c60e1f6cb0c9ca0390c488224c313269fcd59fcb611fb2d9b4c8fa601bb1cb8d07d797bf5de52bceeb02301c8962ac1fc0491dc81affd6c1ebf89a13d6f290eda5d5cef382215c5e951d71305ef33d9737126d0e662905f125092", "8052ef0d6cfc70d7bc82538cac8cd898de00a7f8590fbf480b316116866ace8583438d8a67b2f8d1f0f931c941ceefcfa0f18e26f4fa45d1be8f3dc4a707133e"], + ["050000800a27a72695d2ad596c03d2492343dc1302d6425efb9c1d504e6fd5575340945601fe806f5756acb562f13c0ca1d803a195c2ebb2ef02ac53e6a88dea075ba996d3c336648e8694d3a19d3dca531beb50d4327c5c0c23cb7cfdb08ca7cf2cac6b075100acac535365029cb4ab03798fb67e661002000800636aac51516a5174c8d381ec71030005ac6a526551acc23e3ad324070009655251006365656a6500020f3ee263f592f02decbf089d3167cd94c4fe7e642d5efcb1ddd2bb241571579fa9293d3f632b309d65243ee1e393cd16a7770949746b9312a58d9ef0f7f7c319f356133afe06426839ede7b87d6fe36e4d52dfd192f97395e09cfe4870f1cd100e4fba92c7b606a5cb122f140cf1a3596f2788f3c8b92660f14cb65af5dd23dfdbac1371ecf4b33712fed2292c44f70834cf96c05d58827e69bfc2e696fa0874869c02f3dca11c3b90cb214e68bc1cae039d7a146cdc1d609d7a6b3fd5d461b0951c82cfb3e763fad2d1bc7678cdf82779f8fd5a1ce22a8d3c4547abd959838a46fb80afe01f8ecc9931513b1962ec540856cb189387cfbfcc0f7c68223cba47fb0c9b486e4d99171941f7675a8b46328a3bc109bf07c66d5ede771cc4c74ce80333829191eedc493508a644530a6144f22dcf97525a4cdca1ad71073b080b73ea4549f5401bff4318268e6ad637363157a19a53f123a0b0e16d0b77f02028da464100fde76d83dd0bb224f7b57a00c02f68ae648fdc529957a10490dce1fddbb0904f0d518bb387544019983b616975a78e74d854fddc49b255167b55ef4bee465668b20ea4118ca569ae480e0f6e5e043a357b36d3ab36c861f2278301dce57674d5073b3a6f5103a0793af1b7d46f957e22d8d2583bf181836c3be9930bac8fa460e968aa7109870bbed17df5f888c8ca1467ae17dbbcde31c1105cb5bda88ac6c627002ce21c02140ffe81ec58bf1e6d1bb7aaada41fba0bb588778a7f65202ad811ea73d26c74550395aff75325107c9b3f9ae9dcdcd86ed081a2e7424719a3d185b7e0a43a472e298ac0afdc5287d7ad124cd9405a62cd1ca08b282efef7f928df76e2821a418413eb7ceaa5ff1290b03ec91ce6dd28130c3ab0b23b602bd5be5dc26003aae04b33d7bd2590e90c8c388ea7955122dbaca67b30395a928b57b8575123205ae19152e41e002931b45746198e5dd9571a56a7e0d423ff27989d3eb417ecd3c3093fb82c5658e29624c53219a60cd0a8c4da367e29a71779a73032985a3d1fd03dd4d06e05566f3b84367cf02fdb52e6b514ba80685af3d4499a6f7b4d5940d4fb60c0f2d86057324838294194ca80bb0a1d13cd4cd69ab98304ae2515d5f7699d4abee5c20be609d873511041d5b83ea4f9ba03add3364ef3d92cb1a6dc99169418fbceae95cdc39c9ce1c077f261ecdc26bc089d34c6404846e9c647fcfe98cc6acdbb464f64278ad8ce9d1ae0d415bc0c05245fddaf4ebc8dc703a85cb270f796ad2d937e2ac0d5e0a34821758000aa59c9d4652485294ee0ab29696b21430fa54dcfbf2b9c49d142064209eeeed4d471ffc017d4e20a796b0927804c061b9f4a7091fe015ada68fd8442e01825c88dfe55cf5de38936f7ce25311b902ba97a3c12a95cfa1c3a591b818f60832709d9e4839e410fb36b84f3ac4f070fc35e161978259e5b8edc744d90919aa770bb36215128e582b59641e23852e958eb8fc3c0aa96152ba4f77f138d6a6712a3ae3226015883f81db23e583c869c4c71143a6fffd65e8dfdc50c99a2f1f314cdcc71359e235f1d7dc2b5f38ef7b970843163c03f9dd40a8015efdc8791956a3f3cedd9ea64f8efa7a0815a70381d71467817bd04ca529aede07ff60d176aed0f855a2eaea89eaeaca89358c081826a0812a5bca28be1373f086dbdba7e43e203212c9fed21474ba19a055ffcc179412e893a744832298c5fe24cc6b18667f49b34dfb12379267419a9cb9403d8167d8d1e91d2811a043b29243b069b37587847dc6fcddb1831bd1cc2567ca033ac40f74ab6955f683b12e4e8254e4ea760d38b3f46791c5c4cb12bc7ccb0ed1865f25d601c303f81fb1fa1db48533d3d6b288e4d9a4dff8ec21c96f578399710c825fe7e32f93a8c0743f9ebd54cc151c7610337aebf7e9b915720a54351d49ab8c22fa34998dcf583d4387361ef3ff86f50ec53f49249e4ad349603066fc9c661d69f911dfa7241c8d5792d43c457d5de96523a53d667ec5c4ef9d502a16f1522475896d79bc57833e977171c324dce2a1ea1e4304f49e43ae065e3fb196f76d9b879c7200862ead18dea5fb6a17acea33386eb4ca1b51486a9148fbdf9a95332aa605c0854ab81eba9fafffaee9bc3bd7a3a606a9fdb849c5d82d0a61923c2e5d8aa63a8a50c38bd038772c4143d8b7acfd74e72c04d89248dff20fe8dc5ec2149054ea24164e85f6744ad0cacf1a8b70126f482c092ed9f6127d2050d12e878a79653a1e84daec3ebe62d5f6c4abe5ce90a7fe2e52a8d7846e8edf2f2bce05a037c826f22caad1261467dcfb7d6b6133dc21e8096c7e9f8e9e10c1e3fac4058b682c68e54facae0f9c2dd4d64d9046152b4762332939f17e6aaf7d8b9d358e2218d4e0d69a4f119e1c64e5d5483ce4ba8ece01a8ff2b7ef82d05c0b6e861b915f13ca0eb3ea13d5070807a2cb6680a249ea9c7224392cbc8ab82501b26f112ac789a12a31ad1314e2ede08fad3143af30c27f403bc866c755177852afd0abb90ade1d682726f42008b46ad7f8abdb18117f72641390f086b6e1498be69548527e6ada2b38b9fe121ef670af7437d32536d5cf5c4ab19dd99771582d038104b7e039a376f7acbbeadb34f945beb9d7ca0e4e3d5c5e4eb1d8526ebd13dacb1ba35735c6d04a4555acf4bf115dde42d6e155c1f549790e7ff2ceaf12d3eacbefe1edf26ffaee8051d97765c1ab05b3a2e56a82f4cde52b535815e075b8e7a92cb4797329d8e452b217d9b40801fa9c799dba216c8170c2e381d5e38869e6b5358ce67ba5a97c65852b0a38838ef7781ebe5718addd7662c7d057b4646daa9b4e67b14910984802c2a7e381933c5957907b7fdd0ba2295bff88e9b717e9705580d20c48b76fe78471c99080d61035515456dee9f2c517895172f42655b899de0ae2a2613a0612c469df792b8d34e53fc96acfbfb9a1411fcbc56348c001d6ecdd0a25d620e5c77f0cdc831efd3299094babaf1f3f07da9a390b1d9fc9a08327987adfe9564863fbdfa8f6b46a8841583099afb7870118face76347e40b6fd8cd15582ae8e23be9a0219bc3e4e4546a30d3bbbbd1686086876be0e4c859be71fb58f4fab3d28c0b4f7e75ad1edb7f88946fb40cfa5786a0fcba1303c8347ecee93d46d140bb5f69531d666548b109ce764bead7c87bd4c876494de82db6e5073a6c94f7c099a40d7a31c4a04b69c9fccf3c7dd56f5544776c53b4df7953981d55a96a6dcff9904a90842e5bafec8840c2d255bf5ad61c460f98feb82a10fa1c099f62776798236c5ca7f1e46ebdb2b144d8713e56c772f2c3b860ea5b03a8854bc6e6590d63cc0ea54f10b73ba241bf74b635551a2aaca9687ac5269fd368b26d70a737f267685998a3f7d2637914909c746495d24c498635ef97ac66a400894c09f73488eb7cf33f6dad1666a05f91ad7757965c29936e7fa48d77e89ee0962f58c051d11d055fce204a562de68088a1b2648b8174cbcfc8b5b5cd077115afde18405054e5da9a04310342c5d3b526e0b02c5ca1722badeee23d145e8eb2213fc4af1e450e4d5217c6617008c78f4fb1112f4028a704fc5a9382c6b03e7d8085e906cf84ca2c1207c87a2bce2080a9891668d69b044beced6cda32c229c9117917aa07ddffcd377395cba616d63c0b69c01fcc45391fd5b8763fb96d7ca333a12de3cefa91c6c98f9473b8e104a71293e46374705baf65fa41384ba5c8e0c88a3eb07e0be34daddfabb7b65543b5f39cb2023d46789eb7d989af779e5b8d28385a85b0da2abe07f0c2bb4255fcea03188527a307d409159e90166fac6a070ba05b3e4dbfd3a2bfcc9ee6ed016c0f665be8133b7dc1d86044db0f9db40fb0e9f8bc2e4db5382a8b4f815b4e8434ad0dfbc51a5e9b145e1596cbf4670b7e05dfdafbb03f23461a2d0ec0400b3a5944e20950e8b3df72298aaee8e5939975f939ed5c6e4c400d88775943313cd716da0cb446113c7727a64b58c3f8a0f81189f98005233a81366aee73cec85228ebcfd5ee3c3fb44db76ba243f2842b7b5fc746ae51b0bc4bd4fc9fd833565ea852b92b224f6990318ad8c7d9437e20e2a1f20e818f9057c5abaaa2e5c15b94945cd424c28a5fa385dadfe4907b274d842707db3697a5ae6c8f542e5ecc07fe47350d1014670212efe81fb7c73e8450df814ef6232f7490f63ccf07480f884a66eaffc28fea448d7b401cdae10e7c0c7f9a7b15331969fc8cb36396773de191931c750f6ce5caaf29768ebb27d31282137c414971612739509800e2ab30c3aa84e8ce01c50911754463760b182ad6cc3945b00c3605a6dd2172eead43185eafce8488188ea4e27d0cdf7ddd3085e33f5e115f399fc60b9fcc833c3a3e2e1b9dccbdf548f0a6756395a1bbe218eb7f671e9626bd263e31181a604b506a03b439a7ffe4355892477e2bdf338c62c", "8d11f22615de0b6eb9ce2f5eb9ffa541185aa0722faf86e9421bc32eed59459e", 5, 648488714, 1504563861, 1238500204, 333202211, 2, 3, 0, 2, -1502020902366200, "02a45c01578f5052f17a044e31fef91fc8f53b9bd9e45595b4a8f247b926f32e", "5dde42d6e155c1f549790e7ff2ceaf12d3eacbefe1edf26ffaee8051d97765c1ab05b3a2e56a82f4cde52b535815e075b8e7a92cb4797329d8e452b217d9b408", 1, 3, 1386280728474866, "1333947587d800c4e4c6d59e935f9739598eeeaa9822f73d8b0e95204e94a5b3", "716da0cb446113c7727a64b58c3f8a0f81189f98005233a81366aee73cec85228ebcfd5ee3c3fb44db76ba243f2842b7b5fc746ae51b0bc4bd4fc9fd833565ea852b92b224f6990318ad8c7d9437e20e2a1f20e818f9057c5abaaa2e5c15b94945cd424c28a5fa385dadfe4907b274d842707db3697a5ae6c8f542e5ecc07fe47350d1014670212efe81fb7c73e8450df814ef6232f7490f63ccf07480f884a66eaffc28fea448d7b401cdae10e7c0c7f9a7b15331969fc8cb36396773de191931c750f6ce5caaf29768ebb27d", "5e33f5e115f399fc60b9fcc833c3a3e2e1b9dccbdf548f0a6756395a1bbe218eb7f671e9626bd263e31181a604b506a03b439a7ffe4355892477e2bdf338c62c"], + ["050000800a27a7263922f7d3a56c7103d97d5e1301b5ae2dbb16a3761add053a0f967e6b5bc94211b6547153267c6ee1cad0d974a71088583703ac656333156dad00000003e5013132f6ae2d67e3ec68aa9b80612833941e312c13e67f2f7a2a8abe5f59bbd51a75f37b99763985ddb4efca8e17723d0cc949801d63a64cb2d32373b2c7329f701b4d58be9ea9275245c67e5009264bd2867df4505b4f50318cadb5d5582ab978d21c3fda63337fa364554a0a91e8302e2776fa24ece84683e74876c55e2022148027904a67543b478465351afe5565555fcc3cec5654b15380d778306bb51c11a2e1d184c67c528df92d53aec44a40a4ea2a131b4733cfe45c6b0012c3e9e20975baaecb0232df880bd7d1de13e1349462ec8d5df3e780ffa72eba8a8df7fcf398ec230513ca9d6123f8b9d8178560daf975111955a2bca3423eeefc527be3a8543eb90a5ec02f35a7c64b7dd59a72da0074634e01d2abf3637add77c7350f12b011b294168ec75576e47d169e3938bf6ae2aa8ff7cfba7cacb1f92b6e4c2497bffa9f17cad242fa9c3179c1a3aa81f7361649572c715c25a1f6cd5ace82c00ab2342b9c3cb4fffdda160ca5ab9e9baf2139ef9afbe1b1f309462afce462a79bb9698e22c957c590a753a76b87e009121e06f6a1bf62a08bf435d92e2fffe86e2a9cbba9133a68e4aebf33c38436f2545fc2d52832d165af415b244adc5f57377deedf460aa3beb43419c6b082e835ce84ca13b6908a8813c021de9fa9a44e4c18dcb3d21faabdb41931b2fd497644dc3a1507fa5ac7c76beebbdbd1d49299a55bd49927e9d7f4884e6ed3fd5e4b7cb835b83308964e3c46873fd613317b91d29236ea90e365d162cc051c846d242176daf6d28618ae31fbaae999a93f175c6938e631a081f2c1f3fd782549d3f3245759606d9f92d5548acfeadbaf9caa6b93dc08828d74f6d5fdd83331f0969145955297e69f00fd2987f2da2b94b995fecbe622a735ef7f1207f671629489202bea0b475e51681aa16778b39bd923c98dc6ff8373c79bb17030417bc200c8f0b855acfec179f7674cec2721a10fca693d83cfe5b8cdcc18f81ad617fa26f0dfb83655b8a29a7f834232425e8c474588f18dd326aa396c3e4775e00205fc9e45f7b7d2e6d55dcb90e23ff6b508459aa699bfcbd56f10997764d087408986e73d6e284fea9a23c39311782f86cabff9455e4cf699e5f5d4bc0b3905a4e3bd01c54df864342eeeba5cecb7e67ddedca09f1e2add3ee6e550c5fc6959da03acc03f9728728fe0c28ee873d39ef0290ebc467ab99958278ef64979bf6515ed4a6840b0883a1ea3bd692980208c59dbc62741aea7323c578e8d073df1d27ecd72a8cf0ca546202862e4e8a7d9a4a282866f9a7b2cfc9a56313da0c47a34b7b9cda3ace8185f07c8858b16d753225be959351b64cbb277b83330217efea9171bb2388a5642283fe5b51e233ca6155d101585bc2c40158ac2106e66a26e46423370636876b434a74f8ce8060050b082a79b61bb5d344eb5a1158326ced9a9d9f54fb2fe8f9f05cd111ee46c4710f6f63a62694557ef1b12c88006b67872505f4e883b585907929a2f3fdb0d8f7914c42dde2d2000f5ae02d41821c8e1ee0138ebcb728d7c6c3c80027e437594c670fd6f3908222ee7a1b917f8271abe660e39e051aaa6fca1862276e2baa0fe0b162aebcfe3d9349c8d154bb7ee28212c1baa705d82070d7032f2695d1796809fab41246926af992b6eee95a9a06bc4562c5f2f1b19549500372e7ad579a6d6d78b33153130fb448fb79e8a669db8a0f35cdf9ae5d32d732fc79418e23b451ddc95a22ababb056ec6b5e8ba4f524dfafe875262dd7be41cbbc62420d4ad6df5c9b713604f656088a4485e93be1907d27ac6ec3c57259bd6981d42c1b78a29ad9685e63c494d4129623ea1a7ffec85fa29411073edb2978ef4e469ddd5cda986189995f88d6ab366db019001f5b25288cf860fd998ee573c8cc48aa9efcf9b617e043c329cd1aa1a0ed3a402fb96e336c719e6253cb691aa0db52736626ed1978875888ec76c846bc227272a585317dff0b1148d92d6f5fb7d95336770a7d16fac1add860776cb480221f8fb33d7e4e9b07902d2ff86fdac72096234aed48de892ff7355073bbf0615f67b1100cc2ea3ba3d6c1a1a9087b119baeebfa62bc9f0ec479d99c1a3b158b514d1629db3993f11672a26708e5ad816b547ab7e827d071ba7842b3e90305383896ec4905f70c78b694e6a5a3e4312cd8208132b840f05c714523ca819720ae227fd1acba714fa4fc45fc5398857b40dc14879856f354ba4d2581d0cda54b638ba9d76f9b52d17c8f88ee63f5845b5dcefa4c3479bce9acad18b4aeae03c0eae225d42848bdedd6971b4d264bdc0ee24487e461b1edccfb2d16a6cc84d8a8b5dcb56a9a1ed31e106f73c261d8398b2e72698f9554afe8a1e9d479c18237b9828bca8b98c9d1ba40a719ebc170adfedd969f4ccc164dba045144aaae5cdc65c464f086b3584bd9e34a6290335aa1fbd83d54aaf441e319ea47a862ad0293cedf5dd9edadeee3361ae3a450b88bbd5139a883f4841f2780ec968aa51ceb1de9068fea1a7d767b0678bc97214b31b37bab46b88f27f0448decb31622d0f0f87a855ba54000332031f73abffd46591da0b88723504edb2337230dad2acc0d8bb68bc837a2ff930bff06fde74eb90aae4f60dbb6eb827ea99884acd6285a98892802cf59d5d60d01663387b3ed2723bd6489e9c2c106d4aa2de23ced16c720429c7753a7738ec7d9db8624229edd217b80d74875a14cae4863f139e9c0b131b2a4c28071a38ec61f66801aa5956fcb2a46b9587665b7571aa03481fd8d9d5698f836fc8635e69e3bde42f4ac071328b5409f6e42d790aedd73bc1a2354723b3b819d0637a6fa4663946a30ac5afdd30ce830f6791b4575270a1720f91866e2b86f4788894c8da62d8b91faf520e3bedbc1206a5a5e6efd3dfde0843c3b06757643fc006008838ca473087f8977918cc1b81c9e68e3b888fe6f7c630f1bc7ae188f512842041cada1e05f866d2562dbe09c4b43068f754dad34df0fcfc181f31801a7992d2f16be0211b4a22f62aab64701bf4a4e6d666fc304a5c79c609acc43b00b4864893d37d5007f0c329a4755052577570dd38fac043cd91c12ee34e9cfae392a78bdabd4ee31dc0deb02fe7b1d8b0178ac9513105fcc7e30ba8e016aa36a6b5df5e5a1909f63aba095d9877a8f2dc53f46f6c9b07addf146f4ffa501f9dd3cff924e3010faf504e2b8aca7357acbffec73ac34c1a73160f2cea1e0510f84d2fe2f73b6e921907a1b7b3751213241b2cfaa55a5ea4dd517e7b49d2de8c090843730d2408a2a304aa1e2e1370a6bf6c2bc73ff00d893bc1285efca82599d181f12351f939a94ea8b975c065a91ff257cac7a92385fc8fa921b106ba8660c60ac8ba5ece45606f04f36a3a90bb3838c42abf62dd2d84babef3e188e9171aff9bc116669009d887130ac9f7396a627a8474c1811b696f99552b14c402e9019b207452ffff2dbb4e2658b73873dcbaa36c52ccdfd6bcc657585080bb5a0f25973d63eb202dc0166bbd8a39ff93246f2789732ad05587f8db7bc87c242cfd36ce685a4b656986c39fd7fcb23c91913e4611191edcc88b78f145ea29d271b940c69941e4c3fd2d71f3b190690ee16f5d14ac2224e6fc89597654527dabe72e75d2d2a13a9fbaa6378e8a264321087a1900efe3cad14a579686aa3636bd375bd3136bee0bdaabcfac881bc701812721e6fb75aa072d2d187e62258d65a192157cdf2ec321407f682f5eec6a3297ab20b7061c62245716a44f71fbfc34c79b44e09e4212ac2653f662c5b2da843041f4032ac6796efa4131770dcdd613d4bc9d3ebd7db6b5e97519ed0e85a16de5d3ebe84504d840f70efaeeb0bca2003504c99993a9e1c0ff9c2f340836dfcf7f9d796e7cfe98412986f5e75b9213b4684ebbfa0023633e08fab91a5b7252b56832918b18f2717e1d233f1b4a1a36890e224c01acfce48ee3ed1365ba0c3d4233966a1d9ce3ca3cb43d4fb5a9f27181aaa83ca444b0275f4fa7a665e33a3b7a4698999724bd7ba85ab62c4c3d402ed42046f81f974816d279b11160bb635cca3044c3bd024f269016f24a9260fa70a7f052fd91cee315100b9516027584926aa9efc607206d1a2eea1067afbb3f36785f424af044dac5db5f7d38", "1c9aa200ca7fdfdc94cf735cec417e7781a7f67677f3ffe8efa5bafcf476bc57", 5, 648488714, 3556188729, 57765029, 324959705, 1, 0, 0, 0, 0, null, null, 3, 2, -190816259997207, "2d20eb633d97250f5abb80505857c6bcd6dfcc526ca3badc7338b758264ebb2d", "166bbd8a39ff93246f2789732ad05587f8db7bc87c242cfd36ce685a4b656986c39fd7fcb23c91913e4611191edcc88b78f145ea29d271b940c69941e4c3fd2d71f3b190690ee16f5d14ac2224e6fc89597654527dabe72e75d2d2a13a9fbaa6378e8a264321087a1900efe3cad14a579686aa3636bd375bd3136bee0bdaabcfac881bc701812721e6fb75aa072d2d187e62258d65a192157cdf2ec321407f682f5eec6a3297ab20b7061c62245716a44f71fbfc34c79b44e09e4212ac2653f6", "60bb635cca3044c3bd024f269016f24a9260fa70a7f052fd91cee315100b9516027584926aa9efc607206d1a2eea1067afbb3f36785f424af044dac5db5f7d38"], + ["050000800a27a72639eb63c07d8b0c79dbf2fa1c0315be13f79af6f43e5ab0778114798f442258eedc436fcc386b36b57e1917d720177366f4060063535300acfb1358c20aa41dc502e1dd8a1633f3d8e3276b59e7d2c4e624a6f53695bcaf247e36483f13b20442046aac5253eba02fc4142b4297ebb5683db8d24319706ad26aafd81c53b740f34543a6b3e9f5bb7d5c49e8c37f075151636a5252514c797d1c00000000", "17b38a0e93ff5df79278706bb6cc88c53d06a24ce53318cb92dba463a8b08944", 5, 648488714, 3227773753, 2030865277, 486208219, 3, 0, 0, 0, 0, null, null, 0, null, 0, null, null, null], + ["050000800a27a726ee7899b7b65b59b73465f717010000000000000000000000000000000000000000000000000000000000000000ffffffff06043465f71700ffffffff00000118b1c702951281215a743b10227e548dea9616e3a111430e483f91aa902d2655d6eb293b3bbad57fd69413646d89f010b8e2ea8847d83f63315ae26e805ca32b296241b8febfe1b8b6594c333a4f5335443a7d0008c1a2b6d87bc85692a7ed460430423dbdf06605f5b54b808feb22b208b064581847b2f64ca64837007216de6ecaffeb4b69e63347f84abcad8f2e757d5861ce77ee46513da7416837dcb23d33ea72af23d0ad8c9307d0b5858da95b77fff9027b8859e11dcbd598350eee50939481708ea708eb9f664388b9c64d6af0f96690342400348e929e07460253f38390f87bd6c05308c3bde25228e0fa0880b08ef34a5a9cc0ea0a67ca65b6ffd005572909f1c42dd745eeee9dd6b4439c9f3f98a118fe16698e9ceff558f16066975fe39583e9b5853b1311391580019fe55d59d1c828d3feb6a3b9ce92d089ae4b408e23d6a437d4989b519b7a9eb08ae6d448a7a16e8aed26a2ecd0cad80844fd0650d8c4e4d2af90656748d8099a0c756fc16cca06a334430702ae1961665b4845acd1a8e34101e68bb644ac034dc63e6e344c3d63762a7a5bf59f13095410981d6b6b16bcd4c9fa68af6e5365e94ecbe7ab8b8043dfbacb23c84d71a8fe5d9ac5502ce9f73f408e14376db86ef57cc37d09896fa906972e557180a4ab5ad09d8846dd6da748765436e0160240f8d41c0ac783f939f2d0ed262ce859c131ebc93ff2e6e407d4e243e1e931d53a4543b6e26d82596fc53b52312c776d12eb2b659b4fb098df87d683cf9e5412ee56c3fe9841d73fd070dfa51f5bafedf206f13c524e5c50cac9906efa393290042e3bc59f960b7d240ae443fc49269ce00061e65c6d74812a30dd5f5fe74eff61e0cbab3cec75d0aef95083189452dd3d9edf4487bc734c8b24f21296e4e9ef117d7fb977e3b0e6406e63085906331a93033d1cb8360fe6fea61a6826df36255789f92e40bafcb2ebcb9e556f6c0ccadc6af08e31ec4ad5288034e16d155cfdcada7bab599c2fa4ad2e6293f9fe097169148276b6a9eaa72f148b0c9565c3c2dd63125e0fa530ac2f5935bd220300861a710df8e481f2712920f8787e0aedfe618aff50a3b56213884d6262c11debf2ba7e8ad6692cb17078331418da4be064ff5270073934abcd2ab0469ecaf7275b4bd72bc6ed34478ea4089b736a16dd906d49f25c33827c571ce0b5d72177aa3508804bc0f8faa947122231402d2f5cc9a0eb0e09d427b427288d937d9d72b77456f886594cd8c6a462f77fd83076469cc0ecba3cc40cad69e5b54112eab33396aecfbc211f1f79cf33108e93d95378bae6958274b31088fbd8b3a3a0d154a77e229185ba2b9164acf008ff999973c7ce98b10afdc59090521196b90be68b87b11d1d7803da2631259c3f36e65aad69082303f31c2cab1f752cd1aedd0ce60500", "7a55e494f8d969d9a016b7d651fda313fd10273bc427947194bb2c03d76584a6", 5, 648488714, 3080288494, 3076086710, 402089268, 1, 0, 0, 1, 882620969332652, "6c61e0354f955a113c012f559e9b7ca6f9d00bd88c43147431b77079e1591d1c", "7e229185ba2b9164acf008ff999973c7ce98b10afdc59090521196b90be68b87b11d1d7803da2631259c3f36e65aad69082303f31c2cab1f752cd1aedd0ce605", 0, null, 0, null, null, null] +] diff --git a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go index 8fb1d9e..179d6e8 100644 --- a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go +++ b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go @@ -744,9 +744,6 @@ func (d decoder) skipValue() error { // Skip items. This will not validate whether skipped values are // of the same type or not, same behavior as C++ // TextFormat::Parser::AllowUnknownField(true) version 3.8.0. - if err := d.skipValue(); err != nil { - return err - } } } } diff --git a/vendor/google.golang.org/protobuf/internal/encoding/text/encode.go b/vendor/google.golang.org/protobuf/internal/encoding/text/encode.go index aa66bdd..da289cc 100644 --- a/vendor/google.golang.org/protobuf/internal/encoding/text/encode.go +++ b/vendor/google.golang.org/protobuf/internal/encoding/text/encode.go @@ -263,3 +263,8 @@ func (e *Encoder) Snapshot() encoderState { func (e *Encoder) Reset(es encoderState) { 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) +} diff --git a/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go b/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go index 3759b01..029feee 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go +++ b/vendor/google.golang.org/protobuf/internal/impl/legacy_message.go @@ -440,6 +440,13 @@ func legacyMerge(in piface.MergeInput) piface.MergeOutput { if !ok { 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() if err != nil { return piface.MergeOutput{} diff --git a/vendor/google.golang.org/protobuf/internal/version/version.go b/vendor/google.golang.org/protobuf/internal/version/version.go index 5879131..14e774f 100644 --- a/vendor/google.golang.org/protobuf/internal/version/version.go +++ b/vendor/google.golang.org/protobuf/internal/version/version.go @@ -52,8 +52,8 @@ import ( // 10. Send out the CL for review and submit it. const ( Major = 1 - Minor = 26 - Patch = 0 + Minor = 27 + Patch = 1 PreRelease = "" ) diff --git a/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go b/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go index 66dcbcd..59f024c 100644 --- a/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go +++ b/vendor/google.golang.org/protobuf/reflect/protoregistry/registry.go @@ -94,7 +94,8 @@ type Files struct { // Note that enum values are in the top-level since that are in the same // scope as the parent enum. descsByName map[protoreflect.FullName]interface{} - filesByPath map[string]protoreflect.FileDescriptor + filesByPath map[string][]protoreflect.FileDescriptor + numFiles int } type packageDescriptor struct { @@ -117,17 +118,16 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error { r.descsByName = map[protoreflect.FullName]interface{}{ "": &packageDescriptor{}, } - r.filesByPath = make(map[string]protoreflect.FileDescriptor) + r.filesByPath = make(map[string][]protoreflect.FileDescriptor) } path := file.Path() - if prev := r.filesByPath[path]; prev != nil { + if prev := r.filesByPath[path]; len(prev) > 0 { r.checkGenProtoConflict(path) err := errors.New("file %q is already registered", file.Path()) - err = amendErrorWithCaller(err, prev, file) - if r == GlobalFiles && ignoreConflict(file, err) { - err = nil + err = amendErrorWithCaller(err, prev[0], file) + if !(r == GlobalFiles && ignoreConflict(file, err)) { + return err } - return err } 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) { r.descsByName[d.FullName()] = d }) - r.filesByPath[path] = file + r.filesByPath[path] = append(r.filesByPath[path], file) + r.numFiles++ return nil } @@ -308,6 +309,7 @@ func (s *nameSuffix) Pop() (name protoreflect.Name) { // FindFileByPath looks up a file by the path. // // 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) { if r == nil { return nil, NotFound @@ -316,13 +318,19 @@ func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error) globalMutex.RLock() defer globalMutex.RUnlock() } - if fd, ok := r.filesByPath[path]; ok { - return fd, nil + fds := r.filesByPath[path] + 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 { if r == nil { return 0 @@ -331,10 +339,11 @@ func (r *Files) NumFiles() int { globalMutex.RLock() defer globalMutex.RUnlock() } - return len(r.filesByPath) + return r.numFiles } // 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. func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) { if r == nil { @@ -344,9 +353,11 @@ func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) { globalMutex.RLock() defer globalMutex.RUnlock() } - for _, file := range r.filesByPath { - if !f(file) { - return + for _, files := range r.filesByPath { + for _, file := range files { + if !f(file) { + return + } } } } diff --git a/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go b/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go index f77239f..abe4ab5 100644 --- a/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go +++ b/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go @@ -43,7 +43,6 @@ package descriptorpb import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" @@ -829,15 +828,6 @@ func (*ExtensionRangeOptions) Descriptor() ([]byte, []int) { 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 { if x != nil { return x.UninterpretedOption @@ -1520,15 +1510,6 @@ func (*FileOptions) Descriptor() ([]byte, []int) { 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 { if x != nil && x.JavaPackage != nil { return *x.JavaPackage @@ -1776,15 +1757,6 @@ func (*MessageOptions) Descriptor() ([]byte, []int) { 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 { if x != nil && x.MessageSetWireFormat != nil { return *x.MessageSetWireFormat @@ -1930,15 +1902,6 @@ func (*FieldOptions) Descriptor() ([]byte, []int) { 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 { if x != nil && x.Ctype != nil { return *x.Ctype @@ -2030,15 +1993,6 @@ func (*OneofOptions) Descriptor() ([]byte, []int) { 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 { if x != nil { return x.UninterpretedOption @@ -2101,15 +2055,6 @@ func (*EnumOptions) Descriptor() ([]byte, []int) { 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 { if x != nil && x.AllowAlias != nil { return *x.AllowAlias @@ -2183,15 +2128,6 @@ func (*EnumValueOptions) Descriptor() ([]byte, []int) { 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 { if x != nil && x.Deprecated != nil { return *x.Deprecated @@ -2258,15 +2194,6 @@ func (*ServiceOptions) Descriptor() ([]byte, []int) { 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 { if x != nil && x.Deprecated != nil { return *x.Deprecated @@ -2335,15 +2262,6 @@ func (*MethodOptions) Descriptor() ([]byte, []int) { 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 { if x != nil && x.Deprecated != nil { return *x.Deprecated diff --git a/vendor/modules.txt b/vendor/modules.txt index b4e4088..25460a7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -156,7 +156,7 @@ google.golang.org/grpc/serviceconfig google.golang.org/grpc/stats google.golang.org/grpc/status 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/protowire google.golang.org/protobuf/internal/descfmt diff --git a/walletrpc/compact_formats.pb.go b/walletrpc/compact_formats.pb.go index cff1522..d7c0327 100644 --- a/walletrpc/compact_formats.pb.go +++ b/walletrpc/compact_formats.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.28.0 // protoc v3.6.1 // source: compact_formats.proto @@ -138,9 +138,10 @@ type CompactTx struct { // unset because the calculation requires reference to prior transactions. // in a pure-Sapling context, the fee will be calculable as: // valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut)) - 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 - Outputs []*CompactOutput `protobuf:"bytes,5,rep,name=outputs,proto3" json:"outputs,omitempty"` // outputs + Fee uint32 `protobuf:"varint,3,opt,name=fee,proto3" json:"fee,omitempty"` + Spends []*CompactSaplingSpend `protobuf:"bytes,4,rep,name=spends,proto3" json:"spends,omitempty"` // inputs + 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() { @@ -196,23 +197,30 @@ func (x *CompactTx) GetFee() uint32 { return 0 } -func (x *CompactTx) GetSpends() []*CompactSpend { +func (x *CompactTx) GetSpends() []*CompactSaplingSpend { if x != nil { return x.Spends } return nil } -func (x *CompactTx) GetOutputs() []*CompactOutput { +func (x *CompactTx) GetOutputs() []*CompactSaplingOutput { if x != nil { return x.Outputs } 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. -type CompactSpend struct { +type CompactSaplingSpend struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache 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) } -func (x *CompactSpend) Reset() { - *x = CompactSpend{} +func (x *CompactSaplingSpend) Reset() { + *x = CompactSaplingSpend{} if protoimpl.UnsafeEnabled { mi := &file_compact_formats_proto_msgTypes[2] 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) } -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] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -247,12 +255,12 @@ func (x *CompactSpend) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CompactSpend.ProtoReflect.Descriptor instead. -func (*CompactSpend) Descriptor() ([]byte, []int) { +// Deprecated: Use CompactSaplingSpend.ProtoReflect.Descriptor instead. +func (*CompactSaplingSpend) Descriptor() ([]byte, []int) { return file_compact_formats_proto_rawDescGZIP(), []int{2} } -func (x *CompactSpend) GetNf() []byte { +func (x *CompactSaplingSpend) GetNf() []byte { if x != nil { 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 // Zcash protocol spec. Total size is 948. -type CompactOutput struct { +type CompactSaplingOutput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields 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 - 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() { - *x = CompactOutput{} +func (x *CompactSaplingOutput) Reset() { + *x = CompactSaplingOutput{} if protoimpl.UnsafeEnabled { mi := &file_compact_formats_proto_msgTypes[3] 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) } -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] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -298,26 +306,99 @@ func (x *CompactOutput) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CompactOutput.ProtoReflect.Descriptor instead. -func (*CompactOutput) Descriptor() ([]byte, []int) { +// Deprecated: Use CompactSaplingOutput.ProtoReflect.Descriptor instead. +func (*CompactSaplingOutput) Descriptor() ([]byte, []int) { return file_compact_formats_proto_rawDescGZIP(), []int{3} } -func (x *CompactOutput) GetCmu() []byte { +func (x *CompactSaplingOutput) GetCmu() []byte { if x != nil { return x.Cmu } return nil } -func (x *CompactOutput) GetEpk() []byte { +func (x *CompactSaplingOutput) GetEpk() []byte { if x != nil { return x.Epk } 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 { 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, 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, - 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, 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, 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, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, + 0x52, 0x03, 0x66, 0x65, 0x65, 0x12, 0x42, 0x0a, 0x06, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x18, + 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, - 0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x52, 0x06, 0x73, 0x70, 0x65, 0x6e, - 0x64, 0x73, 0x12, 0x3e, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x24, 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, 0x70, - 0x61, 0x63, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x73, 0x22, 0x1e, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x70, 0x65, - 0x6e, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x6e, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, - 0x6e, 0x66, 0x22, 0x53, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 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, + 0x6d, 0x70, 0x61, 0x63, 0x74, 0x53, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x6e, + 0x64, 0x52, 0x06, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x45, 0x0a, 0x07, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 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, 0x70, 0x61, 0x63, 0x74, 0x53, 0x61, 0x70, 0x6c, 0x69, 0x6e, + 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x45, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2b, 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, 0x70, 0x61, 0x63, + 0x74, 0x4f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x25, 0x0a, 0x13, 0x43, 0x6f, 0x6d, 0x70, 0x61, + 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, 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, @@ -380,22 +476,24 @@ func file_compact_formats_proto_rawDescGZIP() []byte { 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{}{ - (*CompactBlock)(nil), // 0: cash.z.wallet.sdk.rpc.CompactBlock - (*CompactTx)(nil), // 1: cash.z.wallet.sdk.rpc.CompactTx - (*CompactSpend)(nil), // 2: cash.z.wallet.sdk.rpc.CompactSpend - (*CompactOutput)(nil), // 3: cash.z.wallet.sdk.rpc.CompactOutput + (*CompactBlock)(nil), // 0: cash.z.wallet.sdk.rpc.CompactBlock + (*CompactTx)(nil), // 1: cash.z.wallet.sdk.rpc.CompactTx + (*CompactSaplingSpend)(nil), // 2: cash.z.wallet.sdk.rpc.CompactSaplingSpend + (*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{ 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 - 3, // 2: cash.z.wallet.sdk.rpc.CompactTx.outputs:type_name -> cash.z.wallet.sdk.rpc.CompactOutput - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 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.CompactSaplingOutput + 4, // 3: cash.z.wallet.sdk.rpc.CompactTx.actions:type_name -> cash.z.wallet.sdk.rpc.CompactOrchardAction + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension 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() } @@ -429,7 +527,7 @@ func file_compact_formats_proto_init() { } } 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: return &v.state 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{} { - 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: return &v.state case 1: @@ -459,7 +569,7 @@ func file_compact_formats_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_compact_formats_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 0, }, diff --git a/walletrpc/compact_formats.proto b/walletrpc/compact_formats.proto index bf51ebb..f2129f2 100644 --- a/walletrpc/compact_formats.proto +++ b/walletrpc/compact_formats.proto @@ -37,20 +37,30 @@ message CompactTx { // valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut)) uint32 fee = 3; - repeated CompactSpend spends = 4; // inputs - repeated CompactOutput outputs = 5; // outputs + repeated CompactSaplingSpend spends = 4; // inputs + 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. -message CompactSpend { +message CompactSaplingSpend { bytes nf = 1; // nullifier (see the Zcash protocol specification) } // output is a Sapling Output Description as described in section 7.4 of the // Zcash protocol spec. Total size is 948. -message CompactOutput { +message CompactSaplingOutput { bytes cmu = 1; // note commitment u-coordinate 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 } diff --git a/walletrpc/darkside.pb.go b/walletrpc/darkside.pb.go index 0ffa24e..1c437b0 100644 --- a/walletrpc/darkside.pb.go +++ b/walletrpc/darkside.pb.go @@ -4,8 +4,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.15.7 +// protoc-gen-go v1.27.1 +// protoc v3.19.4 // source: darkside.proto 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, 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, - 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, 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, @@ -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, 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, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x5d, 0x0a, 0x0e, 0x41, 0x64, 0x64, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x12, 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, 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 ( @@ -464,31 +475,36 @@ var file_darkside_proto_goTypes = []interface{}{ (*DarksideEmptyBlocks)(nil), // 5: cash.z.wallet.sdk.rpc.DarksideEmptyBlocks (*RawTransaction)(nil), // 6: cash.z.wallet.sdk.rpc.RawTransaction (*Empty)(nil), // 7: cash.z.wallet.sdk.rpc.Empty + (*GetAddressUtxosReply)(nil), // 8: cash.z.wallet.sdk.rpc.GetAddressUtxosReply } var file_darkside_proto_depIdxs = []int32{ - 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 - 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 - 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 - 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, // 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 - 7, // 10: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksStream:output_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, // 12: cash.z.wallet.sdk.rpc.DarksideStreamer.StageBlocksCreate: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, // 14: cash.z.wallet.sdk.rpc.DarksideStreamer.StageTransactions: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 - 6, // 16: cash.z.wallet.sdk.rpc.DarksideStreamer.GetIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.RawTransaction - 7, // 17: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.Empty - 9, // [9:18] is the sub-list for method output_type - 0, // [0:9] 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 + 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 + 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 + 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 + 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, // 8: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearIncomingTransactions:input_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.ClearAddressUtxo:input_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.StageBlocksStream: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.StageBlocksCreate: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 + 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.ApplyStaged:output_type -> cash.z.wallet.sdk.rpc.Empty + 6, // 18: cash.z.wallet.sdk.rpc.DarksideStreamer.GetIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.RawTransaction + 7, // 19: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearIncomingTransactions:output_type -> cash.z.wallet.sdk.rpc.Empty + 7, // 20: cash.z.wallet.sdk.rpc.DarksideStreamer.AddAddressUtxo:output_type -> cash.z.wallet.sdk.rpc.Empty + 7, // 21: cash.z.wallet.sdk.rpc.DarksideStreamer.ClearAddressUtxo:output_type -> cash.z.wallet.sdk.rpc.Empty + 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() } diff --git a/walletrpc/darkside.proto b/walletrpc/darkside.proto index e2e0341..f84e615 100644 --- a/walletrpc/darkside.proto +++ b/walletrpc/darkside.proto @@ -114,4 +114,11 @@ service DarksideStreamer { // Clear the incoming transaction pool. 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) {} } diff --git a/walletrpc/darkside_grpc.pb.go b/walletrpc/darkside_grpc.pb.go index 4ebd58f..0e4e795 100644 --- a/walletrpc/darkside_grpc.pb.go +++ b/walletrpc/darkside_grpc.pb.go @@ -1,4 +1,8 @@ // 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 @@ -76,6 +80,11 @@ type DarksideStreamerClient interface { GetIncomingTransactions(ctx context.Context, in *Empty, opts ...grpc.CallOption) (DarksideStreamer_GetIncomingTransactionsClient, error) // Clear the incoming transaction pool. 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 { @@ -240,6 +249,24 @@ func (c *darksideStreamerClient) ClearIncomingTransactions(ctx context.Context, 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. // All implementations must embed UnimplementedDarksideStreamerServer // for forward compatibility @@ -302,6 +329,11 @@ type DarksideStreamerServer interface { GetIncomingTransactions(*Empty, DarksideStreamer_GetIncomingTransactionsServer) error // Clear the incoming transaction pool. 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() } @@ -336,6 +368,12 @@ func (UnimplementedDarksideStreamerServer) GetIncomingTransactions(*Empty, Darks func (UnimplementedDarksideStreamerServer) ClearIncomingTransactions(context.Context, *Empty) (*Empty, error) { 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() {} // 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) } +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. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -561,6 +635,14 @@ var DarksideStreamer_ServiceDesc = grpc.ServiceDesc{ MethodName: "ClearIncomingTransactions", Handler: _DarksideStreamer_ClearIncomingTransactions_Handler, }, + { + MethodName: "AddAddressUtxo", + Handler: _DarksideStreamer_AddAddressUtxo_Handler, + }, + { + MethodName: "ClearAddressUtxo", + Handler: _DarksideStreamer_ClearAddressUtxo_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/walletrpc/service.pb.go b/walletrpc/service.pb.go index 2f09ebc..070e15a 100644 --- a/walletrpc/service.pb.go +++ b/walletrpc/service.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 +// protoc-gen-go v1.28.0 // protoc v3.6.1 // source: service.proto @@ -205,7 +205,8 @@ func (x *TxFilter) GetHash() []byte { } // 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 { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -909,11 +910,12 @@ type TreeState struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - 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"` - 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 - Tree string `protobuf:"bytes,5,opt,name=tree,proto3" json:"tree,omitempty"` // sapling commitment tree state + 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"` // block height + 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 + 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() { @@ -976,9 +978,16 @@ func (x *TreeState) GetTime() uint32 { return 0 } -func (x *TreeState) GetTree() string { +func (x *TreeState) GetSaplingTree() string { if x != nil { - return x.Tree + return x.SaplingTree + } + return "" +} + +func (x *TreeState) GetOrchardTree() string { + if x != nil { + return x.OrchardTree } 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, 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, - 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0x79, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x16, 0x0a, 0x06, - 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, - 0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x72, 0x65, 0x65, - 0x22, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, - 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, 0x69, - 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x14, 0x0a, - 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, - 0x6b, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0c, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 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, 0x52, 0x0c, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x48, 0x0a, 0x0c, - 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, - 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5f, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, - 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x32, 0xd0, 0x0c, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, - 0x61, 0x63, 0x74, 0x54, 0x78, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x12, 0x54, 0x0a, - 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, - 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, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x70, 0x65, - 0x63, 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, 0x6c, 0x6f, 0x63, 0x6b, 0x49, - 0x44, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 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, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 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, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, - 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, - 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 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, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, - 0x00, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x5a, 0x45, 0x43, 0x50, 0x72, 0x69, - 0x63, 0x65, 0x12, 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, 0x72, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 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, 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, + 0x04, 0x74, 0x78, 0x69, 0x64, 0x22, 0xa9, 0x01, 0x0a, 0x09, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x16, 0x0a, + 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x0a, + 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x73, 0x61, 0x70, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x65, 0x65, 0x12, + 0x20, 0x0a, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x54, 0x72, 0x65, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x72, 0x63, 0x68, 0x61, 0x72, 0x64, 0x54, 0x72, 0x65, + 0x65, 0x22, 0x74, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, + 0x74, 0x78, 0x6f, 0x73, 0x41, 0x72, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x45, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, + 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5a, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x22, 0x6b, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0c, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 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, 0x52, + 0x0c, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0x48, 0x0a, + 0x0c, 0x50, 0x72, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x5f, 0x0a, 0x0d, 0x50, 0x72, 0x69, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x05, 0x70, 0x72, 0x69, 0x63, 0x65, 0x32, 0xd0, 0x0c, 0x0a, 0x11, 0x43, 0x6f, 0x6d, + 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x12, 0x54, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x12, 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, 0x68, 0x61, 0x69, 0x6e, 0x53, 0x70, + 0x65, 0x63, 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, 0x6c, 0x6f, 0x63, 0x6b, + 0x49, 0x44, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 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, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, + 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, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x21, 0x2e, 0x63, 0x61, 0x73, 0x68, 0x2e, + 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, 0x2e, 0x72, 0x70, 0x63, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x61, 0x6e, 0x67, 0x65, 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, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x22, 0x00, 0x30, 0x01, 0x12, 0x5a, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x5a, 0x45, 0x43, 0x50, 0x72, + 0x69, 0x63, 0x65, 0x12, 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, 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, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 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, 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, - 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, + 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 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, 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, - 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, 0x6b, - 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, - 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, + 0x70, 0x63, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x1a, 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, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x22, 0x00, 0x30, 0x01, + 0x12, 0x5b, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 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, 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, 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, 0x70, - 0x63, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x1a, 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, 0x70, 0x61, 0x63, 0x74, 0x54, 0x78, 0x22, 0x00, 0x30, 0x01, 0x12, - 0x5b, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x6d, 0x70, 0x6f, 0x6f, 0x6c, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 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, 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, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0c, - 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 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, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x20, 0x2e, 0x63, - 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, 0x6b, - 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, - 0x12, 0x6f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x74, - 0x78, 0x6f, 0x73, 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, 0x2f, - 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, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, + 0x0c, 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 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, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x49, 0x44, 0x1a, 0x20, 0x2e, + 0x63, 0x61, 0x73, 0x68, 0x2e, 0x7a, 0x2e, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2e, 0x73, 0x64, + 0x6b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, + 0x00, 0x12, 0x6f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, + 0x74, 0x78, 0x6f, 0x73, 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, + 0x2f, 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 ( diff --git a/walletrpc/service.proto b/walletrpc/service.proto index b99e7f9..12ad833 100644 --- a/walletrpc/service.proto +++ b/walletrpc/service.proto @@ -32,7 +32,8 @@ message TxFilter { } // 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 { bytes data = 1; // exact data returned by Zcash 'getrawtransaction' 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. message TreeState { - string network = 1; // "main" or "test" - uint64 height = 2; - string hash = 3; // block id - uint32 time = 4; // Unix epoch time when the block was mined - string tree = 5; // sapling commitment tree state + string network = 1; // "main" or "test" + uint64 height = 2; // block height + string hash = 3; // block id + uint32 time = 4; // Unix epoch time when the block was mined + 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 diff --git a/walletrpc/service_grpc.pb.go b/walletrpc/service_grpc.pb.go index 3500757..90aa238 100644 --- a/walletrpc/service_grpc.pb.go +++ b/walletrpc/service_grpc.pb.go @@ -1,4 +1,8 @@ // 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 @@ -45,6 +49,8 @@ type CompactTxStreamerClient interface { // 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. 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) // 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 @@ -391,6 +397,8 @@ type CompactTxStreamerServer interface { // 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. 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 // 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