diff --git a/asset/asset.go b/asset/asset.go index 4c016bd4a..f23eeb33f 100644 --- a/asset/asset.go +++ b/asset/asset.go @@ -10,12 +10,14 @@ import ( "io" "reflect" "strings" + "time" "unicode" "unicode/utf8" "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" @@ -1418,3 +1420,53 @@ func ValidateAssetName(name string) error { return nil } + +// ChainAsset is a wrapper around the base asset struct that includes +// information detailing where in the chain the asset is currently anchored. +type ChainAsset struct { + *Asset + + // IsSpent indicates whether the above asset was previously spent. + IsSpent bool + + // AnchorTx is the transaction that anchors this chain asset. + AnchorTx *wire.MsgTx + + // AnchorBlockHash is the blockhash that mined the anchor tx. + AnchorBlockHash chainhash.Hash + + // AnchorBlockHeight is the height of the block that mined the anchor + // tx. + AnchorBlockHeight uint32 + + // AnchorOutpoint is the outpoint that commits to the asset. + AnchorOutpoint wire.OutPoint + + // AnchorInternalKey is the raw internal key that was used to create the + // anchor Taproot output key. + AnchorInternalKey *btcec.PublicKey + + // AnchorMerkleRoot is the Taproot merkle root hash of the anchor output + // the asset was committed to. If there is no Tapscript sibling, this is + // equal to the Taproot Asset root commitment hash. + AnchorMerkleRoot []byte + + // AnchorTapscriptSibling is the serialized preimage of a Tapscript + // sibling, if there was one. If this is empty, then the + // AnchorTapscriptSibling hash is equal to the Taproot root hash of the + // anchor output. + AnchorTapscriptSibling []byte + + // AnchorLeaseOwner is the identity of the application that currently + // has a lease on this UTXO. If empty/nil, then the UTXO is not + // currently leased. A lease means that the UTXO is being + // reserved/locked to be spent in an upcoming transaction and that it + // should not be available for coin selection through any of the wallet + // RPCs. + AnchorLeaseOwner [32]byte + + // AnchorLeaseExpiry is the expiry of the lease. If the expiry is nil or + // the time is in the past, then the lease is not valid and the UTXO is + // available for coin selection. + AnchorLeaseExpiry *time.Time +} diff --git a/cmd/tapcli/universe.go b/cmd/tapcli/universe.go index 5c6b64868..7b5a98260 100644 --- a/cmd/tapcli/universe.go +++ b/cmd/tapcli/universe.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" + "github.com/btcsuite/btcd/wire" tap "github.com/lightninglabs/taproot-assets" "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/proof" @@ -413,7 +414,7 @@ func parseAssetKey(ctx *cli.Context) (*unirpc.AssetKey, error) { return nil, fmt.Errorf("outpoint and script key must be set") } - outpoint, err := tap.UnmarshalOutpoint(ctx.String(outpointName)) + outpoint, err := wire.NewOutPointFromString(ctx.String(outpointName)) if err != nil { return nil, err } diff --git a/itest/addrs_test.go b/itest/addrs_test.go index b03ddfbc9..6fa71950b 100644 --- a/itest/addrs_test.go +++ b/itest/addrs_test.go @@ -5,6 +5,7 @@ import ( "context" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/wire" tap "github.com/lightninglabs/taproot-assets" "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/internal/test" @@ -515,16 +516,34 @@ func runMultiSendTest(ctxt context.Context, t *harnessTest, alice, // sendProof manually exports a proof from the given source node and imports it // using the development only ImportProof RPC on the destination node. -func sendProof(t *harnessTest, src, dst *tapdHarness, scriptKey []byte, +func sendProof(t *harnessTest, src, dst *tapdHarness, + sendResp *taprpc.SendAssetResponse, scriptKey []byte, genInfo *taprpc.GenesisInfo) *tapdevrpc.ImportProofResponse { ctxb := context.Background() + // We need to find the outpoint of the asset we sent to the address. + var outpoint *taprpc.OutPoint + for _, out := range sendResp.Transfer.Outputs { + if bytes.Equal(out.ScriptKey, scriptKey) { + wireOutPoint, err := wire.NewOutPointFromString( + out.Anchor.Outpoint, + ) + require.NoError(t.t, err) + + outpoint = &taprpc.OutPoint{ + Txid: wireOutPoint.Hash[:], + OutputIndex: wireOutPoint.Index, + } + } + } + var proofResp *taprpc.ProofFile waitErr := wait.NoError(func() error { resp, err := src.ExportProof(ctxb, &taprpc.ExportProofRequest{ AssetId: genInfo.AssetId, ScriptKey: scriptKey, + Outpoint: outpoint, }) if err != nil { return err diff --git a/itest/psbt_test.go b/itest/psbt_test.go index 245ac0566..5a51f4100 100644 --- a/itest/psbt_test.go +++ b/itest/psbt_test.go @@ -132,7 +132,7 @@ func testPsbtScriptHashLockSend(t *harnessTest) { // This is an interactive/PSBT based transfer, so we do need to manually // send the proof from the sender to the receiver because the proof // courier address gets lost in the address->PSBT conversion. - _ = sendProof(t, bob, alice, aliceAddr.ScriptKey, genInfo) + _ = sendProof(t, bob, alice, sendResp, aliceAddr.ScriptKey, genInfo) AssertNonInteractiveRecvComplete(t.t, alice, 1) aliceAssets, err := alice.ListAssets(ctxb, &taprpc.ListAssetRequest{ @@ -258,7 +258,7 @@ func testPsbtScriptCheckSigSend(t *harnessTest) { // This is an interactive/PSBT based transfer, so we do need to manually // send the proof from the sender to the receiver because the proof // courier address gets lost in the address->PSBT conversion. - _ = sendProof(t, bob, alice, aliceAddr.ScriptKey, genInfo) + _ = sendProof(t, bob, alice, sendResp, aliceAddr.ScriptKey, genInfo) AssertNonInteractiveRecvComplete(t.t, alice, 1) aliceAssets, err := alice.ListAssets(ctxb, &taprpc.ListAssetRequest{ @@ -434,7 +434,7 @@ func runPsbtInteractiveFullValueSendTest(ctxt context.Context, t *harnessTest, // This is an interactive transfer, so we do need to manually // send the proof from the sender to the receiver. _ = sendProof( - t, sender, receiver, + t, sender, receiver, sendResp, receiverScriptKey.PubKey.SerializeCompressed(), genInfo, ) @@ -647,7 +647,7 @@ func runPsbtInteractiveSplitSendTest(ctxt context.Context, t *harnessTest, // This is an interactive transfer, so we do need to manually // send the proof from the sender to the receiver. _ = sendProof( - t, sender, receiver, + t, sender, receiver, sendResp, receiverScriptKey.PubKey.SerializeCompressed(), genInfo, ) @@ -769,7 +769,7 @@ func testPsbtInteractiveTapscriptSibling(t *harnessTest) { // This is an interactive transfer, so we do need to manually send the // proof from the sender to the receiver. _ = sendProof( - t, alice, bob, + t, alice, bob, sendResp, receiverScriptKey.PubKey.SerializeCompressed(), genInfo, ) @@ -916,11 +916,11 @@ func testPsbtMultiSend(t *harnessTest) { // This is an interactive transfer, so we do need to manually send the // proof from the sender to the receiver. _ = sendProof( - t, sender, receiver, + t, sender, receiver, sendResp, receiverScriptKey1.PubKey.SerializeCompressed(), genInfo, ) _ = sendProof( - t, sender, receiver, + t, sender, receiver, sendResp, receiverScriptKey2.PubKey.SerializeCompressed(), genInfo, ) diff --git a/itest/round_trip_send_test.go b/itest/round_trip_send_test.go index d312eed21..cc199d663 100644 --- a/itest/round_trip_send_test.go +++ b/itest/round_trip_send_test.go @@ -127,7 +127,7 @@ func testRoundTripSend(t *harnessTest) { // recipient's output is the second one. bobToAliceOutput := transferResp.Transfers[0].Outputs[1] bobToAliceAnchor := bobToAliceOutput.Anchor - outpoint, err := ParseOutPoint(bobToAliceAnchor.Outpoint) + outpoint, err := wire.NewOutPointFromString(bobToAliceAnchor.Outpoint) require.NoError(t.t, err) internalKey, err := btcec.ParsePubKey(bobToAliceAnchor.InternalKey) diff --git a/itest/test_list_on_test.go b/itest/test_list_on_test.go index 00fbe7914..b7cca0db2 100644 --- a/itest/test_list_on_test.go +++ b/itest/test_list_on_test.go @@ -41,7 +41,7 @@ var testCases = []*testCase{ test: testReOrgMintAndSend, }, { - name: "basic send unidirectional", + name: "basic send unidirectional hashmail courier", test: testBasicSendUnidirectional, proofCourierType: proof.HashmailCourierType, }, @@ -54,7 +54,8 @@ var testCases = []*testCase{ test: testRestartReceiverCheckBalance, }, { - name: "resume pending package send", + name: "resume pending package send hashmail " + + "courier", test: testResumePendingPackageSend, proofCourierType: proof.HashmailCourierType, }, @@ -72,7 +73,8 @@ var testCases = []*testCase{ test: testReattemptFailedReceiveUniCourier, }, { - name: "offline receiver eventually receives", + name: "offline receiver eventually receives " + + "hashmail courier", test: testOfflineReceiverEventuallyReceives, proofCourierType: proof.HashmailCourierType, }, @@ -81,7 +83,7 @@ var testCases = []*testCase{ test: testSendNoCourierUniverseImport, }, { - name: "basic send passive asset", + name: "basic send passive asset hashmail courier", test: testBasicSendPassiveAsset, proofCourierType: proof.HashmailCourierType, }, @@ -123,7 +125,7 @@ var testCases = []*testCase{ test: testMintMultiAssetGroups, }, { - name: "sending multi asset groups", + name: "sending multi asset groups hashmail courier", test: testMultiAssetGroupSend, proofCourierType: proof.HashmailCourierType, }, diff --git a/itest/universe_test.go b/itest/universe_test.go index 55795b201..b984697d4 100644 --- a/itest/universe_test.go +++ b/itest/universe_test.go @@ -11,6 +11,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/wire" tap "github.com/lightninglabs/taproot-assets" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/fn" @@ -150,7 +151,7 @@ func testUniverseSync(t *harnessTest) { // query for that asset with the compressed script key. firstAssetID := rpcSimpleAssets[0].AssetGenesis.AssetId firstScriptKey := hex.EncodeToString(rpcSimpleAssets[0].ScriptKey) - firstOutpoint, err := tap.UnmarshalOutpoint( + firstOutpoint, err := wire.NewOutPointFromString( rpcSimpleAssets[0].ChainAnchor.AnchorOutpoint, ) require.NoError(t.t, err) @@ -297,7 +298,7 @@ func testUniverseManualSync(t *harnessTest) { // We should also be able to fetch an asset from Bob's Universe, and // query for that asset with the compressed script key. - firstOutpoint, err := tap.UnmarshalOutpoint( + firstOutpoint, err := wire.NewOutPointFromString( firstAsset.ChainAnchor.AnchorOutpoint, ) require.NoError(t.t, err) diff --git a/itest/utils.go b/itest/utils.go index 6d144b96c..cc82dcf90 100644 --- a/itest/utils.go +++ b/itest/utils.go @@ -2,9 +2,6 @@ package itest import ( "context" - "fmt" - "strconv" - "strings" "testing" "time" @@ -44,34 +41,10 @@ func CopyRequests( return copied } -// ParseOutPoint -func ParseOutPoint(s string) (*wire.OutPoint, error) { - split := strings.Split(s, ":") - if len(split) != 2 { - return nil, fmt.Errorf("expecting outpoint to be in format " + - "of: txid:index") - } - - index, err := strconv.ParseInt(split[1], 10, 32) - if err != nil { - return nil, fmt.Errorf("unable to decode output index: %v", err) - } - - txid, err := chainhash.NewHashFromStr(split[0]) - if err != nil { - return nil, fmt.Errorf("unable to parse hex string: %v", err) - } - - return &wire.OutPoint{ - Hash: *txid, - Index: uint32(index), - }, nil -} - // ParseGenInfo converts a taprpc.GenesisInfo into its asset.Genesis // counterpart. func ParseGenInfo(t *testing.T, genInfo *taprpc.GenesisInfo) *asset.Genesis { - genPoint, err := ParseOutPoint(genInfo.GenesisPoint) + genPoint, err := wire.NewOutPointFromString(genInfo.GenesisPoint) require.NoError(t, err) parsedGenesis := asset.Genesis{ diff --git a/proof/archive.go b/proof/archive.go index 9530a616f..d4de97bcd 100644 --- a/proof/archive.go +++ b/proof/archive.go @@ -9,6 +9,7 @@ import ( "fmt" "os" "path/filepath" + "regexp" "strings" "time" @@ -21,16 +22,29 @@ import ( ) const ( + // TaprootAssetsFileEnding is the main file suffix for the Taproot Asset + // proof files stored on disk, without the dot. + TaprootAssetsFileEnding = "assetproof" + // TaprootAssetsFileSuffix is the main file suffix for the Taproot Asset - // proof files stored on disk. - TaprootAssetsFileSuffix = ".assetproof" + // proof files stored on disk, including the dot. + TaprootAssetsFileSuffix = "." + TaprootAssetsFileEnding // ProofDirName is the name of the directory we'll use to store our // proofs. ProofDirName = "proofs" + + // outpointTruncateLength is the number of hex characters we use to + // represent the outpoint hash in the file name. This is to avoid + // problems with long file names on some operating systems. + outpointTruncateLength = 32 ) var ( + // emptyKey is an empty public key that we use to check if a script key + // is valid. + emptyKey btcec.PublicKey + // ErrProofNotFound is returned when a user attempts to look up a proof // based on a Locator, but we can't find it on disk. ErrProofNotFound = fmt.Errorf("unable to find proof") @@ -42,6 +56,28 @@ var ( // ErrInvalidLocatorKey is returned when a specified locator script key // is invalid. ErrInvalidLocatorKey = fmt.Errorf("invalid script key locator") + + // ErrOutPointMissing is returned when a specified locator does not + // contain an outpoint. The outpoint is required when storing a proof. + ErrOutPointMissing = fmt.Errorf("outpoint missing in key locator") + + // ErrMultipleProofs is returned if looking up a proof with only the + // asset ID and script key results in multiple proofs being found. + ErrMultipleProofs = fmt.Errorf( + "multiple proofs found with asset ID and script key, specify " + + "outpoint to disambiguate", + ) + + // OutPointFileNamePattern is the regular expression we use to find out + // if a proof file on disk already has the new naming scheme. The first + // number (66) is the number of hex characters in the compressed script + // key, the second number (32) is the number of hex characters in the + // truncated outpoint txid (16 bytes of the txid). The last part is the + // variable length outpoint index (at least one digit). + OutPointFileNamePattern = regexp.MustCompile( + `^[0-9a-f]{66}-[0-9a-f]{32}-[0-9]+\.` + + TaprootAssetsFileEnding + "$", + ) ) // Locator is able to uniquely identify a proof in the extended Taproot Asset @@ -104,7 +140,9 @@ type Archiver interface { // passed ProofIdentifier. // // If a proof cannot be found, then ErrProofNotFound should be - // returned. + // returned. If multiple proofs exist for the given fields of the + // locator then ErrMultipleProofs should be returned to indicate more + // specific fields need to be set in the Locator (e.g. the OutPoint). FetchProof(ctx context.Context, id Locator) (Blob, error) // HasProof returns true if the proof for the given locator exists. This @@ -231,10 +269,10 @@ var _ NotifyArchiver = (*MultiArchiveNotifier)(nil) // archiver takes a single root directory then creates the following overlap // mapping: // -// proofs/ -// ├─ asset_id1/ -// │ ├─ script_key1 -// │ ├─ script_key2 +// proofs/ +// ├─ asset_id1/ +// │ ├─ scriptKey1-outpointTxid[:32]-outpointIndex.assetproof +// │ ├─ scriptKey2-outpointTxid[:32]-outpointIndex.assetproof type FileArchiver struct { // proofPath is the directory name that we'll use as the roof for all // our files. @@ -260,43 +298,220 @@ func NewFileArchiver(dirName string) (*FileArchiver, error) { return nil, fmt.Errorf("unable to create proof dir: %w", err) } + // We need to make sure that all our proof files have the new naming + // scheme. If they don't, we'll rename them now. This might take quite a + // while since we need to read each proof file and parse it to extract + // the outpoint and then rename it. + err := migrateOldFileNames(proofPath) + if err != nil { + return nil, fmt.Errorf("error migrating old proof file "+ + "names: %w", err) + } + return &FileArchiver{ proofPath: proofPath, eventDistributor: fn.NewEventDistributor[Blob](), }, nil } -// genProofFilePath generates the full proof file path based on a rootPath and -// a valid locator. The final path is: root/assetID/scriptKey.assetproof -func genProofFilePath(rootPath string, loc Locator) (string, error) { - var emptyKey btcec.PublicKey - +// genProofFileStoragePath generates the full proof file path for storing a +// proof based on a rootPath and a valid locator. +// The final path is: +// +// root/assetID/scriptKey-outpointTxid[:32]-outpointIndex.assetproof +// +// NOTE: Because some operating systems have issues with paths longer than 256 +// characters, we don't use the full outpoint in the file name, but only the +// first 16 bytes (32 hex characters) of the hash. That should be enough to +// avoid collisions but saves us a full 32 characters (we already use 130 for +// the hex encoded asset ID and script key). +func genProofFileStoragePath(rootPath string, loc Locator) (string, error) { switch { case loc.AssetID == nil: return "", ErrInvalidLocatorID case loc.ScriptKey.IsEqual(&emptyKey): return "", ErrInvalidLocatorKey + + case loc.OutPoint == nil: + return "", ErrOutPointMissing + } + + assetID := hex.EncodeToString(loc.AssetID[:]) + + truncatedHash := loc.OutPoint.Hash.String()[:outpointTruncateLength] + fileName := fmt.Sprintf("%x-%s-%d.%s", + loc.ScriptKey.SerializeCompressed(), truncatedHash, + loc.OutPoint.Index, TaprootAssetsFileEnding) + + return filepath.Join(rootPath, assetID, fileName), nil +} + +// lookupProofFilePath returns the full path for reading a proof file, based on +// the given locator. If the locator does not contain an outpoint, we'll check +// if there is just a single proof available on disk. If there is, we return +// that. If there are multiple, then the user needs to also specify the outpoint +// and we return ErrMultipleProofs. +func lookupProofFilePath(rootPath string, loc Locator) (string, error) { + // If an outpoint is specified, we want to look up a very specific file + // on disk. + if loc.OutPoint != nil { + fullName, err := genProofFileStoragePath(rootPath, loc) + if err != nil { + return "", err + } + + // If the file doesn't exist under the full name, we know there + // just isn't a proof file for that asset yet. + if !lnrpc.FileExists(fullName) { + return "", fmt.Errorf("proof file %s does not "+ + "exist: %w", fullName, ErrProofNotFound) + } + + return fullName, nil } + // If the user didn't specify an outpoint, we look up all proof files + // that start with the script key given. If there is exactly one, we + // return it. + switch { + case loc.AssetID == nil: + return "", ErrInvalidLocatorID + + case loc.ScriptKey.IsEqual(&emptyKey): + return "", ErrInvalidLocatorKey + } assetID := hex.EncodeToString(loc.AssetID[:]) scriptKey := hex.EncodeToString(loc.ScriptKey.SerializeCompressed()) - return filepath.Join(rootPath, assetID, scriptKey+TaprootAssetsFileSuffix), nil + searchPattern := filepath.Join(rootPath, assetID, scriptKey+"*") + matches, err := filepath.Glob(searchPattern) + if err != nil { + return "", fmt.Errorf("error listing proof files: %w", err) + } + + switch { + // We have no proof for this script key. + case len(matches) == 0: + return "", ErrProofNotFound + + // Exactly one proof for this script key, we'll return it. + case len(matches) == 1: + return matches[0], nil + + // User needs to specify the outpoint as well, since we have multiple + // proofs for this script key. + default: + return "", ErrMultipleProofs + } +} + +// extractLastProof extracts the last proof from a proof file. +func extractLastProof(fileContent Blob) (*Proof, error) { + parsedFile := &File{} + err := parsedFile.Decode(bytes.NewReader(fileContent)) + if err != nil { + return nil, fmt.Errorf("error parsing proof file: %w", err) + } + + // To find out the new file name, we need to parse the proof + // file and extract the last proof in it. + lastProof, err := parsedFile.LastProof() + if err != nil { + return nil, fmt.Errorf("error extracting last proof from "+ + "proof file: %w", err) + } + + return lastProof, nil +} + +// migrateOldFileNames looks for proof files in the root path that don't conform +// to the new naming scheme and renames them to the new scheme. +func migrateOldFileNames(rootPath string) error { + // List all files matching rootPath/*/*.assetproof. + searchPattern := filepath.Join( + rootPath, "*", "*"+TaprootAssetsFileSuffix, + ) + oldProofs, err := filepath.Glob(searchPattern) + if err != nil { + return fmt.Errorf("error listing old proof files: %w", err) + } + + // Skip files that already have the new naming pattern. + oldProofs = fn.Filter(oldProofs, func(path string) bool { + return !OutPointFileNamePattern.MatchString(filepath.Base(path)) + }) + + // Nothing to migrate, let's not even log a message to avoid startup + // log spam. + if len(oldProofs) == 0 { + return nil + } + + log.Infof("Found %d proof files in %s with old naming scheme, "+ + "renaming now (will take a while)", len(oldProofs), rootPath) + + var ( + startTime = time.Now() + numFilesRenamed int + ) + for _, oldPath := range oldProofs { + proofFile, err := os.ReadFile(oldPath) + if err != nil { + return fmt.Errorf("unable to read proof: %w", err) + } + + // To find out the new file name, we need to parse the proof + // file and extract the last proof in it. + lastProof, err := extractLastProof(proofFile) + if err != nil { + return fmt.Errorf("unable to extract last proof from "+ + "proof file: %w", err) + } + + newFileName, err := genProofFileStoragePath(rootPath, Locator{ + AssetID: fn.Ptr(lastProof.Asset.ID()), + ScriptKey: *lastProof.Asset.ScriptKey.PubKey, + OutPoint: fn.Ptr(lastProof.OutPoint()), + }) + if err != nil { + return fmt.Errorf("error generating new file name: "+ + "%w", err) + } + + err = os.Rename(oldPath, newFileName) + if err != nil { + return fmt.Errorf("error renaming file %s to %s: %w", + oldPath, newFileName, err) + } + + numFilesRenamed++ + if numFilesRenamed%1000 == 0 { + log.Infof("Renamed %d of %d old files", numFilesRenamed, + len(oldProofs)) + } + } + + log.Infof("Done renaming %d proof files, took %v", len(oldProofs), + time.Since(startTime)) + + return nil } -// FetchProof fetches a proof for an asset uniquely identified by the -// passed ProofIdentifier. +// FetchProof fetches a proof for an asset uniquely identified by the passed +// ProofIdentifier. // -// If a proof cannot be found, then ErrProofNotFound should be -// returned. +// If a proof cannot be found, then ErrProofNotFound should be returned. If +// multiple proofs exist for the given fields of the locator then +// ErrMultipleProofs is returned to indicate more specific fields need to be set +// in the Locator (e.g. the OutPoint). // // NOTE: This implements the Archiver interface. func (f *FileArchiver) FetchProof(_ context.Context, id Locator) (Blob, error) { // All our on-disk storage is based on asset IDs, so to look up a path, // we just need to compute the full file path and see if it exists on // disk. - proofPath, err := genProofFilePath(f.proofPath, id) + proofPath, err := lookupProofFilePath(f.proofPath, id) if err != nil { return nil, fmt.Errorf("unable to make proof file path: %w", err) @@ -320,7 +535,7 @@ func (f *FileArchiver) HasProof(_ context.Context, id Locator) (bool, error) { // All our on-disk storage is based on asset IDs, so to look up a path, // we just need to compute the full file path and see if it exists on // disk. - proofPath, err := genProofFilePath(f.proofPath, id) + proofPath, err := lookupProofFilePath(f.proofPath, id) if err != nil { return false, fmt.Errorf("unable to make proof file path: %w", err) @@ -352,9 +567,16 @@ func (f *FileArchiver) FetchProofs(_ context.Context, continue } - scriptKeyBytes, err := hex.DecodeString(strings.ReplaceAll( + parts := strings.Split(strings.ReplaceAll( fileName, TaprootAssetsFileSuffix, "", - )) + ), "-") + if len(parts) != 3 { + return nil, fmt.Errorf("malformed proof file name "+ + "'%s', expected two parts, got %d", fileName, + len(parts)) + } + + scriptKeyBytes, err := hex.DecodeString(parts[0]) if err != nil { return nil, fmt.Errorf("malformed proof file name, "+ "unable to decode script key: %w", err) @@ -372,10 +594,21 @@ func (f *FileArchiver) FetchProofs(_ context.Context, return nil, fmt.Errorf("unable to read proof: %w", err) } + // We only have part of the outpoint in the file name, so we + // need to read the file and parse the last proof to extract the + // outpoint. + lastProof, err := extractLastProof(proofFile) + if err != nil { + return nil, fmt.Errorf("unable to extract last proof "+ + "from proof file: %w", err) + } + + outPoint := lastProof.OutPoint() proofs[idx] = &AnnotatedProof{ Locator: Locator{ AssetID: &id, ScriptKey: *scriptKey, + OutPoint: &outPoint, }, Blob: proofFile, } @@ -396,7 +629,9 @@ func (f *FileArchiver) ImportProofs(_ context.Context, proofs ...*AnnotatedProof) error { for _, proof := range proofs { - proofPath, err := genProofFilePath(f.proofPath, proof.Locator) + proofPath, err := genProofFileStoragePath( + f.proofPath, proof.Locator, + ) if err != nil { return err } @@ -411,6 +646,9 @@ func (f *FileArchiver) ImportProofs(_ context.Context, "%s does not exist", proofPath) } + log.Tracef("Importing proof file %s (replace=%v)", proofPath, + replace) + err = os.WriteFile(proofPath, proof.Blob, 0666) if err != nil { return fmt.Errorf("unable to store proof: %v", err) diff --git a/proof/archive_test.go b/proof/archive_test.go index f1789abbe..894b0b1d8 100644 --- a/proof/archive_test.go +++ b/proof/archive_test.go @@ -3,12 +3,15 @@ package proof import ( "bytes" "context" - "math/rand" + "encoding/hex" "os" + "path/filepath" "testing" "time" + "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/internal/test" "github.com/stretchr/testify/require" ) @@ -17,14 +20,74 @@ var ( testTimeout = 5 * time.Second ) -func randAssetID(t *testing.T) *asset.ID { +func randAssetID() *asset.ID { var a asset.ID - _, err := rand.Read(a[:]) - require.NoError(t, err) + copy(a[:], test.RandBytes(32)) return &a } +// TestFileArchiverProofCollision tests that we can store two different proofs +// with the same script key but different outpoints. +func TestFileArchiverProofCollision(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + // First, we'll make a temp directory we'll use as the root of our file + // system. + tempDir := t.TempDir() + + fileArchive, err := NewFileArchiver(tempDir) + require.NoError(t, err) + + // We store two different proofs with the same script key but different + // outpoints. This should result in two different files on disk. + var ( + scriptKey = *test.RandPubKey(t) + assetID = randAssetID() + testOp1 = test.RandOp(t) + testOp2 = test.RandOp(t) + locator1 = Locator{ + AssetID: assetID, + ScriptKey: scriptKey, + OutPoint: &testOp1, + } + locator2 = Locator{ + AssetID: assetID, + ScriptKey: scriptKey, + OutPoint: &testOp2, + } + blob1 = []byte("this is the first blob") + blob2 = []byte("this is the second blob") + ) + err = fileArchive.ImportProofs( + ctx, MockHeaderVerifier, MockGroupVerifier, false, + &AnnotatedProof{ + Locator: locator1, + Blob: blob1, + }, + ) + require.NoError(t, err) + err = fileArchive.ImportProofs( + ctx, MockHeaderVerifier, MockGroupVerifier, false, + &AnnotatedProof{ + Locator: locator2, + Blob: blob2, + }, + ) + require.NoError(t, err) + + // When retrieving the proofs, we should get the same blobs back. + proof1, err := fileArchive.FetchProof(ctx, locator1) + require.NoError(t, err) + require.EqualValues(t, blob1, proof1) + + proof2, err := fileArchive.FetchProof(ctx, locator2) + require.NoError(t, err) + require.EqualValues(t, blob2, proof2) +} + // TestFileArchiver tests that the file archiver functions as advertised when // it comes to writing and also reading proof file on disk. func TestFileArchiver(t *testing.T) { @@ -32,12 +95,9 @@ func TestFileArchiver(t *testing.T) { // First, we'll make a temp directory we'll use as the root of our file // system. - dir, err := os.MkdirTemp("", "tap-proofs-") - require.NoError(t, err) - - defer os.RemoveAll(dir) + tempDir := t.TempDir() - fileArchive, err := NewFileArchiver(dir) + fileArchive, err := NewFileArchiver(tempDir) require.NoError(t, err) // We'll use a fake verifier that just returns that the proof is valid. @@ -47,7 +107,7 @@ func TestFileArchiver(t *testing.T) { ctx := context.Background() - var tests = []struct { + var testCases = []struct { name string locator Locator @@ -56,27 +116,28 @@ func TestFileArchiver(t *testing.T) { fetchFunc func(*FileArchiver) error - expectedErorr error + expectedFetchError error + expectedStoreError error }{ // Attempting to fetch a proof that doesn't exist on disk should // return an error. { name: "proof not found", locator: Locator{ - AssetID: randAssetID(t), + AssetID: randAssetID(), ScriptKey: *test.RandPubKey(t), }, - expectedErorr: ErrProofNotFound, + expectedFetchError: ErrProofNotFound, }, - // Attempting to fetch a file on disk that doesn't have an asset ID - // specified should return an error. + // Attempting to fetch a file on disk that doesn't have an asset + // ID specified should return an error. { name: "invalid asset ID", locator: Locator{ ScriptKey: *test.RandPubKey(t), }, - expectedErorr: ErrInvalidLocatorID, + expectedFetchError: ErrInvalidLocatorID, }, // Fetching w/ the assetID, but not script key should return an @@ -84,9 +145,23 @@ func TestFileArchiver(t *testing.T) { { name: "invalid script key", locator: Locator{ - AssetID: randAssetID(t), + AssetID: randAssetID(), }, - expectedErorr: ErrInvalidLocatorKey, + expectedFetchError: ErrInvalidLocatorKey, + }, + + // Storing a proof with assetID and script key, but no outpoint + // should return an error as well. + { + name: "invalid outpoint", + locator: Locator{ + AssetID: randAssetID(), + ScriptKey: *test.RandPubKey(t), + }, + proofBlob: func() Blob { + return bytes.Repeat([]byte{0x01}, 100) + }, + expectedStoreError: ErrOutPointMissing, }, // We should be able to insert a proof, then get it right back @@ -94,38 +169,168 @@ func TestFileArchiver(t *testing.T) { { name: "proof happy path", locator: Locator{ - AssetID: randAssetID(t), + AssetID: randAssetID(), ScriptKey: *test.RandPubKey(t), + OutPoint: &wire.OutPoint{}, }, proofBlob: func() Blob { return bytes.Repeat([]byte{0x01}, 100) }, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { var proofBlob Blob - if test.proofBlob != nil { - proofBlob = test.proofBlob() + if testCase.proofBlob != nil { + proofBlob = testCase.proofBlob() proof := &AnnotatedProof{ Blob: proofBlob, - Locator: test.locator, + Locator: testCase.locator, } - require.NoError( - t, archive.ImportProofs( - ctx, MockHeaderVerifier, - MockGroupVerifier, false, - proof, - ), + + err = archive.ImportProofs( + ctx, MockHeaderVerifier, + MockGroupVerifier, false, proof, ) + + if testCase.expectedStoreError != nil { + require.ErrorIs( + t, err, + testCase.expectedStoreError, + ) + + return + } + + require.NoError(t, err) } - diskProof, err := archive.FetchProof(ctx, test.locator) - require.ErrorIs(t, err, test.expectedErorr) + diskProof, err := archive.FetchProof( + ctx, testCase.locator, + ) + require.ErrorIs(t, err, testCase.expectedFetchError) - if test.proofBlob != nil { + if testCase.proofBlob != nil { require.Equal(t, proofBlob, diskProof) } }) } } + +// TestMigrateOldFileNames tests that we can migrate old file names to the new +// format. +func TestMigrateOldFileNames(t *testing.T) { + // First, we'll make a temp directory we'll use as the root of our file + // system. + tempDir := t.TempDir() + proofDir := filepath.Join(tempDir, ProofDirName) + + toFileBlob := func(proof Proof) []byte { + file, err := NewFile(V0, proof, proof) + require.NoError(t, err) + + var buf bytes.Buffer + err = file.Encode(&buf) + require.NoError(t, err) + + return buf.Bytes() + } + + // storeProofOldName is a helper that stores a proof file under the old + // naming scheme. + storeProofOldName := func(proof Proof) { + assetID := hex.EncodeToString(fn.ByteSlice(proof.Asset.ID())) + scriptKey := proof.Asset.ScriptKey.PubKey + fileName := filepath.Join( + proofDir, assetID, hex.EncodeToString( + scriptKey.SerializeCompressed(), + )+TaprootAssetsFileSuffix, + ) + + err := os.MkdirAll(filepath.Dir(fileName), 0755) + require.NoError(t, err) + err = os.WriteFile(fileName, toFileBlob(proof), 0644) + require.NoError(t, err) + } + + // storeProofNewName is a helper that stores a proof file under the new + // naming scheme. + storeProofNewName := func(proof Proof) { + fileName, err := genProofFileStoragePath(proofDir, Locator{ + AssetID: fn.Ptr(proof.Asset.ID()), + ScriptKey: *proof.Asset.ScriptKey.PubKey, + OutPoint: fn.Ptr(proof.OutPoint()), + }) + require.NoError(t, err) + + err = os.MkdirAll(filepath.Dir(fileName), 0755) + require.NoError(t, err) + err = os.WriteFile(fileName, toFileBlob(proof), 0644) + require.NoError(t, err) + } + + // assertProofAtNewName is a helper that asserts that a proof file is + // stored under the new naming scheme. + assertProofAtNewName := func(proof Proof) { + fileName, err := genProofFileStoragePath(proofDir, Locator{ + AssetID: fn.Ptr(proof.Asset.ID()), + ScriptKey: *proof.Asset.ScriptKey.PubKey, + OutPoint: fn.Ptr(proof.OutPoint()), + }) + require.NoError(t, err) + + _, err = os.Stat(fileName) + require.NoError(t, err) + } + + testBlocks := readTestData(t) + oddTxBlock := testBlocks[0] + + genesis1 := asset.RandGenesis(t, asset.Collectible) + genesis2 := asset.RandGenesis(t, asset.Collectible) + scriptKey1 := test.RandPubKey(t) + scriptKey2 := test.RandPubKey(t) + + // We create 4 different proofs with the old naming scheme. + proof1 := randomProof(t, genesis1, scriptKey1, oddTxBlock, 0, 1) + storeProofOldName(proof1) + proof2 := randomProof(t, genesis1, scriptKey2, oddTxBlock, 0, 1) + storeProofOldName(proof2) + proof3 := randomProof(t, genesis2, scriptKey1, oddTxBlock, 1, 1) + storeProofOldName(proof3) + proof4 := randomProof(t, genesis2, scriptKey2, oddTxBlock, 1, 1) + storeProofOldName(proof4) + + // We also create a proof with the new naming scheme. + proof5 := randomProof(t, genesis1, scriptKey1, oddTxBlock, 1, 1) + storeProofNewName(proof5) + + // We now create the file archive and expect the 4 proofs to be renamed. + fileArchive, err := NewFileArchiver(tempDir) + require.NoError(t, err) + + // After creating the archiver, we should now have all 4 proofs with the + // old name be moved/renamed to the new name. + assertProofAtNewName(proof1) + assertProofAtNewName(proof2) + assertProofAtNewName(proof3) + assertProofAtNewName(proof4) + + // The proof that was already there with the new name should still be + // there. + assertProofAtNewName(proof5) + + // We should be able to import a new proof, and it should be stored + // under the new naming scheme. + proof6 := randomProof(t, genesis2, scriptKey2, oddTxBlock, 2, 1) + err = fileArchive.ImportProofs(nil, nil, nil, false, &AnnotatedProof{ + Locator: Locator{ + AssetID: fn.Ptr(proof6.Asset.ID()), + ScriptKey: *proof6.Asset.ScriptKey.PubKey, + OutPoint: fn.Ptr(proof6.OutPoint()), + }, + Blob: toFileBlob(proof6), + }) + require.NoError(t, err) + assertProofAtNewName(proof6) +} diff --git a/proof/courier.go b/proof/courier.go index c3586751f..65bd57bbe 100644 --- a/proof/courier.go +++ b/proof/courier.go @@ -85,6 +85,10 @@ type CourierCfg struct { // TransferLog is a log for recording proof delivery and retrieval // attempts. TransferLog TransferLog + + // LocalArchive is an archive that can be used to fetch proofs from the + // local archive. + LocalArchive Archiver } // CourierDispatch is an interface that abstracts away the different proof @@ -123,10 +127,6 @@ func (u *URLDispatch) NewCourier(addr *url.URL, cfg.BackoffCfg, u.cfg.TransferLog, ) - hashMailCfg := HashMailCourierCfg{ - ReceiverAckTimeout: cfg.ReceiverAckTimeout, - } - hashMailBox, err := NewHashMailBox(addr) if err != nil { return nil, fmt.Errorf("unable to make mailbox: %v", @@ -134,7 +134,7 @@ func (u *URLDispatch) NewCourier(addr *url.URL, } return &HashMailCourier{ - cfg: &hashMailCfg, + cfg: u.cfg, backoffHandle: backoffHandler, recipient: recipient, mailbox: hashMailBox, @@ -165,7 +165,7 @@ func (u *URLDispatch) NewCourier(addr *url.URL, recipient: recipient, client: client, backoffHandle: backoffHandler, - transfer: u.cfg.TransferLog, + cfg: u.cfg, subscribers: subscribers, rawConn: conn, }, nil @@ -593,9 +593,9 @@ func (b *BackoffHandler) initialDelay(ctx context.Context, // Exec attempts to execute the given proof transfer function using a repeating // backoff time delayed strategy. The backoff strategy is used to ensure that we // don't spam the courier service with proof transfer attempts. -func (b *BackoffHandler) Exec(ctx context.Context, - proofLocator Locator, transferType TransferType, - transferFunc func() error, subscriberEvent func(fn.Event)) error { +func (b *BackoffHandler) Exec(ctx context.Context, proofLocator Locator, + transferType TransferType, transferFunc func() error, + subscriberEvent func(fn.Event)) error { if b.cfg == nil { return fmt.Errorf("backoff config not specified") @@ -721,8 +721,8 @@ type HashMailCourierCfg struct { // HashMailCourier is a hashmail proof courier service handle. It implements the // Courier interface. type HashMailCourier struct { - // cfg contains the courier's configuration parameters. - cfg *HashMailCourierCfg + // cfg is the general courier configuration. + cfg *CourierCfg // backoffHandle is a handle to the backoff procedure used in proof // delivery. @@ -786,10 +786,10 @@ func (h *HashMailCourier) DeliverProof(ctx context.Context, // Wait to receive the ACK from the remote party over // their stream. log.Infof("Waiting (%v) for receiver ACK via sid=%x", - h.cfg.ReceiverAckTimeout, receiverStreamID) + h.cfg.HashMailCfg.ReceiverAckTimeout, receiverStreamID) ctxTimeout, cancel := context.WithTimeout( - ctx, h.cfg.ReceiverAckTimeout, + ctx, h.cfg.HashMailCfg.ReceiverAckTimeout, ) defer cancel() err = h.mailbox.RecvAck(ctxTimeout, receiverStreamID) @@ -1008,6 +1008,9 @@ type UniverseRpcCourier struct { // the universe RPC server. client unirpc.UniverseClient + // cfg is the general courier configuration. + cfg *CourierCfg + // rawConn is the raw connection that the courier will use to interact // with the remote gRPC service. rawConn *grpc.ClientConn @@ -1016,10 +1019,6 @@ type UniverseRpcCourier struct { // delivery. backoffHandle *BackoffHandler - // transfer is the log that the courier will use to record the - // attempted delivery of proofs to the receiver. - transfer TransferLog - // subscribers is a map of components that want to be notified on new // events, keyed by their subscription ID. subscribers map[uint64]*fn.EventReceiver[fn.Event] @@ -1188,7 +1187,9 @@ func (c *UniverseRpcCourier) ReceiveProof(ctx context.Context, return proofBlob, nil } - proofFile, err := FetchProofProvenance(ctx, originLocator, fetchProof) + proofFile, err := FetchProofProvenance( + ctx, c.cfg.LocalArchive, originLocator, fetchProof, + ) if err != nil { return nil, fmt.Errorf("error fetching proof provenance: %w", err) @@ -1270,14 +1271,19 @@ type TransferLog interface { // FetchProofProvenance iterates backwards through the main chain of proofs // until it reaches the genesis point (the asset is the genesis asset) and then // returns the full proof file with the full provenance for the asset. -func FetchProofProvenance(ctx context.Context, originLocator Locator, +func FetchProofProvenance(ctx context.Context, localArchive Archiver, + originLocator Locator, fetchSingleProof func(context.Context, Locator) (Blob, error)) (*File, error) { // In order to reconstruct the proof file we must collect all the // transition proofs that make up the main chain of proofs. That is // accomplished by iterating backwards through the main chain of proofs - // until we reach the genesis point (minting proof). + // until we reach the genesis point (minting proof). The local archive + // can be a proof file based archive or a single proof based archive. If + // we do get a full proof file from the local archive, we do have a + // shortcut to the full remaining provenance, and we can stop the + // iterative lookup. // We will update the locator at each iteration. currentLocator := originLocator @@ -1287,6 +1293,57 @@ func FetchProofProvenance(ctx context.Context, originLocator Locator, // is a reversal of that found in the proof file. var reversedProofs []Blob for { + // Before we attempt to fetch the proof from the potentially + // remote universe, we'll check our local archive to see if we + // already have it. This doesn't make sense in all cases, so we + // allow the local archive to be nil, in which case we just skip + // this step. The local universe might give us a single proof or + // a full file, depending on its type. If we get a full file, we + // are already done. + var ( + fullProof Blob + err error + ) + if localArchive != nil { + fullProof, err = localArchive.FetchProof( + ctx, currentLocator, + ) + } + + // If we don't have a local archive, then the IsFile() check + // returns false, and we skip this block. + if err == nil && fullProof.IsFile() { + // The file in the local archive contains the full + // provenance from the current proof back to the + // genesis. + proofFile, err := fullProof.AsFile() + if err != nil { + return nil, fmt.Errorf("unable to decode "+ + "proof file: %w", err) + } + + // So if this is the first proof we've fetched, we're + // already done. + if len(reversedProofs) == 0 { + return proofFile, nil + } + + // If we have already fetched some proofs, we'll need to + // append them to the proof file we just fetched. + for i := len(reversedProofs) - 1; i >= 0; i-- { + err := proofFile.AppendProofRaw( + reversedProofs[i], + ) + if err != nil { + return nil, fmt.Errorf("error "+ + "appending proof to proof "+ + "file: %w", err) + } + } + + return proofFile, nil + } + // Setup proof receive/query routine and start backoff // procedure. proofBlob, err := fetchSingleProof(ctx, currentLocator) diff --git a/proof/courier_test.go b/proof/courier_test.go new file mode 100644 index 000000000..f9bc61adb --- /dev/null +++ b/proof/courier_test.go @@ -0,0 +1,115 @@ +package proof + +import ( + "bytes" + "context" + "fmt" + "testing" + + "github.com/lightninglabs/taproot-assets/asset" + "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/internal/test" + "github.com/stretchr/testify/require" +) + +type mockProofArchive struct { + proofs map[Locator]Blob +} + +func newMockProofArchive() *mockProofArchive { + return &mockProofArchive{ + proofs: make(map[Locator]Blob), + } +} + +func (m *mockProofArchive) FetchProof(ctx context.Context, + id Locator) (Blob, error) { + + proof, ok := m.proofs[id] + if !ok { + return nil, ErrProofNotFound + } + + return proof, nil +} + +func (m *mockProofArchive) HasProof(ctx context.Context, + id Locator) (bool, error) { + + _, ok := m.proofs[id] + + return ok, nil +} + +func (m *mockProofArchive) FetchProofs(ctx context.Context, + id asset.ID) ([]*AnnotatedProof, error) { + + return nil, fmt.Errorf("not implemented") +} + +func (m *mockProofArchive) ImportProofs(ctx context.Context, + headerVerifier HeaderVerifier, groupVerifier GroupVerifier, + replace bool, proofs ...*AnnotatedProof) error { + + return fmt.Errorf("not implemented") +} + +// TestUniverseRpcCourierLocalArchiveShortCut tests that the local archive is +// used as a shortcut to fetch a proof if it's available. +func TestUniverseRpcCourierLocalArchiveShortCut(t *testing.T) { + localArchive := newMockProofArchive() + + testBlocks := readTestData(t) + oddTxBlock := testBlocks[0] + + genesis := asset.RandGenesis(t, asset.Collectible) + scriptKey := test.RandPubKey(t) + proof := randomProof(t, genesis, scriptKey, oddTxBlock, 0, 1) + + file, err := NewFile(V0, proof, proof) + require.NoError(t, err) + proof.AdditionalInputs = []File{*file, *file} + + var fileBuf bytes.Buffer + require.NoError(t, file.Encode(&fileBuf)) + proofBlob := Blob(fileBuf.Bytes()) + + locator := Locator{ + AssetID: fn.Ptr(genesis.ID()), + ScriptKey: *proof.Asset.ScriptKey.PubKey, + OutPoint: fn.Ptr(proof.OutPoint()), + } + localArchive.proofs[locator] = proofBlob + + courier := &UniverseRpcCourier{ + recipient: Recipient{}, + client: nil, + cfg: &CourierCfg{ + LocalArchive: localArchive, + }, + rawConn: nil, + backoffHandle: nil, + subscribers: nil, + } + + ctx := context.Background() + ctxt, cancel := context.WithTimeout(ctx, testTimeout) + defer cancel() + + // If we attempt to receive a proof that the local archive has, we + // expect to get it back. + annotatedProof, err := courier.ReceiveProof(ctxt, locator) + require.NoError(t, err) + + require.Equal(t, proofBlob, annotatedProof.Blob) + + // If we query for a proof that the local archive doesn't have, we + // should end up in the code path that attempts to fetch the proof from + // the universe. Since we don't want to set up a full universe server + // in the test, we just make sure we get an error from that code path. + _, err = courier.ReceiveProof(ctxt, Locator{ + AssetID: fn.Ptr(genesis.ID()), + ScriptKey: *proof.Asset.ScriptKey.PubKey, + }) + require.ErrorContains(t, err, "is missing outpoint") +} diff --git a/proof/proof_test.go b/proof/proof_test.go index 671bedcb1..f83ff67de 100644 --- a/proof/proof_test.go +++ b/proof/proof_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/hex" + "encoding/json" "fmt" "os" "path/filepath" @@ -136,17 +137,13 @@ func assertEqualProof(t *testing.T, expected, actual *Proof) { require.Equal(t, expected.ChallengeWitness, actual.ChallengeWitness) } -func TestProofEncoding(t *testing.T) { - t.Parallel() - - testBlocks := readTestData(t) - oddTxBlock := testBlocks[0] +func randomProof(t *testing.T, genesis asset.Genesis, + scriptKey *btcec.PublicKey, block wire.MsgBlock, txIndex int, + outputIndex uint32) Proof { - txMerkleProof, err := NewTxMerkleProof(oddTxBlock.Transactions, 0) + txMerkleProof, err := NewTxMerkleProof(block.Transactions, txIndex) require.NoError(t, err) - genesis := asset.RandGenesis(t, asset.Collectible) - scriptKey := test.RandPubKey(t) tweakedScriptKey := asset.NewScriptKey(scriptKey) protoAsset := asset.NewAssetNoErr( t, genesis, 1, 0, 0, tweakedScriptKey, nil, @@ -167,26 +164,26 @@ func TestProofEncoding(t *testing.T) { }, ) require.NoError(t, err) - asset := assets[0] - asset.GroupKey.RawKey = keychain.KeyDescriptor{} + proofAsset := assets[0] + proofAsset.GroupKey.RawKey = keychain.KeyDescriptor{} // Empty the group witness, since it will eventually be stored as the // asset's witness within the proof. // TODO(guggero): Actually store the witness in the proof. - asset.GroupKey.Witness = nil + proofAsset.GroupKey.Witness = nil // Empty the raw script key, since we only serialize the tweaked // pubkey. We'll also force the main script key to be an x-only key as // well. - asset.ScriptKey.PubKey, err = schnorr.ParsePubKey( - schnorr.SerializePubKey(asset.ScriptKey.PubKey), + proofAsset.ScriptKey.PubKey, err = schnorr.ParsePubKey( + schnorr.SerializePubKey(proofAsset.ScriptKey.PubKey), ) require.NoError(t, err) - asset.ScriptKey.TweakedScriptKey = nil + proofAsset.ScriptKey.TweakedScriptKey = nil _, commitmentProof, err := mintCommitment.Proof( - asset.TapCommitmentKey(), asset.AssetCommitmentKey(), + proofAsset.TapCommitmentKey(), proofAsset.AssetCommitmentKey(), ) require.NoError(t, err) @@ -197,15 +194,15 @@ func TestProofEncoding(t *testing.T) { testBranchPreimage := commitment.NewPreimageFromBranch( txscript.NewTapBranch(leaf1, leaf2), ) - proof := Proof{ + return Proof{ PrevOut: genesis.FirstPrevOut, - BlockHeader: oddTxBlock.Header, + BlockHeader: block.Header, BlockHeight: 42, - AnchorTx: *oddTxBlock.Transactions[0], + AnchorTx: *block.Transactions[txIndex], TxMerkleProof: *txMerkleProof, - Asset: *asset, + Asset: *proofAsset, InclusionProof: TaprootProof{ - OutputIndex: 1, + OutputIndex: outputIndex, InternalKey: test.RandPubKey(t), CommitmentProof: &CommitmentProof{ Proof: *commitmentProof, @@ -259,6 +256,18 @@ func TestProofEncoding(t *testing.T) { GenesisReveal: &genesis, GroupKeyReveal: &groupReveal, } +} + +func TestProofEncoding(t *testing.T) { + t.Parallel() + + testBlocks := readTestData(t) + oddTxBlock := testBlocks[0] + + genesis := asset.RandGenesis(t, asset.Collectible) + scriptKey := test.RandPubKey(t) + proof := randomProof(t, genesis, scriptKey, oddTxBlock, 0, 1) + file, err := NewFile(V0, proof, proof) require.NoError(t, err) proof.AdditionalInputs = []File{*file, *file} @@ -750,6 +759,12 @@ func TestProofVerification(t *testing.T) { require.NoError(t, p.Asset.Encode(&buf)) t.Logf("Proof asset encoded: %x", buf.Bytes()) + ta := asset.NewTestFromAsset(t, &p.Asset) + assetJSON, err := json.Marshal(ta) + require.NoError(t, err) + + t.Logf("Proof asset JSON: %s", assetJSON) + // Ensure that verification of a proof of unknown version fails. p.Version = TransitionVersion(212) diff --git a/rpcserver.go b/rpcserver.go index ac2809820..eecdf0ee2 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -9,7 +9,6 @@ import ( "fmt" "math" "net/http" - "strconv" "strings" "sync" "sync/atomic" @@ -30,7 +29,6 @@ import ( "github.com/lightninglabs/taproot-assets/mssmt" "github.com/lightninglabs/taproot-assets/proof" "github.com/lightninglabs/taproot-assets/rpcperms" - "github.com/lightninglabs/taproot-assets/tapdb" "github.com/lightninglabs/taproot-assets/tapfreighter" "github.com/lightninglabs/taproot-assets/tapgarden" "github.com/lightninglabs/taproot-assets/tappsbt" @@ -723,7 +721,7 @@ func (r *rpcServer) fetchRpcAssets(ctx context.Context, withWitness, return rpcAssets, nil } -func (r *rpcServer) marshalChainAsset(ctx context.Context, a *tapdb.ChainAsset, +func (r *rpcServer) marshalChainAsset(ctx context.Context, a *asset.ChainAsset, withWitness bool) (*taprpc.Asset, error) { rpcAsset, err := taprpc.MarshalAsset( @@ -1388,7 +1386,7 @@ func (r *rpcServer) marshalProof(ctx context.Context, p *proof.Proof, } } - rpcAsset, err := r.marshalChainAsset(ctx, &tapdb.ChainAsset{ + rpcAsset, err := r.marshalChainAsset(ctx, &asset.ChainAsset{ Asset: &p.Asset, AnchorTx: &p.AnchorTx, AnchorBlockHash: p.BlockHeader.BlockHash(), @@ -1477,12 +1475,32 @@ func (r *rpcServer) ExportProof(ctx context.Context, return nil, fmt.Errorf("asset ID must be 32 bytes") } - var assetID asset.ID + var ( + assetID asset.ID + outPoint *wire.OutPoint + ) copy(assetID[:], req.AssetId) + // The outpoint is optional when querying for a proof file. But if + // multiple proofs exist for the same assetID and script key, then an + // error will be returned and the outpoint needs to be specified to + // disambiguate. + if req.Outpoint != nil { + txid, err := chainhash.NewHash(req.Outpoint.Txid) + if err != nil { + return nil, fmt.Errorf("error parsing outpoint: %w", + err) + } + outPoint = &wire.OutPoint{ + Hash: *txid, + Index: req.Outpoint.OutputIndex, + } + } + proofBlob, err := r.cfg.ProofArchive.FetchProof(ctx, proof.Locator{ AssetID: &assetID, ScriptKey: *scriptKey, + OutPoint: outPoint, }) if err != nil { return nil, err @@ -1505,14 +1523,34 @@ func (r *rpcServer) ImportProof(ctx context.Context, return nil, fmt.Errorf("proof file must be specified") } + // We need to parse the proof file and extract the last proof, so we can + // get the locator that is required for storage. + var proofFile proof.File + err := proofFile.Decode(bytes.NewReader(req.ProofFile)) + if err != nil { + return nil, fmt.Errorf("unable to decode proof file: %w", err) + } + + lastProof, err := proofFile.LastProof() + if err != nil { + return nil, fmt.Errorf("error extracting last proof: %w", err) + } + headerVerifier := tapgarden.GenHeaderVerifier(ctx, r.cfg.ChainBridge) groupVerifier := tapgarden.GenGroupVerifier(ctx, r.cfg.MintingStore) // Now that we know the proof file is at least present, we'll attempt // to import it into the main archive. - err := r.cfg.ProofArchive.ImportProofs( + err = r.cfg.ProofArchive.ImportProofs( ctx, headerVerifier, groupVerifier, false, - &proof.AnnotatedProof{Blob: req.ProofFile}, + &proof.AnnotatedProof{ + Locator: proof.Locator{ + AssetID: fn.Ptr(lastProof.Asset.ID()), + ScriptKey: *lastProof.Asset.ScriptKey.PubKey, + OutPoint: fn.Ptr(lastProof.OutPoint()), + }, + Blob: req.ProofFile, + }, ) if err != nil { return nil, err @@ -3421,34 +3459,6 @@ func (r *rpcServer) AssetLeaves(ctx context.Context, return resp, nil } -// UnmarshalOutpoint un-marshals an outpoint from a string received via RPC. -func UnmarshalOutpoint(outpoint string) (*wire.OutPoint, error) { - parts := strings.Split(outpoint, ":") - if len(parts) != 2 { - return nil, errors.New("outpoint should be of form txid:index") - } - - txidStr := parts[0] - if hex.DecodedLen(len(txidStr)) != chainhash.HashSize { - return nil, fmt.Errorf("invalid hex-encoded txid %v", txidStr) - } - - txid, err := chainhash.NewHashFromStr(txidStr) - if err != nil { - return nil, err - } - - outputIndex, err := strconv.Atoi(parts[1]) - if err != nil { - return nil, fmt.Errorf("invalid output index: %v", err) - } - - return &wire.OutPoint{ - Hash: *txid, - Index: uint32(outputIndex), - }, nil -} - // unmarshalLeafKey un-marshals a leaf key from the RPC form. func unmarshalLeafKey(key *unirpc.AssetKey) (universe.LeafKey, error) { var ( @@ -3491,8 +3501,7 @@ func unmarshalLeafKey(key *unirpc.AssetKey) (universe.LeafKey, error) { case key.GetOpStr() != "": // Parse a bitcoin outpoint in the form txid:index into a // wire.OutPoint struct. - outpointStr := key.GetOpStr() - outpoint, err := UnmarshalOutpoint(outpointStr) + outpoint, err := wire.NewOutPointFromString(key.GetOpStr()) if err != nil { return leafKey, err } @@ -4136,10 +4145,31 @@ func (r *rpcServer) ProveAssetOwnership(ctx context.Context, return nil, fmt.Errorf("asset ID must be 32 bytes") } - assetID := fn.ToArray[asset.ID](req.AssetId) + var ( + assetID = fn.ToArray[asset.ID](req.AssetId) + outPoint *wire.OutPoint + ) + + // The outpoint is optional when querying for a proof file. But if + // multiple proofs exist for the same assetID and script key, then an + // error will be returned and the outpoint needs to be specified to + // disambiguate. + if req.Outpoint != nil { + txid, err := chainhash.NewHash(req.Outpoint.Txid) + if err != nil { + return nil, fmt.Errorf("error parsing outpoint: %w", + err) + } + outPoint = &wire.OutPoint{ + Hash: *txid, + Index: req.Outpoint.OutputIndex, + } + } + proofBlob, err := r.cfg.ProofArchive.FetchProof(ctx, proof.Locator{ AssetID: &assetID, ScriptKey: *scriptKey, + OutPoint: outPoint, }) if err != nil { return nil, fmt.Errorf("cannot fetch proof: %w", err) diff --git a/tapcfg/server.go b/tapcfg/server.go index 862de4653..8c06e2ccf 100644 --- a/tapcfg/server.go +++ b/tapcfg/server.go @@ -12,7 +12,6 @@ import ( tap "github.com/lightninglabs/taproot-assets" "github.com/lightninglabs/taproot-assets/address" "github.com/lightninglabs/taproot-assets/asset" - "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/proof" "github.com/lightninglabs/taproot-assets/tapdb" "github.com/lightninglabs/taproot-assets/tapdb/sqlc" @@ -238,22 +237,13 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger, ), ProofArchive: proofArchive, NonBuriedAssetFetcher: func(ctx context.Context, - minHeight int32) ([]*asset.Asset, error) { + minHeight int32) ([]*asset.ChainAsset, error) { - assets, err := assetStore.FetchAllAssets( + return assetStore.FetchAllAssets( ctx, false, true, &tapdb.AssetQueryFilters{ MinAnchorHeight: minHeight, }, ) - if err != nil { - return nil, err - } - - return fn.Map( - assets, func(a *tapdb.ChainAsset) *asset.Asset { - return a.Asset - }, - ), nil }, SafeDepth: cfg.ReOrgSafeDepth, ErrChan: mainErrChan, @@ -325,6 +315,7 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger, HashMailCfg: cfg.HashMailCourier, UniverseRpcCfg: cfg.UniverseRpcCourier, TransferLog: assetStore, + LocalArchive: proofArchive, }) multiNotifier := proof.NewMultiArchiveNotifier(assetStore, multiverse) diff --git a/tapdb/addrs.go b/tapdb/addrs.go index 3e243d94b..f16803e96 100644 --- a/tapdb/addrs.go +++ b/tapdb/addrs.go @@ -20,6 +20,7 @@ import ( "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/commitment" "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/proof" "github.com/lightninglabs/taproot-assets/tapdb/sqlc" "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/keychain" @@ -127,8 +128,8 @@ type AddrBook interface { // FetchAssetProof fetches the asset proof for a given asset identified // by its script key. - FetchAssetProof(ctx context.Context, scriptKey []byte) (AssetProofI, - error) + FetchAssetProof(ctx context.Context, + arg FetchAssetProof) ([]AssetProofI, error) // FetchGenesisByAssetID attempts to fetch asset genesis information // for a given asset ID. @@ -887,15 +888,39 @@ func (t *TapAddressBook) CompleteEvent(ctx context.Context, event *address.Event, status address.Status, anchorPoint wire.OutPoint) error { - scriptKeyBytes := event.Addr.ScriptKey.SerializeCompressed() + outpoint, err := encodeOutpoint(anchorPoint) + if err != nil { + return fmt.Errorf("unable to encode outpoint: %w", err) + } + + args := FetchAssetProof{ + TweakedScriptKey: event.Addr.ScriptKey.SerializeCompressed(), + Outpoint: outpoint, + } var writeTxOpts AddrBookTxOptions return t.db.ExecTx(ctx, &writeTxOpts, func(db AddrBook) error { - proofData, err := db.FetchAssetProof(ctx, scriptKeyBytes) + proofData, err := db.FetchAssetProof(ctx, args) if err != nil { return fmt.Errorf("error fetching asset proof: %w", err) } + switch { + // We have no proof for this script key and outpoint. + case len(proofData) == 0: + return fmt.Errorf("proof for script key %x and "+ + "outpoint %v not found: %w", + args.TweakedScriptKey, anchorPoint, + proof.ErrProofNotFound) + + // Something is quite wrong if we have multiple proofs for the + // same script key and outpoint. + case len(proofData) > 1: + return fmt.Errorf("expected exactly one proof, got "+ + "%d: %w", len(proofData), + proof.ErrMultipleProofs) + } + _, err = db.UpsertAddrEvent(ctx, UpsertAddrEvent{ TaprootOutputKey: schnorr.SerializePubKey( &event.Addr.TaprootOutputKey, @@ -903,8 +928,8 @@ func (t *TapAddressBook) CompleteEvent(ctx context.Context, Status: int16(status), Txid: anchorPoint.Hash[:], ChainTxnOutputIndex: int32(anchorPoint.Index), - AssetProofID: sqlInt64(proofData.ProofID), - AssetID: sqlInt64(proofData.AssetID), + AssetProofID: sqlInt64(proofData[0].ProofID), + AssetID: sqlInt64(proofData[0].AssetID), }) return err }) diff --git a/tapdb/asset_minting.go b/tapdb/asset_minting.go index de20ea173..967999acf 100644 --- a/tapdb/asset_minting.go +++ b/tapdb/asset_minting.go @@ -109,6 +109,10 @@ type ( // ProofUpdate is used to update a proof file on disk. ProofUpdate = sqlc.UpsertAssetProofParams + // ProofUpdateByID is used to update a proof file on disk by asset + // database ID. + ProofUpdateByID = sqlc.UpsertAssetProofByIDParams + // NewScriptKey wraps the params needed to insert a new script key on // disk. NewScriptKey = sqlc.UpsertScriptKeyParams diff --git a/tapdb/asset_minting_test.go b/tapdb/asset_minting_test.go index d3486abc0..b6776e58d 100644 --- a/tapdb/asset_minting_test.go +++ b/tapdb/asset_minting_test.go @@ -752,17 +752,17 @@ func TestCommitBatchChainActions(t *testing.T) { // Count the number of assets with a group key. Each grouped asset // should have a grouped genesis witness. - groupCount := fn.Count(assets, func(a *ChainAsset) bool { + groupCount := fn.Count(assets, func(a *asset.ChainAsset) bool { return a.GroupKey != nil }) - groupWitnessCount := fn.Count(assets, func(a *ChainAsset) bool { + groupWitnessCount := fn.Count(assets, func(a *asset.ChainAsset) bool { return a.HasGenesisWitnessForGroup() }) require.Equal(t, groupCount, groupWitnessCount) // All the assets returned should have the genesis prev ID set up. ungroupedCount := len(assets) - groupCount - genesisWitnessCount := fn.Count(assets, func(a *ChainAsset) bool { + genesisWitnessCount := fn.Count(assets, func(a *asset.ChainAsset) bool { return a.HasGenesisWitness() }) require.Equal(t, ungroupedCount, genesisWitnessCount) @@ -770,7 +770,7 @@ func TestCommitBatchChainActions(t *testing.T) { // All the assets should also have a matching asset version as the // seedlings we created. mintingBatch := randAssetCtx.mintingBatch - require.True(t, fn.All(assets, func(dbAsset *ChainAsset) bool { + require.True(t, fn.All(assets, func(dbAsset *asset.ChainAsset) bool { seedling, ok := mintingBatch.Seedlings[dbAsset.Genesis.Tag] if !ok { t.Logf("seedling for %v not found", @@ -796,15 +796,17 @@ func TestCommitBatchChainActions(t *testing.T) { // If we look up all the proofs by their specific script key, we should // get the same set of proofs. - scriptKeys := fMapKeys( - assetProofs, func(k asset.SerializedKey) *btcec.PublicKey { - parsed, err := btcec.ParsePubKey(k.CopyBytes()) + proofLocators := fMapKeys( + assetProofs, func(k asset.SerializedKey) proof.Locator { + parsedScriptKey, err := btcec.ParsePubKey(k.CopyBytes()) require.NoError(t, err) - return parsed + return proof.Locator{ + ScriptKey: *parsedScriptKey, + } }, ) - diskProofs, err = confAssets.FetchAssetProofs(ctx, scriptKeys...) + diskProofs, err = confAssets.FetchAssetProofs(ctx, proofLocators...) require.NoError(t, err) require.Equal(t, assetProofs, diskProofs) diff --git a/tapdb/assets_store.go b/tapdb/assets_store.go index 606622601..1e6101747 100644 --- a/tapdb/assets_store.go +++ b/tapdb/assets_store.go @@ -45,13 +45,16 @@ type ( // where the proofs for a specific asset are fetched. AssetProofI = sqlc.FetchAssetProofRow + // FetchAssetProof are the query parameters for fetching an asset proof. + FetchAssetProof = sqlc.FetchAssetProofParams + // AssetProofByIDRow is the asset proof for a given asset, identified by // its asset ID. AssetProofByIDRow = sqlc.FetchAssetProofsByAssetIDRow // PrevInput stores the full input information including the prev out, // and also the witness information itself. - PrevInput = sqlc.InsertAssetWitnessParams + PrevInput = sqlc.UpsertAssetWitnessParams // AssetWitness is the full prev input for an asset that also couples // along the asset ID that the witness belong to. @@ -173,7 +176,7 @@ type ActiveAssetsStore interface { // FetchAssetProof fetches the asset proof for a given asset identified // by its script key. FetchAssetProof(ctx context.Context, - scriptKey []byte) (AssetProofI, error) + arg FetchAssetProof) ([]AssetProofI, error) // HasAssetProof returns true if we have proof for a given asset // identified by its script key. @@ -198,12 +201,15 @@ type ActiveAssetsStore interface { // UpsertAssetProof inserts a new or updates an existing asset proof on // disk. - UpsertAssetProof(ctx context.Context, - arg sqlc.UpsertAssetProofParams) error + UpsertAssetProof(ctx context.Context, arg ProofUpdate) error + + // UpsertAssetProofByID inserts a new or updates an existing asset + // proof on disk. + UpsertAssetProofByID(ctx context.Context, arg ProofUpdateByID) error - // InsertAssetWitness inserts a new prev input for an asset into the + // UpsertAssetWitness upserts a new prev input for an asset into the // database. - InsertAssetWitness(context.Context, PrevInput) error + UpsertAssetWitness(context.Context, PrevInput) error // FetchAssetWitnesses attempts to fetch either all the asset witnesses // on disk (NULL param), or the witness for a given asset ID. @@ -355,56 +361,6 @@ func NewAssetStore(db BatchedAssetStore, clock clock.Clock) *AssetStore { } } -// ChainAsset is a wrapper around the base asset struct that includes -// information detailing where in the chain the asset is currently anchored. -type ChainAsset struct { - *asset.Asset - - // IsSpent indicates whether the above asset was previously spent. - IsSpent bool - - // AnchorTx is the transaction that anchors this chain asset. - AnchorTx *wire.MsgTx - - // AnchorBlockHash is the blockhash that mined the anchor tx. - AnchorBlockHash chainhash.Hash - - // AnchorBlockHeight is the height of the block that mined the anchor - // tx. - AnchorBlockHeight uint32 - - // AnchorOutpoint is the outpoint that commits to the asset. - AnchorOutpoint wire.OutPoint - - // AnchorInternalKey is the raw internal key that was used to create the - // anchor Taproot output key. - AnchorInternalKey *btcec.PublicKey - - // AnchorMerkleRoot is the Taproot merkle root hash of the anchor output - // the asset was committed to. If there is no Tapscript sibling, this is - // equal to the Taproot Asset root commitment hash. - AnchorMerkleRoot []byte - - // AnchorTapscriptSibling is the serialized preimage of a Tapscript - // sibling, if there was one. If this is empty, then the - // AnchorTapscriptSibling hash is equal to the Taproot root hash of the - // anchor output. - AnchorTapscriptSibling []byte - - // AnchorLeaseOwner is the identity of the application that currently - // has a lease on this UTXO. If empty/nil, then the UTXO is not - // currently leased. A lease means that the UTXO is being - // reserved/locked to be spent in an upcoming transaction and that it - // should not be available for coin selection through any of the wallet - // RPCs. - AnchorLeaseOwner [32]byte - - // AnchorLeaseExpiry is the expiry of the lease. If the expiry is nil or - // the time is in the past, then the lease is not valid and the UTXO is - // available for coin selection. - AnchorLeaseExpiry *time.Time -} - // ManagedUTXO holds information about a given UTXO we manage. type ManagedUTXO struct { // OutPoint is the outpoint of the UTXO. @@ -565,9 +521,9 @@ func parseAssetWitness(input AssetWitness) (asset.Witness, error) { // the witnesses of those assets to a set of normal ChainAsset structs needed // by a higher level application. func (a *AssetStore) dbAssetsToChainAssets(dbAssets []ConfirmedAsset, - witnesses assetWitnesses) ([]*ChainAsset, error) { + witnesses assetWitnesses) ([]*asset.ChainAsset, error) { - chainAssets := make([]*ChainAsset, len(dbAssets)) + chainAssets := make([]*asset.ChainAsset, len(dbAssets)) for i := range dbAssets { sprout := dbAssets[i] @@ -758,7 +714,7 @@ func (a *AssetStore) dbAssetsToChainAssets(dbAssets []ConfirmedAsset, "internal key: %w", err) } - chainAssets[i] = &ChainAsset{ + chainAssets[i] = &asset.ChainAsset{ Asset: assetSprout, IsSpent: sprout.Spent, AnchorTx: anchorTx, @@ -1048,7 +1004,8 @@ func (a *AssetStore) FetchGroupedAssets(ctx context.Context) ( // FetchAllAssets fetches the set of confirmed assets stored on disk. func (a *AssetStore) FetchAllAssets(ctx context.Context, includeSpent, - includeLeased bool, query *AssetQueryFilters) ([]*ChainAsset, error) { + includeLeased bool, query *AssetQueryFilters) ([]*asset.ChainAsset, + error) { var ( dbAssets []ConfirmedAsset @@ -1149,7 +1106,7 @@ func (a *AssetStore) FetchManagedUTXOs(ctx context.Context) ( // TODO(roasbeef): potentially have a version that writes thru a reader // instead? func (a *AssetStore) FetchAssetProofs(ctx context.Context, - targetAssets ...*btcec.PublicKey) (proof.AssetBlobs, error) { + targetAssets ...proof.Locator) (proof.AssetBlobs, error) { proofs := make(proof.AssetBlobs) @@ -1182,19 +1139,32 @@ func (a *AssetStore) FetchAssetProofs(ctx context.Context, // TODO(roasbeef): can modify the query to use IN somewhere // instead? then would take input params and insert into // virtual rows to use - for _, scriptKey := range targetAssets { - scriptKey := scriptKey - serializedKey := asset.ToSerialized(scriptKey) + for _, locator := range targetAssets { + args, err := locatorToProofQuery(locator) + if err != nil { + return err + } - assetProof, err := q.FetchAssetProof( - ctx, serializedKey[:], - ) + assetProofs, err := q.FetchAssetProof(ctx, args) if err != nil { return fmt.Errorf("unable to fetch asset "+ "proof: %w", err) } - proofs[serializedKey] = assetProof.ProofFile + switch { + // We have no proof for this script key. + case len(assetProofs) == 0: + return proof.ErrProofNotFound + + // Something went wrong, presumably because the outpoint + // was not specified in the locator, and we got multiple + // proofs. + case len(assetProofs) > 1: + return proof.ErrMultipleProofs + } + + serializedKey := asset.ToSerialized(&locator.ScriptKey) + proofs[serializedKey] = assetProofs[0].ProofFile } return nil }) @@ -1208,29 +1178,48 @@ func (a *AssetStore) FetchAssetProofs(ctx context.Context, // FetchProof fetches a proof for an asset uniquely identified by the passed // ProofIdentifier. // +// If a proof cannot be found, then ErrProofNotFound should be returned. If +// multiple proofs exist for the given fields of the locator then +// ErrMultipleProofs is returned to indicate more specific fields need to be set +// in the Locator (e.g. the OutPoint). +// // NOTE: This implements the proof.Archiver interface. func (a *AssetStore) FetchProof(ctx context.Context, locator proof.Locator) (proof.Blob, error) { - // We don't need anything else but the script key since we have an - // on-disk index for all proofs we store. - scriptKey := locator.ScriptKey + args, err := locatorToProofQuery(locator) + if err != nil { + return nil, err + } var diskProof proof.Blob readOpts := NewAssetStoreReadTx() dbErr := a.db.ExecTx(ctx, &readOpts, func(q ActiveAssetsStore) error { - assetProof, err := q.FetchAssetProof( - ctx, scriptKey.SerializeCompressed(), - ) + assetProofs, err := q.FetchAssetProof(ctx, args) if err != nil { - return fmt.Errorf("unable to fetch asset "+ - "proof: %w", err) + return fmt.Errorf("unable to fetch asset proof: %w", + err) } - diskProof = assetProof.ProofFile + switch { + // We have no proof for this script key. + case len(assetProofs) == 0: + return proof.ErrProofNotFound - return nil + // If the query without the outpoint returns exactly one proof + // then we're fine. If there actually are multiple proofs, we + // require the user to specify the outpoint as well. + case len(assetProofs) == 1: + diskProof = assetProofs[0].ProofFile + + return nil + + // User needs to specify the outpoint as well, since we have + // multiple proofs for this script key. + default: + return proof.ErrMultipleProofs + } }) switch { case errors.Is(dbErr, sql.ErrNoRows): @@ -1242,6 +1231,30 @@ func (a *AssetStore) FetchProof(ctx context.Context, return diskProof, nil } +// locatorToProofQuery turns a proof locator into a FetchAssetProof query +// struct. +func locatorToProofQuery(locator proof.Locator) (FetchAssetProof, error) { + // We have an on-disk index for all proofs we store, so we can use the + // script key as the primary identifier. + args := FetchAssetProof{ + TweakedScriptKey: locator.ScriptKey.SerializeCompressed(), + } + + // But script keys aren't unique, so if the locator explicitly specifies + // an outpoint, we'll use that as well. + if locator.OutPoint != nil { + outpoint, err := encodeOutpoint(*locator.OutPoint) + if err != nil { + return args, fmt.Errorf("unable to encode outpoint: %w", + err) + } + + args.Outpoint = outpoint + } + + return args, nil +} + // HasProof returns true if the proof for the given locator exists. This is // intended to be a performance optimized lookup compared to fetching a proof // and checking for ErrProofNotFound. @@ -1304,10 +1317,26 @@ func (a *AssetStore) FetchProofs(ctx context.Context, "script key: %w", err) } + f := proof.File{} + err = f.Decode(bytes.NewReader(dbRow.ProofFile)) + if err != nil { + return nil, fmt.Errorf("error "+ + "decoding proof file: %w", err) + } + + lastProof, err := f.LastProof() + if err != nil { + return nil, fmt.Errorf("error "+ + "decoding last proof: %w", err) + } + return &proof.AnnotatedProof{ Locator: proof.Locator{ AssetID: &id, ScriptKey: *scriptKey, + OutPoint: fn.Ptr( + lastProof.OutPoint(), + ), }, Blob: dbRow.ProofFile, }, nil @@ -1331,8 +1360,6 @@ func (a *AssetStore) FetchProofs(ctx context.Context, // insertAssetWitnesses attempts to insert the set of asset witnesses in to the // database, referencing the passed asset primary key. -// -// TODO(ffranr): Change insert function into an upsert. func (a *AssetStore) insertAssetWitnesses(ctx context.Context, db ActiveAssetsStore, assetID int64, inputs []asset.Witness) error { @@ -1375,13 +1402,14 @@ func (a *AssetStore) insertAssetWitnesses(ctx context.Context, copy(splitCommitmentProof, b.Bytes()) } - err = db.InsertAssetWitness(ctx, PrevInput{ + err = db.UpsertAssetWitness(ctx, PrevInput{ AssetID: assetID, PrevOutPoint: prevOutpoint, PrevAssetID: prevID.ID[:], PrevScriptKey: prevID.ScriptKey.CopyBytes(), WitnessStack: witnessStack, SplitCommitmentProof: splitCommitmentProof, + WitnessIndex: int32(idx), }) if err != nil { return fmt.Errorf("unable to insert witness: %v", err) @@ -1500,6 +1528,7 @@ func (a *AssetStore) importAssetFromProof(ctx context.Context, scriptKeyBytes := newAsset.ScriptKey.PubKey.SerializeCompressed() return db.UpsertAssetProof(ctx, ProofUpdate{ TweakedScriptKey: scriptKeyBytes, + Outpoint: anchorPoint, ProofFile: proof.Blob, }) } @@ -1532,11 +1561,20 @@ func (a *AssetStore) upsertAssetProof(ctx context.Context, return fmt.Errorf("unable to insert chain tx: %w", err) } + outpointBytes, err := encodeOutpoint(wire.OutPoint{ + Hash: anchorTXID, + Index: proof.OutputIndex, + }) + if err != nil { + return err + } + // As a final step, we'll insert the proof file we used to generate all // the above information. scriptKeyBytes := proof.Asset.ScriptKey.PubKey.SerializeCompressed() return db.UpsertAssetProof(ctx, ProofUpdate{ TweakedScriptKey: scriptKeyBytes, + Outpoint: outpointBytes, ProofFile: proof.Blob, }) } @@ -1546,9 +1584,9 @@ func (a *AssetStore) upsertAssetProof(ctx context.Context, // The final resting place of the asset will be used as the script key itself. // // NOTE: This implements the proof.ArchiveBackend interface. -func (a *AssetStore) ImportProofs(ctx context.Context, - headerVerifier proof.HeaderVerifier, groupVerifier proof.GroupVerifier, - replace bool, proofs ...*proof.AnnotatedProof) error { +func (a *AssetStore) ImportProofs(ctx context.Context, _ proof.HeaderVerifier, + _ proof.GroupVerifier, replace bool, + proofs ...*proof.AnnotatedProof) error { var writeTxOpts AssetStoreTxOptions err := a.db.ExecTx(ctx, &writeTxOpts, func(q ActiveAssetsStore) error { @@ -1628,7 +1666,7 @@ func (a *AssetStore) RemoveSubscriber( // queryChainAssets queries the database for assets matching the passed filter. // The returned assets have all anchor and witness information populated. func (a *AssetStore) queryChainAssets(ctx context.Context, q ActiveAssetsStore, - filter QueryAssetFilters) ([]*ChainAsset, error) { + filter QueryAssetFilters) ([]*asset.ChainAsset, error) { dbAssets, assetWitnesses, err := fetchAssetsWithWitness( ctx, q, filter, @@ -1791,10 +1829,12 @@ func (a *AssetStore) queryCommitments(ctx context.Context, error) { var ( - matchingAssets []*ChainAsset - chainAnchorToAssets = make(map[wire.OutPoint][]*ChainAsset) - anchorPoints = make(map[wire.OutPoint]AnchorPoint) - err error + matchingAssets []*asset.ChainAsset + chainAnchorToAssets = make( + map[wire.OutPoint][]*asset.ChainAsset, + ) + anchorPoints = make(map[wire.OutPoint]AnchorPoint) + err error ) readOpts := NewAssetStoreReadTx() @@ -1875,7 +1915,7 @@ func (a *AssetStore) queryCommitments(ctx context.Context, // Fetch the asset leaves from each chain asset, and then // build a Taproot Asset commitment from this set of assets. - fetchAsset := func(cAsset *ChainAsset) *asset.Asset { + fetchAsset := func(cAsset *asset.ChainAsset) *asset.Asset { return cAsset.Asset } @@ -2604,6 +2644,7 @@ func (a *AssetStore) ConfirmParcelDelivery(ctx context.Context, // this given delta. err = q.UpsertAssetProof(ctx, ProofUpdate{ TweakedScriptKey: out.ScriptKeyBytes, + Outpoint: out.AnchorOutpoint, ProofFile: receiverProof.Blob, }) if err != nil { @@ -2655,9 +2696,12 @@ func (a *AssetStore) ConfirmParcelDelivery(ctx context.Context, finalProof := conf.FinalProofs[localKey] a.eventDistributor.NotifySubscribers(finalProof.Blob) } - for idx := range conf.PassiveAssetProofFiles { - passiveProof := conf.PassiveAssetProofFiles[idx] - a.eventDistributor.NotifySubscribers(passiveProof) + for assetID := range conf.PassiveAssetProofFiles { + passiveProofs := conf.PassiveAssetProofFiles[assetID] + for idx := range passiveProofs { + passiveProof := passiveProofs[idx] + a.eventDistributor.NotifySubscribers(passiveProof.Blob) + } } return nil @@ -2667,7 +2711,7 @@ func (a *AssetStore) ConfirmParcelDelivery(ctx context.Context, // the given transfer output. func (a *AssetStore) reAnchorPassiveAssets(ctx context.Context, q ActiveAssetsStore, transferID int64, - proofFiles map[[32]byte]proof.Blob) error { + proofFiles map[asset.ID][]*proof.AnnotatedProof) error { passiveAssets, err := q.QueryPassiveAssets(ctx, transferID) if err != nil { @@ -2686,18 +2730,20 @@ func (a *AssetStore) reAnchorPassiveAssets(ctx context.Context, return fmt.Errorf("failed to parse script key: %w", err) } - // Fetch the proof file for this asset. - locator := proof.Locator{ - AssetID: &assetID, - ScriptKey: *scriptKey, - } - locatorHash, err := locator.Hash() - if err != nil { - return fmt.Errorf("failed to hash locator: %w", err) + var proofFile proof.Blob + for _, f := range proofFiles[assetID] { + // Check if this proof is for the script key of the + // passive asset. + if f.Locator.ScriptKey == *scriptKey { + proofFile = f.Blob + + break + } } - proofFile := proofFiles[locatorHash] - if proofFile == nil { + // Something wasn't mapped correctly, we should've found a proof + // for each passive asset. + if len(proofFile) == 0 { return fmt.Errorf("failed to find proof file for " + "passive asset") } @@ -2728,8 +2774,8 @@ func (a *AssetStore) reAnchorPassiveAssets(ctx context.Context, } // Update the asset proof. - err = q.UpsertAssetProof(ctx, ProofUpdate{ - AssetID: sqlInt64(passiveAsset.AssetID), + err = q.UpsertAssetProofByID(ctx, ProofUpdateByID{ + AssetID: passiveAsset.AssetID, ProofFile: proofFile, }) if err != nil { diff --git a/tapdb/assets_store_test.go b/tapdb/assets_store_test.go index 82c607300..91c85da73 100644 --- a/tapdb/assets_store_test.go +++ b/tapdb/assets_store_test.go @@ -320,6 +320,14 @@ func TestImportAssetProof(t *testing.T) { require.NoError(t, err) require.Equal(t, updatedBlob, []byte(currentBlob)) + // Make sure we get the same result if we also query by proof outpoint. + currentBlob, err = assetStore.FetchProof(ctxb, proof.Locator{ + ScriptKey: *testAsset.ScriptKey.PubKey, + OutPoint: &testProof.AssetSnapshot.OutPoint, + }) + require.NoError(t, err) + require.Equal(t, updatedBlob, []byte(currentBlob)) + // Make sure the chain TX was updated as well. assets, err = assetStore.FetchAllAssets(ctxb, false, false, nil) require.NoError(t, err) @@ -337,6 +345,45 @@ func TestImportAssetProof(t *testing.T) { t, testProof.AssetSnapshot.OutPoint, dbAsset.AnchorOutpoint, ) require.Equal(t, testProof.AnchorTx.TxHash(), dbAsset.AnchorTx.TxHash()) + + // We now add a second proof for the same script key but a different + // outpoint and expect that to be stored and retrieved correctly. + oldOutpoint := testProof.AssetSnapshot.OutPoint + newChainTx := wire.NewMsgTx(2) + newChainTx.TxIn = []*wire.TxIn{{ + PreviousOutPoint: test.RandOp(t), + }} + newChainTx.TxOut = []*wire.TxOut{{ + PkScript: bytes.Repeat([]byte{0x01}, 34), + }} + newOutpoint := wire.OutPoint{ + Hash: newChainTx.TxHash(), + Index: 0, + } + testProof.AssetSnapshot.AnchorTx = newChainTx + testProof.AssetSnapshot.OutPoint = newOutpoint + testProof.Blob = []byte("new proof") + + require.NoError(t, assetStore.ImportProofs( + ctxb, proof.MockHeaderVerifier, proof.MockGroupVerifier, false, + testProof, + )) + + // We should still be able to fetch the old proof. + dbBlob, err := assetStore.FetchProof(ctxb, proof.Locator{ + ScriptKey: *testAsset.ScriptKey.PubKey, + OutPoint: &oldOutpoint, + }) + require.NoError(t, err) + require.Equal(t, updatedBlob, []byte(dbBlob)) + + // But also the new one. + dbBlob, err = assetStore.FetchProof(ctxb, proof.Locator{ + ScriptKey: *testAsset.ScriptKey.PubKey, + OutPoint: &newOutpoint, + }) + require.NoError(t, err) + require.EqualValues(t, testProof.Blob, []byte(dbBlob)) } // TestInternalKeyUpsert tests that if we insert an internal key that's a @@ -1390,11 +1437,11 @@ func TestAssetExportLog(t *testing.T) { // As a final check for the asset, we'll fetch its blob to ensure it's // been updated on disk. - diskSenderBlob, err := db.FetchAssetProof( - ctx, newScriptKey.PubKey.SerializeCompressed(), - ) + diskSenderBlob, err := db.FetchAssetProof(ctx, FetchAssetProof{ + TweakedScriptKey: newScriptKey.PubKey.SerializeCompressed(), + }) require.NoError(t, err) - require.Equal(t, receiverBlob, diskSenderBlob.ProofFile) + require.Equal(t, receiverBlob, diskSenderBlob[0].ProofFile) // If we fetch the chain transaction again, then it should have the // conf information populated. diff --git a/tapdb/multiverse.go b/tapdb/multiverse.go index edc62cb07..c5468ab91 100644 --- a/tapdb/multiverse.go +++ b/tapdb/multiverse.go @@ -917,7 +917,9 @@ func (b *MultiverseStore) FetchProof(ctx context.Context, return proofs[0].Leaf.RawProof, nil } - file, err := proof.FetchProofProvenance(ctx, originLocator, fetchProof) + file, err := proof.FetchProofProvenance( + ctx, nil, originLocator, fetchProof, + ) if err != nil { return nil, fmt.Errorf("error fetching proof from archive: %w", err) diff --git a/tapdb/sqlc/assets.sql.go b/tapdb/sqlc/assets.sql.go index a89066174..ee8673026 100644 --- a/tapdb/sqlc/assets.sql.go +++ b/tapdb/sqlc/assets.sql.go @@ -506,38 +506,65 @@ func (q *Queries) FetchAssetMetaForAsset(ctx context.Context, assetID []byte) (F return i, err } -const fetchAssetProof = `-- name: FetchAssetProof :one +const fetchAssetProof = `-- name: FetchAssetProof :many WITH asset_info AS ( - SELECT assets.asset_id, script_keys.tweaked_script_key + SELECT assets.asset_id, script_keys.tweaked_script_key, utxos.outpoint FROM assets JOIN script_keys ON assets.script_key_id = script_keys.script_key_id - WHERE script_keys.tweaked_script_key = $1 + JOIN managed_utxos utxos + ON assets.anchor_utxo_id = utxos.utxo_id + WHERE script_keys.tweaked_script_key = $1 + AND (utxos.outpoint = $2 OR $2 IS NULL) ) SELECT asset_info.tweaked_script_key AS script_key, asset_proofs.proof_file, - asset_info.asset_id as asset_id, asset_proofs.proof_id as proof_id + asset_info.asset_id as asset_id, asset_proofs.proof_id as proof_id, + asset_info.outpoint as outpoint FROM asset_proofs JOIN asset_info - ON asset_info.asset_id = asset_proofs.asset_id + ON asset_info.asset_id = asset_proofs.asset_id ` +type FetchAssetProofParams struct { + TweakedScriptKey []byte + Outpoint []byte +} + type FetchAssetProofRow struct { ScriptKey []byte ProofFile []byte AssetID int64 ProofID int64 + Outpoint []byte } -func (q *Queries) FetchAssetProof(ctx context.Context, tweakedScriptKey []byte) (FetchAssetProofRow, error) { - row := q.db.QueryRowContext(ctx, fetchAssetProof, tweakedScriptKey) - var i FetchAssetProofRow - err := row.Scan( - &i.ScriptKey, - &i.ProofFile, - &i.AssetID, - &i.ProofID, - ) - return i, err +func (q *Queries) FetchAssetProof(ctx context.Context, arg FetchAssetProofParams) ([]FetchAssetProofRow, error) { + rows, err := q.db.QueryContext(ctx, fetchAssetProof, arg.TweakedScriptKey, arg.Outpoint) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FetchAssetProofRow + for rows.Next() { + var i FetchAssetProofRow + if err := rows.Scan( + &i.ScriptKey, + &i.ProofFile, + &i.AssetID, + &i.ProofID, + &i.Outpoint, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil } const fetchAssetProofs = `-- name: FetchAssetProofs :many @@ -635,6 +662,7 @@ JOIN assets WHERE ( (assets.asset_id = $1) OR ($1 IS NULL) ) +ORDER BY witness_index ` type FetchAssetWitnessesRow struct { @@ -1704,36 +1732,6 @@ func (q *Queries) InsertAssetSeedlingIntoBatch(ctx context.Context, arg InsertAs return err } -const insertAssetWitness = `-- name: InsertAssetWitness :exec -INSERT INTO asset_witnesses ( - asset_id, prev_out_point, prev_asset_id, prev_script_key, witness_stack, - split_commitment_proof -) VALUES ( - $1, $2, $3, $4, $5, $6 -) -` - -type InsertAssetWitnessParams struct { - AssetID int64 - PrevOutPoint []byte - PrevAssetID []byte - PrevScriptKey []byte - WitnessStack []byte - SplitCommitmentProof []byte -} - -func (q *Queries) InsertAssetWitness(ctx context.Context, arg InsertAssetWitnessParams) error { - _, err := q.db.ExecContext(ctx, insertAssetWitness, - arg.AssetID, - arg.PrevOutPoint, - arg.PrevAssetID, - arg.PrevScriptKey, - arg.WitnessStack, - arg.SplitCommitmentProof, - ) - return err -} - const insertNewAsset = `-- name: InsertNewAsset :one INSERT INTO assets ( genesis_id, version, script_key_id, asset_group_witness_id, script_version, @@ -2300,14 +2298,13 @@ WITH target_asset(asset_id) AS ( FROM assets JOIN script_keys ON assets.script_key_id = script_keys.script_key_id + JOIN managed_utxos utxos + ON assets.anchor_utxo_id = utxos.utxo_id WHERE (script_keys.tweaked_script_key = $2 - OR $2 IS NULL) - AND (assets.asset_id = $3 - OR $3 IS NULL) - -- TODO(guggero): Fix this by disallowing multiple assets with the same - -- script key! - LIMIT 1 + OR $2 IS NULL) + AND (utxos.outpoint = $3 + OR $3 IS NULL) ) INSERT INTO asset_proofs ( asset_id, proof_file @@ -2321,11 +2318,69 @@ INSERT INTO asset_proofs ( type UpsertAssetProofParams struct { ProofFile []byte TweakedScriptKey []byte - AssetID sql.NullInt64 + Outpoint []byte } func (q *Queries) UpsertAssetProof(ctx context.Context, arg UpsertAssetProofParams) error { - _, err := q.db.ExecContext(ctx, upsertAssetProof, arg.ProofFile, arg.TweakedScriptKey, arg.AssetID) + _, err := q.db.ExecContext(ctx, upsertAssetProof, arg.ProofFile, arg.TweakedScriptKey, arg.Outpoint) + return err +} + +const upsertAssetProofByID = `-- name: UpsertAssetProofByID :exec +INSERT INTO asset_proofs ( + asset_id, proof_file +) VALUES ( + $1, $2 +) ON CONFLICT (asset_id) + -- This is not a NOP, we always overwrite the proof with the new one. + DO UPDATE SET proof_file = EXCLUDED.proof_file +` + +type UpsertAssetProofByIDParams struct { + AssetID int64 + ProofFile []byte +} + +func (q *Queries) UpsertAssetProofByID(ctx context.Context, arg UpsertAssetProofByIDParams) error { + _, err := q.db.ExecContext(ctx, upsertAssetProofByID, arg.AssetID, arg.ProofFile) + return err +} + +const upsertAssetWitness = `-- name: UpsertAssetWitness :exec +INSERT INTO asset_witnesses ( + asset_id, prev_out_point, prev_asset_id, prev_script_key, witness_stack, + split_commitment_proof, witness_index +) VALUES ( + $1, $2, $3, $4, $5, $6, $7 +) ON CONFLICT (asset_id, witness_index) + -- We overwrite the witness with the new one. + DO UPDATE SET prev_out_point = EXCLUDED.prev_out_point, + prev_asset_id = EXCLUDED.prev_asset_id, + prev_script_key = EXCLUDED.prev_script_key, + witness_stack = EXCLUDED.witness_stack, + split_commitment_proof = EXCLUDED.split_commitment_proof +` + +type UpsertAssetWitnessParams struct { + AssetID int64 + PrevOutPoint []byte + PrevAssetID []byte + PrevScriptKey []byte + WitnessStack []byte + SplitCommitmentProof []byte + WitnessIndex int32 +} + +func (q *Queries) UpsertAssetWitness(ctx context.Context, arg UpsertAssetWitnessParams) error { + _, err := q.db.ExecContext(ctx, upsertAssetWitness, + arg.AssetID, + arg.PrevOutPoint, + arg.PrevAssetID, + arg.PrevScriptKey, + arg.WitnessStack, + arg.SplitCommitmentProof, + arg.WitnessIndex, + ) return err } diff --git a/tapdb/sqlc/migrations/000015_asset_witnesses.down.sql b/tapdb/sqlc/migrations/000015_asset_witnesses.down.sql new file mode 100644 index 000000000..9e487c47c --- /dev/null +++ b/tapdb/sqlc/migrations/000015_asset_witnesses.down.sql @@ -0,0 +1,2 @@ +DROP INDEX IF EXISTS asset_witnesses_asset_id_witness_index_unique; +ALTER TABLE asset_witnesses DROP COLUMN witness_index; diff --git a/tapdb/sqlc/migrations/000015_asset_witnesses.up.sql b/tapdb/sqlc/migrations/000015_asset_witnesses.up.sql new file mode 100644 index 000000000..4cb82f0c4 --- /dev/null +++ b/tapdb/sqlc/migrations/000015_asset_witnesses.up.sql @@ -0,0 +1,11 @@ +-- The witness index indicates the order of the witness in the list of witnesses +-- for a given asset. We didn't really support more than one witness before, so +-- the default value of 0 should be fine for all existing assets. +ALTER TABLE asset_witnesses ADD COLUMN witness_index INTEGER NOT NULL DEFAULT 0; + +-- We need to be able to upsert witnesses, so we need a unique constraint on +-- (asset_id, witness_index). +CREATE UNIQUE INDEX asset_witnesses_asset_id_witness_index_unique +ON asset_witnesses ( + asset_id, witness_index +); diff --git a/tapdb/sqlc/models.go b/tapdb/sqlc/models.go index 26eef9b5d..3502246e1 100644 --- a/tapdb/sqlc/models.go +++ b/tapdb/sqlc/models.go @@ -139,6 +139,7 @@ type AssetWitness struct { PrevScriptKey []byte WitnessStack []byte SplitCommitmentProof []byte + WitnessIndex int32 } type AssetsMetum struct { diff --git a/tapdb/sqlc/querier.go b/tapdb/sqlc/querier.go index 71fad7803..a90619e3e 100644 --- a/tapdb/sqlc/querier.go +++ b/tapdb/sqlc/querier.go @@ -41,7 +41,7 @@ type Querier interface { FetchAssetMeta(ctx context.Context, metaID int64) (FetchAssetMetaRow, error) FetchAssetMetaByHash(ctx context.Context, metaDataHash []byte) (FetchAssetMetaByHashRow, error) FetchAssetMetaForAsset(ctx context.Context, assetID []byte) (FetchAssetMetaForAssetRow, error) - FetchAssetProof(ctx context.Context, tweakedScriptKey []byte) (FetchAssetProofRow, error) + FetchAssetProof(ctx context.Context, arg FetchAssetProofParams) ([]FetchAssetProofRow, error) FetchAssetProofs(ctx context.Context) ([]FetchAssetProofsRow, error) FetchAssetProofsByAssetID(ctx context.Context, assetID []byte) ([]FetchAssetProofsByAssetIDRow, error) FetchAssetWitnesses(ctx context.Context, assetID sql.NullInt64) ([]FetchAssetWitnessesRow, error) @@ -86,7 +86,6 @@ type Querier interface { InsertAssetTransfer(ctx context.Context, arg InsertAssetTransferParams) (int64, error) InsertAssetTransferInput(ctx context.Context, arg InsertAssetTransferInputParams) error InsertAssetTransferOutput(ctx context.Context, arg InsertAssetTransferOutputParams) error - InsertAssetWitness(ctx context.Context, arg InsertAssetWitnessParams) error InsertBranch(ctx context.Context, arg InsertBranchParams) error InsertCompactedLeaf(ctx context.Context, arg InsertCompactedLeafParams) error InsertLeaf(ctx context.Context, arg InsertLeafParams) error @@ -148,6 +147,8 @@ type Querier interface { UpsertAssetGroupWitness(ctx context.Context, arg UpsertAssetGroupWitnessParams) (int64, error) UpsertAssetMeta(ctx context.Context, arg UpsertAssetMetaParams) (int64, error) UpsertAssetProof(ctx context.Context, arg UpsertAssetProofParams) error + UpsertAssetProofByID(ctx context.Context, arg UpsertAssetProofByIDParams) error + UpsertAssetWitness(ctx context.Context, arg UpsertAssetWitnessParams) error UpsertChainTx(ctx context.Context, arg UpsertChainTxParams) (int64, error) UpsertFederationGlobalSyncConfig(ctx context.Context, arg UpsertFederationGlobalSyncConfigParams) error UpsertFederationProofSyncLog(ctx context.Context, arg UpsertFederationProofSyncLogParams) (int64, error) diff --git a/tapdb/sqlc/queries/assets.sql b/tapdb/sqlc/queries/assets.sql index 84a68ab5d..b602bba1d 100644 --- a/tapdb/sqlc/queries/assets.sql +++ b/tapdb/sqlc/queries/assets.sql @@ -632,14 +632,13 @@ WITH target_asset(asset_id) AS ( FROM assets JOIN script_keys ON assets.script_key_id = script_keys.script_key_id + JOIN managed_utxos utxos + ON assets.anchor_utxo_id = utxos.utxo_id WHERE (script_keys.tweaked_script_key = sqlc.narg('tweaked_script_key') - OR sqlc.narg('tweaked_script_key') IS NULL) - AND (assets.asset_id = sqlc.narg('asset_id') - OR sqlc.narg('asset_id') IS NULL) - -- TODO(guggero): Fix this by disallowing multiple assets with the same - -- script key! - LIMIT 1 + OR sqlc.narg('tweaked_script_key') IS NULL) + AND (utxos.outpoint = sqlc.narg('outpoint') + OR sqlc.narg('outpoint') IS NULL) ) INSERT INTO asset_proofs ( asset_id, proof_file @@ -649,6 +648,15 @@ INSERT INTO asset_proofs ( -- This is not a NOP, we always overwrite the proof with the new one. DO UPDATE SET proof_file = EXCLUDED.proof_file; +-- name: UpsertAssetProofByID :exec +INSERT INTO asset_proofs ( + asset_id, proof_file +) VALUES ( + @asset_id, @proof_file +) ON CONFLICT (asset_id) + -- This is not a NOP, we always overwrite the proof with the new one. + DO UPDATE SET proof_file = EXCLUDED.proof_file; + -- name: FetchAssetProofs :many WITH asset_info AS ( SELECT assets.asset_id, script_keys.tweaked_script_key @@ -676,19 +684,23 @@ FROM asset_proofs JOIN asset_info ON asset_info.asset_id = asset_proofs.asset_id; --- name: FetchAssetProof :one +-- name: FetchAssetProof :many WITH asset_info AS ( - SELECT assets.asset_id, script_keys.tweaked_script_key + SELECT assets.asset_id, script_keys.tweaked_script_key, utxos.outpoint FROM assets JOIN script_keys ON assets.script_key_id = script_keys.script_key_id - WHERE script_keys.tweaked_script_key = $1 + JOIN managed_utxos utxos + ON assets.anchor_utxo_id = utxos.utxo_id + WHERE script_keys.tweaked_script_key = $1 + AND (utxos.outpoint = sqlc.narg('outpoint') OR sqlc.narg('outpoint') IS NULL) ) SELECT asset_info.tweaked_script_key AS script_key, asset_proofs.proof_file, - asset_info.asset_id as asset_id, asset_proofs.proof_id as proof_id + asset_info.asset_id as asset_id, asset_proofs.proof_id as proof_id, + asset_info.outpoint as outpoint FROM asset_proofs JOIN asset_info - ON asset_info.asset_id = asset_proofs.asset_id; + ON asset_info.asset_id = asset_proofs.asset_id; -- name: HasAssetProof :one WITH asset_info AS ( @@ -703,13 +715,19 @@ FROM asset_proofs JOIN asset_info ON asset_info.asset_id = asset_proofs.asset_id; --- name: InsertAssetWitness :exec +-- name: UpsertAssetWitness :exec INSERT INTO asset_witnesses ( asset_id, prev_out_point, prev_asset_id, prev_script_key, witness_stack, - split_commitment_proof + split_commitment_proof, witness_index ) VALUES ( - $1, $2, $3, $4, $5, $6 -); + $1, $2, $3, $4, $5, $6, $7 +) ON CONFLICT (asset_id, witness_index) + -- We overwrite the witness with the new one. + DO UPDATE SET prev_out_point = EXCLUDED.prev_out_point, + prev_asset_id = EXCLUDED.prev_asset_id, + prev_script_key = EXCLUDED.prev_script_key, + witness_stack = EXCLUDED.witness_stack, + split_commitment_proof = EXCLUDED.split_commitment_proof; -- name: FetchAssetWitnesses :many SELECT @@ -720,7 +738,8 @@ JOIN assets ON asset_witnesses.asset_id = assets.asset_id WHERE ( (assets.asset_id = sqlc.narg('asset_id')) OR (sqlc.narg('asset_id') IS NULL) -); +) +ORDER BY witness_index; -- name: DeleteManagedUTXO :exec DELETE FROM managed_utxos diff --git a/tapdb/sqlc/queries/transfers.sql b/tapdb/sqlc/queries/transfers.sql index 234397f9f..3575924d9 100644 --- a/tapdb/sqlc/queries/transfers.sql +++ b/tapdb/sqlc/queries/transfers.sql @@ -155,10 +155,13 @@ INSERT INTO passive_assets ( -- name: QueryPassiveAssets :many SELECT passive.asset_id, passive.new_anchor_utxo, passive.script_key, passive.new_witness_stack, passive.new_proof, - genesis_assets.asset_id AS genesis_id, passive.asset_version + genesis_assets.asset_id AS genesis_id, passive.asset_version, + utxos.outpoint FROM passive_assets as passive JOIN assets ON passive.asset_id = assets.asset_id JOIN genesis_assets ON assets.genesis_id = genesis_assets.gen_asset_id + JOIN managed_utxos utxos + ON passive.new_anchor_utxo = utxos.utxo_id WHERE passive.transfer_id = @transfer_id; diff --git a/tapdb/sqlc/transfers.sql.go b/tapdb/sqlc/transfers.sql.go index 38f9d8327..079ac54c8 100644 --- a/tapdb/sqlc/transfers.sql.go +++ b/tapdb/sqlc/transfers.sql.go @@ -455,12 +455,15 @@ func (q *Queries) QueryAssetTransfers(ctx context.Context, arg QueryAssetTransfe const queryPassiveAssets = `-- name: QueryPassiveAssets :many SELECT passive.asset_id, passive.new_anchor_utxo, passive.script_key, passive.new_witness_stack, passive.new_proof, - genesis_assets.asset_id AS genesis_id, passive.asset_version + genesis_assets.asset_id AS genesis_id, passive.asset_version, + utxos.outpoint FROM passive_assets as passive JOIN assets ON passive.asset_id = assets.asset_id JOIN genesis_assets ON assets.genesis_id = genesis_assets.gen_asset_id + JOIN managed_utxos utxos + ON passive.new_anchor_utxo = utxos.utxo_id WHERE passive.transfer_id = $1 ` @@ -472,6 +475,7 @@ type QueryPassiveAssetsRow struct { NewProof []byte GenesisID []byte AssetVersion int32 + Outpoint []byte } func (q *Queries) QueryPassiveAssets(ctx context.Context, transferID int64) ([]QueryPassiveAssetsRow, error) { @@ -491,6 +495,7 @@ func (q *Queries) QueryPassiveAssets(ctx context.Context, transferID int64) ([]Q &i.NewProof, &i.GenesisID, &i.AssetVersion, + &i.Outpoint, ); err != nil { return nil, err } diff --git a/tapfreighter/chain_porter.go b/tapfreighter/chain_porter.go index d345cf2c1..f0bde0ee6 100644 --- a/tapfreighter/chain_porter.go +++ b/tapfreighter/chain_porter.go @@ -333,7 +333,8 @@ func (p *ChainPorter) storeProofs(sendPkg *sendPackage) error { for _, passiveAsset := range sendPkg.PassiveAssets { newAnnotatedProofFile, rawProof, err := p.updateAssetProofFile( ctx, passiveAsset.GenesisID, - passiveAsset.ScriptKey.PubKey, confEvent, + passiveAsset.ScriptKey.PubKey, + &passiveAsset.PrevAnchorPoint, confEvent, passiveAsset.NewProof, ) if err != nil { @@ -457,7 +458,7 @@ func (p *ChainPorter) storeProofs(sendPkg *sendPackage) error { outputProofLocator := proof.Locator{ AssetID: &firstInput.ID, ScriptKey: *out.ScriptKey.PubKey, - OutPoint: &firstInput.OutPoint, + OutPoint: fn.Ptr(proofSuffix.OutPoint()), } outputProof := &proof.AnnotatedProof{ Locator: outputProofLocator, @@ -515,6 +516,7 @@ func (p *ChainPorter) fetchInputProof(ctx context.Context, inputProofLocator := proof.Locator{ AssetID: &input.ID, ScriptKey: *scriptKey, + OutPoint: &input.OutPoint, } inputProofBytes, err := p.cfg.AssetProofs.FetchProof( ctx, inputProofLocator, @@ -534,17 +536,20 @@ func (p *ChainPorter) fetchInputProof(ctx context.Context, // updateAssetProofFile retrieves and updates the proof file for the given asset // ID and script key with the new proof. func (p *ChainPorter) updateAssetProofFile(ctx context.Context, assetID asset.ID, - scriptKeyPub *btcec.PublicKey, confEvent *chainntnfs.TxConfirmation, + scriptKeyPub *btcec.PublicKey, oldOutPoint *wire.OutPoint, + confEvent *chainntnfs.TxConfirmation, newProof *proof.Proof) (*proof.AnnotatedProof, *proof.Proof, error) { // Retrieve current proof file. locator := proof.Locator{ AssetID: &assetID, ScriptKey: *scriptKeyPub, + OutPoint: oldOutPoint, } currentProofFileBlob, err := p.cfg.AssetProofs.FetchProof(ctx, locator) if err != nil { - return nil, nil, fmt.Errorf("error fetching proof: %w", err) + return nil, nil, fmt.Errorf("error fetching current proof: %w", + err) } currentProofFile := proof.NewEmptyFile(proof.V0) err = currentProofFile.Decode(bytes.NewReader(currentProofFileBlob)) @@ -581,6 +586,7 @@ func (p *ChainPorter) updateAssetProofFile(ctx context.Context, assetID asset.ID Locator: proof.Locator{ AssetID: &assetID, ScriptKey: *newProof.Asset.ScriptKey.PubKey, + OutPoint: fn.Ptr(newProof.OutPoint()), }, Blob: newProofFileBuffer.Bytes(), } @@ -723,12 +729,13 @@ func (p *ChainPorter) transferReceiverProof(pkg *sendPackage) error { pkg.OutboundPkg.AnchorTx.TxHash()) // Load passive asset proof files from archive. - passiveAssetProofFiles := map[[32]byte]proof.Blob{} + passiveAssetProofFiles := map[asset.ID][]*proof.AnnotatedProof{} for idx := range pkg.OutboundPkg.PassiveAssets { passiveAsset := pkg.OutboundPkg.PassiveAssets[idx] proofLocator := proof.Locator{ AssetID: &passiveAsset.GenesisID, ScriptKey: *passiveAsset.ScriptKey.PubKey, + OutPoint: fn.Ptr(passiveAsset.NewProof.OutPoint()), } proofFileBlob, err := p.cfg.AssetProofs.FetchProof( ctx, proofLocator, @@ -738,14 +745,13 @@ func (p *ChainPorter) transferReceiverProof(pkg *sendPackage) error { "proof file: %w", err) } - // Hash proof locator. - hash, err := proofLocator.Hash() - if err != nil { - return fmt.Errorf("error hashing proof locator: %w", - err) - } - - passiveAssetProofFiles[hash] = proofFileBlob + passiveAssetProofFiles[passiveAsset.GenesisID] = append( + passiveAssetProofFiles[passiveAsset.GenesisID], + &proof.AnnotatedProof{ + Locator: proofLocator, + Blob: proofFileBlob, + }, + ) } // At this point we have the confirmation signal, so we can mark the diff --git a/tapfreighter/interface.go b/tapfreighter/interface.go index 8f9f3f2ab..13eddc724 100644 --- a/tapfreighter/interface.go +++ b/tapfreighter/interface.go @@ -271,7 +271,7 @@ type AssetConfirmEvent struct { // PassiveAssetProofFiles is the set of passive asset proof files that // are re-anchored during the parcel confirmation process. - PassiveAssetProofFiles map[[32]byte]proof.Blob + PassiveAssetProofFiles map[asset.ID][]*proof.AnnotatedProof } // PassiveAssetReAnchor includes the information needed to re-anchor a passive diff --git a/tapfreighter/wallet.go b/tapfreighter/wallet.go index 5e6bd0f48..4eedf9416 100644 --- a/tapfreighter/wallet.go +++ b/tapfreighter/wallet.go @@ -956,6 +956,7 @@ func (f *AssetWallet) setVPacketInputs(ctx context.Context, proofLocator := proof.Locator{ AssetID: &assetID, ScriptKey: *assetInput.Asset.ScriptKey.PubKey, + OutPoint: &assetInput.AnchorPoint, } if assetInput.Asset.GroupKey != nil { proofLocator.GroupKey = &assetInput.Asset.GroupKey.GroupPubKey diff --git a/tapgarden/caretaker.go b/tapgarden/caretaker.go index 78b867174..6a3819d9c 100644 --- a/tapgarden/caretaker.go +++ b/tapgarden/caretaker.go @@ -1108,6 +1108,7 @@ func (b *BatchCaretaker) storeMintingProof(ctx context.Context, Locator: proof.Locator{ AssetID: &assetID, ScriptKey: *a.ScriptKey.PubKey, + OutPoint: fn.Ptr(mintingProof.OutPoint()), }, Blob: blob, } diff --git a/tapgarden/custodian.go b/tapgarden/custodian.go index a30f7eb8c..ad82c60c1 100644 --- a/tapgarden/custodian.go +++ b/tapgarden/custodian.go @@ -621,12 +621,13 @@ func (c *Custodian) checkProofAvailable(event *address.Event) (bool, error) { // be a multi archiver that includes file based storage) to make sure // the proof is available in the relational database. If the proof is // not in the DB, we can't update the event. - blob, err := c.cfg.ProofNotifier.FetchProof(ctxt, proof.Locator{ + locator := proof.Locator{ AssetID: fn.Ptr(event.Addr.AssetID), GroupKey: event.Addr.GroupKey, ScriptKey: event.Addr.ScriptKey, OutPoint: &event.Outpoint, - }) + } + blob, err := c.cfg.ProofNotifier.FetchProof(ctxt, locator) switch { case errors.Is(err, proof.ErrProofNotFound): return false, nil @@ -645,6 +646,19 @@ func (c *Custodian) checkProofAvailable(event *address.Event) (bool, error) { "but got something else") } + // In case we missed a notification from the local universe and didn't + // previously import the proof (for example because we were shutting + // down), we could be in a situation where the local database doesn't + // have the proof yet. So we make sure to import it now. + err = c.assertProofInLocalArchive(&proof.AnnotatedProof{ + Locator: locator, + Blob: blob, + }) + if err != nil { + return false, fmt.Errorf("error asserting proof in local "+ + "archive: %w", err) + } + file, err := blob.AsFile() if err != nil { return false, fmt.Errorf("error extracting proof file: %w", err) @@ -729,29 +743,13 @@ func (c *Custodian) mapProofToEvent(p proof.Blob) error { // local universe instead of the local proof archive (which the // couriers use). This is mainly an optimization to make sure we // don't unnecessarily overwrite the proofs in our main archive. - haveProof, err := c.cfg.ProofArchive.HasProof(ctxt, loc) + err := c.assertProofInLocalArchive(&proof.AnnotatedProof{ + Locator: loc, + Blob: proofBlob, + }) if err != nil { - return fmt.Errorf("error checking if proof is "+ - "available: %w", err) - } - - // We don't have the proof yet, or not in all backends, so we - // need to import it now. - if !haveProof { - headerVerifier := GenHeaderVerifier( - ctxt, c.cfg.ChainBridge, - ) - err = c.cfg.ProofArchive.ImportProofs( - ctxt, headerVerifier, c.cfg.GroupVerifier, - false, &proof.AnnotatedProof{ - Locator: loc, - Blob: proofBlob, - }, - ) - if err != nil { - return fmt.Errorf("error importing proof "+ - "file into main archive: %w", err) - } + return fmt.Errorf("error asserting proof in local "+ + "archive: %w", err) } } @@ -802,6 +800,34 @@ func (c *Custodian) mapProofToEvent(p proof.Blob) error { return nil } +// assertProofInLocalArchive checks if the proof is already in the local proof +// archive. If it isn't, it is imported now. +func (c *Custodian) assertProofInLocalArchive(p *proof.AnnotatedProof) error { + ctxt, cancel := c.WithCtxQuit() + defer cancel() + + haveProof, err := c.cfg.ProofArchive.HasProof(ctxt, p.Locator) + if err != nil { + return fmt.Errorf("error checking if proof is available: %w", + err) + } + + // We don't have the proof yet, or not in all backends, so we + // need to import it now. + if !haveProof { + headerVerifier := GenHeaderVerifier(ctxt, c.cfg.ChainBridge) + err = c.cfg.ProofArchive.ImportProofs( + ctxt, headerVerifier, c.cfg.GroupVerifier, false, p, + ) + if err != nil { + return fmt.Errorf("error importing proof file into "+ + "main archive: %w", err) + } + } + + return nil +} + // setReceiveCompleted updates the address event in the database to mark it as // completed successfully and to link it to the proof we received. func (c *Custodian) setReceiveCompleted(event *address.Event, diff --git a/tapgarden/custodian_test.go b/tapgarden/custodian_test.go index 9f2fcf860..04f0b71b7 100644 --- a/tapgarden/custodian_test.go +++ b/tapgarden/custodian_test.go @@ -5,6 +5,7 @@ import ( "context" "database/sql" "fmt" + "io" "math/rand" "net/url" "testing" @@ -23,6 +24,7 @@ import ( "github.com/lightninglabs/taproot-assets/tapdb" "github.com/lightninglabs/taproot-assets/tapgarden" "github.com/lightninglabs/taproot-assets/tapscript" + "github.com/lightninglabs/taproot-assets/universe" "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest/wait" @@ -59,9 +61,46 @@ func newAddrBookForDB(db *tapdb.BaseDB, keyRing *tapgarden.MockKeyRing, return book, tapdbBook } +type mockVerifier struct { + t *testing.T +} + +func newMockVerifier(t *testing.T) *mockVerifier { + return &mockVerifier{ + t: t, + } +} + +func (m *mockVerifier) Verify(_ context.Context, r io.Reader, + headerVerifier proof.HeaderVerifier, + groupVerifier proof.GroupVerifier) (*proof.AssetSnapshot, error) { + + f := &proof.File{} + err := f.Decode(r) + require.NoError(m.t, err) + + lastProof, err := f.LastProof() + require.NoError(m.t, err) + + ac, err := commitment.NewAssetCommitment(&lastProof.Asset) + require.NoError(m.t, err) + tc, err := commitment.NewTapCommitment(ac) + require.NoError(m.t, err) + + return &proof.AssetSnapshot{ + Asset: &lastProof.Asset, + OutPoint: lastProof.OutPoint(), + OutputIndex: lastProof.InclusionProof.OutputIndex, + AnchorBlockHash: lastProof.BlockHeader.BlockHash(), + AnchorTx: &lastProof.AnchorTx, + InternalKey: lastProof.InclusionProof.InternalKey, + ScriptRoot: tc, + }, nil +} + // newProofArchive creates a new instance of the MultiArchiver. func newProofArchiveForDB(t *testing.T, db *tapdb.BaseDB) (*proof.MultiArchiver, - *tapdb.AssetStore) { + *tapdb.AssetStore, *tapdb.MultiverseStore) { txCreator := func(tx *sql.Tx) tapdb.ActiveAssetsStore { return db.WithTx(tx) @@ -78,13 +117,21 @@ func newProofArchiveForDB(t *testing.T, db *tapdb.BaseDB) (*proof.MultiArchiver, assetStore, ) - return proofArchive, assetStore + multiverseDB := tapdb.NewTransactionExecutor( + db, func(tx *sql.Tx) tapdb.BaseMultiverseStore { + return db.WithTx(tx) + }, + ) + multiverse := tapdb.NewMultiverseStore(multiverseDB) + + return proofArchive, assetStore, multiverse } type custodianHarness struct { t *testing.T c *tapgarden.Custodian cfg *tapgarden.CustodianConfig + errChan chan error chainBridge *tapgarden.MockChainBridge walletAnchor *tapgarden.MockWalletAnchor keyRing *tapgarden.MockKeyRing @@ -92,6 +139,7 @@ type custodianHarness struct { addrBook *address.Book syncer *tapgarden.MockAssetSyncer assetDB *tapdb.AssetStore + multiverse *tapdb.MultiverseStore courier *proof.MockProofCourier } @@ -103,11 +151,27 @@ func (h *custodianHarness) assertStartup() { ) require.NoError(h.t, err) + // Make sure we don't have an error on startup. + select { + case err := <-h.errChan: + require.NoError(h.t, err) + + case <-time.After(testPollInterval): + } + // Make sure ListTransactions is called on startup. _, err = fn.RecvOrTimeout( h.walletAnchor.ListTxnsSignal, testTimeout, ) require.NoError(h.t, err) + + // Make sure we don't have an error on startup. + select { + case err := <-h.errChan: + require.NoError(h.t, err) + + case <-time.After(testPollInterval): + } } // eventually is a shortcut for require.Eventually with the timeout and poll @@ -175,6 +239,48 @@ func (h *custodianHarness) assertAddrsRegistered( } } +// addProofFileToMultiverse adds the given proof to the multiverse store. +func (h *custodianHarness) addProofFileToMultiverse(p *proof.AnnotatedProof) { + f := &proof.File{} + err := f.Decode(bytes.NewReader(p.Blob)) + require.NoError(h.t, err) + + ctx := context.Background() + ctxt, cancel := context.WithTimeout(ctx, testTimeout) + defer cancel() + + for i := uint32(0); i < uint32(f.NumProofs()); i++ { + transition, err := f.ProofAt(i) + require.NoError(h.t, err) + + rawTransition, err := f.RawProofAt(i) + require.NoError(h.t, err) + + id := universe.NewUniIDFromAsset(transition.Asset) + key := universe.LeafKey{ + OutPoint: transition.OutPoint(), + ScriptKey: fn.Ptr(asset.NewScriptKey( + transition.Asset.ScriptKey.PubKey, + )), + } + leaf := &universe.Leaf{ + GenesisWithGroup: universe.GenesisWithGroup{ + Genesis: transition.Asset.Genesis, + GroupKey: transition.Asset.GroupKey, + }, + RawProof: rawTransition, + Asset: &transition.Asset, + Amt: transition.Asset.Amount, + } + h.t.Logf("Importing proof with script key %x and outpoint %v "+ + "into multiverse", + key.ScriptKey.PubKey.SerializeCompressed(), + key.OutPoint) + _, err = h.multiverse.UpsertProofLeaf(ctxt, id, key, leaf, nil) + require.NoError(h.t, err) + } +} + func newHarness(t *testing.T, initialAddrs []*address.AddrWithKeyInfo) *custodianHarness { @@ -184,7 +290,10 @@ func newHarness(t *testing.T, syncer := tapgarden.NewMockAssetSyncer() db := tapdb.NewTestDB(t) addrBook, tapdbBook := newAddrBookForDB(db.BaseDB, keyRing, syncer) - _, assetDB := newProofArchiveForDB(t, db.BaseDB) + + _, assetDB, multiverse := newProofArchiveForDB(t, db.BaseDB) + notifier := proof.NewMultiArchiveNotifier(assetDB, multiverse) + courier := proof.NewMockProofCourier() courierDispatch := &proof.MockProofCourierDispatcher{ Courier: courier, @@ -197,21 +306,27 @@ func newHarness(t *testing.T, require.NoError(t, err) } + archive := proof.NewMultiArchiver( + newMockVerifier(t), testTimeout, assetDB, + ) + + errChan := make(chan error, 1) cfg := &tapgarden.CustodianConfig{ ChainParams: chainParams, ChainBridge: chainBridge, WalletAnchor: walletAnchor, AddrBook: addrBook, - ProofArchive: assetDB, - ProofNotifier: assetDB, + ProofArchive: archive, + ProofNotifier: notifier, ProofCourierDispatcher: courierDispatch, ProofWatcher: proofWatcher, - ErrChan: make(chan error, 1), + ErrChan: errChan, } return &custodianHarness{ t: t, c: tapgarden.NewCustodian(cfg), cfg: cfg, + errChan: errChan, chainBridge: chainBridge, walletAnchor: walletAnchor, keyRing: keyRing, @@ -219,6 +334,7 @@ func newHarness(t *testing.T, addrBook: addrBook, syncer: syncer, assetDB: assetDB, + multiverse: multiverse, courier: courier, } } @@ -296,6 +412,11 @@ func randProof(t *testing.T, outputIndex int, tx *wire.MsgTx, Genesis: *genesis, Amount: addr.Amount, ScriptKey: asset.NewScriptKey(&addr.ScriptKey), + PrevWitnesses: []asset.Witness{ + { + PrevID: &asset.PrevID{}, + }, + }, } if addr.GroupKey != nil { a.GroupKey = &asset.GroupKey{ @@ -634,6 +755,49 @@ func mustMakeAddr(t *testing.T, return addr } +// TestProofInMultiverseOnly tests that the custodian imports a proof correctly +// into the local archive if it's only present in the multiverse. +func TestProofInMultiverseOnly(t *testing.T) { + h := newHarness(t, nil) + + // Before we start the custodian, we create a random address and a + // corresponding wallet transaction. + ctx := context.Background() + + addr, genesis := randAddr(h) + err := h.tapdbBook.InsertAddrs(ctx, *addr) + require.NoError(t, err) + + // We now start the custodian and make sure it's started up correctly + // and the pending event is registered. + require.NoError(t, h.c.Start()) + h.assertStartup() + h.assertAddrsRegistered(addr) + + // Receiving a TX for it should create a pending event and cause the + // proof courier to attempt to fetch it. But the courier won't find it. + outputIdx, tx := randWalletTx(addr) + h.walletAnchor.SubscribeTx <- *tx + h.assertEventsPresent(1, address.StatusTransactionDetected) + + // We now stop the custodian again. + require.NoError(t, h.c.Stop()) + + // The proof is only in the multiverse, not in the local archive. And we + // add the proof to the multiverse before starting the custodian, so the + // notification for it doesn't trigger. + mockProof := randProof(t, outputIdx, tx.Tx, genesis, addr) + h.addProofFileToMultiverse(mockProof) + + // And a new start should import the proof into the local archive. + h.c = tapgarden.NewCustodian(h.cfg) + require.NoError(t, h.c.Start()) + t.Cleanup(func() { + require.NoError(t, h.c.Stop()) + }) + h.assertStartup() +} + // TestAddrMatchesAsset tests that the AddrMatchesAsset function works // correctly. func TestAddrMatchesAsset(t *testing.T) { diff --git a/tapgarden/re-org_watcher.go b/tapgarden/re-org_watcher.go index 3bb20201e..735253269 100644 --- a/tapgarden/re-org_watcher.go +++ b/tapgarden/re-org_watcher.go @@ -73,7 +73,7 @@ type ReOrgWatcherConfig struct { // NonBuriedAssetFetcher is a function that returns all assets that are // not yet sufficiently deep buried. NonBuriedAssetFetcher func(ctx context.Context, - minHeight int32) ([]*asset.Asset, error) + minHeight int32) ([]*asset.ChainAsset, error) // SafeDepth is the number of confirmations we require before we // consider a transaction to be safely buried in the chain. @@ -159,12 +159,15 @@ func (w *ReOrgWatcher) Start() error { locator := proof.Locator{ AssetID: fn.Ptr(assets[idx].ID()), ScriptKey: *assets[idx].ScriptKey.PubKey, + OutPoint: &assets[idx].AnchorOutpoint, } blob, err := w.cfg.ProofArchive.FetchProof(ctx, locator) if err != nil { startErr = fmt.Errorf("unable to fetch proof "+ - "for asset %v: %w", assets[idx].ID(), - err) + "for asset_id=%v, script_key=%x, "+ + "outpoint=%v: %w", assets[idx].ID(), + locator.ScriptKey.SerializeCompressed(), + locator.OutPoint, err) return } diff --git a/tapgarden/re-org_watcher_test.go b/tapgarden/re-org_watcher_test.go index d4329e777..29150acbd 100644 --- a/tapgarden/re-org_watcher_test.go +++ b/tapgarden/re-org_watcher_test.go @@ -53,7 +53,7 @@ func newReOrgWatcherHarness(t *testing.T) *reOrgWatcherHarness { ChainBridge: chainBridge, GroupVerifier: GenMockGroupVerifier(), NonBuriedAssetFetcher: func(ctx context.Context, - minHeight int32) ([]*asset.Asset, error) { + minHeight int32) ([]*asset.ChainAsset, error) { return nil, nil }, diff --git a/taprpc/assetwalletrpc/assetwallet.pb.go b/taprpc/assetwalletrpc/assetwallet.pb.go index 820b400ae..486ee85c4 100644 --- a/taprpc/assetwalletrpc/assetwallet.pb.go +++ b/taprpc/assetwalletrpc/assetwallet.pb.go @@ -234,7 +234,7 @@ type PrevId struct { unknownFields protoimpl.UnknownFields // The bitcoin anchor output on chain that contains the input asset. - Outpoint *OutPoint `protobuf:"bytes,1,opt,name=outpoint,proto3" json:"outpoint,omitempty"` + Outpoint *taprpc.OutPoint `protobuf:"bytes,1,opt,name=outpoint,proto3" json:"outpoint,omitempty"` // The asset ID of the previous asset tree. Id []byte `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` // The tweaked Taproot output key committing to the possible spending @@ -274,7 +274,7 @@ func (*PrevId) Descriptor() ([]byte, []int) { return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{3} } -func (x *PrevId) GetOutpoint() *OutPoint { +func (x *PrevId) GetOutpoint() *taprpc.OutPoint { if x != nil { return x.Outpoint } @@ -295,63 +295,6 @@ func (x *PrevId) GetScriptKey() []byte { return nil } -type OutPoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Raw bytes representing the transaction id. - Txid []byte `protobuf:"bytes,1,opt,name=txid,proto3" json:"txid,omitempty"` - // The index of the output on the transaction. - OutputIndex uint32 `protobuf:"varint,2,opt,name=output_index,json=outputIndex,proto3" json:"output_index,omitempty"` -} - -func (x *OutPoint) Reset() { - *x = OutPoint{} - if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *OutPoint) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*OutPoint) ProtoMessage() {} - -func (x *OutPoint) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_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 OutPoint.ProtoReflect.Descriptor instead. -func (*OutPoint) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{4} -} - -func (x *OutPoint) GetTxid() []byte { - if x != nil { - return x.Txid - } - return nil -} - -func (x *OutPoint) GetOutputIndex() uint32 { - if x != nil { - return x.OutputIndex - } - return 0 -} - type SignVirtualPsbtRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -366,7 +309,7 @@ type SignVirtualPsbtRequest struct { func (x *SignVirtualPsbtRequest) Reset() { *x = SignVirtualPsbtRequest{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[5] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -379,7 +322,7 @@ func (x *SignVirtualPsbtRequest) String() string { func (*SignVirtualPsbtRequest) ProtoMessage() {} func (x *SignVirtualPsbtRequest) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[5] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -392,7 +335,7 @@ func (x *SignVirtualPsbtRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SignVirtualPsbtRequest.ProtoReflect.Descriptor instead. func (*SignVirtualPsbtRequest) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{5} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{4} } func (x *SignVirtualPsbtRequest) GetFundedPsbt() []byte { @@ -416,7 +359,7 @@ type SignVirtualPsbtResponse struct { func (x *SignVirtualPsbtResponse) Reset() { *x = SignVirtualPsbtResponse{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[6] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -429,7 +372,7 @@ func (x *SignVirtualPsbtResponse) String() string { func (*SignVirtualPsbtResponse) ProtoMessage() {} func (x *SignVirtualPsbtResponse) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[6] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -442,7 +385,7 @@ func (x *SignVirtualPsbtResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SignVirtualPsbtResponse.ProtoReflect.Descriptor instead. func (*SignVirtualPsbtResponse) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{6} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{5} } func (x *SignVirtualPsbtResponse) GetSignedPsbt() []byte { @@ -472,7 +415,7 @@ type AnchorVirtualPsbtsRequest struct { func (x *AnchorVirtualPsbtsRequest) Reset() { *x = AnchorVirtualPsbtsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[7] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -485,7 +428,7 @@ func (x *AnchorVirtualPsbtsRequest) String() string { func (*AnchorVirtualPsbtsRequest) ProtoMessage() {} func (x *AnchorVirtualPsbtsRequest) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[7] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -498,7 +441,7 @@ func (x *AnchorVirtualPsbtsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AnchorVirtualPsbtsRequest.ProtoReflect.Descriptor instead. func (*AnchorVirtualPsbtsRequest) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{7} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{6} } func (x *AnchorVirtualPsbtsRequest) GetVirtualPsbts() [][]byte { @@ -519,7 +462,7 @@ type NextInternalKeyRequest struct { func (x *NextInternalKeyRequest) Reset() { *x = NextInternalKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[8] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -532,7 +475,7 @@ func (x *NextInternalKeyRequest) String() string { func (*NextInternalKeyRequest) ProtoMessage() {} func (x *NextInternalKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[8] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -545,7 +488,7 @@ func (x *NextInternalKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use NextInternalKeyRequest.ProtoReflect.Descriptor instead. func (*NextInternalKeyRequest) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{8} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{7} } func (x *NextInternalKeyRequest) GetKeyFamily() uint32 { @@ -566,7 +509,7 @@ type NextInternalKeyResponse struct { func (x *NextInternalKeyResponse) Reset() { *x = NextInternalKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[9] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -579,7 +522,7 @@ func (x *NextInternalKeyResponse) String() string { func (*NextInternalKeyResponse) ProtoMessage() {} func (x *NextInternalKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[9] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -592,7 +535,7 @@ func (x *NextInternalKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use NextInternalKeyResponse.ProtoReflect.Descriptor instead. func (*NextInternalKeyResponse) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{9} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{8} } func (x *NextInternalKeyResponse) GetInternalKey() *taprpc.KeyDescriptor { @@ -613,7 +556,7 @@ type NextScriptKeyRequest struct { func (x *NextScriptKeyRequest) Reset() { *x = NextScriptKeyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[10] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -626,7 +569,7 @@ func (x *NextScriptKeyRequest) String() string { func (*NextScriptKeyRequest) ProtoMessage() {} func (x *NextScriptKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[10] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -639,7 +582,7 @@ func (x *NextScriptKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use NextScriptKeyRequest.ProtoReflect.Descriptor instead. func (*NextScriptKeyRequest) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{10} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{9} } func (x *NextScriptKeyRequest) GetKeyFamily() uint32 { @@ -660,7 +603,7 @@ type NextScriptKeyResponse struct { func (x *NextScriptKeyResponse) Reset() { *x = NextScriptKeyResponse{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[11] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -673,7 +616,7 @@ func (x *NextScriptKeyResponse) String() string { func (*NextScriptKeyResponse) ProtoMessage() {} func (x *NextScriptKeyResponse) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[11] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -686,7 +629,7 @@ func (x *NextScriptKeyResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use NextScriptKeyResponse.ProtoReflect.Descriptor instead. func (*NextScriptKeyResponse) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{11} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{10} } func (x *NextScriptKeyResponse) GetScriptKey() *taprpc.ScriptKey { @@ -701,14 +644,15 @@ type ProveAssetOwnershipRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AssetId []byte `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - ScriptKey []byte `protobuf:"bytes,2,opt,name=script_key,json=scriptKey,proto3" json:"script_key,omitempty"` + AssetId []byte `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` + ScriptKey []byte `protobuf:"bytes,2,opt,name=script_key,json=scriptKey,proto3" json:"script_key,omitempty"` + Outpoint *taprpc.OutPoint `protobuf:"bytes,3,opt,name=outpoint,proto3" json:"outpoint,omitempty"` } func (x *ProveAssetOwnershipRequest) Reset() { *x = ProveAssetOwnershipRequest{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[12] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -721,7 +665,7 @@ func (x *ProveAssetOwnershipRequest) String() string { func (*ProveAssetOwnershipRequest) ProtoMessage() {} func (x *ProveAssetOwnershipRequest) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[12] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -734,7 +678,7 @@ func (x *ProveAssetOwnershipRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ProveAssetOwnershipRequest.ProtoReflect.Descriptor instead. func (*ProveAssetOwnershipRequest) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{12} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{11} } func (x *ProveAssetOwnershipRequest) GetAssetId() []byte { @@ -751,6 +695,13 @@ func (x *ProveAssetOwnershipRequest) GetScriptKey() []byte { return nil } +func (x *ProveAssetOwnershipRequest) GetOutpoint() *taprpc.OutPoint { + if x != nil { + return x.Outpoint + } + return nil +} + type ProveAssetOwnershipResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -762,7 +713,7 @@ type ProveAssetOwnershipResponse struct { func (x *ProveAssetOwnershipResponse) Reset() { *x = ProveAssetOwnershipResponse{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[13] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -775,7 +726,7 @@ func (x *ProveAssetOwnershipResponse) String() string { func (*ProveAssetOwnershipResponse) ProtoMessage() {} func (x *ProveAssetOwnershipResponse) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[13] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -788,7 +739,7 @@ func (x *ProveAssetOwnershipResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ProveAssetOwnershipResponse.ProtoReflect.Descriptor instead. func (*ProveAssetOwnershipResponse) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{13} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{12} } func (x *ProveAssetOwnershipResponse) GetProofWithWitness() []byte { @@ -809,7 +760,7 @@ type VerifyAssetOwnershipRequest struct { func (x *VerifyAssetOwnershipRequest) Reset() { *x = VerifyAssetOwnershipRequest{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[14] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -822,7 +773,7 @@ func (x *VerifyAssetOwnershipRequest) String() string { func (*VerifyAssetOwnershipRequest) ProtoMessage() {} func (x *VerifyAssetOwnershipRequest) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[14] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -835,7 +786,7 @@ func (x *VerifyAssetOwnershipRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyAssetOwnershipRequest.ProtoReflect.Descriptor instead. func (*VerifyAssetOwnershipRequest) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{14} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{13} } func (x *VerifyAssetOwnershipRequest) GetProofWithWitness() []byte { @@ -856,7 +807,7 @@ type VerifyAssetOwnershipResponse struct { func (x *VerifyAssetOwnershipResponse) Reset() { *x = VerifyAssetOwnershipResponse{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[15] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -869,7 +820,7 @@ func (x *VerifyAssetOwnershipResponse) String() string { func (*VerifyAssetOwnershipResponse) ProtoMessage() {} func (x *VerifyAssetOwnershipResponse) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[15] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -882,7 +833,7 @@ func (x *VerifyAssetOwnershipResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyAssetOwnershipResponse.ProtoReflect.Descriptor instead. func (*VerifyAssetOwnershipResponse) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{15} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{14} } func (x *VerifyAssetOwnershipResponse) GetValidProof() bool { @@ -898,13 +849,13 @@ type RemoveUTXOLeaseRequest struct { unknownFields protoimpl.UnknownFields // The outpoint of the UTXO to remove the lease for. - Outpoint *OutPoint `protobuf:"bytes,1,opt,name=outpoint,proto3" json:"outpoint,omitempty"` + Outpoint *taprpc.OutPoint `protobuf:"bytes,1,opt,name=outpoint,proto3" json:"outpoint,omitempty"` } func (x *RemoveUTXOLeaseRequest) Reset() { *x = RemoveUTXOLeaseRequest{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[16] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -917,7 +868,7 @@ func (x *RemoveUTXOLeaseRequest) String() string { func (*RemoveUTXOLeaseRequest) ProtoMessage() {} func (x *RemoveUTXOLeaseRequest) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[16] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -930,10 +881,10 @@ func (x *RemoveUTXOLeaseRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveUTXOLeaseRequest.ProtoReflect.Descriptor instead. func (*RemoveUTXOLeaseRequest) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{16} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{15} } -func (x *RemoveUTXOLeaseRequest) GetOutpoint() *OutPoint { +func (x *RemoveUTXOLeaseRequest) GetOutpoint() *taprpc.OutPoint { if x != nil { return x.Outpoint } @@ -949,7 +900,7 @@ type RemoveUTXOLeaseResponse struct { func (x *RemoveUTXOLeaseResponse) Reset() { *x = RemoveUTXOLeaseResponse{} if protoimpl.UnsafeEnabled { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[17] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -962,7 +913,7 @@ func (x *RemoveUTXOLeaseResponse) String() string { func (*RemoveUTXOLeaseResponse) ProtoMessage() {} func (x *RemoveUTXOLeaseResponse) ProtoReflect() protoreflect.Message { - mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[17] + mi := &file_assetwalletrpc_assetwallet_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -975,7 +926,7 @@ func (x *RemoveUTXOLeaseResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RemoveUTXOLeaseResponse.ProtoReflect.Descriptor instead. func (*RemoveUTXOLeaseResponse) Descriptor() ([]byte, []int) { - return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{17} + return file_assetwalletrpc_assetwallet_proto_rawDescGZIP(), []int{16} } var File_assetwalletrpc_assetwallet_proto protoreflect.FileDescriptor @@ -1011,131 +962,129 @@ var file_assetwalletrpc_assetwallet_proto_rawDesc = []byte{ 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6d, 0x0a, 0x06, 0x50, 0x72, 0x65, - 0x76, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, - 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x41, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x74, 0x78, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x39, 0x0a, 0x16, 0x53, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x65, 0x0a, 0x06, 0x50, 0x72, 0x65, + 0x76, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, + 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, + 0x22, 0x39, 0x0a, 0x16, 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, + 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75, + 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0a, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x22, 0x5f, 0x0a, 0x17, 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x5f, - 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x66, 0x75, 0x6e, 0x64, - 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x22, 0x5f, 0x0a, 0x17, 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x70, 0x73, 0x62, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x73, - 0x62, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x22, 0x40, 0x0a, 0x19, 0x41, 0x6e, 0x63, 0x68, 0x6f, - 0x72, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, - 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x76, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x22, 0x37, 0x0a, 0x16, 0x4e, 0x65, 0x78, - 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x46, 0x61, 0x6d, 0x69, - 0x6c, 0x79, 0x22, 0x53, 0x0a, 0x17, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, - 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x22, 0x35, 0x0a, 0x14, 0x4e, 0x65, 0x78, 0x74, 0x53, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, 0x49, - 0x0a, 0x15, 0x4e, 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x61, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x09, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x56, 0x0a, 0x1a, 0x50, 0x72, 0x6f, - 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, - 0x79, 0x22, 0x4b, 0x0a, 0x1b, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, - 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x77, - 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x72, - 0x6f, 0x6f, 0x66, 0x57, 0x69, 0x74, 0x68, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x22, 0x4b, - 0x0a, 0x1b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, - 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, - 0x12, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x77, 0x69, 0x74, 0x6e, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x6f, 0x66, - 0x57, 0x69, 0x74, 0x68, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x22, 0x3f, 0x0a, 0x1c, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, - 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x4e, 0x0a, 0x16, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x19, 0x0a, 0x17, - 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xba, 0x06, 0x0a, 0x0b, 0x41, 0x73, 0x73, 0x65, - 0x74, 0x57, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x62, 0x0a, 0x0f, 0x46, 0x75, 0x6e, 0x64, 0x56, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x50, 0x73, 0x62, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0c, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x22, 0x40, 0x0a, 0x19, + 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, + 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x22, 0x37, + 0x0a, 0x16, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, + 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6b, 0x65, + 0x79, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x22, 0x53, 0x0a, 0x17, 0x4e, 0x65, 0x78, 0x74, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0c, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, + 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x22, 0x35, 0x0a, 0x14, + 0x4e, 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x66, 0x61, 0x6d, 0x69, + 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x46, 0x61, 0x6d, + 0x69, 0x6c, 0x79, 0x22, 0x49, 0x0a, 0x15, 0x4e, 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x0a, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x4b, 0x65, 0x79, 0x52, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x84, + 0x01, 0x0a, 0x1a, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, + 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x4b, 0x0a, 0x1b, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x77, 0x69, + 0x74, 0x68, 0x5f, 0x77, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x10, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x57, 0x69, 0x74, 0x68, 0x57, 0x69, 0x74, 0x6e, 0x65, + 0x73, 0x73, 0x22, 0x4b, 0x0a, 0x1b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, + 0x77, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x70, + 0x72, 0x6f, 0x6f, 0x66, 0x57, 0x69, 0x74, 0x68, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x22, + 0x3f, 0x0a, 0x1c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, + 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x22, 0x46, 0x0a, 0x16, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, + 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, + 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, + 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, + 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x19, 0x0a, 0x17, 0x52, 0x65, 0x6d, 0x6f, + 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x32, 0xba, 0x06, 0x0a, 0x0b, 0x41, 0x73, 0x73, 0x65, 0x74, 0x57, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x12, 0x62, 0x0a, 0x0f, 0x46, 0x75, 0x6e, 0x64, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x12, 0x26, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x56, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, + 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x46, 0x75, 0x6e, 0x64, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x12, 0x26, 0x2e, 0x61, 0x73, 0x73, - 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, + 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x46, 0x75, 0x6e, 0x64, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, - 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x53, - 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x12, 0x26, - 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x5a, 0x0a, 0x12, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x50, 0x73, 0x62, 0x74, 0x73, 0x12, 0x29, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x56, 0x69, 0x72, - 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x4e, - 0x65, 0x78, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x26, - 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x4e, 0x65, 0x78, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x5c, 0x0a, 0x0d, 0x4e, 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, - 0x12, 0x24, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, - 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, - 0x13, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, - 0x73, 0x68, 0x69, 0x70, 0x12, 0x2a, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2b, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, + 0x73, 0x62, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x12, 0x41, + 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, + 0x73, 0x12, 0x29, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x50, 0x73, 0x62, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, + 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, 0x4e, 0x65, 0x78, 0x74, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x2e, 0x61, 0x73, 0x73, + 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x78, 0x74, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x0d, 0x4e, + 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x2e, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, + 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x78, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x13, 0x50, 0x72, 0x6f, + 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, + 0x12, 0x2a, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, - 0x14, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x2b, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, - 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, - 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x62, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, - 0x61, 0x73, 0x65, 0x12, 0x26, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, - 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x73, - 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, - 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, - 0x2f, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x2f, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, - 0x65, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, + 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, + 0x6f, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x71, 0x0a, 0x14, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x12, 0x2b, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, + 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, + 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x62, 0x0a, 0x0f, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x12, + 0x26, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x4c, 0x65, 0x61, 0x73, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, + 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, + 0x54, 0x58, 0x4f, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x42, 0x3f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, + 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x70, + 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, + 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1150,27 +1099,27 @@ func file_assetwalletrpc_assetwallet_proto_rawDescGZIP() []byte { return file_assetwalletrpc_assetwallet_proto_rawDescData } -var file_assetwalletrpc_assetwallet_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_assetwalletrpc_assetwallet_proto_msgTypes = make([]protoimpl.MessageInfo, 18) var file_assetwalletrpc_assetwallet_proto_goTypes = []interface{}{ (*FundVirtualPsbtRequest)(nil), // 0: assetwalletrpc.FundVirtualPsbtRequest (*FundVirtualPsbtResponse)(nil), // 1: assetwalletrpc.FundVirtualPsbtResponse (*TxTemplate)(nil), // 2: assetwalletrpc.TxTemplate (*PrevId)(nil), // 3: assetwalletrpc.PrevId - (*OutPoint)(nil), // 4: assetwalletrpc.OutPoint - (*SignVirtualPsbtRequest)(nil), // 5: assetwalletrpc.SignVirtualPsbtRequest - (*SignVirtualPsbtResponse)(nil), // 6: assetwalletrpc.SignVirtualPsbtResponse - (*AnchorVirtualPsbtsRequest)(nil), // 7: assetwalletrpc.AnchorVirtualPsbtsRequest - (*NextInternalKeyRequest)(nil), // 8: assetwalletrpc.NextInternalKeyRequest - (*NextInternalKeyResponse)(nil), // 9: assetwalletrpc.NextInternalKeyResponse - (*NextScriptKeyRequest)(nil), // 10: assetwalletrpc.NextScriptKeyRequest - (*NextScriptKeyResponse)(nil), // 11: assetwalletrpc.NextScriptKeyResponse - (*ProveAssetOwnershipRequest)(nil), // 12: assetwalletrpc.ProveAssetOwnershipRequest - (*ProveAssetOwnershipResponse)(nil), // 13: assetwalletrpc.ProveAssetOwnershipResponse - (*VerifyAssetOwnershipRequest)(nil), // 14: assetwalletrpc.VerifyAssetOwnershipRequest - (*VerifyAssetOwnershipResponse)(nil), // 15: assetwalletrpc.VerifyAssetOwnershipResponse - (*RemoveUTXOLeaseRequest)(nil), // 16: assetwalletrpc.RemoveUTXOLeaseRequest - (*RemoveUTXOLeaseResponse)(nil), // 17: assetwalletrpc.RemoveUTXOLeaseResponse - nil, // 18: assetwalletrpc.TxTemplate.RecipientsEntry + (*SignVirtualPsbtRequest)(nil), // 4: assetwalletrpc.SignVirtualPsbtRequest + (*SignVirtualPsbtResponse)(nil), // 5: assetwalletrpc.SignVirtualPsbtResponse + (*AnchorVirtualPsbtsRequest)(nil), // 6: assetwalletrpc.AnchorVirtualPsbtsRequest + (*NextInternalKeyRequest)(nil), // 7: assetwalletrpc.NextInternalKeyRequest + (*NextInternalKeyResponse)(nil), // 8: assetwalletrpc.NextInternalKeyResponse + (*NextScriptKeyRequest)(nil), // 9: assetwalletrpc.NextScriptKeyRequest + (*NextScriptKeyResponse)(nil), // 10: assetwalletrpc.NextScriptKeyResponse + (*ProveAssetOwnershipRequest)(nil), // 11: assetwalletrpc.ProveAssetOwnershipRequest + (*ProveAssetOwnershipResponse)(nil), // 12: assetwalletrpc.ProveAssetOwnershipResponse + (*VerifyAssetOwnershipRequest)(nil), // 13: assetwalletrpc.VerifyAssetOwnershipRequest + (*VerifyAssetOwnershipResponse)(nil), // 14: assetwalletrpc.VerifyAssetOwnershipResponse + (*RemoveUTXOLeaseRequest)(nil), // 15: assetwalletrpc.RemoveUTXOLeaseRequest + (*RemoveUTXOLeaseResponse)(nil), // 16: assetwalletrpc.RemoveUTXOLeaseResponse + nil, // 17: assetwalletrpc.TxTemplate.RecipientsEntry + (*taprpc.OutPoint)(nil), // 18: taprpc.OutPoint (*taprpc.KeyDescriptor)(nil), // 19: taprpc.KeyDescriptor (*taprpc.ScriptKey)(nil), // 20: taprpc.ScriptKey (*taprpc.SendAssetResponse)(nil), // 21: taprpc.SendAssetResponse @@ -1178,32 +1127,33 @@ var file_assetwalletrpc_assetwallet_proto_goTypes = []interface{}{ var file_assetwalletrpc_assetwallet_proto_depIdxs = []int32{ 2, // 0: assetwalletrpc.FundVirtualPsbtRequest.raw:type_name -> assetwalletrpc.TxTemplate 3, // 1: assetwalletrpc.TxTemplate.inputs:type_name -> assetwalletrpc.PrevId - 18, // 2: assetwalletrpc.TxTemplate.recipients:type_name -> assetwalletrpc.TxTemplate.RecipientsEntry - 4, // 3: assetwalletrpc.PrevId.outpoint:type_name -> assetwalletrpc.OutPoint + 17, // 2: assetwalletrpc.TxTemplate.recipients:type_name -> assetwalletrpc.TxTemplate.RecipientsEntry + 18, // 3: assetwalletrpc.PrevId.outpoint:type_name -> taprpc.OutPoint 19, // 4: assetwalletrpc.NextInternalKeyResponse.internal_key:type_name -> taprpc.KeyDescriptor 20, // 5: assetwalletrpc.NextScriptKeyResponse.script_key:type_name -> taprpc.ScriptKey - 4, // 6: assetwalletrpc.RemoveUTXOLeaseRequest.outpoint:type_name -> assetwalletrpc.OutPoint - 0, // 7: assetwalletrpc.AssetWallet.FundVirtualPsbt:input_type -> assetwalletrpc.FundVirtualPsbtRequest - 5, // 8: assetwalletrpc.AssetWallet.SignVirtualPsbt:input_type -> assetwalletrpc.SignVirtualPsbtRequest - 7, // 9: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:input_type -> assetwalletrpc.AnchorVirtualPsbtsRequest - 8, // 10: assetwalletrpc.AssetWallet.NextInternalKey:input_type -> assetwalletrpc.NextInternalKeyRequest - 10, // 11: assetwalletrpc.AssetWallet.NextScriptKey:input_type -> assetwalletrpc.NextScriptKeyRequest - 12, // 12: assetwalletrpc.AssetWallet.ProveAssetOwnership:input_type -> assetwalletrpc.ProveAssetOwnershipRequest - 14, // 13: assetwalletrpc.AssetWallet.VerifyAssetOwnership:input_type -> assetwalletrpc.VerifyAssetOwnershipRequest - 16, // 14: assetwalletrpc.AssetWallet.RemoveUTXOLease:input_type -> assetwalletrpc.RemoveUTXOLeaseRequest - 1, // 15: assetwalletrpc.AssetWallet.FundVirtualPsbt:output_type -> assetwalletrpc.FundVirtualPsbtResponse - 6, // 16: assetwalletrpc.AssetWallet.SignVirtualPsbt:output_type -> assetwalletrpc.SignVirtualPsbtResponse - 21, // 17: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:output_type -> taprpc.SendAssetResponse - 9, // 18: assetwalletrpc.AssetWallet.NextInternalKey:output_type -> assetwalletrpc.NextInternalKeyResponse - 11, // 19: assetwalletrpc.AssetWallet.NextScriptKey:output_type -> assetwalletrpc.NextScriptKeyResponse - 13, // 20: assetwalletrpc.AssetWallet.ProveAssetOwnership:output_type -> assetwalletrpc.ProveAssetOwnershipResponse - 15, // 21: assetwalletrpc.AssetWallet.VerifyAssetOwnership:output_type -> assetwalletrpc.VerifyAssetOwnershipResponse - 17, // 22: assetwalletrpc.AssetWallet.RemoveUTXOLease:output_type -> assetwalletrpc.RemoveUTXOLeaseResponse - 15, // [15:23] is the sub-list for method output_type - 7, // [7:15] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 18, // 6: assetwalletrpc.ProveAssetOwnershipRequest.outpoint:type_name -> taprpc.OutPoint + 18, // 7: assetwalletrpc.RemoveUTXOLeaseRequest.outpoint:type_name -> taprpc.OutPoint + 0, // 8: assetwalletrpc.AssetWallet.FundVirtualPsbt:input_type -> assetwalletrpc.FundVirtualPsbtRequest + 4, // 9: assetwalletrpc.AssetWallet.SignVirtualPsbt:input_type -> assetwalletrpc.SignVirtualPsbtRequest + 6, // 10: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:input_type -> assetwalletrpc.AnchorVirtualPsbtsRequest + 7, // 11: assetwalletrpc.AssetWallet.NextInternalKey:input_type -> assetwalletrpc.NextInternalKeyRequest + 9, // 12: assetwalletrpc.AssetWallet.NextScriptKey:input_type -> assetwalletrpc.NextScriptKeyRequest + 11, // 13: assetwalletrpc.AssetWallet.ProveAssetOwnership:input_type -> assetwalletrpc.ProveAssetOwnershipRequest + 13, // 14: assetwalletrpc.AssetWallet.VerifyAssetOwnership:input_type -> assetwalletrpc.VerifyAssetOwnershipRequest + 15, // 15: assetwalletrpc.AssetWallet.RemoveUTXOLease:input_type -> assetwalletrpc.RemoveUTXOLeaseRequest + 1, // 16: assetwalletrpc.AssetWallet.FundVirtualPsbt:output_type -> assetwalletrpc.FundVirtualPsbtResponse + 5, // 17: assetwalletrpc.AssetWallet.SignVirtualPsbt:output_type -> assetwalletrpc.SignVirtualPsbtResponse + 21, // 18: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:output_type -> taprpc.SendAssetResponse + 8, // 19: assetwalletrpc.AssetWallet.NextInternalKey:output_type -> assetwalletrpc.NextInternalKeyResponse + 10, // 20: assetwalletrpc.AssetWallet.NextScriptKey:output_type -> assetwalletrpc.NextScriptKeyResponse + 12, // 21: assetwalletrpc.AssetWallet.ProveAssetOwnership:output_type -> assetwalletrpc.ProveAssetOwnershipResponse + 14, // 22: assetwalletrpc.AssetWallet.VerifyAssetOwnership:output_type -> assetwalletrpc.VerifyAssetOwnershipResponse + 16, // 23: assetwalletrpc.AssetWallet.RemoveUTXOLease:output_type -> assetwalletrpc.RemoveUTXOLeaseResponse + 16, // [16:24] is the sub-list for method output_type + 8, // [8:16] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_assetwalletrpc_assetwallet_proto_init() } @@ -1261,18 +1211,6 @@ func file_assetwalletrpc_assetwallet_proto_init() { } } file_assetwalletrpc_assetwallet_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OutPoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_assetwalletrpc_assetwallet_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SignVirtualPsbtRequest); i { case 0: return &v.state @@ -1284,7 +1222,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SignVirtualPsbtResponse); i { case 0: return &v.state @@ -1296,7 +1234,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AnchorVirtualPsbtsRequest); i { case 0: return &v.state @@ -1308,7 +1246,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NextInternalKeyRequest); i { case 0: return &v.state @@ -1320,7 +1258,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NextInternalKeyResponse); i { case 0: return &v.state @@ -1332,7 +1270,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NextScriptKeyRequest); i { case 0: return &v.state @@ -1344,7 +1282,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*NextScriptKeyResponse); i { case 0: return &v.state @@ -1356,7 +1294,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ProveAssetOwnershipRequest); i { case 0: return &v.state @@ -1368,7 +1306,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ProveAssetOwnershipResponse); i { case 0: return &v.state @@ -1380,7 +1318,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VerifyAssetOwnershipRequest); i { case 0: return &v.state @@ -1392,7 +1330,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*VerifyAssetOwnershipResponse); i { case 0: return &v.state @@ -1404,7 +1342,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RemoveUTXOLeaseRequest); i { case 0: return &v.state @@ -1416,7 +1354,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { return nil } } - file_assetwalletrpc_assetwallet_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_assetwalletrpc_assetwallet_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RemoveUTXOLeaseResponse); i { case 0: return &v.state @@ -1439,7 +1377,7 @@ func file_assetwalletrpc_assetwallet_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_assetwalletrpc_assetwallet_proto_rawDesc, NumEnums: 0, - NumMessages: 19, + NumMessages: 18, NumExtensions: 0, NumServices: 1, }, diff --git a/taprpc/assetwalletrpc/assetwallet.proto b/taprpc/assetwalletrpc/assetwallet.proto index 5a0709655..c73240d76 100644 --- a/taprpc/assetwalletrpc/assetwallet.proto +++ b/taprpc/assetwalletrpc/assetwallet.proto @@ -125,7 +125,7 @@ message PrevId { /* The bitcoin anchor output on chain that contains the input asset. */ - OutPoint outpoint = 1; + taprpc.OutPoint outpoint = 1; /* The asset ID of the previous asset tree. @@ -139,18 +139,6 @@ message PrevId { bytes script_key = 3; } -message OutPoint { - /* - Raw bytes representing the transaction id. - */ - bytes txid = 1; - - /* - The index of the output on the transaction. - */ - uint32 output_index = 2; -} - message SignVirtualPsbtRequest { /* The PSBT of the virtual transaction that should be signed. The PSBT must @@ -200,6 +188,8 @@ message ProveAssetOwnershipRequest { bytes asset_id = 1; bytes script_key = 2; + + taprpc.OutPoint outpoint = 3; } message ProveAssetOwnershipResponse { @@ -216,7 +206,7 @@ message VerifyAssetOwnershipResponse { message RemoveUTXOLeaseRequest { // The outpoint of the UTXO to remove the lease for. - OutPoint outpoint = 1; + taprpc.OutPoint outpoint = 1; } message RemoveUTXOLeaseResponse { diff --git a/taprpc/assetwalletrpc/assetwallet.swagger.json b/taprpc/assetwalletrpc/assetwallet.swagger.json index 4d778587a..5841d4224 100644 --- a/taprpc/assetwalletrpc/assetwallet.swagger.json +++ b/taprpc/assetwalletrpc/assetwallet.swagger.json @@ -359,26 +359,11 @@ } } }, - "assetwalletrpcOutPoint": { - "type": "object", - "properties": { - "txid": { - "type": "string", - "format": "byte", - "description": "Raw bytes representing the transaction id." - }, - "output_index": { - "type": "integer", - "format": "int64", - "description": "The index of the output on the transaction." - } - } - }, "assetwalletrpcPrevId": { "type": "object", "properties": { "outpoint": { - "$ref": "#/definitions/assetwalletrpcOutPoint", + "$ref": "#/definitions/taprpcOutPoint", "description": "The bitcoin anchor output on chain that contains the input asset." }, "id": { @@ -403,6 +388,9 @@ "script_key": { "type": "string", "format": "byte" + }, + "outpoint": { + "$ref": "#/definitions/taprpcOutPoint" } } }, @@ -419,7 +407,7 @@ "type": "object", "properties": { "outpoint": { - "$ref": "#/definitions/assetwalletrpcOutPoint", + "$ref": "#/definitions/taprpcOutPoint", "description": "The outpoint of the UTXO to remove the lease for." } } @@ -596,6 +584,21 @@ } } }, + "taprpcOutPoint": { + "type": "object", + "properties": { + "txid": { + "type": "string", + "format": "byte", + "description": "Raw bytes representing the transaction id." + }, + "output_index": { + "type": "integer", + "format": "int64", + "description": "The index of the output on the transaction." + } + } + }, "taprpcOutputType": { "type": "string", "enum": [ diff --git a/taprpc/taprootassets.pb.go b/taprpc/taprootassets.pb.go index 45ac220c6..42ff4a74c 100644 --- a/taprpc/taprootassets.pb.go +++ b/taprpc/taprootassets.pb.go @@ -3572,8 +3572,9 @@ type ExportProofRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AssetId []byte `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - ScriptKey []byte `protobuf:"bytes,2,opt,name=script_key,json=scriptKey,proto3" json:"script_key,omitempty"` + AssetId []byte `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` + ScriptKey []byte `protobuf:"bytes,2,opt,name=script_key,json=scriptKey,proto3" json:"script_key,omitempty"` + Outpoint *OutPoint `protobuf:"bytes,3,opt,name=outpoint,proto3" json:"outpoint,omitempty"` } func (x *ExportProofRequest) Reset() { @@ -3622,6 +3623,13 @@ func (x *ExportProofRequest) GetScriptKey() []byte { return nil } +func (x *ExportProofRequest) GetOutpoint() *OutPoint { + if x != nil { + return x.Outpoint + } + return nil +} + type AddrEvent struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -4873,6 +4881,63 @@ func (x *BurnAssetResponse) GetBurnProof() *DecodedProof { return nil } +type OutPoint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Raw bytes representing the transaction id. + Txid []byte `protobuf:"bytes,1,opt,name=txid,proto3" json:"txid,omitempty"` + // The index of the output on the transaction. + OutputIndex uint32 `protobuf:"varint,2,opt,name=output_index,json=outputIndex,proto3" json:"output_index,omitempty"` +} + +func (x *OutPoint) Reset() { + *x = OutPoint{} + if protoimpl.UnsafeEnabled { + mi := &file_taprootassets_proto_msgTypes[64] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OutPoint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OutPoint) ProtoMessage() {} + +func (x *OutPoint) ProtoReflect() protoreflect.Message { + mi := &file_taprootassets_proto_msgTypes[64] + 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 OutPoint.ProtoReflect.Descriptor instead. +func (*OutPoint) Descriptor() ([]byte, []int) { + return file_taprootassets_proto_rawDescGZIP(), []int{64} +} + +func (x *OutPoint) GetTxid() []byte { + if x != nil { + return x.Txid + } + return nil +} + +func (x *OutPoint) GetOutputIndex() uint32 { + if x != nil { + return x.OutputIndex + } + return 0 +} + var File_taprootassets_proto protoreflect.FileDescriptor var file_taprootassets_proto_rawDesc = []byte{ @@ -5341,302 +5406,310 @@ var file_taprootassets_proto_rawDesc = []byte{ 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x0c, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, - 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x4e, 0x0a, 0x12, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, + 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x7c, 0x0a, 0x12, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x22, 0xd0, 0x02, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x72, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x1a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, - 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x73, 0x12, 0x20, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x04, 0x61, - 0x64, 0x64, 0x72, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, - 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x74, 0x78, 0x6f, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x73, 0x61, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x74, 0x78, 0x6f, 0x41, 0x6d, 0x74, 0x53, - 0x61, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x73, 0x69, - 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x74, 0x61, 0x70, - 0x72, 0x6f, 0x6f, 0x74, 0x53, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x13, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, - 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1b, 0x0a, 0x09, - 0x68, 0x61, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x08, 0x68, 0x61, 0x73, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x74, 0x0a, 0x13, 0x41, 0x64, 0x64, - 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x12, 0x3c, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x0c, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, - 0x41, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x41, 0x64, 0x64, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x73, 0x22, 0x4a, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x70, 0x5f, 0x61, 0x64, - 0x64, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x70, 0x41, 0x64, - 0x64, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x22, 0x85, - 0x01, 0x0a, 0x0e, 0x50, 0x72, 0x65, 0x76, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x41, 0x73, 0x73, 0x65, - 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, - 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x16, - 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, - 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x46, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x52, 0x08, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x22, 0x10, - 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x9b, 0x02, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, - 0x0a, 0x0b, 0x6c, 0x6e, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x2e, 0x0a, 0x13, 0x6c, 0x6e, 0x64, - 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6c, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x64, - 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, - 0x6f, 0x64, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, - 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, - 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x79, - 0x6e, 0x63, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0b, 0x73, 0x79, 0x6e, 0x63, 0x54, 0x6f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x25, - 0x0a, 0x23, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x41, - 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xe6, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x18, 0x65, 0x78, 0x65, 0x63, - 0x75, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x61, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x65, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x71, 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x77, 0x61, 0x69, - 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, + 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x22, 0xd0, 0x02, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x72, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x1a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x20, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, + 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x04, 0x61, 0x64, 0x64, + 0x72, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x20, + 0x0a, 0x0c, 0x75, 0x74, 0x78, 0x6f, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x73, 0x61, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x74, 0x78, 0x6f, 0x41, 0x6d, 0x74, 0x53, 0x61, 0x74, + 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x73, 0x69, 0x62, 0x6c, + 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x74, 0x61, 0x70, 0x72, 0x6f, + 0x6f, 0x74, 0x53, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x61, + 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x68, + 0x61, 0x73, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x74, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x72, 0x52, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, + 0x0a, 0x0b, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x12, + 0x3c, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x41, 0x64, 0x64, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x0c, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x41, 0x0a, + 0x14, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, + 0x64, 0x64, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x22, 0x4a, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x70, 0x41, 0x64, 0x64, 0x72, + 0x73, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x07, 0x66, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x22, 0x85, 0x01, 0x0a, + 0x0e, 0x50, 0x72, 0x65, 0x76, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, + 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x46, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x52, 0x08, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x22, 0x10, 0x0a, 0x0e, + 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x9b, + 0x02, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, + 0x6c, 0x6e, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x6c, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x2e, 0x0a, 0x13, 0x6c, 0x6e, 0x64, 0x5f, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6c, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x5f, + 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x64, + 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x73, 0x79, 0x6e, 0x63, + 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0b, 0x73, 0x79, 0x6e, 0x63, 0x54, 0x6f, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x25, 0x0a, 0x23, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0xe6, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x18, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x65, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x71, 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x77, 0x61, 0x69, 0x74, 0x5f, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x54, 0x0a, 0x15, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 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, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x22, 0xbc, 0x01, 0x0a, 0x1d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x54, - 0x0a, 0x15, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 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, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x64, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x22, 0xbc, 0x01, 0x0a, 0x1d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 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, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x12, 0x23, - 0x0a, 0x0d, 0x74, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x72, 0x69, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x74, 0x61, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, - 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, - 0x79, 0x70, 0x65, 0x22, 0x28, 0x0a, 0x26, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7d, 0x0a, - 0x19, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 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, 0x26, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x61, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0xf5, 0x01, 0x0a, - 0x11, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x71, 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x77, 0x61, 0x69, - 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x64, 0x0a, 0x1c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x72, - 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x61, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, - 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x19, 0x61, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x15, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, - 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x00, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x09, 0x6d, - 0x65, 0x74, 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, - 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x73, - 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x53, 0x74, 0x72, 0x12, 0x24, - 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x72, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x65, 0x74, 0x61, 0x48, 0x61, 0x73, - 0x68, 0x53, 0x74, 0x72, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x22, 0xaf, 0x01, - 0x0a, 0x10, 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, - 0x22, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, - 0x53, 0x74, 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x6f, - 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x61, 0x6d, 0x6f, - 0x75, 0x6e, 0x74, 0x54, 0x6f, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x65, 0x78, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x22, - 0x84, 0x01, 0x0a, 0x11, 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0d, 0x62, 0x75, 0x72, 0x6e, 0x5f, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, - 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x66, 0x65, 0x72, 0x52, 0x0c, 0x62, 0x75, 0x72, 0x6e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, - 0x72, 0x12, 0x33, 0x0a, 0x0a, 0x62, 0x75, 0x72, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, - 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x09, 0x62, 0x75, 0x72, - 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x2a, 0x28, 0x0a, 0x09, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, - 0x0f, 0x0a, 0x0b, 0x43, 0x4f, 0x4c, 0x4c, 0x45, 0x43, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x10, 0x01, - 0x2a, 0x25, 0x0a, 0x0d, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x14, 0x0a, 0x10, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, - 0x50, 0x41, 0x51, 0x55, 0x45, 0x10, 0x00, 0x2a, 0x3a, 0x0a, 0x0c, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x53, 0x53, 0x45, 0x54, - 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x30, 0x10, 0x00, 0x12, 0x14, 0x0a, - 0x10, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, - 0x31, 0x10, 0x01, 0x2a, 0xb0, 0x01, 0x0a, 0x0a, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x4f, 0x55, - 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x50, 0x4c, 0x49, 0x54, 0x5f, - 0x52, 0x4f, 0x4f, 0x54, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x53, - 0x53, 0x45, 0x54, 0x53, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x12, 0x22, 0x0a, 0x1e, 0x4f, - 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x49, - 0x56, 0x45, 0x5f, 0x53, 0x50, 0x4c, 0x49, 0x54, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x10, 0x03, 0x12, - 0x25, 0x0a, 0x21, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, - 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, 0x53, - 0x53, 0x45, 0x54, 0x53, 0x10, 0x04, 0x2a, 0xd0, 0x01, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x72, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x44, - 0x44, 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x2a, 0x0a, 0x26, 0x41, 0x44, 0x44, - 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54, - 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x54, 0x45, 0x43, - 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x2b, 0x0a, 0x27, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x45, 0x56, - 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, - 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, - 0x10, 0x02, 0x12, 0x24, 0x0a, 0x20, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x52, 0x45, - 0x43, 0x45, 0x49, 0x56, 0x45, 0x44, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x41, 0x44, 0x44, 0x52, - 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, - 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x52, 0x0a, 0x11, 0x50, 0x72, 0x6f, - 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1c, - 0x0a, 0x18, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x1f, 0x0a, 0x1b, - 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x10, 0x01, 0x32, 0x86, 0x0b, - 0x0a, 0x0d, 0x54, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x12, - 0x41, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x12, 0x18, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x40, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x12, - 0x18, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x74, 0x78, - 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x12, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0c, 0x4c, 0x69, 0x73, - 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x61, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, - 0x12, 0x13, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x44, - 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, - 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x41, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, 0x18, - 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x12, 0x16, - 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x41, 0x64, 0x64, 0x72, 0x12, 0x35, 0x0a, 0x0a, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x41, 0x64, - 0x64, 0x72, 0x12, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6f, - 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x49, 0x0a, 0x0c, 0x41, - 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x61, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x1a, 0x1b, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1a, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, - 0x63, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1b, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, - 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1a, 0x2e, 0x74, - 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x09, 0x53, - 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, - 0x09, 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x18, 0x2e, 0x74, 0x61, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, - 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x3a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x74, 0x61, 0x70, - 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x1c, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x74, 0x61, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, - 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x30, 0x01, 0x12, 0x6e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, + 0x76, 0x65, 0x6e, 0x74, 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, 0x18, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x12, 0x23, 0x0a, 0x0d, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x72, 0x69, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x28, 0x0a, 0x26, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, + 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, + 0x74, 0x66, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x7d, 0x0a, 0x19, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 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, 0x26, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0xf5, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x12, 0x2e, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, - 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, - 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, - 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, - 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, - 0x62, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x71, 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x77, 0x61, 0x69, 0x74, 0x5f, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x57, 0x61, 0x69, 0x74, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x64, 0x0a, 0x1c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x63, + 0x65, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x19, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x15, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x08, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, + 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x09, 0x6d, 0x65, 0x74, + 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x53, 0x74, 0x72, 0x12, 0x24, 0x0a, 0x0d, + 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x6d, 0x65, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x53, + 0x74, 0x72, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x22, 0xaf, 0x01, 0x0a, 0x10, + 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1b, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x12, 0x22, 0x0a, + 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x73, 0x73, 0x65, 0x74, 0x49, 0x64, 0x53, 0x74, + 0x72, 0x12, 0x24, 0x0a, 0x0e, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x62, + 0x75, 0x72, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x61, 0x6d, 0x6f, 0x75, 0x6e, + 0x74, 0x54, 0x6f, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x65, 0x78, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x22, 0x84, 0x01, + 0x0a, 0x11, 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x0d, 0x62, 0x75, 0x72, 0x6e, 0x5f, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x66, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x61, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, + 0x72, 0x52, 0x0c, 0x62, 0x75, 0x72, 0x6e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, + 0x33, 0x0a, 0x0a, 0x62, 0x75, 0x72, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, + 0x6f, 0x64, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x09, 0x62, 0x75, 0x72, 0x6e, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x41, 0x0a, 0x08, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x74, 0x78, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x2a, 0x28, 0x0a, 0x09, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, + 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x4f, 0x4c, 0x4c, 0x45, 0x43, 0x54, 0x49, 0x42, 0x4c, 0x45, 0x10, + 0x01, 0x2a, 0x25, 0x0a, 0x0d, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x4f, 0x50, 0x41, 0x51, 0x55, 0x45, 0x10, 0x00, 0x2a, 0x3a, 0x0a, 0x0c, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x53, 0x53, 0x45, + 0x54, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x30, 0x10, 0x00, 0x12, 0x14, + 0x0a, 0x10, 0x41, 0x53, 0x53, 0x45, 0x54, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, + 0x56, 0x31, 0x10, 0x01, 0x2a, 0xb0, 0x01, 0x0a, 0x0a, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x4f, + 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x50, 0x4c, 0x49, 0x54, + 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x4f, 0x55, 0x54, 0x50, 0x55, + 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, + 0x53, 0x53, 0x45, 0x54, 0x53, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x12, 0x22, 0x0a, 0x1e, + 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, + 0x49, 0x56, 0x45, 0x5f, 0x53, 0x50, 0x4c, 0x49, 0x54, 0x5f, 0x52, 0x4f, 0x4f, 0x54, 0x10, 0x03, + 0x12, 0x25, 0x0a, 0x21, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x53, 0x49, 0x4d, 0x50, 0x4c, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x41, + 0x53, 0x53, 0x45, 0x54, 0x53, 0x10, 0x04, 0x2a, 0xd0, 0x01, 0x0a, 0x0f, 0x41, 0x64, 0x64, 0x72, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x41, + 0x44, 0x44, 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x2a, 0x0a, 0x26, 0x41, 0x44, + 0x44, 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x54, 0x52, 0x41, 0x4e, 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x54, 0x45, + 0x43, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x2b, 0x0a, 0x27, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x45, + 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54, 0x52, 0x41, 0x4e, + 0x53, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, + 0x44, 0x10, 0x02, 0x12, 0x24, 0x0a, 0x20, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, + 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x52, + 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x44, 0x10, 0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x41, 0x44, 0x44, + 0x52, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, + 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x52, 0x0a, 0x11, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x1c, 0x0a, 0x18, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, + 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x1f, 0x0a, + 0x1b, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x45, 0x49, 0x56, 0x45, 0x10, 0x01, 0x32, 0x86, + 0x0b, 0x0a, 0x0d, 0x54, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, + 0x12, 0x41, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x12, 0x18, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x12, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x74, + 0x78, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x12, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0c, 0x4c, 0x69, + 0x73, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x61, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x70, 0x44, 0x61, 0x65, 0x6d, 0x6f, + 0x6e, 0x12, 0x13, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0a, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x19, 0x2e, 0x74, 0x61, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, + 0x65, 0x62, 0x75, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x41, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x73, 0x12, + 0x18, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x64, + 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x12, + 0x16, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x35, 0x0a, 0x0a, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x41, + 0x64, 0x64, 0x72, 0x12, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, + 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x12, 0x49, 0x0a, 0x0c, + 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x74, + 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0b, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x1a, 0x1b, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1a, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, + 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6f, 0x64, + 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, + 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x1a, 0x2e, + 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x09, + 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, + 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, + 0x0a, 0x09, 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x18, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x42, 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x42, + 0x75, 0x72, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x3a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x1c, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x74, + 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, + 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x30, 0x01, 0x12, 0x6e, 0x0a, 0x1f, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x12, 0x2e, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4e, 0x74, 0x66, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, + 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, + 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x73, 0x2f, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -5652,7 +5725,7 @@ func file_taprootassets_proto_rawDescGZIP() []byte { } var file_taprootassets_proto_enumTypes = make([]protoimpl.EnumInfo, 6) -var file_taprootassets_proto_msgTypes = make([]protoimpl.MessageInfo, 68) +var file_taprootassets_proto_msgTypes = make([]protoimpl.MessageInfo, 69) var file_taprootassets_proto_goTypes = []interface{}{ (AssetType)(0), // 0: taprpc.AssetType (AssetMetaType)(0), // 1: taprpc.AssetMetaType @@ -5724,10 +5797,11 @@ var file_taprootassets_proto_goTypes = []interface{}{ (*FetchAssetMetaRequest)(nil), // 67: taprpc.FetchAssetMetaRequest (*BurnAssetRequest)(nil), // 68: taprpc.BurnAssetRequest (*BurnAssetResponse)(nil), // 69: taprpc.BurnAssetResponse - nil, // 70: taprpc.ListUtxosResponse.ManagedUtxosEntry - nil, // 71: taprpc.ListGroupsResponse.GroupsEntry - nil, // 72: taprpc.ListBalancesResponse.AssetBalancesEntry - nil, // 73: taprpc.ListBalancesResponse.AssetGroupBalancesEntry + (*OutPoint)(nil), // 70: taprpc.OutPoint + nil, // 71: taprpc.ListUtxosResponse.ManagedUtxosEntry + nil, // 72: taprpc.ListGroupsResponse.GroupsEntry + nil, // 73: taprpc.ListBalancesResponse.AssetBalancesEntry + nil, // 74: taprpc.ListBalancesResponse.AssetGroupBalancesEntry } var file_taprootassets_proto_depIdxs = []int32{ 1, // 0: taprpc.AssetMeta.type:type_name -> taprpc.AssetMetaType @@ -5743,14 +5817,14 @@ var file_taprootassets_proto_depIdxs = []int32{ 13, // 10: taprpc.SplitCommitment.root_asset:type_name -> taprpc.Asset 13, // 11: taprpc.ListAssetResponse.assets:type_name -> taprpc.Asset 13, // 12: taprpc.ManagedUtxo.assets:type_name -> taprpc.Asset - 70, // 13: taprpc.ListUtxosResponse.managed_utxos:type_name -> taprpc.ListUtxosResponse.ManagedUtxosEntry + 71, // 13: taprpc.ListUtxosResponse.managed_utxos:type_name -> taprpc.ListUtxosResponse.ManagedUtxosEntry 0, // 14: taprpc.AssetHumanReadable.type:type_name -> taprpc.AssetType 2, // 15: taprpc.AssetHumanReadable.version:type_name -> taprpc.AssetVersion 21, // 16: taprpc.GroupedAssets.assets:type_name -> taprpc.AssetHumanReadable - 71, // 17: taprpc.ListGroupsResponse.groups:type_name -> taprpc.ListGroupsResponse.GroupsEntry + 72, // 17: taprpc.ListGroupsResponse.groups:type_name -> taprpc.ListGroupsResponse.GroupsEntry 9, // 18: taprpc.AssetBalance.asset_genesis:type_name -> taprpc.GenesisInfo - 72, // 19: taprpc.ListBalancesResponse.asset_balances:type_name -> taprpc.ListBalancesResponse.AssetBalancesEntry - 73, // 20: taprpc.ListBalancesResponse.asset_group_balances:type_name -> taprpc.ListBalancesResponse.AssetGroupBalancesEntry + 73, // 19: taprpc.ListBalancesResponse.asset_balances:type_name -> taprpc.ListBalancesResponse.AssetBalancesEntry + 74, // 20: taprpc.ListBalancesResponse.asset_group_balances:type_name -> taprpc.ListBalancesResponse.AssetGroupBalancesEntry 30, // 21: taprpc.ListTransfersResponse.transfers:type_name -> taprpc.AssetTransfer 31, // 22: taprpc.AssetTransfer.inputs:type_name -> taprpc.TransferInput 33, // 23: taprpc.AssetTransfer.outputs:type_name -> taprpc.TransferOutput @@ -5771,68 +5845,69 @@ var file_taprootassets_proto_depIdxs = []int32{ 11, // 38: taprpc.DecodedProof.group_key_reveal:type_name -> taprpc.GroupKeyReveal 47, // 39: taprpc.VerifyProofResponse.decoded_proof:type_name -> taprpc.DecodedProof 47, // 40: taprpc.DecodeProofResponse.decoded_proof:type_name -> taprpc.DecodedProof - 38, // 41: taprpc.AddrEvent.addr:type_name -> taprpc.Addr - 4, // 42: taprpc.AddrEvent.status:type_name -> taprpc.AddrEventStatus - 4, // 43: taprpc.AddrReceivesRequest.filter_status:type_name -> taprpc.AddrEventStatus - 52, // 44: taprpc.AddrReceivesResponse.events:type_name -> taprpc.AddrEvent - 30, // 45: taprpc.SendAssetResponse.transfer:type_name -> taprpc.AssetTransfer - 62, // 46: taprpc.SendAssetEvent.execute_send_state_event:type_name -> taprpc.ExecuteSendStateEvent - 63, // 47: taprpc.SendAssetEvent.proof_transfer_backoff_wait_event:type_name -> taprpc.ProofTransferBackoffWaitEvent - 5, // 48: taprpc.ProofTransferBackoffWaitEvent.transfer_type:type_name -> taprpc.ProofTransferType - 38, // 49: taprpc.AssetReceiveCompleteEvent.address:type_name -> taprpc.Addr - 63, // 50: taprpc.ReceiveAssetEvent.proof_transfer_backoff_wait_event:type_name -> taprpc.ProofTransferBackoffWaitEvent - 65, // 51: taprpc.ReceiveAssetEvent.asset_receive_complete_event:type_name -> taprpc.AssetReceiveCompleteEvent - 30, // 52: taprpc.BurnAssetResponse.burn_transfer:type_name -> taprpc.AssetTransfer - 47, // 53: taprpc.BurnAssetResponse.burn_proof:type_name -> taprpc.DecodedProof - 18, // 54: taprpc.ListUtxosResponse.ManagedUtxosEntry.value:type_name -> taprpc.ManagedUtxo - 22, // 55: taprpc.ListGroupsResponse.GroupsEntry.value:type_name -> taprpc.GroupedAssets - 25, // 56: taprpc.ListBalancesResponse.AssetBalancesEntry.value:type_name -> taprpc.AssetBalance - 26, // 57: taprpc.ListBalancesResponse.AssetGroupBalancesEntry.value:type_name -> taprpc.AssetGroupBalance - 7, // 58: taprpc.TaprootAssets.ListAssets:input_type -> taprpc.ListAssetRequest - 17, // 59: taprpc.TaprootAssets.ListUtxos:input_type -> taprpc.ListUtxosRequest - 20, // 60: taprpc.TaprootAssets.ListGroups:input_type -> taprpc.ListGroupsRequest - 24, // 61: taprpc.TaprootAssets.ListBalances:input_type -> taprpc.ListBalancesRequest - 28, // 62: taprpc.TaprootAssets.ListTransfers:input_type -> taprpc.ListTransfersRequest - 34, // 63: taprpc.TaprootAssets.StopDaemon:input_type -> taprpc.StopRequest - 36, // 64: taprpc.TaprootAssets.DebugLevel:input_type -> taprpc.DebugLevelRequest - 39, // 65: taprpc.TaprootAssets.QueryAddrs:input_type -> taprpc.QueryAddrRequest - 41, // 66: taprpc.TaprootAssets.NewAddr:input_type -> taprpc.NewAddrRequest - 45, // 67: taprpc.TaprootAssets.DecodeAddr:input_type -> taprpc.DecodeAddrRequest - 53, // 68: taprpc.TaprootAssets.AddrReceives:input_type -> taprpc.AddrReceivesRequest - 46, // 69: taprpc.TaprootAssets.VerifyProof:input_type -> taprpc.ProofFile - 49, // 70: taprpc.TaprootAssets.DecodeProof:input_type -> taprpc.DecodeProofRequest - 51, // 71: taprpc.TaprootAssets.ExportProof:input_type -> taprpc.ExportProofRequest - 55, // 72: taprpc.TaprootAssets.SendAsset:input_type -> taprpc.SendAssetRequest - 68, // 73: taprpc.TaprootAssets.BurnAsset:input_type -> taprpc.BurnAssetRequest - 58, // 74: taprpc.TaprootAssets.GetInfo:input_type -> taprpc.GetInfoRequest - 60, // 75: taprpc.TaprootAssets.SubscribeSendAssetEventNtfns:input_type -> taprpc.SubscribeSendAssetEventNtfnsRequest - 64, // 76: taprpc.TaprootAssets.SubscribeReceiveAssetEventNtfns:input_type -> taprpc.SubscribeReceiveAssetEventNtfnsRequest - 67, // 77: taprpc.TaprootAssets.FetchAssetMeta:input_type -> taprpc.FetchAssetMetaRequest - 16, // 78: taprpc.TaprootAssets.ListAssets:output_type -> taprpc.ListAssetResponse - 19, // 79: taprpc.TaprootAssets.ListUtxos:output_type -> taprpc.ListUtxosResponse - 23, // 80: taprpc.TaprootAssets.ListGroups:output_type -> taprpc.ListGroupsResponse - 27, // 81: taprpc.TaprootAssets.ListBalances:output_type -> taprpc.ListBalancesResponse - 29, // 82: taprpc.TaprootAssets.ListTransfers:output_type -> taprpc.ListTransfersResponse - 35, // 83: taprpc.TaprootAssets.StopDaemon:output_type -> taprpc.StopResponse - 37, // 84: taprpc.TaprootAssets.DebugLevel:output_type -> taprpc.DebugLevelResponse - 40, // 85: taprpc.TaprootAssets.QueryAddrs:output_type -> taprpc.QueryAddrResponse - 38, // 86: taprpc.TaprootAssets.NewAddr:output_type -> taprpc.Addr - 38, // 87: taprpc.TaprootAssets.DecodeAddr:output_type -> taprpc.Addr - 54, // 88: taprpc.TaprootAssets.AddrReceives:output_type -> taprpc.AddrReceivesResponse - 48, // 89: taprpc.TaprootAssets.VerifyProof:output_type -> taprpc.VerifyProofResponse - 50, // 90: taprpc.TaprootAssets.DecodeProof:output_type -> taprpc.DecodeProofResponse - 46, // 91: taprpc.TaprootAssets.ExportProof:output_type -> taprpc.ProofFile - 57, // 92: taprpc.TaprootAssets.SendAsset:output_type -> taprpc.SendAssetResponse - 69, // 93: taprpc.TaprootAssets.BurnAsset:output_type -> taprpc.BurnAssetResponse - 59, // 94: taprpc.TaprootAssets.GetInfo:output_type -> taprpc.GetInfoResponse - 61, // 95: taprpc.TaprootAssets.SubscribeSendAssetEventNtfns:output_type -> taprpc.SendAssetEvent - 66, // 96: taprpc.TaprootAssets.SubscribeReceiveAssetEventNtfns:output_type -> taprpc.ReceiveAssetEvent - 6, // 97: taprpc.TaprootAssets.FetchAssetMeta:output_type -> taprpc.AssetMeta - 78, // [78:98] is the sub-list for method output_type - 58, // [58:78] is the sub-list for method input_type - 58, // [58:58] is the sub-list for extension type_name - 58, // [58:58] is the sub-list for extension extendee - 0, // [0:58] is the sub-list for field type_name + 70, // 41: taprpc.ExportProofRequest.outpoint:type_name -> taprpc.OutPoint + 38, // 42: taprpc.AddrEvent.addr:type_name -> taprpc.Addr + 4, // 43: taprpc.AddrEvent.status:type_name -> taprpc.AddrEventStatus + 4, // 44: taprpc.AddrReceivesRequest.filter_status:type_name -> taprpc.AddrEventStatus + 52, // 45: taprpc.AddrReceivesResponse.events:type_name -> taprpc.AddrEvent + 30, // 46: taprpc.SendAssetResponse.transfer:type_name -> taprpc.AssetTransfer + 62, // 47: taprpc.SendAssetEvent.execute_send_state_event:type_name -> taprpc.ExecuteSendStateEvent + 63, // 48: taprpc.SendAssetEvent.proof_transfer_backoff_wait_event:type_name -> taprpc.ProofTransferBackoffWaitEvent + 5, // 49: taprpc.ProofTransferBackoffWaitEvent.transfer_type:type_name -> taprpc.ProofTransferType + 38, // 50: taprpc.AssetReceiveCompleteEvent.address:type_name -> taprpc.Addr + 63, // 51: taprpc.ReceiveAssetEvent.proof_transfer_backoff_wait_event:type_name -> taprpc.ProofTransferBackoffWaitEvent + 65, // 52: taprpc.ReceiveAssetEvent.asset_receive_complete_event:type_name -> taprpc.AssetReceiveCompleteEvent + 30, // 53: taprpc.BurnAssetResponse.burn_transfer:type_name -> taprpc.AssetTransfer + 47, // 54: taprpc.BurnAssetResponse.burn_proof:type_name -> taprpc.DecodedProof + 18, // 55: taprpc.ListUtxosResponse.ManagedUtxosEntry.value:type_name -> taprpc.ManagedUtxo + 22, // 56: taprpc.ListGroupsResponse.GroupsEntry.value:type_name -> taprpc.GroupedAssets + 25, // 57: taprpc.ListBalancesResponse.AssetBalancesEntry.value:type_name -> taprpc.AssetBalance + 26, // 58: taprpc.ListBalancesResponse.AssetGroupBalancesEntry.value:type_name -> taprpc.AssetGroupBalance + 7, // 59: taprpc.TaprootAssets.ListAssets:input_type -> taprpc.ListAssetRequest + 17, // 60: taprpc.TaprootAssets.ListUtxos:input_type -> taprpc.ListUtxosRequest + 20, // 61: taprpc.TaprootAssets.ListGroups:input_type -> taprpc.ListGroupsRequest + 24, // 62: taprpc.TaprootAssets.ListBalances:input_type -> taprpc.ListBalancesRequest + 28, // 63: taprpc.TaprootAssets.ListTransfers:input_type -> taprpc.ListTransfersRequest + 34, // 64: taprpc.TaprootAssets.StopDaemon:input_type -> taprpc.StopRequest + 36, // 65: taprpc.TaprootAssets.DebugLevel:input_type -> taprpc.DebugLevelRequest + 39, // 66: taprpc.TaprootAssets.QueryAddrs:input_type -> taprpc.QueryAddrRequest + 41, // 67: taprpc.TaprootAssets.NewAddr:input_type -> taprpc.NewAddrRequest + 45, // 68: taprpc.TaprootAssets.DecodeAddr:input_type -> taprpc.DecodeAddrRequest + 53, // 69: taprpc.TaprootAssets.AddrReceives:input_type -> taprpc.AddrReceivesRequest + 46, // 70: taprpc.TaprootAssets.VerifyProof:input_type -> taprpc.ProofFile + 49, // 71: taprpc.TaprootAssets.DecodeProof:input_type -> taprpc.DecodeProofRequest + 51, // 72: taprpc.TaprootAssets.ExportProof:input_type -> taprpc.ExportProofRequest + 55, // 73: taprpc.TaprootAssets.SendAsset:input_type -> taprpc.SendAssetRequest + 68, // 74: taprpc.TaprootAssets.BurnAsset:input_type -> taprpc.BurnAssetRequest + 58, // 75: taprpc.TaprootAssets.GetInfo:input_type -> taprpc.GetInfoRequest + 60, // 76: taprpc.TaprootAssets.SubscribeSendAssetEventNtfns:input_type -> taprpc.SubscribeSendAssetEventNtfnsRequest + 64, // 77: taprpc.TaprootAssets.SubscribeReceiveAssetEventNtfns:input_type -> taprpc.SubscribeReceiveAssetEventNtfnsRequest + 67, // 78: taprpc.TaprootAssets.FetchAssetMeta:input_type -> taprpc.FetchAssetMetaRequest + 16, // 79: taprpc.TaprootAssets.ListAssets:output_type -> taprpc.ListAssetResponse + 19, // 80: taprpc.TaprootAssets.ListUtxos:output_type -> taprpc.ListUtxosResponse + 23, // 81: taprpc.TaprootAssets.ListGroups:output_type -> taprpc.ListGroupsResponse + 27, // 82: taprpc.TaprootAssets.ListBalances:output_type -> taprpc.ListBalancesResponse + 29, // 83: taprpc.TaprootAssets.ListTransfers:output_type -> taprpc.ListTransfersResponse + 35, // 84: taprpc.TaprootAssets.StopDaemon:output_type -> taprpc.StopResponse + 37, // 85: taprpc.TaprootAssets.DebugLevel:output_type -> taprpc.DebugLevelResponse + 40, // 86: taprpc.TaprootAssets.QueryAddrs:output_type -> taprpc.QueryAddrResponse + 38, // 87: taprpc.TaprootAssets.NewAddr:output_type -> taprpc.Addr + 38, // 88: taprpc.TaprootAssets.DecodeAddr:output_type -> taprpc.Addr + 54, // 89: taprpc.TaprootAssets.AddrReceives:output_type -> taprpc.AddrReceivesResponse + 48, // 90: taprpc.TaprootAssets.VerifyProof:output_type -> taprpc.VerifyProofResponse + 50, // 91: taprpc.TaprootAssets.DecodeProof:output_type -> taprpc.DecodeProofResponse + 46, // 92: taprpc.TaprootAssets.ExportProof:output_type -> taprpc.ProofFile + 57, // 93: taprpc.TaprootAssets.SendAsset:output_type -> taprpc.SendAssetResponse + 69, // 94: taprpc.TaprootAssets.BurnAsset:output_type -> taprpc.BurnAssetResponse + 59, // 95: taprpc.TaprootAssets.GetInfo:output_type -> taprpc.GetInfoResponse + 61, // 96: taprpc.TaprootAssets.SubscribeSendAssetEventNtfns:output_type -> taprpc.SendAssetEvent + 66, // 97: taprpc.TaprootAssets.SubscribeReceiveAssetEventNtfns:output_type -> taprpc.ReceiveAssetEvent + 6, // 98: taprpc.TaprootAssets.FetchAssetMeta:output_type -> taprpc.AssetMeta + 79, // [79:99] is the sub-list for method output_type + 59, // [59:79] is the sub-list for method input_type + 59, // [59:59] is the sub-list for extension type_name + 59, // [59:59] is the sub-list for extension extendee + 0, // [0:59] is the sub-list for field type_name } func init() { file_taprootassets_proto_init() } @@ -6609,6 +6684,18 @@ func file_taprootassets_proto_init() { return nil } } + file_taprootassets_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OutPoint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_taprootassets_proto_msgTypes[18].OneofWrappers = []interface{}{ (*ListBalancesRequest_AssetId)(nil), @@ -6638,7 +6725,7 @@ func file_taprootassets_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_taprootassets_proto_rawDesc, NumEnums: 6, - NumMessages: 68, + NumMessages: 69, NumExtensions: 0, NumServices: 1, }, diff --git a/taprpc/taprootassets.proto b/taprpc/taprootassets.proto index d9db14112..18ec0311a 100644 --- a/taprpc/taprootassets.proto +++ b/taprpc/taprootassets.proto @@ -848,6 +848,7 @@ message DecodeProofResponse { message ExportProofRequest { bytes asset_id = 1; bytes script_key = 2; + OutPoint outpoint = 3; // TODO(roasbeef): specify information to make new state transition in proof // file? @@ -1063,3 +1064,15 @@ message BurnAssetResponse { // The burn transition proof for the asset burn output. DecodedProof burn_proof = 2; } + +message OutPoint { + /* + Raw bytes representing the transaction id. + */ + bytes txid = 1; + + /* + The index of the output on the transaction. + */ + uint32 output_index = 2; +} diff --git a/taprpc/taprootassets.swagger.json b/taprpc/taprootassets.swagger.json index f88eecd71..ce19c84c9 100644 --- a/taprpc/taprootassets.swagger.json +++ b/taprpc/taprootassets.swagger.json @@ -1449,6 +1449,9 @@ "script_key": { "type": "string", "format": "byte" + }, + "outpoint": { + "$ref": "#/definitions/taprpcOutPoint" } } }, @@ -1718,6 +1721,21 @@ } } }, + "taprpcOutPoint": { + "type": "object", + "properties": { + "txid": { + "type": "string", + "format": "byte", + "description": "Raw bytes representing the transaction id." + }, + "output_index": { + "type": "integer", + "format": "int64", + "description": "The index of the output on the transaction." + } + } + }, "taprpcOutputType": { "type": "string", "enum": [ diff --git a/version.go b/version.go index c3e6eb1d1..1d8b3002c 100644 --- a/version.go +++ b/version.go @@ -49,7 +49,7 @@ const ( // AppPreRelease MUST only contain characters from semanticAlphabet // per the semantic versioning spec. - AppPreRelease = "alpha.rc1" + AppPreRelease = "alpha.rc2" // defaultAgentName is the default name of the software that is added as // the first part of the user agent string.