diff --git a/address/address.go b/address/address.go index b13787c3d..0d49eb906 100644 --- a/address/address.go +++ b/address/address.go @@ -17,6 +17,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/taprpc" "github.com/lightningnetwork/lnd/tlv" ) @@ -48,7 +49,8 @@ var ( // create a Taproot Asset address for a Normal asset with an amount of // zero. ErrInvalidAmountNormal = errors.New( - "address: normal asset amount of zero", + "address: zero amount cannot be used for normal asset " + + "addresses of V0 or V1", ) // ErrUnsupportedAssetType is an error returned when we attempt to @@ -72,6 +74,12 @@ var ( // ErrUnknownVersion is returned when encountering an address with an // unrecognised version number. ErrUnknownVersion = errors.New("address: unknown version number") + + // ErrInvalidProofCourierAddr is returned when we attempt to create a + // Taproot Asset address with a proof courier address that is not valid. + ErrInvalidProofCourierAddr = errors.New( + "address: invalid proof courier address", + ) ) // Version denotes the version of a Taproot Asset address format. @@ -84,8 +92,12 @@ const ( // V1 addresses use V2 Taproot Asset commitments. V1 Version = 1 + // V2 addresses support sending grouped assets and require the new + // auth mailbox proof courier address format. + V2 Version = 2 + // LatestVersion is the latest supported Taproot Asset address version. - latestVersion = V1 + latestVersion = V2 ) // Tap represents a Taproot Asset address. Taproot Asset addresses specify an @@ -101,7 +113,8 @@ type Tap struct { // AssetVersion is the Taproot Asset version of the asset. AssetVersion asset.Version - // AssetID is the asset ID of the asset. + // AssetID is the asset ID of the asset. This will be all zeroes for + // V2 addresses that have a group key set. AssetID asset.ID // GroupKey is the tweaked public key that is used to associate assets @@ -110,7 +123,12 @@ type Tap struct { GroupKey *btcec.PublicKey // ScriptKey represents a tweaked Taproot output key encumbering the - // different ways an asset can be spent. + // different ways an asset can be spent. For V2 addresses, this key is + // not the tweaked Taproot output key but instead the bare/raw/internal + // script key. The sender will use this key to encrypt the send fragment + // that they post to the proof courier's mailbox. The raw script key + // will also be used by the sender to derive different Taproot output + // script keys for each asset ID. ScriptKey btcec.PublicKey // InternalKey is the BIP-0340/0341 public key of the receiver. @@ -122,6 +140,9 @@ type Tap struct { TapscriptSibling *commitment.TapscriptPreimage // Amount is the number of asset units being requested by the receiver. + // The amount is allowed to be zero for V2 addresses, where the sender + // will post a fragment containing the asset IDs and amounts to the + // proof courier's mailbox. Amount uint64 // assetGen is the receiving asset's genesis metadata which directly @@ -129,7 +150,9 @@ type Tap struct { assetGen asset.Genesis // ProofCourierAddr is the address of the proof courier that will be - // used to distribute related proofs for this address. + // used to distribute related proofs for this address. For V2 addresses + // the proof courier address is mandatory and must be a valid auth + // mailbox address. ProofCourierAddr url.URL // UnknownOddTypes is a map of unknown odd types that were encountered @@ -191,7 +214,7 @@ func New(version Version, genesis asset.Genesis, groupKey *btcec.PublicKey, } case asset.Normal: - if amt == 0 { + if amt == 0 && version < V2 { return nil, ErrInvalidAmountNormal } @@ -208,6 +231,16 @@ func New(version Version, genesis asset.Genesis, groupKey *btcec.PublicKey, return nil, ErrUnknownVersion } + // Addresses with version 2 or later must use the new authmailbox proof + // courier type. + if version >= V2 && + proofCourierAddr.Scheme != proof.AuthMailboxUniRpcCourierType { + + return nil, fmt.Errorf("%w: address version %d must use the "+ + "'%s' proof courier type", ErrInvalidProofCourierAddr, + version, proof.AuthMailboxUniRpcCourierType) + } + // We can only use a tapscript sibling that is not a Taproot Asset // commitment. if tapscriptSibling != nil { @@ -259,13 +292,39 @@ func CommitmentVersion(vers Version) (*commitment.TapCommitmentVersion, // can't know without accessing all leaves of the commitment itself. case V0: return nil, nil - case V1: + case V1, V2: return fn.Ptr(commitment.TapCommitmentV2), nil default: return nil, ErrUnknownVersion } } +// ScriptKeyForAssetID returns the script key for this address for the given +// asset ID. For V2 addresses, this will derive a unique script key for the +// asset ID using the internal script key and a Pedersen commitment. For +// addresses before V2, the script key is always the Taproot output key as +// specified in the address directly. +func (a *Tap) ScriptKeyForAssetID(assetID asset.ID) (*btcec.PublicKey, error) { + // For addresses before V2, the script key is always the Taproot output + // key as specified in the address directly. + if a.Version < V2 { + return &a.ScriptKey, nil + } + + // For V2 addresses, the script key is the internal key, which is used + // to derive the Taproot output key for each asset ID using a unique + // Pedersen commitment. + scriptKey, err := asset.DeriveUniqueScriptKey( + a.ScriptKey, assetID, asset.ScriptKeyDerivationUniquePedersen, + ) + if err != nil { + return nil, fmt.Errorf("unable to derive unique script key: %w", + err) + } + + return scriptKey.PubKey, nil +} + // Net returns the ChainParams struct matching the Taproot Asset address // network. func (a *Tap) Net() (*ChainParams, error) { @@ -465,15 +524,16 @@ func (a *Tap) EncodeAddress() (string, error) { // String returns the string representation of a Taproot Asset address. func (a *Tap) String() string { - return fmt.Sprintf("TapAddr{id=%s, amount=%d, script_key=%x}", - a.AssetID, a.Amount, a.ScriptKey.SerializeCompressed()) + s := asset.NewSpecifierOptionalGroupPubKey(a.AssetID, a.GroupKey) + return fmt.Sprintf("TapAddr{specifier=%s, amount=%d, script_key=%x}", + &s, a.Amount, a.ScriptKey.SerializeCompressed()) } // IsUnknownVersion returns true if the address version is not recognized by // this implementation of tap. func IsUnknownVersion(v Version) bool { switch v { - case V0, V1: + case V0, V1, V2: return false default: return true @@ -553,6 +613,9 @@ func UnmarshalVersion(version taprpc.AddrVersion) (Version, error) { case taprpc.AddrVersion_ADDR_VERSION_V1: return V1, nil + case taprpc.AddrVersion_ADDR_VERSION_V2: + return V2, nil + default: return 0, fmt.Errorf("unknown address version: %v", version) } @@ -570,6 +633,9 @@ func MarshalVersion(version Version) (taprpc.AddrVersion, error) { case V1: return taprpc.AddrVersion_ADDR_VERSION_V1, nil + case V2: + return taprpc.AddrVersion_ADDR_VERSION_V2, nil + default: return 0, fmt.Errorf("unknown address version: %v", version) } diff --git a/address/address_test.go b/address/address_test.go index 77efeef07..ce817c9d7 100644 --- a/address/address_test.go +++ b/address/address_test.go @@ -3,6 +3,7 @@ package address import ( "bytes" "encoding/hex" + "net/url" "testing" "github.com/btcsuite/btcd/btcec/v2" @@ -36,11 +37,16 @@ var ( ) func randAddress(t *testing.T, net *ChainParams, v *Version, groupPubKey, - sibling bool, amt *uint64, assetType asset.Type, + sibling bool, amt *uint64, assetType asset.Type, courier *url.URL, addrOpts ...NewAddrOpt) (*Tap, error) { t.Helper() + vers := RandVersion() + if v != nil { + vers = *v + } + amount := uint64(1) if amt != nil { amount = *amt @@ -48,6 +54,13 @@ func randAddress(t *testing.T, net *ChainParams, v *Version, groupPubKey, if amt == nil && assetType == asset.Normal { amount = test.RandInt[uint64]() + + // Version 2 addresses can have a zero amount, so let's randomly + // set the amount to zero for those addresses (but only if the + // test didn't specify a specific amount). + if vers == V2 && test.RandBool() { + amount = 0 + } } var ( @@ -81,11 +94,9 @@ func randAddress(t *testing.T, net *ChainParams, v *Version, groupPubKey, groupWitness = groupInfo.Witness } - proofCourierAddr := RandProofCourierAddr(t) - - vers := test.RandFlip(V0, V1) - if v != nil { - vers = *v + proofCourierAddr := RandProofCourierAddrForVersion(t, vers) + if courier != nil { + proofCourierAddr = *courier } return New( @@ -102,7 +113,8 @@ func randEncodedAddress(t *testing.T, net *ChainParams, groupPubKey, t.Helper() newAddr, err := randAddress( - t, net, nil, groupPubKey, sibling, nil, assetType, addrOpts..., + t, net, nil, groupPubKey, sibling, nil, assetType, nil, + addrOpts..., ) if err != nil { return nil, "", err @@ -141,7 +153,7 @@ func TestNewAddress(t *testing.T) { f: func() (*Tap, error) { return randAddress( t, &TestNet3Tap, nil, false, false, nil, - asset.Normal, + asset.Normal, nil, ) }, err: nil, @@ -151,7 +163,8 @@ func TestNewAddress(t *testing.T) { f: func() (*Tap, error) { return randAddress( t, &TestNet3Tap, nil, false, false, nil, - asset.Normal, WithAssetVersion(asset.V1), + asset.Normal, nil, + WithAssetVersion(asset.V1), ) }, err: nil, @@ -162,7 +175,7 @@ func TestNewAddress(t *testing.T) { f: func() (*Tap, error) { return randAddress( t, &MainNetTap, nil, true, false, nil, - asset.Collectible, + asset.Collectible, nil, WithAssetVersion(asset.V1), ) }, @@ -173,7 +186,7 @@ func TestNewAddress(t *testing.T) { f: func() (*Tap, error) { return randAddress( t, &MainNetTap, nil, true, false, nil, - asset.Collectible, + asset.Collectible, nil, ) }, err: nil, @@ -183,7 +196,7 @@ func TestNewAddress(t *testing.T) { f: func() (*Tap, error) { return randAddress( t, &MainNetTap, nil, true, true, nil, - asset.Collectible, + asset.Collectible, nil, ) }, err: nil, @@ -192,9 +205,10 @@ func TestNewAddress(t *testing.T) { name: "invalid normal asset value", f: func() (*Tap, error) { zeroAmt := uint64(0) + v1 := V1 return randAddress( - t, &TestNet3Tap, nil, false, false, - &zeroAmt, asset.Normal, + t, &TestNet3Tap, &v1, false, false, + &zeroAmt, asset.Normal, nil, ) }, err: ErrInvalidAmountNormal, @@ -205,7 +219,7 @@ func TestNewAddress(t *testing.T) { badAmt := uint64(2) return randAddress( t, &TestNet3Tap, nil, false, false, - &badAmt, asset.Collectible, + &badAmt, asset.Collectible, nil, ) }, err: ErrInvalidAmountCollectible, @@ -215,7 +229,7 @@ func TestNewAddress(t *testing.T) { f: func() (*Tap, error) { return randAddress( t, &invalidNet, nil, false, false, nil, - asset.Normal, + asset.Normal, nil, ) }, err: ErrUnsupportedHRP, @@ -225,11 +239,34 @@ func TestNewAddress(t *testing.T) { f: func() (*Tap, error) { return randAddress( t, &TestNet3Tap, fn.Ptr(Version(123)), - false, false, nil, asset.Normal, + false, false, nil, asset.Normal, nil, ) }, err: ErrUnknownVersion, }, + { + name: "v2 with zero amount", + f: func() (*Tap, error) { + zeroAmt := uint64(0) + v2 := V2 + return randAddress( + t, &TestNet3Tap, &v2, false, false, + &zeroAmt, asset.Normal, nil, + ) + }, + }, + { + name: "v2 with v1 courier", + f: func() (*Tap, error) { + v2 := V2 + courier := RandProofCourierAddrForVersion(t, V1) + return randAddress( + t, &TestNet3Tap, &v2, false, false, + nil, asset.Normal, &courier, + ) + }, + err: ErrInvalidProofCourierAddr, + }, } for _, testCase := range testCases { @@ -237,7 +274,7 @@ func TestNewAddress(t *testing.T) { success := t.Run(testCase.name, func(t *testing.T) { address, err := testCase.f() - require.Equal(t, testCase.err, err) + require.ErrorIs(t, err, testCase.err) if testCase.err == nil { require.NotNil(t, address) @@ -380,7 +417,6 @@ func TestAddressEncoding(t *testing.T) { t, &SimNetTap, false, true, asset.Collectible, ) - if err != nil { return nil, "", err } @@ -395,6 +431,24 @@ func TestAddressEncoding(t *testing.T) { }, err: nil, }, + { + name: "testnet4 address v2 with zero amount", + f: func() (*Tap, string, error) { + zeroAmt := uint64(0) + v2 := V2 + addr, err := randAddress( + t, &TestNet4Tap, &v2, false, false, + &zeroAmt, asset.Normal, nil, + ) + if err != nil { + return nil, "", err + } + + str, err := addr.EncodeAddress() + return addr, str, err + }, + err: nil, + }, { name: "unsupported hrp", f: func() (*Tap, string, error) { @@ -437,9 +491,11 @@ func TestAddressEncoding(t *testing.T) { { name: "unknown version number in constructor", f: func() (*Tap, string, error) { + courier := RandProofCourierAddrForVersion(t, V1) _, err := randAddress( t, &TestNet3Tap, fn.Ptr(Version(255)), false, true, nil, asset.Collectible, + &courier, ) return nil, "", err }, @@ -450,7 +506,7 @@ func TestAddressEncoding(t *testing.T) { f: func() (*Tap, string, error) { newAddr, err := randAddress( t, &TestNet3Tap, nil, false, true, nil, - asset.Collectible, + asset.Collectible, nil, ) require.NoError(t, err) @@ -600,7 +656,9 @@ func FuzzAddressDecode(f *testing.F) { // TestAddressUnknownOddType tests that an unknown odd type is allowed in an // address and that we can still arrive at the correct leaf hash with it. func TestAddressUnknownOddType(t *testing.T) { - knownAddr, _, _ := RandAddr(t, &TestNet3Tap, RandProofCourierAddr(t)) + knownAddr, _, _ := RandAddr( + t, &TestNet3Tap, RandProofCourierAddrForVersion(t, V2), + ) knownAddrString, err := knownAddr.EncodeAddress() require.NoError(t, err) diff --git a/address/book.go b/address/book.go index 7f54d7444..b7f45fbfb 100644 --- a/address/book.go +++ b/address/book.go @@ -10,8 +10,8 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/lightninglabs/lndclient" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/commitment" "github.com/lightninglabs/taproot-assets/fn" @@ -138,6 +138,11 @@ type Storage interface { SetAddrManaged(ctx context.Context, addr *AddrWithKeyInfo, managedFrom time.Time) error + // LastEventHeightByVersion returns the last event height for a given + // address version. + LastEventHeightByVersion(ctx context.Context, + version Version) (uint32, error) + // InsertInternalKey inserts an internal key into the database to make // sure it is identified as a local key later on when importing proofs. // The key can be an internal key for an asset script key or the @@ -485,6 +490,14 @@ func (b *Book) NewAddressWithKeys(ctx context.Context, addrVersion Version, groupWitness = assetGroup.Witness } + // For V2 addresses, we need to derive the script key individually for + // each asset piece/UTXO that's being sent. To be able to do that, we + // encode the bare/raw internal key instead of the BIP-0086 tweaked + // Taproot output key as the address's script key. + if addrVersion >= V2 { + scriptKey.PubKey = scriptKey.TweakedScriptKey.RawKey.PubKey + } + baseAddr, err := New( addrVersion, *assetGroup.Genesis, groupKey, groupWitness, *scriptKey.PubKey, *internalKeyDesc.PubKey, amount, @@ -625,15 +638,25 @@ func (b *Book) SetAddrManaged(ctx context.Context, addr *AddrWithKeyInfo, return b.cfg.Store.SetAddrManaged(ctx, addr, managedFrom) } +// LastEventHeightByVersion returns the last event height for a given address +// version. +func (b *Book) LastEventHeightByVersion(ctx context.Context, + version Version) (uint32, error) { + + return b.cfg.Store.LastEventHeightByVersion(ctx, version) +} + // GetOrCreateEvent creates a new address event for the given status, address // and transaction. If an event for that address and transaction already exists, // then the status and transaction information is updated instead. func (b *Book) GetOrCreateEvent(ctx context.Context, status Status, - addr *AddrWithKeyInfo, walletTx *lndclient.Transaction, - outputIdx uint32) (*Event, error) { + addr *AddrWithKeyInfo, walletTx *wire.MsgTx, outputIdx uint32, + blockHeight uint32, blockHash *chainhash.Hash, + outputs map[asset.ID]SendOutput) (*Event, error) { return b.cfg.Store.GetOrCreateEvent( - ctx, status, addr, walletTx, outputIdx, + ctx, status, addr, walletTx, outputIdx, blockHeight, blockHash, + outputs, ) } diff --git a/address/book_test.go b/address/book_test.go index f68c95876..83a9f56fb 100644 --- a/address/book_test.go +++ b/address/book_test.go @@ -7,8 +7,8 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/lightninglabs/lndclient" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/internal/test" "github.com/lightninglabs/taproot-assets/proof" @@ -146,8 +146,8 @@ func TestBook_QueryAssetInfo(t *testing.T) { expectsError: false, }} - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { mockStorage := &MockStorage{} mockSyncer := &MockAssetSyncer{} book := NewBook(BookConfig{ @@ -157,9 +157,9 @@ func TestBook_QueryAssetInfo(t *testing.T) { Chain: ChainParams{}, StoreTimeout: time.Second, }) - test.setupMocks(mockStorage, mockSyncer) - _, err := book.QueryAssetInfo(ctx, test.specifier) - if test.expectsError { + tc.setupMocks(mockStorage, mockSyncer) + _, err := book.QueryAssetInfo(ctx, tc.specifier) + if tc.expectsError { require.Error(t, err) } else { require.NoError(t, err) @@ -175,6 +175,13 @@ type MockStorage struct { mock.Mock } +func (m *MockStorage) LastEventHeightByVersion(ctx context.Context, + version Version) (uint32, error) { + + args := m.Called(ctx, version) + return args.Get(0).(uint32), args.Error(1) +} + func (m *MockStorage) AddrByScriptKeyAndVersion(ctx context.Context, key *btcec.PublicKey, version Version) (*AddrWithKeyInfo, error) { @@ -183,10 +190,14 @@ func (m *MockStorage) AddrByScriptKeyAndVersion(ctx context.Context, } func (m *MockStorage) GetOrCreateEvent(ctx context.Context, status Status, - addr *AddrWithKeyInfo, walletTx *lndclient.Transaction, - outputIdx uint32) (*Event, error) { + addr *AddrWithKeyInfo, walletTx *wire.MsgTx, outputIdx uint32, + blockHeight uint32, blockHash *chainhash.Hash, + outputs map[asset.ID]SendOutput) (*Event, error) { - args := m.Called(ctx, status, addr, walletTx, outputIdx) + args := m.Called( + ctx, status, addr, walletTx, outputIdx, blockHeight, blockHash, + outputs, + ) return args.Get(0).(*Event), args.Error(1) } diff --git a/address/event.go b/address/event.go index 0ec2d39d4..3a876ae84 100644 --- a/address/event.go +++ b/address/event.go @@ -6,8 +6,9 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/lightninglabs/lndclient" + "github.com/lightninglabs/taproot-assets/asset" ) // Status denotes an address event's current status. @@ -55,6 +56,19 @@ type EventQueryParams struct { CreationTimeFrom *time.Time } +// SendOutput holds the information about a single asset output that was sent +// as part of an incoming asset transfer. Each event can have multiple outputs, +// in case multiple tranches of a grouped asset were transferred using a V2 +// address. +type SendOutput struct { + // Amount is the amount of this asset output. + Amount uint64 + + // ScriptKey is the serialized script key that can be used to spend the + // output. + ScriptKey asset.ScriptKey +} + // Event represents a single incoming asset transfer that was initiated by // sending an on-chain transaction to the Taproot output key generated by a // Taproot Asset address. Each event represents a single on-chain UTXO that is @@ -90,14 +104,20 @@ type Event struct { // TaprootOutputKey of the Addr. InternalKey *btcec.PublicKey + // The map of asset ID to SendOutput that contains the amount and script + // key of each asset output that was sent as part of the incoming asset + // transfer. + Outputs map[asset.ID]SendOutput + // ConfirmationHeight is the block height at which the incoming asset // transfer transaction was first confirmed. ConfirmationHeight uint32 - // HasProof indicates that a proof for this transfer was imported. We - // don't keep a reference to it in memory as the proof itself can be - // large. The proof can be fetched by the script key of the address. - HasProof bool + // HasAllProofs indicates that a proof for each output of this transfer + // was imported. We don't keep a reference to them in memory as the + // proofs themselves can be large. The proofs can be fetched by the + // script keys of the address. + HasAllProofs bool } // EventStorage is the interface that a component storing address events should @@ -108,8 +128,9 @@ type EventStorage interface { // already exists, then the status and transaction information is // updated instead. GetOrCreateEvent(ctx context.Context, status Status, - addr *AddrWithKeyInfo, walletTx *lndclient.Transaction, - outputIdx uint32) (*Event, error) + addr *AddrWithKeyInfo, walletTx *wire.MsgTx, outputIdx uint32, + blockHeight uint32, blockHash *chainhash.Hash, + outputs map[asset.ID]SendOutput) (*Event, error) // QueryAddrEvents returns a list of event that match the given query // parameters. diff --git a/address/mock.go b/address/mock.go index 2faa2bda2..fe0a3a0c9 100644 --- a/address/mock.go +++ b/address/mock.go @@ -19,20 +19,52 @@ import ( // RandProofCourierAddr returns a proof courier address with fields populated // with valid but random values. func RandProofCourierAddr(t testing.TB) url.URL { - // TODO(ffranr): Add more randomness to the address. - addr, err := url.ParseRequestURI( - "hashmail://rand.hashmail.proof.courier:443", + return RandProofCourierAddrForVersion(t, V0) +} + +// RandProofCourierAddrForVersion returns a proof courier address with fields +// populated with valid but dummy values for the given address version. +func RandProofCourierAddrForVersion(t testing.TB, version Version) url.URL { + var ( + addr *url.URL + err error ) + switch version { + case V2: + addr, err = url.ParseRequestURI( + "authmailbox+universerpc://foo.bar:10029", + ) + + default: + protocol := test.RandFlip("hashmail", "universerpc") + addr, err = url.ParseRequestURI( + protocol + "://rand.hashmail.proof.courier:443", + ) + } require.NoError(t, err) return *addr } +// RandVersion returns a random address version for testing. +func RandVersion() Version { + return Version(test.RandIntn(int(latestVersion) + 1)) +} + // RandAddr creates a random address for testing. func RandAddr(t testing.TB, params *ChainParams, proofCourierAddr url.URL) (*AddrWithKeyInfo, *asset.Genesis, *asset.GroupKey) { + return RandAddrWithVersion(t, params, proofCourierAddr, RandVersion()) +} + +// RandAddrWithVersion creates a random address for testing, using the specified +// version. +func RandAddrWithVersion(t testing.TB, params *ChainParams, + proofCourierAddr url.URL, addrVersion Version) (*AddrWithKeyInfo, + *asset.Genesis, *asset.GroupKey) { + scriptKeyPriv := test.RandPrivKey() scriptKey := asset.NewScriptKeyBip86(keychain.KeyDescriptor{ PubKey: scriptKeyPriv.PubKey(), @@ -52,7 +84,6 @@ func RandAddr(t testing.TB, params *ChainParams, var ( assetVersion asset.Version - addrVersion Version groupInfo *asset.GroupKey groupPubKey *btcec.PublicKey groupWitness wire.TxWitness @@ -79,8 +110,6 @@ func RandAddr(t testing.TB, params *ChainParams, require.NoError(t, err) } - addrVersion = test.RandFlip(V0, V1) - tapAddr, err := New( addrVersion, genesis, groupPubKey, groupWitness, *scriptKey.PubKey, *internalKey.PubKey(), amount, diff --git a/address/testdata/address_tlv_encoding_generated.json b/address/testdata/address_tlv_encoding_generated.json index abd331d1d..f0238fc55 100644 --- a/address/testdata/address_tlv_encoding_generated.json +++ b/address/testdata/address_tlv_encoding_generated.json @@ -2,36 +2,36 @@ "valid_test_cases": [ { "address": { - "version": 0, + "version": 2, "chain_params_hrp": "taprt", "asset_version": 0, - "asset_id": "7a3811630bb33503c6536c3a223d3caecb93fe55f4b3439528edf27b10d38e93", + "asset_id": "7c08f12ca0d5589e87c632644388fabe08e423a87dd4ed5279b82db43e7f7dce", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", - "amount": 5577006791947779410, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "amount": 8674665223082153551, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", "unknown_odd_types": null }, - "expected": "taprt1qqqsqqspqqzzq73cz93shve4q0r9xmp6yg7netktj0l9ta9ngw2j3m0j0vgd8r5nqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl7nt9sgss0l8a2gxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpn5zn5dz", + "expected": "taprt1qqqsyqspqqzzqlqg7yk2p42cn6ruvvnygwy040sgus36slw5a4f8nwpdksl87lwwqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl77rzng8470ckfuxzwct4w35x6ctfd33x77ptw4hxjan9wfek2unsvvaz7tmxdahjucnpwgarzvpsxgusxl3f4t", "comment": "valid regtest address" }, { "address": { - "version": 0, + "version": 2, "chain_params_hrp": "tapsb", "asset_version": 0, - "asset_id": "d72fb1b19be12cbf6223d94abafff5b89ffac4cfd9be3bd9f81556c5dcd7c397", + "asset_id": "6d46e01d92cc4c427acc18f3d2f09e60e5b6b5ff950f841bee097bad461998d8", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", - "amount": 2933568871211445515, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "amount": 2610529275472644968, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", "unknown_odd_types": null }, - "expected": "tapsb1qqqsqqspqqzzp4e0kxcehcfvha3z8k22htlltwylltzvlkd780vls92kchwd0suhqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl729ky9v8evadpvxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpn76z4sn", + "expected": "tapsb1qqqsyqspqqzzqm2xuqwe9nzvgfavcx8n6tcfuc89k66ll9g0ssd7uztm44rpnxxcqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl7fp6w69hcnstdqxzwct4w35x6ctfd33x77ptw4hxjan9wfek2unsvvaz7tmxdahjucnpwgarzvpsxgusejet74", "comment": "valid simnet address" }, { @@ -39,50 +39,50 @@ "version": 0, "chain_params_hrp": "taptb", "asset_version": 0, - "asset_id": "4c9a938dea549244e66763a94c605c934968960f634e18a29ea1cfcd6e5c1797", + "asset_id": "ea9706c3f0a86f0987c63bbf410512e773c5d6baf54a2a2dd3c6e48c2e01d03b", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", - "amount": 1905388747193831650, + "amount": 4831389563158288344, "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", "unknown_odd_types": null }, - "expected": "taptb1qqqsqqspqqzzqny6jwx754yjgnnxwcaff3s9ey6fdztq7c6wrz3fagw0e4h9c9uhqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl7xn3fnuxhq7sugxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpnfaa7x2", + "expected": "taptb1qqqsqqspqqzzp65hqmplp2r0pxruvwalgyz39emnchtt4a229gka83hy3shqr5pmqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl7scv3v6mh9zhmqxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpn2h736f", "comment": "valid testnet address" }, { "address": { - "version": 1, + "version": 0, "chain_params_hrp": "tapbc", "asset_version": 0, - "asset_id": "b89d0b077ee5a3a603c4ed367dc4433082247b1706e261d1ca22a2d5ee0661a1", + "asset_id": "9c48f86912ed24bd0f9ec5fe76b639fbd2b876acf6f44472e8819117c89ef4f4", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", - "amount": 1598098976185383115, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "amount": 3902890183311134652, + "proof_courier_addr": "universerpc://rand.hashmail.proof.courier:443", "unknown_odd_types": null }, - "expected": "tapbc1qqqszqspqqzzpwyapvrhaedr5cpufmfk0hzyxvyzy3a3wphzv8gu5g4z6hhqvcdpqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl793dj6xn7u0cevxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpnyqawrf", + "expected": "tapbc1qqqsqqspqqzzp8zglp539mfyh58ea307w6mrn77jhpm2eah5g3ew3qv3zlyfaa85qcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl7d3fm8chm850hsxz6atwd9mx2unnv4e8qce69uhhyctwvshxsctndpkkz6tv9ec8ymm0vchxxmm4wf5k2u36xs6rx8qfez4", "comment": "valid mainnet address" }, { "address": { - "version": 1, + "version": 0, "chain_params_hrp": "tapbc", "asset_version": 1, - "asset_id": "d2ac8f6aa63e6d3e15f7380dbdbc26d60802115ed3eedad25af418cd81fde097", + "asset_id": "786244a8df10a0cb481afde9fa6f0b7287858f9c86e246142e088b6dd23a1a0a", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", - "amount": 898860202204764712, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "amount": 2227583514184312746, + "proof_courier_addr": "universerpc://rand.hashmail.proof.courier:443", "unknown_odd_types": null }, - "expected": "tapbc1qqqszqspqyzzp54v3a42v0nd8c2lwwqdhk7zd4sgqgg4a5lwmtf94aqcekqlmcyhqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl7rrevjtk7f569qxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpnk2wtnl", + "expected": "tapbc1qqqsqqspqyzzq7rzgj5d7y9qedyp4l0flfhsku58sk8eephzgc2zuzytdhfr5xs2qcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgyl78hf7ankv7884gxz6atwd9mx2unnv4e8qce69uhhyctwvshxsctndpkkz6tv9ec8ymm0vchxxmm4wf5k2u36xs6rx9ja99q", "comment": "valid addr, v1 asset version" }, { @@ -90,16 +90,16 @@ "version": 0, "chain_params_hrp": "taptb", "asset_version": 0, - "asset_id": "79c2e7658214f22af8f157400063a631ec4f8e85859a542b20d03128bddc1942", - "group_key": "024c33bbd182ac25f05c2ae71f91b05e14d83cb28abb845fb054411ab2e8ee0a44", + "asset_id": "e16973000f6bdf9a306ddc1df367a44a0551a5035d53bca28f62c9a3625fcd41", + "group_key": "038651c337e53772de4ff003408ac7544b97daf58e7e3754230b742a89c91d5565", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", "amount": 1, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "proof_courier_addr": "universerpc://rand.hashmail.proof.courier:443", "unknown_odd_types": null }, - "expected": "taptb1qqqsqqspqqzzq7wzuajcy98j9tu0z46qqp36vv0vf78gtpv62s4jp5p39z7acx2zq5ssynpnh0gc9tp97pwz4ecljxc9u9xc8jeg4wuyt7c9gsg6kt5wuzjyqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgqszrp2dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xses8qwtmu", + "expected": "taptb1qqqsqqspqqzzpctfwvqq767lngcxmhqa7dn6gjs92xjsxh2nhj3g7ckf5d39ln2pq5ss8pj3cvm72dmjme8lqq6q3tr4gjuhmt6cul3h2s3skap238y364t9qcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgqszrpdw4hxjan9wfek2unsvvaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpnl9fkw8", "comment": "signet group collectible" }, { @@ -107,8 +107,8 @@ "version": 1, "chain_params_hrp": "taptb", "asset_version": 0, - "asset_id": "b285b6a5adca55cabdda0f1204427e0b6238c0a311965caa87cecac849ba76c2", - "group_key": "03ff4d197521b1af73f4e2ad529abd38d2e7309bdfd4c378f51fb5d920f816c936", + "asset_id": "adec5c264996d35d451558d9dcbef4d2f6afcc5310030f891865653a3bdaf322", + "group_key": "037c76c5182695c47a661d88f8c57a49252457545d1a7ba8dfbfdb2dda1171a606", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", @@ -116,7 +116,7 @@ "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", "unknown_odd_types": null }, - "expected": "taptb1qqqszqspqqzzpv59k6j6mjj4e27a5rcjq3p8uzmz8rq2xyvktj4g0nk2epym5akzq5ss8l6dr96jrvd0w06w9t2jn27n35h8xzdal4xr0r63ldweyrupdjfkqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgqszrp2dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xsesy0g396", + "expected": "taptb1qqqszqspqqzzpt0vtsnyn9knt4z32kxemjl0f5hk4lx9xyqrp7y3set98gaa4uezq5ssxlrkc5vzd9wy0fnpmz8cc4ayjffy2a296xnm4r0mlkedmgghrfsxqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgqszrp2dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xses2ftttc", "comment": "testnet4 group collectible" }, { @@ -124,53 +124,70 @@ "version": 1, "chain_params_hrp": "tapsb", "asset_version": 0, - "asset_id": "3ea23fd8d66115c9676a57d5684864fd337343e1cce8e6f7e6d2262141cf7795", + "asset_id": "bd357594f7d2f1d71436a0ff56a98ae54cce15337b364a546d2f4a47a0026694", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "", "amount": 1, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "proof_courier_addr": "universerpc://rand.hashmail.proof.courier:443", "unknown_odd_types": null }, - "expected": "tapsb1qqqszqspqqzzq04z8lvdvcg4e9nk5474dpyxflfnwdp7rn8gumm7d53xy9qu7au4qcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgqszrp2dpshx6rdv95kcw309aexzmny9e5xzumgd4skjmpwwpex7mmx9e3k7atjd9jhyw35xsesk46mnu", + "expected": "tapsb1qqqszqspqqzzp0f4wk2005h36u2rdg8l265c4e2vec2nx7ekff2x6t62g7sqye55qcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgqszrpdw4hxjan9wfek2unsvvaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpncrylu0", "comment": "simnet collectible" }, { "address": { - "version": 1, + "version": 2, "chain_params_hrp": "tapsb", "asset_version": 0, - "asset_id": "10d5dc5afdab33b767003f8f20d726eadab89419a18b435280affabfb659eeb1", + "asset_id": "8f0ccf71bf7a96c13918f9f1bc79180d1423fde8d25bbeff0fe65a9e43b0b497", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", "amount": 1, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", "unknown_odd_types": null }, - "expected": "tapsb1qqqszqspqqzzqyx4m3d0m2enkansq0u0yrtjd6k6hz2pngvtgdfgptl6h7m9nm43qcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0py2spsqjdehhggrpypmxzmrfvss8xcmjd9c8gzspqyxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpntpzt44", + "expected": "tapsb1qqqsyqspqqzzprcveacm775kcyu33703h3u3srg5y07735jmhmlslej6nepmpdyhqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0py2spsqjdehhggrpypmxzmrfvss8xcmjd9c8gzspqyxzwct4w35x6ctfd33x77ptw4hxjan9wfek2unsvvaz7tmxdahjucnpwgarzvpsxgusddtaz8", "comment": "simnet collectible with sibling" }, { "address": { - "version": 0, + "version": 1, "chain_params_hrp": "tapsb", "asset_version": 0, - "asset_id": "bb0f263c1689547badf0bc87ad378aac0e19131613a5da5ef675c30c251bbc8c", + "asset_id": "d99cc3cbda6f3083c9edc9628c81e63c6a2c455b88e2d0fd06fdb71dc91054ba", "group_key": "", "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", "tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", "amount": 1, - "proof_courier_addr": "hashmail://rand.hashmail.proof.courier:443", + "proof_courier_addr": "universerpc://rand.hashmail.proof.courier:443", "unknown_odd_types": { "31337": "Zm9v" } }, - "expected": "tapsb1qqqsqqspqqzzpwc0yc7pdz250wklp0y845mc4tqwryf3vya9mf00vawrpsj3h0yvqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0py2spsqjdehhggrpypmxzmrfvss8xcmjd9c8gzspqyxz56rpwd5x6ctfdsaz7tmjv9hxgtngv9eksmtpd9kzuurjdahkvtnrda6hy6t9wgargdpnl4axjqmxdahs5ptw90", + "expected": "tapsb1qqqszqspqqzzpkvuc09a5mess0y7mjtz3jq7v0r293z4hz8z6r7sdldhrhy3q496qcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0py2spsqjdehhggrpypmxzmrfvss8xcmjd9c8gzspqyxz6atwd9mx2unnv4e8qce69uhhyctwvshxsctndpkkz6tv9ec8ymm0vchxxmm4wf5k2u36xs6r8lt6dypkvmm0alur27", "comment": "simnet collectible with sibling and unknown TLV type" + }, + { + "address": { + "version": 2, + "chain_params_hrp": "taptb", + "asset_version": 0, + "asset_id": "6cd649ede785f79a11a227ccfc1fd32902c32c39ec63364107bbd86583fd1726", + "group_key": "", + "script_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", + "internal_key": "02a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e078f", + "tapscript_sibling": "", + "amount": 0, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", + "unknown_odd_types": null + }, + "expected": "taptb1qqqsyqspqqzzqmxkf8k70p0hngg6yf7vls0ax2gzcvkrnmrrxeqs0w7cvkpl69exqcss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pqss9g90avt97rkrdzqtdrst427e4kwx9lg6dx4fnz7rp6drgcszupu0pgqsqrp8v96hg6rdv95kccn00q4h2mnfwejhyum9wfcxxw309anx7mewvfshyw33xqcrywgrwcyqj", + "comment": "testnet4 address v2 with zero amount" } ], "error_test_cases": null diff --git a/authmailbox/client_test.go b/authmailbox/client_test.go index 0353d472d..519373999 100644 --- a/authmailbox/client_test.go +++ b/authmailbox/client_test.go @@ -379,6 +379,7 @@ func TestSendMessage(t *testing.T) { clientKey1, _ := test.RandKeyDesc(t) clientKey2, _ := test.RandKeyDesc(t) + clientKey3, _ := test.RandKeyDesc(t) proofWithHeight := func(p proof.TxProof, h uint32) proof.TxProof { p.BlockHeight = h @@ -391,7 +392,7 @@ func TestSendMessage(t *testing.T) { testCases := []struct { name string txProofs []proof.TxProof - recvKey keychain.KeyDescriptor + recvKeys []keychain.KeyDescriptor sendKey keychain.KeyDescriptor msgs [][]byte expiryHeight uint32 @@ -400,7 +401,7 @@ func TestSendMessage(t *testing.T) { { name: "empty payload", txProofs: []proof.TxProof{*txProof1}, - recvKey: clientKey2, + recvKeys: []keychain.KeyDescriptor{clientKey2}, sendKey: clientKey1, msgs: [][]byte{nil}, expectedErrs: []string{"empty payload"}, @@ -408,7 +409,7 @@ func TestSendMessage(t *testing.T) { { name: "long payload", txProofs: []proof.TxProof{*txProof1}, - recvKey: clientKey2, + recvKeys: []keychain.KeyDescriptor{clientKey2}, sendKey: clientKey1, msgs: [][]byte{ bytes.Repeat([]byte("foo"), MsgMaxSize), @@ -418,7 +419,7 @@ func TestSendMessage(t *testing.T) { { name: "missing expiry height", txProofs: []proof.TxProof{*txProof1}, - recvKey: clientKey2, + recvKeys: []keychain.KeyDescriptor{clientKey2}, sendKey: clientKey1, msgs: [][]byte{[]byte("yoooo")}, expectedErrs: []string{"missing expiry block height"}, @@ -428,7 +429,7 @@ func TestSendMessage(t *testing.T) { txProofs: []proof.TxProof{ proofWithHeight(*txProof1, 100002), }, - recvKey: clientKey2, + recvKeys: []keychain.KeyDescriptor{clientKey2}, sendKey: clientKey1, msgs: [][]byte{[]byte("yoooo")}, expiryHeight: 123, @@ -442,7 +443,7 @@ func TestSendMessage(t *testing.T) { txProofs: []proof.TxProof{ proofWithHeight(*txProof1, 100002), }, - recvKey: clientKey2, + recvKeys: []keychain.KeyDescriptor{clientKey2}, sendKey: clientKey1, msgs: [][]byte{[]byte("yoooo")}, expiryHeight: 100002 + 123, @@ -453,7 +454,10 @@ func TestSendMessage(t *testing.T) { proofWithHeight(*txProof1, 100002), proofWithHeight(*txProof1, 100002), }, - recvKey: clientKey2, + recvKeys: []keychain.KeyDescriptor{ + clientKey2, + clientKey3, + }, sendKey: clientKey1, msgs: [][]byte{ []byte("yoooo"), @@ -472,7 +476,11 @@ func TestSendMessage(t *testing.T) { proofWithHeight(*txProof2, 100002), proofWithHeight(*txProof3, 100002), }, - recvKey: clientKey2, + recvKeys: []keychain.KeyDescriptor{ + clientKey2, + clientKey2, + clientKey2, + }, sendKey: clientKey1, msgs: [][]byte{ []byte("yoooo"), @@ -507,9 +515,10 @@ func TestSendMessage(t *testing.T) { for idx := range tc.msgs { msg := tc.msgs[idx] txProof := tc.txProofs[idx] + recvKey := tc.recvKeys[idx] msgID, err := client1.client.SendMessage( - ctx, *tc.recvKey.PubKey, msg, txProof, + ctx, *recvKey.PubKey, msg, txProof, tc.expiryHeight, ) @@ -528,6 +537,18 @@ func TestSendMessage(t *testing.T) { // We should be able to read the message if // there was no error sending it. client2.readMessages(t, msgID) + + // Sending the same message again should result + // in the same message ID, but should not cause + // another message to be sent to any recipients. + msgIDReSend, err := client1.client.SendMessage( + ctx, *recvKey.PubKey, msg, txProof, + tc.expiryHeight, + ) + require.NoError(t, err) + + require.Equal(t, msgID, msgIDReSend) + client2.expectNoMessage(t) } }) } diff --git a/authmailbox/message.go b/authmailbox/message.go index 83f827045..5eba7b853 100644 --- a/authmailbox/message.go +++ b/authmailbox/message.go @@ -96,6 +96,11 @@ type MsgStore interface { // FetchMessage retrieves a message from the mailbox by its ID. FetchMessage(ctx context.Context, id uint64) (*Message, error) + // FetchMessageByOutPoint retrieves a message from the mailbox by its + // claimed outpoint of the TX proof that was used to send it. + FetchMessageByOutPoint(ctx context.Context, + claimedOp wire.OutPoint) (*Message, error) + // QueryMessages retrieves messages based on a query. QueryMessages(ctx context.Context, filter MessageFilter) ([]*Message, error) diff --git a/authmailbox/mock.go b/authmailbox/mock.go index 76bc40a4c..726ce3c35 100644 --- a/authmailbox/mock.go +++ b/authmailbox/mock.go @@ -10,20 +10,22 @@ import ( ) type MockMsgStore struct { - messages map[uint64]*Message - nextMessageID atomic.Uint64 - mu sync.RWMutex + messages map[uint64]*Message + outpointToMessage map[wire.OutPoint]uint64 + nextMessageID atomic.Uint64 + mu sync.RWMutex } var _ MsgStore = (*MockMsgStore)(nil) func NewMockStore() *MockMsgStore { return &MockMsgStore{ - messages: make(map[uint64]*Message), + messages: make(map[uint64]*Message), + outpointToMessage: make(map[wire.OutPoint]uint64), } } -func (s *MockMsgStore) StoreMessage(_ context.Context, _ wire.OutPoint, +func (s *MockMsgStore) StoreMessage(_ context.Context, claimedOp wire.OutPoint, msg *Message) (uint64, error) { s.mu.Lock() @@ -31,6 +33,7 @@ func (s *MockMsgStore) StoreMessage(_ context.Context, _ wire.OutPoint, id := s.nextMessageID.Add(1) s.messages[id] = msg + s.outpointToMessage[claimedOp] = id return id, nil } @@ -49,6 +52,21 @@ func (s *MockMsgStore) FetchMessage(_ context.Context, return msg, nil } +func (s *MockMsgStore) FetchMessageByOutPoint(ctx context.Context, + claimedOp wire.OutPoint) (*Message, error) { + + s.mu.RLock() + defer s.mu.RUnlock() + + msgID, exists := s.outpointToMessage[claimedOp] + if !exists { + return nil, fmt.Errorf("message with outpoint %v not found", + claimedOp) + } + + return s.FetchMessage(ctx, msgID) +} + func (s *MockMsgStore) QueryMessages(_ context.Context, filter MessageFilter) ([]*Message, error) { diff --git a/authmailbox/server.go b/authmailbox/server.go index fd0e05d7b..4bc6a5d78 100644 --- a/authmailbox/server.go +++ b/authmailbox/server.go @@ -230,7 +230,38 @@ func (s *Server) SendMessage(ctx context.Context, err) } if haveProof { - return nil, proof.ErrTxMerkleProofExists + // If we already have this proof, we check if it's for + // the same recipient. If it is, we'll return the + // message ID, making this call idempotent to simplify + // the client re-try logic. Because the encryption + // algorithm will produce a different ciphertext for the + // same message each time, we cannot compare the actual + // message itself. So we have to assume that using the + // same outpoint in the proof for the same recipient + // means it's also the same message. Since the proof + // still has to be valid, there is only a limited risk + // of a DoS vector here. Also, the message lookup by + // outpoint is backed by a database index. + dbMsg, err := s.cfg.MsgStore.FetchMessageByOutPoint( + ctx, txProof.ClaimedOutPoint, + ) + if err != nil { + return nil, proof.ErrTxMerkleProofExists + } + + // It's a different recipient, so someone is attempting + // to re-use a proof for a different recipient. + if !dbMsg.ReceiverKey.IsEqual(&msg.ReceiverKey) { + return nil, proof.ErrTxMerkleProofExists + } + + // We have a message with the same outpoint and + // recipient, so we can return the message ID, so it + // looks to the client as if we stored the message, even + // though we have it already. + return &mboxrpc.SendMessageResponse{ + MessageId: dbMsg.ID, + }, nil } // We didn't have the proof before, so we store it now. If at diff --git a/itest/addrs_group_key_test.go b/itest/addrs_group_key_test.go new file mode 100644 index 000000000..5e7ad28b5 --- /dev/null +++ b/itest/addrs_group_key_test.go @@ -0,0 +1,104 @@ +package itest + +import ( + "context" + "encoding/hex" + "fmt" + + "github.com/lightninglabs/taproot-assets/taprpc" + "github.com/lightninglabs/taproot-assets/taprpc/mintrpc" + "github.com/stretchr/testify/require" +) + +func testAddressV2WithGroupKey(t *harnessTest) { + // We begin by minting a new asset group with a group key. + firstTrancheReq := CopyRequest(issuableAssets[0]) + + firstTranche := MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner().Client, t.tapd, + []*mintrpc.MintAssetRequest{firstTrancheReq}, + ) + firstAsset := firstTranche[0] + + groupKey := firstTranche[0].AssetGroup.TweakedGroupKey + + // And then we mint a second tranche of the same asset group. + secondTrancheReq := CopyRequest(firstTrancheReq) + secondTrancheReq.Asset.Name = "itestbuxx-money-printer-brrr-tranche-2" + secondTrancheReq.Asset.GroupedAsset = true + secondTrancheReq.Asset.NewGroupedAsset = false + secondTrancheReq.Asset.GroupKey = groupKey + + secondTranche := MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner().Client, t.tapd, + []*mintrpc.MintAssetRequest{secondTrancheReq}, + ) + secondAsset := secondTranche[0] + + totalAmount := firstAsset.Amount + secondAsset.Amount + t.Logf("Minted %d units for group %x", totalAmount, groupKey) + + // Now we can create an address with the group key. + // We'll make a second node now that'll be the receiver of all the + // assets made above. + bobLnd := t.lndHarness.NewNodeWithCoins("Bob", nil) + bobTapd := setupTapdHarness(t.t, t, bobLnd, t.universeServer) + defer func() { + require.NoError(t.t, bobTapd.stop(!*noDelete)) + }() + + ctxb := context.Background() + ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout) + defer cancel() + + groupAddr, addrEvents := NewAddrWithEventStream( + t.t, bobTapd, &taprpc.NewAddrRequest{ + ProofCourierAddr: fmt.Sprintf("authmailbox+"+ + "universerpc://%s", + t.universeServer.ListenAddr), + AddressVersion: taprpc.AddrVersion_ADDR_VERSION_V2, + GroupKey: groupKey, + }, + ) + + t.Logf("Got group addr: %v", toJSON(t.t, groupAddr)) + + sendResp, err := t.tapd.SendAsset(ctxt, &taprpc.SendAssetRequest{ + AddressesWithAmounts: []*taprpc.AddressWithAmount{ + { + TapAddr: groupAddr.Encoded, + Amount: totalAmount, + }, + }, + }) + require.NoError(t.t, err) + + t.Logf("Sent asset to group addr: %v", toJSON(t.t, sendResp)) + + MineBlocks(t.t, t.lndHarness.Miner().Client, 1, 1) + + AssertReceiveEventsCustom(t.t, addrEvents, []taprpc.AddrEventStatus{ + statusConfirmed, + proofReceived, + }) + AssertAddrEventByStatus(t.t, bobTapd, statusCompleted, 1) + + assets, err := bobTapd.ListAssets(ctxt, &taprpc.ListAssetRequest{ + ScriptKeyType: allScriptKeysQuery, + }) + require.NoError(t.t, err) + + t.Logf("Bob's assets: %v", toJSON(t.t, assets)) + + AssertBalanceByGroup( + t.t, bobTapd, hex.EncodeToString(groupKey), totalAmount, + WithAllScriptKeyTypes(), + ) + + // TODO: + // - multiple outputs with the same address + // - multiple outputs with different addresses + // - re-try sending fragment to courier + // - assert address events for multiple outputs + // - resume pending address events +} diff --git a/itest/addrs_test.go b/itest/addrs_test.go index 5db568027..1cfe613ed 100644 --- a/itest/addrs_test.go +++ b/itest/addrs_test.go @@ -423,12 +423,14 @@ func testAddressAssetSyncer(t *harnessTest) { } // Mint more assets with the main node, which should not sync to Bob. + thirdGroupReq := CopyRequest(issuableAssets[0]) + thirdGroupReq.Asset.Name = "third-group" secondRpcAssets := MintAssetsConfirmBatch( t.t, miner, t.tapd, []*mintrpc.MintAssetRequest{ - simpleAssets[1], issuableAssets[1], + simpleAssets[1], issuableAssets[1], thirdGroupReq, }, ) - require.Len(t.t, secondRpcAssets, 2) + require.Len(t.t, secondRpcAssets, 3) // Verify that Bob will not sync to Alice by default by manually // triggering a sync. @@ -481,7 +483,19 @@ func testAddressAssetSyncer(t *harnessTest) { Amt: firstAsset.Amount, AssetVersion: firstAsset.Version, }) - require.ErrorContains(t.t, err, "asset group is unknown") + require.ErrorContains(t.t, err, address.ErrAssetGroupUnknown.Error()) + + thirdAsset := secondRpcAssets[2] + thirdGroup := thirdAsset.AssetGroup + v2Courier := address.RandProofCourierAddrForVersion(t.t, address.V2) + _, err = bob.NewAddr(ctxt, &taprpc.NewAddrRequest{ + AddressVersion: taprpc.AddrVersion_ADDR_VERSION_V2, + GroupKey: thirdGroup.TweakedGroupKey, + Amt: 0, + AssetVersion: thirdAsset.Version, + ProofCourierAddr: v2Courier.String(), + }) + require.ErrorContains(t.t, err, address.ErrAssetGroupUnknown.Error()) // Restart Bob again with the syncer enabled. Bob should be able to make // an address for both new assets minted by Alice, even though he has @@ -506,30 +520,48 @@ func testAddressAssetSyncer(t *harnessTest) { require.NoError(t.t, err) AssertAddr(t.t, secondAsset, secondAddr) - // Ensure that the asset group of the second asset has a matching - // universe config so Bob will sync future issuances. + thirdAddr, err := bob.NewAddr(ctxt, &taprpc.NewAddrRequest{ + AddressVersion: taprpc.AddrVersion_ADDR_VERSION_V2, + GroupKey: thirdAsset.AssetGroup.TweakedGroupKey, + Amt: 0, + AssetVersion: thirdAsset.Version, + ProofCourierAddr: v2Courier.String(), + }) + require.NoError(t.t, err) + AssertAddr(t.t, thirdAsset, thirdAddr) + + // Ensure that the asset group of the second and third asset has a + // matching universe config so Bob will sync future issuance events. resp, err := bob.UniverseClient.QueryFederationSyncConfig( ctxt, &unirpc.QueryFederationSyncConfigRequest{}, ) require.NoError(t.t, err) - require.Len(t.t, resp.AssetSyncConfigs, 1) + require.Len(t.t, resp.AssetSyncConfigs, 2) - groupSyncConfig := resp.AssetSyncConfigs[0] - require.NotNil(t.t, groupSyncConfig.Id) + var syncGroupKeys [][]byte + for _, groupConfig := range resp.AssetSyncConfigs { + groupUniID, err := tap.UnmarshalUniID(groupConfig.Id) + require.NoError(t.t, err) - groupUniID, err := tap.UnmarshalUniID(groupSyncConfig.Id) - uniIDGroupKey := schnorr.SerializePubKey(groupUniID.GroupKey) - require.NotNil(t.t, groupUniID.GroupKey) - require.Equal(t.t, secondGroup.TweakedGroupKey[1:], uniIDGroupKey) - require.Equal(t.t, groupUniID.ProofType, universe.ProofTypeIssuance) + require.NotNil(t.t, groupUniID.GroupKey) + require.Equal( + t.t, groupUniID.ProofType, universe.ProofTypeIssuance, + ) + + uniIDGroupKey := schnorr.SerializePubKey(groupUniID.GroupKey) + syncGroupKeys = append(syncGroupKeys, uniIDGroupKey) + } + + require.Contains(t.t, syncGroupKeys, secondGroup.TweakedGroupKey[1:]) + require.Contains(t.t, syncGroupKeys, thirdGroup.TweakedGroupKey[1:]) // Bob's Universe stats should show that he has now synced both assets // from the second mint and the single asset group from that mint. - AssertUniverseStats(t.t, bob, 2, 2, 1) + AssertUniverseStats(t.t, bob, 3, 3, 2) // Alice's Universe stats should reflect the extra syncs from the asset // group lookups by Bob. - AssertUniverseStats(t.t, t.tapd, 4, 4, 2) + AssertUniverseStats(t.t, t.tapd, 5, 5, 3) // If Alice now mints a re-issuance for the second asset group, Bob // should successfully sync that new asset. diff --git a/itest/assertions.go b/itest/assertions.go index 3cc9afa18..89ee0823b 100644 --- a/itest/assertions.go +++ b/itest/assertions.go @@ -993,6 +993,57 @@ func AssertReceiveEvents(t *testing.T, addr *taprpc.Addr, } } +// AssertReceiveEventsCustom makes sure we receive the expected events. +func AssertReceiveEventsCustom(t *testing.T, + stream *EventSubscription[*taprpc.ReceiveEvent], + status []taprpc.AddrEventStatus) { + + success := make(chan struct{}) + timeout := time.After(defaultWaitTimeout) + + // To make sure we don't forever hang on receiving on the stream, we'll + // cancel it after the timeout. + go func() { + select { + case <-timeout: + t.Logf("AssertReceiveEventsCustom: cancelling stream " + + "after timeout") + stream.Cancel() + + case <-success: + } + }() + + var index int + for { + if index == len(status) { + return + } + + event, err := stream.Recv() + require.NoError(t, err, "receiving receive event") + + // Check the event's error field for unexpected errors. Perform + // this check before verifying the expected receive state, as + // errors might occur alongside an out-of-order receive state. + require.Emptyf( + t, event.Error, "send event error: %x", event, + ) + require.Equal(t, status[index], event.Status) + + // Fully close the stream once we definitely no longer need the + // stream. + // nolint: lll + if event.Status == taprpc.AddrEventStatus_ADDR_EVENT_STATUS_COMPLETED { + stream.Cancel() + close(success) + return + } + + index++ + } +} + // makeFilterSendEventScriptKey returns a filter function that checks if the // given script key is present in the send event. If it is, the event is // included in the stream. @@ -1387,27 +1438,66 @@ func AssertBalanceByID(t *testing.T, client taprpc.TaprootAssetsClient, // AssertBalanceByGroup asserts that the balance of a single asset group // on the given daemon is correct. func AssertBalanceByGroup(t *testing.T, client taprpc.TaprootAssetsClient, - hexGroupKey string, amt uint64) { + hexGroupKey string, amt uint64, opts ...BalanceOption) { t.Helper() + config := &balanceConfig{} + for _, opt := range opts { + opt(config) + } + + var rpcTypeQuery *taprpc.ScriptKeyTypeQuery + switch { + case config.allScriptKeyTypes: + rpcTypeQuery = &taprpc.ScriptKeyTypeQuery{ + Type: &taprpc.ScriptKeyTypeQuery_AllTypes{ + AllTypes: true, + }, + } + + case config.scriptKeyType != nil: + rpcTypeQuery = &taprpc.ScriptKeyTypeQuery{ + Type: &taprpc.ScriptKeyTypeQuery_ExplicitType{ + ExplicitType: rpcutils.MarshalScriptKeyType( + *config.scriptKeyType, + ), + }, + } + } + groupKey, err := hex.DecodeString(hexGroupKey) require.NoError(t, err) ctxb := context.Background() - balancesResp, err := client.ListBalances( - ctxb, &taprpc.ListBalancesRequest{ - GroupBy: &taprpc.ListBalancesRequest_GroupKey{ - GroupKey: true, + err = wait.NoError(func() error { + balancesResp, err := client.ListBalances( + ctxb, &taprpc.ListBalancesRequest{ + GroupBy: &taprpc.ListBalancesRequest_GroupKey{ + GroupKey: true, + }, + GroupKeyFilter: groupKey, + ScriptKeyType: rpcTypeQuery, }, - GroupKeyFilter: groupKey, - }, - ) - require.NoError(t, err) + ) + if err != nil { + return fmt.Errorf("error listing balances: %w", err) + } - balance, ok := balancesResp.AssetGroupBalances[hexGroupKey] - require.True(t, ok) - require.Equal(t, amt, balance.Balance) + balance, ok := balancesResp.AssetGroupBalances[hexGroupKey] + if !ok { + return fmt.Errorf("no balance found for group key %s", + hexGroupKey) + } + + if balance.Balance != amt { + return fmt.Errorf("expected balance %d, got %d", + amt, balance.Balance) + } + + return nil + }, defaultTimeout) + require.NoError(t, err) } // AssertTransfer asserts that the value of each transfer initiated on the diff --git a/itest/authmailbox_test.go b/itest/authmailbox_test.go index 754e4ffe3..a664778fa 100644 --- a/itest/authmailbox_test.go +++ b/itest/authmailbox_test.go @@ -93,6 +93,10 @@ func testAuthMailboxStoreAndFetchMessage(t *harnessTest) { ctx, int32(asset.TaprootAssetsKeyFamily), ) require.NoError(t.t, err) + receiverKey2, err := lndClient.WalletKit.DeriveNextKey( + ctx, int32(asset.TaprootAssetsKeyFamily), + ) + require.NoError(t.t, err) mboxClient := authmailbox.NewClient(&authmailbox.ClientConfig{ ServerAddress: t.tapd.rpcHost(), @@ -130,12 +134,21 @@ func testAuthMailboxStoreAndFetchMessage(t *harnessTest) { require.NoError(t.t, err) require.Greater(t.t, id2, uint64(0)) - // We check that we can't use the same tx proof again. + // We check that we can't use the same tx proof again for a different + // receiver. _, err = mboxClient.SendMessage( - ctx, *receiverKey.PubKey, []byte("message 3"), txProof1, 3456, + ctx, *receiverKey2.PubKey, []byte("message 3"), txProof1, 3456, ) require.ErrorContains(t.t, err, proof.ErrTxMerkleProofExists.Error()) + // But sending the same message again for the same receiver should + // return the same message ID as in the first attempt. + idReSend, err := mboxClient.SendMessage( + ctx, *receiverKey.PubKey, []byte("message 1"), txProof1, 1234, + ) + require.NoError(t.t, err) + require.Equal(t.t, id, idReSend) + // We also make sure that the TX proof is properly validated. txProof1.MerkleRoot = test.RandBytes(32) _, err = mboxClient.SendMessage( diff --git a/itest/test_list_on_test.go b/itest/test_list_on_test.go index 207eac387..f9a0ae733 100644 --- a/itest/test_list_on_test.go +++ b/itest/test_list_on_test.go @@ -355,6 +355,10 @@ var testCases = []*testCase{ name: "script key type pedersen unique", test: testScriptKeyTypePedersenUnique, }, + { + name: "address v2 with group key", + test: testAddressV2WithGroupKey, + }, } var optionalTestCases = []*testCase{ diff --git a/proof/courier.go b/proof/courier.go index e5db7dc16..bdf513f83 100644 --- a/proof/courier.go +++ b/proof/courier.go @@ -3,6 +3,7 @@ package proof import ( "bytes" "context" + "crypto/sha256" "crypto/sha512" "crypto/tls" "fmt" @@ -12,10 +13,14 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/lightning-node-connect/hashmailrpc" + "github.com/lightninglabs/lndclient" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/internal/ecies" "github.com/lightninglabs/taproot-assets/rpcutils" + mboxrpc "github.com/lightninglabs/taproot-assets/taprpc/authmailboxrpc" unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc" + "github.com/lightningnetwork/lnd/keychain" "google.golang.org/grpc" "google.golang.org/grpc/codes" grpcconn "google.golang.org/grpc/connectivity" @@ -39,6 +44,11 @@ const ( // UniverseRpcCourierType is a courier that uses the daemon universe RPC // endpoints to deliver proofs. UniverseRpcCourierType = "universerpc" + + // AuthMailboxUniRpcCourierType is a courier that uses the authmailbox + // protocol to transmit send specific information to the receiver and a + // universe RPC endpoint to deliver the actual proofs. + AuthMailboxUniRpcCourierType = "authmailbox+universerpc" ) // CourierHarness interface is an integration testing harness for a proof @@ -51,6 +61,24 @@ type CourierHarness interface { Stop() error } +// EncryptionProvider is an interface that provides methods for deriving +// encryption keys used for encrypting and decrypting send fragments sent over +// the auth mailbox protocol. +type EncryptionProvider interface { + // DeriveSharedKey returns a shared secret key by performing + // Diffie-Hellman key derivation between the ephemeral public key and + // the key specified by the key locator (or the node's identity private + // key if no key locator is specified): + // + // P_shared = privKeyNode * ephemeralPubkey + // + // The resulting shared public key is serialized in the compressed + // format and hashed with SHA256, resulting in a final key length of 256 + // bits. + DeriveSharedKey(ctx context.Context, ephemeralPubKey *btcec.PublicKey, + keyLocator *keychain.KeyLocator) ([sha256.Size]byte, error) +} + // Courier abstracts away from the final proof retrieval/delivery process as // part of the non-interactive send flow. A sender can use this given the // abstracted Addr/source type to send a proof to the receiver. Conversely, a @@ -58,7 +86,8 @@ type CourierHarness interface { type Courier interface { // DeliverProof attempts to delivery a proof to the receiver, using the // information in the Addr type. - DeliverProof(context.Context, Recipient, *AnnotatedProof) error + DeliverProof(context.Context, Recipient, *AnnotatedProof, + *SendManifest) error // ReceiveProof attempts to obtain a proof as identified by the passed // locator from the source encapsulated within the specified address. @@ -90,6 +119,10 @@ type CourierCfg struct { // LocalArchive is an archive that can be used to fetch proofs from the // local archive. LocalArchive Archiver + + // Signer is a signer client that can be used to derive shared keys for + // encrypting and decrypting send fragments sent over the auth mailbox. + Signer lndclient.SignerClient } // CourierConnStatus is an enum that represents the different states a courier @@ -193,10 +226,15 @@ func (u *URLDispatch) NewCourier(ctx context.Context, addr *url.URL, lazyConnect, ) - case UniverseRpcCourierType: + // The auth mailbox courier is a universe RPC courier that also + // interacts with an auth mailbox service for transferring send + // fragments. But the proof receive and delivery is done via the + // universe RPC service, so we instantiate the same courier and just + // handle the send fragment fetching differently. + case UniverseRpcCourierType, AuthMailboxUniRpcCourierType: return NewUniverseRpcCourier( ctx, u.cfg.UniverseRpcCfg, u.cfg.TransferLog, - u.cfg.LocalArchive, addr, lazyConnect, + u.cfg.LocalArchive, u.cfg.Signer, addr, lazyConnect, ) default: @@ -235,7 +273,9 @@ func ValidateCourierAddress(addr *url.URL) error { } switch addr.Scheme { - case HashmailCourierType, UniverseRpcCourierType: + case HashmailCourierType, UniverseRpcCourierType, + AuthMailboxUniRpcCourierType: + // Valid and known courier address protocol. return nil @@ -871,8 +911,15 @@ func (h *HashMailCourier) ensureConnect(ctx context.Context) error { // information in the Addr type. // // TODO(roasbeef): other delivery context as type param? -func (h *HashMailCourier) DeliverProof(ctx context.Context, - recipient Recipient, proof *AnnotatedProof) error { +func (h *HashMailCourier) DeliverProof(ctx context.Context, recipient Recipient, + proof *AnnotatedProof, sendFragment *SendManifest) error { + + // Send fragment manifests are only supported by the auth mailbox/ + // universe RPC courier. + if sendFragment != nil { + return fmt.Errorf("send fragment not supported by hashmail " + + "courier") + } // Compute the stream IDs for the sender and receiver. Note that these // stream IDs are derived from the recipient's script key only. Which @@ -1180,6 +1227,10 @@ type UniverseRpcCourier struct { // store and query for proofs. localArchive Archiver + // signer is a signer client that can be used to derive shared keys for + // encrypting and decrypting send fragments sent over the auth mailbox. + signer lndclient.SignerClient + // rawConn is the raw connection that the courier will use to interact // with the remote gRPC service. rawConn *grpc.ClientConn @@ -1188,6 +1239,10 @@ type UniverseRpcCourier struct { // the universe RPC server. client unirpc.UniverseClient + // mboxClient is the RPC client that the courier will use to interact + // with the auth mailbox RPC server. + mboxClient mboxrpc.MailboxClient + // backoffHandle is a handle to the backoff procedure used in proof // delivery. backoffHandle *BackoffHandler @@ -1204,13 +1259,15 @@ type UniverseRpcCourier struct { // NewUniverseRpcCourier creates a new universe RPC proof courier service // handle. func NewUniverseRpcCourier(ctx context.Context, cfg *UniverseRpcCourierCfg, - transferLog TransferLog, localArchive Archiver, addr *url.URL, + transferLog TransferLog, localArchive Archiver, + signer lndclient.SignerClient, addr *url.URL, lazyConnect bool) (*UniverseRpcCourier, error) { courier := UniverseRpcCourier{ cfg: cfg, addr: addr, localArchive: localArchive, + signer: signer, backoffHandle: NewBackoffHandler(cfg.BackoffCfg, transferLog), subscribers: make(map[uint64]*fn.EventReceiver[fn.Event]), } @@ -1272,19 +1329,122 @@ func (c *UniverseRpcCourier) ensureConnect(ctx context.Context) error { } c.client = unirpc.NewUniverseClient(conn) + c.mboxClient = mboxrpc.NewMailboxClient(conn) c.rawConn = conn // Make sure we initiate the connection. The GetInfo RPC method is in // the base macaroon white list, so it doesn't require any // authentication, independent of the universe's configuration. _, err = c.client.Info(ctx, &unirpc.InfoRequest{}) + if err != nil { + // If we fail to connect, we'll close the connection and return + // the error. + if closeErr := c.rawConn.Close(); closeErr != nil { + log.Errorf("Unable to close RPC courier connection: %v", + closeErr) + } - return err + return fmt.Errorf("unable to connect to universe RPC courier "+ + "service: %w", err) + } + + // If this is the "old" universe RPC courier type, then we'll skip the + // additional auth mailbox RPC check, as it is not required for the + // old courier type. + if c.addr.Scheme != AuthMailboxUniRpcCourierType { + return nil + } + + // If this is an auth mailbox type connection (which is a normal + // universe RPC connection plus an auth mailbox RPC for transmitting the + // send fragments), we'll also want to make sure the server supports + // that additional auth mailbox RPC. + _, err = c.mboxClient.MailboxInfo(ctx, &mboxrpc.MailboxInfoRequest{}) + if err != nil { + // If we fail to connect, we'll close the connection and return + // the error. + if closeErr := c.rawConn.Close(); closeErr != nil { + log.Errorf("Unable to close RPC courier connection: %v", + closeErr) + } + + return fmt.Errorf("unable to connect to auth mailbox RPC "+ + "courier service: %w", err) + } + + return nil +} + +// deliverFragment attempts to deliver a send fragment to the recipient +// using the auth mailbox protocol. If the underlying courier doesn't +// support send fragments, then this method will return an error. +func (c *UniverseRpcCourier) deliverFragment(ctx context.Context, + fragment *SendManifest) error { + + if c.addr.Scheme != AuthMailboxUniRpcCourierType { + return fmt.Errorf("send fragment not supported by standalone "+ + "universe RPC courier, must use '%s'", + AuthMailboxUniRpcCourierType) + } + + // We generate an ephemeral key pair that we'll use to encrypt the + // send fragment before sending it to the receiver. The public key of + // the pair will be part of the encrypted payload, so we can throw away + // the private key after doing the ECDH operation below. + privKey, err := btcec.NewPrivateKey() + if err != nil { + return fmt.Errorf("unable to generate ephemeral key: %w", err) + } + senderEphemeralKey := privKey.PubKey() + senderKeyBytes := senderEphemeralKey.SerializeCompressed() + + sharedSecret, err := ecies.ECDH(privKey, &fragment.Receiver) + if err != nil { + return fmt.Errorf("unable to derive shared key: %w", err) + } + + log.Infof("Transferring send fragment to receiver with claimed "+ + "outpoint %v", fragment.Fragment.OutPoint) + + msg, err := fn.Encode(&fragment.Fragment) + if err != nil { + return fmt.Errorf("unable to encode send fragment: %w", err) + } + + encryptedPayload, err := ecies.EncryptSha256ChaCha20Poly1305( + sharedSecret, msg, senderKeyBytes, + ) + if err != nil { + return fmt.Errorf("unable to encrypt send fragment: %w", err) + } + + rpcProof, err := MarshalTxProof(fragment.TxProof) + if err != nil { + return fmt.Errorf("unable to marshal tx proof: %w", err) + } + + resp, err := c.mboxClient.SendMessage(ctx, &mboxrpc.SendMessageRequest{ + ReceiverId: fragment.Receiver.SerializeCompressed(), + EncryptedPayload: encryptedPayload, + Proof: &mboxrpc.SendMessageRequest_TxProof{ + TxProof: rpcProof, + }, + ExpiryBlockHeight: fragment.ExpiryHeight, + }) + if err != nil { + return fmt.Errorf("unable to send message: %w", err) + } + + log.Infof("Successfully sent send fragment to server, ID=%d", + resp.MessageId) + + return nil } // DeliverProof attempts to delivery a proof file to the receiver. func (c *UniverseRpcCourier) DeliverProof(ctx context.Context, - recipient Recipient, annotatedProof *AnnotatedProof) error { + recipient Recipient, annotatedProof *AnnotatedProof, + sendFragment *SendManifest) error { // Decode annotated proof into proof file. proofFile := &File{} @@ -1381,6 +1541,18 @@ func (c *UniverseRpcCourier) DeliverProof(ctx context.Context, ) defer subCtxCancel() + // Sending a message to the courier is idempotent, so we + // can safely retry it every time before we insert the + // proofs. + if sendFragment != nil { + err = c.deliverFragment(subCtx, sendFragment) + if err != nil { + return fmt.Errorf("error delivering "+ + "send fragment to courier "+ + "service: %w", err) + } + } + assetProof := unirpc.AssetProof{ Key: &universeKey, AssetLeaf: &assetLeaf, @@ -1456,6 +1628,9 @@ func (c *UniverseRpcCourier) ReceiveProof(ctx context.Context, ) defer subCtxCancel() + log.Tracef("Querying for proof with script key %x", + loc.ScriptKey.SerializeCompressed()) + resp, err := c.client.QueryProof(subCtx, &universeKey) if err != nil { return fmt.Errorf("error retrieving proof "+ @@ -1710,7 +1885,7 @@ func CheckUniverseRpcCourierConnection(ctx context.Context, ctxt, cancel := context.WithTimeout(ctx, timeout) defer cancel() courier, err := NewUniverseRpcCourier( - ctxt, &UniverseRpcCourierCfg{}, nil, nil, courierURL, + ctxt, &UniverseRpcCourierCfg{}, nil, nil, nil, courierURL, false, ) if err != nil { diff --git a/proof/mock.go b/proof/mock.go index 78bf2d386..35c4791e9 100644 --- a/proof/mock.go +++ b/proof/mock.go @@ -493,7 +493,7 @@ func (m *MockProofCourier) Stop() error { // DeliverProof attempts to delivery a proof to the receiver, using the // information in the Addr type. func (m *MockProofCourier) DeliverProof(_ context.Context, - _ Recipient, proof *AnnotatedProof) error { + _ Recipient, proof *AnnotatedProof, _ *SendManifest) error { m.Lock() defer m.Unlock() diff --git a/proof/send.go b/proof/send.go index bee29f688..59cc6597c 100644 --- a/proof/send.go +++ b/proof/send.go @@ -195,6 +195,10 @@ type SendManifest struct { // to the auth mailbox server. TxProof TxProof + // ExpiryHeight is the block height at which the send fragment will + // expire, allowing the server to clean up old fragments in its DB. + ExpiryHeight uint32 + // Receiver is the receiver's public key of the asset outputs, used // to decrypt the send fragment. This is the internal key of the address // that was used to send the assets. diff --git a/rpcserver.go b/rpcserver.go index fd8b91c8c..2f046579c 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1604,17 +1604,23 @@ func (r *rpcServer) NewAddr(ctx context.Context, return nil, fmt.Errorf("no proof courier address provided") } - if len(req.AssetId) != 32 { - return nil, fmt.Errorf("invalid asset id length") + assetID, groupKey, err := parseAssetSpecifier( + req.AssetId, "", req.GroupKey, "", + ) + if err != nil { + return nil, fmt.Errorf("unable to parse asset specifier: %w", + err) + } + specifier, err := asset.NewSpecifier(assetID, groupKey, nil, true) + if err != nil { + return nil, fmt.Errorf("unable to create asset specifier: %w", + err) } - var assetID asset.ID - copy(assetID[:], req.AssetId) - - rpcsLog.Infof("[NewAddr]: making new addr: asset_id=%x, amt=%v", - assetID[:], req.Amt) + rpcsLog.Infof("[NewAddr]: making new addr: specifier=%s, amt=%v", + &specifier, req.Amt) - err := r.checkBalanceOverflow(ctx, &assetID, nil, req.Amt) + err = r.checkBalanceOverflow(ctx, assetID, groupKey, req.Amt) if err != nil { return nil, err } @@ -1645,9 +1651,8 @@ func (r *rpcServer) NewAddr(ctx context.Context, // Now that we have all the params, we'll try to add a new // address to the addr book. addr, err = r.cfg.AddrBook.NewAddress( - ctx, addrVersion, asset.NewSpecifierFromId(assetID), - req.Amt, tapscriptSibling, *courierAddr, - address.WithAssetVersion(assetVersion), + ctx, addrVersion, specifier, req.Amt, tapscriptSibling, + *courierAddr, address.WithAssetVersion(assetVersion), ) if err != nil { return nil, fmt.Errorf("unable to make new addr: %w", @@ -1695,9 +1700,9 @@ func (r *rpcServer) NewAddr(ctx context.Context, // Now that we have all the params, we'll try to add a new // address to the addr book. addr, err = r.cfg.AddrBook.NewAddressWithKeys( - ctx, addrVersion, asset.NewSpecifierFromId(assetID), - req.Amt, *scriptKey, internalKey, tapscriptSibling, - *courierAddr, address.WithAssetVersion(assetVersion), + ctx, addrVersion, specifier, req.Amt, *scriptKey, + internalKey, tapscriptSibling, *courierAddr, + address.WithAssetVersion(assetVersion), ) if err != nil { return nil, fmt.Errorf("unable to make new addr: %w", @@ -2306,28 +2311,44 @@ func (r *rpcServer) FundVirtualPsbt(ctx context.Context, } prevIDs = append(prevIDs, prevID) } - if len(raw.Recipients) > 1 { - return nil, fmt.Errorf("only one recipient supported") - } - var ( - addr *address.Tap - err error - ) - for a := range raw.Recipients { - addr, err = address.DecodeAddress(a, &r.cfg.ChainParams) - if err != nil { - return nil, fmt.Errorf("unable to decode "+ - "addr: %w", err) - } + var rpcAddrs []*taprpc.AddressWithAmount + switch { + case len(raw.Recipients) > 0 && + len(raw.AddressesWithAmounts) > 0: + + return nil, fmt.Errorf("cannot specify both " + + "recipients and addresses_with_amounts") + + case len(raw.Recipients) > 0: + rpcAddrs = fn.Map( + maps.Keys(raw.Recipients), + func(a string) *taprpc.AddressWithAmount { + return &taprpc.AddressWithAmount{ + TapAddr: a, + } + }, + ) + + case len(raw.AddressesWithAmounts) > 0: + rpcAddrs = raw.AddressesWithAmounts + + default: + return nil, fmt.Errorf("at least one addr is " + + "required, either in the recipients or " + + "addresses_with_amounts") } - if addr == nil { - return nil, fmt.Errorf("no recipients specified") + tapAddrs, err := parseAndValidateAddresses( + rpcAddrs, &r.cfg.ChainParams, + ) + if err != nil { + return nil, fmt.Errorf("error parsing addresses: %w", + err) } fundedVPkt, err = r.cfg.AssetWallet.FundAddressSend( - ctx, scriptKeyType, prevIDs, addr, + ctx, scriptKeyType, prevIDs, tapAddrs..., ) if err != nil { return nil, fmt.Errorf("error funding address send: "+ @@ -3339,7 +3360,7 @@ func marshalAddrEvent(event *address.Event, Outpoint: event.Outpoint.String(), UtxoAmtSat: uint64(event.Amt), ConfirmationHeight: event.ConfirmationHeight, - HasProof: event.HasProof, + HasProof: event.HasAllProofs, }, nil } @@ -3401,48 +3422,32 @@ func marshalAddrEventStatus(status address.Status) (taprpc.AddrEventStatus, func (r *rpcServer) SendAsset(ctx context.Context, req *taprpc.SendAssetRequest) (*taprpc.SendAssetResponse, error) { - if len(req.TapAddrs) == 0 { - return nil, fmt.Errorf("at least one addr is required") - } + var rpcAddrs []*taprpc.AddressWithAmount + switch { + case len(req.TapAddrs) > 0 && len(req.AddressesWithAmounts) > 0: + return nil, fmt.Errorf("cannot specify both tap_addrs and " + + "addresses_with_amounts") + + case len(req.TapAddrs) > 0: + rpcAddrs = fn.Map( + req.TapAddrs, func(a string) *taprpc.AddressWithAmount { + return &taprpc.AddressWithAmount{ + TapAddr: a, + } + }, + ) - var ( - tapAddrs = make([]*address.Tap, len(req.TapAddrs)) - err error - ) - for idx := range req.TapAddrs { - if req.TapAddrs[idx] == "" { - return nil, fmt.Errorf("addr %d must be specified", idx) - } + case len(req.AddressesWithAmounts) > 0: + rpcAddrs = req.AddressesWithAmounts - tapAddrs[idx], err = address.DecodeAddress( - req.TapAddrs[idx], &r.cfg.ChainParams, - ) - if err != nil { - return nil, err - } + default: + return nil, fmt.Errorf("at least one addr is required, " + + "either in the tap_addrs or addresses_with_amounts") + } - // Ensure all addrs are of the same asset ID. Within a single - // transfer (=a single virtual packet), we expect only to have - // inputs and outputs of the same asset ID. Multiple assets can - // be moved in a single BTC level anchor output, but the - // expectation is that they would be in separate virtual - // packets, one for each asset ID. They would then be merged - // into the same anchor output in the wallet's - // AnchorVirtualTransactions call. - // - // TODO(guggero): Support creating multiple virtual packets, one - // for each asset ID when the user wants to send multiple asset - // IDs at the same time without going through the PSBT flow. - // - // TODO(guggero): Revisit after we have a way to send fungible - // assets with different IDs to an address (non-interactive). - if idx > 0 { - if tapAddrs[idx].AssetID != tapAddrs[0].AssetID { - return nil, fmt.Errorf("all addrs must be of "+ - "the same asset ID %v", - tapAddrs[0].AssetID) - } - } + tapAddrs, err := parseAndValidateAddresses(rpcAddrs, &r.cfg.ChainParams) + if err != nil { + return nil, fmt.Errorf("error parsing addresses: %w", err) } feeRate, err := checkFeeRateSanity( @@ -3473,6 +3478,87 @@ func (r *rpcServer) SendAsset(ctx context.Context, }, nil } +// parseAndValidateAddresses parses the addresses with amounts from the RPC +// request and validates them against the chain parameters. It also ensures +// that all addresses are of the same asset specifier, as the wallet only +// supports funding for one asset or group at a time. +func parseAndValidateAddresses(rpcAddrs []*taprpc.AddressWithAmount, + chainParams *address.ChainParams) ([]*address.Tap, error) { + + var ( + tapAddrs = make([]*address.Tap, len(rpcAddrs)) + err error + ) + for idx, rpcAddr := range rpcAddrs { + addrStr := rpcAddr.TapAddr + if addrStr == "" { + return nil, fmt.Errorf("addr %d must be specified", idx) + } + + tapAddrs[idx], err = address.DecodeAddress(addrStr, chainParams) + if err != nil { + return nil, err + } + + // V2 addresses can have the amount defined as zero, which will + // allow users to send any amount. So we expect the amount to + // send being set in the request. + switch { + // A non-zero amount was provided, but the address doesn't need + // one. We allow the user to set a zero amount in the map, in + // which case we just ignore it. + case rpcAddr.Amount > 0 && tapAddrs[idx].Amount > 0: + return nil, fmt.Errorf("addr '%s' has a non-zero "+ + "amount defined, cannot override amount in "+ + "addresses_with_amounts", addrStr) + + // The address has a zero amount, but the user provided a + // non-zero amount in the list, so we override the address' + // value for coin selection. + case rpcAddr.Amount > 0 && tapAddrs[idx].Amount == 0: + tapAddrs[idx].Amount = rpcAddr.Amount + + // The address needs an amount, but the user didn't provide + // one. + case rpcAddr.Amount == 0 && tapAddrs[idx].Amount == 0: + return nil, fmt.Errorf("addr '%s' has no amount "+ + "defined, please set the amount in the "+ + "addresses_with_amounts", addrStr) + + // The last possible case is when the user didn't specify an + // amount in the addresses_with_amounts, but the address has + // one, which is the correct and default behavior for V0/V1 + // addresses. + case rpcAddr.Amount == 0 && tapAddrs[idx].Amount > 0: + // We don't need to do anything here, as the address + // already has the amount set. + } + + // Ensure all addrs are of the same asset specifier, as the + // wallet only supports funding for one asset or group at a + // time. + // + // TODO(guggero): Support creating multiple virtual packets, one + // for each asset ID when the user wants to send multiple asset + // IDs at the same time without going through the PSBT flow. + firstSpec := asset.NewSpecifierOptionalGroupPubKey( + tapAddrs[0].AssetID, tapAddrs[0].GroupKey, + ) + if idx > 0 { + spec := asset.NewSpecifierOptionalGroupPubKey( + tapAddrs[idx].AssetID, tapAddrs[idx].GroupKey, + ) + if spec != firstSpec { + return nil, fmt.Errorf("all addrs must be of "+ + "the same asset ID or group key %v", + firstSpec) + } + } + } + + return tapAddrs, nil +} + // BurnAsset burns the given number of units of a given asset by sending them // to a provably un-spendable script key. Burning means irrevocably destroying // a certain number of assets, reducing the total supply of the asset. Because diff --git a/tapcfg/server.go b/tapcfg/server.go index 20007bae1..9dc73b3cb 100644 --- a/tapcfg/server.go +++ b/tapcfg/server.go @@ -618,10 +618,12 @@ func genServerConfig(cfg *Config, cfgLogger btclog.Logger, context.Background(), assetMintingStore, ), AddrBook: addrBook, + Signer: lndServices.Signer, ProofArchive: proofArchive, ProofNotifier: multiNotifier, ErrChan: mainErrChan, ProofCourierDispatcher: proofCourierDispatcher, + MboxBackoffCfg: cfg.UniverseRpcCourier.BackoffCfg, ProofRetrievalDelay: cfg.CustodianProofRetrievalDelay, ProofWatcher: reOrgWatcher, }), diff --git a/tapdb/addrs.go b/tapdb/addrs.go index 026656edf..0e6d81bc4 100644 --- a/tapdb/addrs.go +++ b/tapdb/addrs.go @@ -15,7 +15,6 @@ import ( "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" - "github.com/lightninglabs/lndclient" "github.com/lightninglabs/taproot-assets/address" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/commitment" @@ -55,9 +54,25 @@ type ( // updating an existing one. UpsertAddrEvent = sqlc.UpsertAddrEventParams + // UpsertAddrEventOutput is a type alias for creating a new address + // event output or updating an existing one. + UpsertAddrEventOutput = sqlc.UpsertAddrEventOutputParams + + // UpsertAddrEventProof is a type alias for creating a new address + // event proof or updating an existing one. + UpsertAddrEventProof = sqlc.UpsertAddrEventProofParams + // AddrEvent is a type alias for fetching an address event row. AddrEvent = sqlc.FetchAddrEventRow + // AddrEventOutput is a type alias for fetching the outputs of an + // address event. + AddrEventOutput = sqlc.FetchAddrEventOutputsRow + + // AddrEventProof is a type alias for fetching the proofs of an address + // event. + AddrEventProof = sqlc.FetchAddrEventProofsRow + // FetchAddrEventByOutpoint is a type alias for the params to fetch an // address event by address and outpoint. FetchAddrEventByOutpoint = sqlc.FetchAddrEventByAddrKeyAndOutpointParams @@ -151,10 +166,28 @@ type AddrBook interface { // and returns the primary key. UpsertAddrEvent(ctx context.Context, arg UpsertAddrEvent) (int64, error) + // UpsertAddrEventOutput inserts a new or updates an existing address + // event output and returns the primary key. + UpsertAddrEventOutput(ctx context.Context, + arg UpsertAddrEventOutput) (int64, error) + + // UpsertAddrEventProof inserts a new or updates an existing address + // event proof and returns the primary key. + UpsertAddrEventProof(ctx context.Context, + arg UpsertAddrEventProof) (int64, error) + // FetchAddrEvent returns a single address event based on its primary // key. FetchAddrEvent(ctx context.Context, id int64) (AddrEvent, error) + // FetchAddrEventOutputs returns the outputs of an address event. + FetchAddrEventOutputs(ctx context.Context, + addrEventID int64) ([]AddrEventOutput, error) + + // FetchAddrEventProofs returns the proofs of an address event. + FetchAddrEventProofs(ctx context.Context, + addrEventID int64) ([]AddrEventProof, error) + // FetchAddrEventByAddrKeyAndOutpoint returns a single address event // based on its address Taproot output key and outpoint. FetchAddrEventByAddrKeyAndOutpoint(ctx context.Context, @@ -186,6 +219,11 @@ type AddrBook interface { // FetchAssetMetaForAsset fetches the asset meta for a given asset. FetchAssetMetaForAsset(ctx context.Context, assetID []byte) (AssetMeta, error) + + // QueryLastEventHeightByAddrVersion queries the last event height for a + // given address version. + QueryLastEventHeightByAddrVersion(ctx context.Context, + version int16) (int64, error) } // AddrBookTxOptions defines the set of db txn options the AddrBook @@ -743,15 +781,16 @@ func (t *TapAddressBook) InsertScriptKey(ctx context.Context, // then the status and transaction information is updated instead. func (t *TapAddressBook) GetOrCreateEvent(ctx context.Context, status address.Status, addr *address.AddrWithKeyInfo, - walletTx *lndclient.Transaction, outputIdx uint32) (*address.Event, - error) { + walletTx *wire.MsgTx, outputIdx uint32, blockHeight uint32, + blockHash *chainhash.Hash, + outputs map[asset.ID]address.SendOutput) (*address.Event, error) { var ( writeTxOpts AddrBookTxOptions event *address.Event - txHash = walletTx.Tx.TxHash() + txHash = walletTx.TxHash() ) - txBytes, err := fn.Serialize(walletTx.Tx) + txBytes, err := fn.Serialize(walletTx) if err != nil { return nil, fmt.Errorf("error serializing tx: %w", err) } @@ -763,7 +802,7 @@ func (t *TapAddressBook) GetOrCreateEvent(ctx context.Context, if err != nil { return nil, fmt.Errorf("error encoding outpoint: %w", err) } - outputDetails := walletTx.OutputDetails[outputIdx] + txOut := walletTx.TxOut[outputIdx] siblingBytes, siblingHash, err := commitment.MaybeEncodeTapscriptPreimage( addr.TapscriptSibling, @@ -780,19 +819,8 @@ func (t *TapAddressBook) GetOrCreateEvent(ctx context.Context, Txid: txHash[:], RawTx: txBytes, } - if walletTx.Confirmations > 0 { - txUpsert.BlockHeight = sqlInt32(walletTx.BlockHeight) - - // We're missing the transaction index within the block, - // we need to update that from the proof. Fortunately we - // only update fields that aren't nil in the upsert. - blockHash, err := chainhash.NewHashFromStr( - walletTx.BlockHash, - ) - if err != nil { - return fmt.Errorf("error parsing block hash: "+ - "%w", err) - } + if blockHeight > 0 && blockHash != nil { + txUpsert.BlockHeight = sqlInt32(blockHeight) txUpsert.BlockHash = blockHash[:] } chainTxID, err := db.UpsertChainTx(ctx, txUpsert) @@ -811,7 +839,7 @@ func (t *TapAddressBook) GetOrCreateEvent(ctx context.Context, utxoUpsert := RawManagedUTXO{ RawKey: addr.InternalKey.SerializeCompressed(), Outpoint: outpointBytes, - AmtSats: outputDetails.Amount, + AmtSats: txOut.Value, TaprootAssetRoot: taprootAssetRoot[:], RootVersion: sqlInt16(commitmentVersion), MerkleRoot: merkleRoot[:], @@ -838,6 +866,47 @@ func (t *TapAddressBook) GetOrCreateEvent(ctx context.Context, err) } + // Upsert the address event outputs. + for assetID, output := range outputs { + scriptKey := output.ScriptKey + scriptKeyBytes := scriptKey.PubKey.SerializeCompressed() + internalKeyID, err := insertInternalKey( + ctx, db, scriptKey.RawKey, + ) + if err != nil { + return fmt.Errorf("error inserting internal "+ + "key: %w", err) + } + + scriptKeyID, err := db.UpsertScriptKey( + ctx, NewScriptKey{ + InternalKeyID: internalKeyID, + TweakedScriptKey: scriptKeyBytes, + Tweak: scriptKey.Tweak, + KeyType: sqlInt16( + scriptKey.Type, + ), + }, + ) + if err != nil { + return fmt.Errorf("error upserting script "+ + "key: %w", err) + } + + _, err = db.UpsertAddrEventOutput( + ctx, UpsertAddrEventOutput{ + AddrEventID: eventID, + Amount: int64(output.Amount), + AssetID: assetID[:], + ScriptKeyID: scriptKeyID, + }, + ) + if err != nil { + return fmt.Errorf("error upserting address "+ + "event output: %w", err) + } + } + event, err = fetchEvent(ctx, db, eventID, addr) return err }) @@ -981,6 +1050,11 @@ func fetchEvent(ctx context.Context, db AddrBook, eventID int64, Index: uint32(dbEvent.OutputIndex), } + outputs, err := fetchEventOutputs(ctx, db, eventID) + if err != nil { + return nil, fmt.Errorf("error fetching event outputs: %w", err) + } + return &address.Event{ ID: eventID, CreationTime: dbEvent.CreationTime.UTC(), @@ -990,7 +1064,8 @@ func fetchEvent(ctx context.Context, db AddrBook, eventID int64, Amt: btcutil.Amount(dbEvent.AmtSats.Int64), InternalKey: internalKey, ConfirmationHeight: uint32(dbEvent.ConfirmationHeight.Int32), - HasProof: dbEvent.AssetProofID.Valid, + Outputs: outputs, + HasAllProofs: dbEvent.NumProofs == int64(len(outputs)), }, nil } @@ -1027,6 +1102,11 @@ func fetchEventByOutpoint(ctx context.Context, db AddrBook, Index: uint32(dbEvent.OutputIndex), } + outputs, err := fetchEventOutputs(ctx, db, dbEvent.ID) + if err != nil { + return nil, fmt.Errorf("error fetching event outputs: %w", err) + } + return &address.Event{ ID: dbEvent.ID, CreationTime: dbEvent.CreationTime.UTC(), @@ -1035,11 +1115,44 @@ func fetchEventByOutpoint(ctx context.Context, db AddrBook, Outpoint: op, Amt: btcutil.Amount(dbEvent.AmtSats.Int64), InternalKey: internalKey, + Outputs: outputs, ConfirmationHeight: uint32(dbEvent.ConfirmationHeight.Int32), - HasProof: dbEvent.AssetProofID.Valid, + HasAllProofs: dbEvent.NumProofs == int64(len(outputs)), }, nil } +// fetchEventOutputs fetches the set of outputs for a given address event ID. +func fetchEventOutputs(ctx context.Context, db AddrBook, + eventID int64) (map[asset.ID]address.SendOutput, error) { + + dbOutputs, err := db.FetchAddrEventOutputs(ctx, eventID) + if err != nil { + return nil, fmt.Errorf("error fetching addr event outputs: %w", + err) + } + + outputs := make(map[asset.ID]address.SendOutput, len(dbOutputs)) + for _, dbOutput := range dbOutputs { + var assetID asset.ID + copy(assetID[:], dbOutput.AssetID) + + sk, err := parseScriptKey( + dbOutput.InternalKey, dbOutput.ScriptKey, + ) + if err != nil { + return nil, fmt.Errorf("error parsing script key: %w", + err) + } + + outputs[assetID] = address.SendOutput{ + Amount: uint64(dbOutput.Amount), + ScriptKey: sk, + } + } + + return outputs, nil +} + // CompleteEvent updates an address event as being complete and links it with // the proof and asset that was imported/created for it. func (t *TapAddressBook) CompleteEvent(ctx context.Context, @@ -1051,46 +1164,92 @@ func (t *TapAddressBook) CompleteEvent(ctx context.Context, 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, 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{ + // We first update the event status and TXID/outpoint. This also + // gives us the event ID that we can use to insert the proof + // data. + eventID, err := db.UpsertAddrEvent(ctx, UpsertAddrEvent{ TaprootOutputKey: schnorr.SerializePubKey( &event.Addr.TaprootOutputKey, ), Status: int16(status), Txid: anchorPoint.Hash[:], ChainTxnOutputIndex: int32(anchorPoint.Index), - AssetProofID: sqlInt64(proofData[0].ProofID), - AssetID: sqlInt64(proofData[0].AssetID), }) + if err != nil { + return fmt.Errorf("error updating addr event: %w", err) + } + + for _, output := range event.Outputs { + scriptPubKey := output.ScriptKey.PubKey + scriptPubKeyBytes := scriptPubKey.SerializeCompressed() + args := FetchAssetProof{ + TweakedScriptKey: scriptPubKeyBytes, + Outpoint: outpoint, + } + + 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.UpsertAddrEventProof( + ctx, UpsertAddrEventProof{ + AddrEventID: eventID, + AssetProofID: proofData[0].ProofID, + AssetIDFk: sqlInt64( + proofData[0].AssetID, + ), + }, + ) + if err != nil { + return fmt.Errorf("error inserting addr event "+ + "proof: %w", err) + } + } + + return nil + }) +} + +// LastEventHeightByVersion returns the last event height for a given address +// version. +func (t *TapAddressBook) LastEventHeightByVersion(ctx context.Context, + version address.Version) (uint32, error) { + + var lastHeight int64 + + readOpts := NewAssetStoreReadTx() + err := t.db.ExecTx(ctx, &readOpts, func(db AddrBook) error { + var err error + lastHeight, err = db.QueryLastEventHeightByAddrVersion( + ctx, int16(version), + ) return err }) + if err != nil { + return 0, err + } + + return uint32(lastHeight), nil } // QueryAssetGroup attempts to fetch an asset group by its asset ID. If the diff --git a/tapdb/addrs_test.go b/tapdb/addrs_test.go index 9acea2be2..4dffd0fbf 100644 --- a/tapdb/addrs_test.go +++ b/tapdb/addrs_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/lightninglabs/lndclient" "github.com/lightninglabs/taproot-assets/address" @@ -47,8 +48,10 @@ func confirmTx(tx *lndclient.Transaction) { func randWalletTx() *lndclient.Transaction { tx := &lndclient.Transaction{ - Tx: wire.NewMsgTx(2), - Timestamp: time.Now(), + Tx: wire.NewMsgTx(2), + Timestamp: time.Now(), + BlockHeight: rand.Int31n(700_000), + BlockHash: test.RandHash().String(), } numInputs := rand.Intn(10) + 1 numOutputs := rand.Intn(5) + 1 @@ -83,6 +86,24 @@ func randWalletTx() *lndclient.Transaction { return tx } +func randOutputs(t *testing.T) map[asset.ID]address.SendOutput { + numOutputs := test.RandIntn(10) + outputs := make(map[asset.ID]address.SendOutput, numOutputs) + for j := 0; j < numOutputs; j++ { + assetID := asset.RandID(t) + amount := rand.Uint64() % 100_000 + outputs[assetID] = address.SendOutput{ + Amount: amount, + ScriptKey: asset.NewScriptKeyBip86( + keychain.KeyDescriptor{ + PubKey: test.RandPubKey(t), + }, + ), + } + } + return outputs +} + // assertEqualAddrs makes sure the given actual addresses match the expected // ones. func assertEqualAddrs(t *testing.T, expected, actual []address.AddrWithKeyInfo) { @@ -155,7 +176,9 @@ func TestAddressInsertion(t *testing.T) { // Make a series of new addrs, then insert them into the DB. const numAddrs = 5 - proofCourierAddr := address.RandProofCourierAddr(t) + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) addrs := make([]address.AddrWithKeyInfo, numAddrs) for i := 0; i < numAddrs; i++ { addr, assetGen, assetGroup := address.RandAddr( @@ -278,7 +301,9 @@ func TestAddressQuery(t *testing.T) { // Make a series of new addrs, then insert them into the DB. const numAddrs = 5 - proofCourierAddr := address.RandProofCourierAddr(t) + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) addrs := make([]address.AddrWithKeyInfo, numAddrs) for i := 0; i < numAddrs; i++ { addr, assetGen, assetGroup := address.RandAddr( @@ -396,7 +421,9 @@ func TestAddrEventStatusDBEnum(t *testing.T) { // Make sure an event with an invalid status cannot be created. This // should be protected by a CHECK constraint on the column. If this // fails, you need to update that constraint in the DB! - proofCourierAddr := address.RandProofCourierAddr(t) + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) addr, assetGen, assetGroup := address.RandAddr( t, chainParams, proofCourierAddr, ) @@ -414,7 +441,8 @@ func TestAddrEventStatusDBEnum(t *testing.T) { outputIndex := rand.Intn(len(txn.Tx.TxOut)) _, err = addrBook.GetOrCreateEvent( - ctx, address.Status(4), addr, txn, uint32(outputIndex), + ctx, address.Status(4), addr, txn.Tx, uint32(outputIndex), + 0, nil, nil, ) require.Error(t, err) require.Contains(t, err.Error(), "constraint") @@ -431,9 +459,23 @@ func TestAddrEventCreation(t *testing.T) { ctx := context.Background() + // Before we start, the last height for any version should be 0, as + // we don't have any events yet. + height, err := addrBook.LastEventHeightByVersion(ctx, address.V0) + require.NoError(t, err) + require.EqualValues(t, 0, height) + height, err = addrBook.LastEventHeightByVersion(ctx, address.V1) + require.NoError(t, err) + require.EqualValues(t, 0, height) + height, err = addrBook.LastEventHeightByVersion(ctx, address.V2) + require.NoError(t, err) + require.EqualValues(t, 0, height) + // Create 5 addresses and then events with unconfirmed transactions. const numAddrs = 5 - proofCourierAddr := address.RandProofCourierAddr(t) + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) txns := make([]*lndclient.Transaction, numAddrs) events := make([]*address.Event, numAddrs) for i := 0; i < numAddrs; i++ { @@ -455,8 +497,9 @@ func TestAddrEventCreation(t *testing.T) { outputIndex := rand.Intn(len(txns[i].Tx.TxOut)) event, err := addrBook.GetOrCreateEvent( - ctx, address.StatusTransactionDetected, addr, txns[i], - uint32(outputIndex), + ctx, address.StatusTransactionDetected, addr, + txns[i].Tx, uint32(outputIndex), 0, nil, + randOutputs(t), ) require.NoError(t, err) @@ -489,7 +532,8 @@ func TestAddrEventCreation(t *testing.T) { for idx := range events { actual, err := addrBook.GetOrCreateEvent( ctx, address.StatusTransactionDetected, - events[idx].Addr, txns[idx], events[idx].Outpoint.Index, + events[idx].Addr, txns[idx].Tx, + events[idx].Outpoint.Index, 0, nil, nil, ) require.NoError(t, err) @@ -498,18 +542,41 @@ func TestAddrEventCreation(t *testing.T) { // Now we update the status of our event, make the transaction confirmed // and set the tapscript sibling to nil for all of them. - for idx := range events { - confirmTx(txns[idx]) + maxHeightByVersion := make(map[address.Version]int32) + for idx, event := range events { + txn := txns[idx] + confirmTx(txn) events[idx].Status = address.StatusTransactionConfirmed - events[idx].ConfirmationHeight = uint32(txns[idx].BlockHeight) + events[idx].ConfirmationHeight = uint32(txn.BlockHeight) + + hash, err := chainhash.NewHashFromStr(txn.TxHash) + require.NoError(t, err) actual, err := addrBook.GetOrCreateEvent( ctx, address.StatusTransactionConfirmed, - events[idx].Addr, txns[idx], events[idx].Outpoint.Index, + event.Addr, txn.Tx, event.Outpoint.Index, + uint32(txn.BlockHeight), hash, nil, ) require.NoError(t, err) assertEqualAddrEvent(t, *events[idx], *actual) + + // We didn't store any proofs for the event. So the HasAllProofs + // field should only be true if there are no outputs (which can + // only happen in this unit test in the first place). + require.Equal( + t, len(event.Outputs) == 0, actual.HasAllProofs, + ) + + if maxHeightByVersion[event.Addr.Version] < txn.BlockHeight { + maxHeightByVersion[event.Addr.Version] = txn.BlockHeight + } + } + + for version, maxHeight := range maxHeightByVersion { + height, err := addrBook.LastEventHeightByVersion(ctx, version) + require.NoError(t, err) + require.EqualValues(t, maxHeight, height) } } @@ -528,7 +595,9 @@ func TestAddressEventQuery(t *testing.T) { // Make a series of new addrs, then insert them into the DB. const numAddrs = 5 - proofCourierAddr := address.RandProofCourierAddr(t) + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) addrs := make([]address.AddrWithKeyInfo, numAddrs) for i := 0; i < numAddrs; i++ { addr, assetGen, assetGroup := address.RandAddr( @@ -549,7 +618,8 @@ func TestAddressEventQuery(t *testing.T) { // Make sure we use all states at least once. status := address.Status(i % int(address.StatusCompleted+1)) event, err := addrBook.GetOrCreateEvent( - ctx, status, addr, txn, uint32(outputIndex), + ctx, status, addr, txn.Tx, uint32(outputIndex), + 0, nil, randOutputs(t), ) require.NoError(t, err) require.EqualValues(t, i+1, event.ID) @@ -798,7 +868,9 @@ func TestQueryAddrEvents(t *testing.T) { ctx := context.Background() // Insert a test address and event into the database. - proofCourierAddr := address.RandProofCourierAddr(t) + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) addr, assetGen, assetGroup := address.RandAddr( t, chainParams, proofCourierAddr, ) @@ -813,7 +885,8 @@ func TestQueryAddrEvents(t *testing.T) { tx := randWalletTx() event, err := addrBook.GetOrCreateEvent( - ctx, address.StatusTransactionDetected, addr, tx, 0, + ctx, address.StatusTransactionDetected, addr, tx.Tx, 0, 0, nil, + nil, ) require.NoError(t, err) @@ -845,7 +918,9 @@ func TestAddrByScriptKeyAndVersion(t *testing.T) { ctx := context.Background() // Insert a test address into the database. - proofCourierAddr := address.RandProofCourierAddr(t) + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) addr, assetGen, assetGroup := address.RandAddr( t, chainParams, proofCourierAddr, ) diff --git a/tapdb/asset_minting_test.go b/tapdb/asset_minting_test.go index dcdfb3604..99f1ed032 100644 --- a/tapdb/asset_minting_test.go +++ b/tapdb/asset_minting_test.go @@ -16,6 +16,7 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btclog/v2" + "github.com/lightninglabs/taproot-assets/address" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/commitment" "github.com/lightninglabs/taproot-assets/fn" @@ -1344,7 +1345,9 @@ func TestGroupStore(t *testing.T) { fetchInvalidGenID := func(q PendingAssetStore) error { dbGroup, err := fetchGroupByGenesis(ctx, q, invalidGenID) require.Nil(t, dbGroup) - require.ErrorContains(t, err, "no matching asset group") + require.ErrorContains( + t, err, address.ErrAssetGroupUnknown.Error(), + ) return nil } @@ -1377,7 +1380,9 @@ func TestGroupStore(t *testing.T) { fetchInvalidGroupKey := func(q PendingAssetStore) error { dbGroup, err := fetchGroupByGroupKey(ctx, q, invalidGroupKey) require.Nil(t, dbGroup) - require.ErrorContains(t, err, "no matching asset group") + require.ErrorContains( + t, err, address.ErrAssetGroupUnknown.Error(), + ) return nil } diff --git a/tapdb/assets_common.go b/tapdb/assets_common.go index 6d4d4c65b..f092727df 100644 --- a/tapdb/assets_common.go +++ b/tapdb/assets_common.go @@ -13,6 +13,7 @@ import ( "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" + "github.com/lightninglabs/taproot-assets/address" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/proof" @@ -120,9 +121,6 @@ var ( // ErrUpsertScriptKey is returned when upserting a script key fails. ErrUpsertScriptKey = errors.New("unable to upsert script key") - // ErrNoAssetGroup is returned when no matching asset group is found. - ErrNoAssetGroup = errors.New("no matching asset group") - // ErrNoAssetMeta is returned when no matching asset meta is found. ErrNoAssetMeta = errors.New("no matching asset meta") @@ -634,7 +632,7 @@ func fetchGroupByGenesis(ctx context.Context, q GroupStore, groupInfo, err := q.FetchGroupByGenesis(ctx, genID) switch { case errors.Is(err, sql.ErrNoRows): - return nil, fmt.Errorf("%w: %w", ErrNoAssetGroup, err) + return nil, address.ErrAssetGroupUnknown case err != nil: return nil, err } @@ -669,7 +667,7 @@ func fetchGroupByGroupKey(ctx context.Context, q GroupStore, groupInfo, err := q.FetchGroupByGroupKey(ctx, groupKeyQuery[:]) switch { case errors.Is(err, sql.ErrNoRows): - return nil, fmt.Errorf("%w: %w", ErrNoAssetGroup, err) + return nil, address.ErrAssetGroupUnknown case err != nil: return nil, err } diff --git a/tapdb/authmailbox.go b/tapdb/authmailbox.go index a7c8accef..479ceaf3b 100644 --- a/tapdb/authmailbox.go +++ b/tapdb/authmailbox.go @@ -24,7 +24,10 @@ type ( NewMailboxMessage = sqlc.InsertAuthMailboxMessageParams // MailboxMessage is a row in the auth mailbox messages table. - MailboxMessage = sqlc.FetchAuthMailboxMessagesRow + MailboxMessage = sqlc.FetchAuthMailboxMessageRow + + // MailboxMessageByOutpoint is a row in the auth mailbox messages table. + MailboxMessageByOutpoint = sqlc.FetchAuthMailboxMessageByOutpointRow // QueryMailboxMessages is used to query mailbox messages from the // database. It contains the parameters for the query. @@ -46,10 +49,15 @@ type AuthMailboxStore interface { // authmailbox database. CountAuthMailboxMessages(ctx context.Context) (int64, error) - // FetchAuthMailboxMessages retrieves a mailbox message by its ID. - FetchAuthMailboxMessages(ctx context.Context, + // FetchAuthMailboxMessage retrieves a mailbox message by its ID. + FetchAuthMailboxMessage(ctx context.Context, id int64) (MailboxMessage, error) + // FetchAuthMailboxMessageByOutpoint retrieves a mailbox message by its + // claimed outpoint. + FetchAuthMailboxMessageByOutpoint(ctx context.Context, + claimedOutpoint []byte) (MailboxMessageByOutpoint, error) + // InsertAuthMailboxMessage inserts a new mailbox message into the // database. It returns an error if the insertion fails. InsertAuthMailboxMessage(ctx context.Context, @@ -102,16 +110,16 @@ var _ proof.TxProofStore = (*MailboxStore)(nil) func (m MailboxStore) StoreMessage(ctx context.Context, claimedOp wire.OutPoint, msg *authmailbox.Message) (uint64, error) { + serializedOp, err := encodeOutpoint(claimedOp) + if err != nil { + return 0, fmt.Errorf("error encoding outpoint: %w", err) + } + var ( txOpt = WriteTxOption() msgID int64 ) dbErr := m.db.ExecTx(ctx, txOpt, func(q AuthMailboxStore) error { - serializedOp, err := encodeOutpoint(claimedOp) - if err != nil { - return fmt.Errorf("error encoding outpoint: %w", err) - } - receiverKey := msg.ReceiverKey.SerializeCompressed() msgID, err = q.InsertAuthMailboxMessage(ctx, NewMailboxMessage{ ClaimedOutpoint: serializedOp, @@ -149,7 +157,7 @@ func (m MailboxStore) FetchMessage(ctx context.Context, msg *authmailbox.Message ) dbErr := m.db.ExecTx(ctx, txOpt, func(q AuthMailboxStore) error { - dbMsg, err := q.FetchAuthMailboxMessages(ctx, int64(id)) + dbMsg, err := q.FetchAuthMailboxMessage(ctx, int64(id)) if err != nil { return fmt.Errorf("error fetching message %d: %w", id, err) @@ -181,6 +189,55 @@ func (m MailboxStore) FetchMessage(ctx context.Context, return msg, nil } +// FetchMessageByOutPoint retrieves a message from the mailbox by its +// claimed outpoint of the TX proof that was used to send it. +func (m MailboxStore) FetchMessageByOutPoint(ctx context.Context, + claimedOp wire.OutPoint) (*authmailbox.Message, error) { + + serializedOp, err := encodeOutpoint(claimedOp) + if err != nil { + return nil, fmt.Errorf("error encoding outpoint: %w", err) + } + + var ( + txOpt = ReadTxOption() + msg *authmailbox.Message + ) + dbErr := m.db.ExecTx(ctx, txOpt, func(q AuthMailboxStore) error { + dbMsg, err := q.FetchAuthMailboxMessageByOutpoint( + ctx, serializedOp, + ) + if err != nil { + return fmt.Errorf("error fetching message by "+ + "outpoint %v: %w", serializedOp, err) + } + + receiverKey, err := btcec.ParsePubKey(dbMsg.ReceiverKey) + if err != nil { + return fmt.Errorf("error parsing receiver key: %w", err) + } + + msg = &authmailbox.Message{ + ID: uint64(dbMsg.ID), + ReceiverKey: *receiverKey, + EncryptedPayload: dbMsg.EncryptedPayload, + ArrivalTimestamp: time.Unix(dbMsg.ArrivalTimestamp, 0), + ProofBlockHeight: uint32(dbMsg.BlockHeight), + ExpiryBlockHeight: extractSqlInt32[uint32]( + dbMsg.ExpiryBlockHeight, + ), + } + + return nil + }) + if dbErr != nil { + return nil, fmt.Errorf("error fetching message by outpoint "+ + "%v: %w", serializedOp, dbErr) + } + + return msg, nil +} + // QueryMessages retrieves messages based on a query. func (m MailboxStore) QueryMessages(ctx context.Context, filter authmailbox.MessageFilter) ([]*authmailbox.Message, error) { diff --git a/tapdb/authmailbox_test.go b/tapdb/authmailbox_test.go index 23522f50d..d75e9b303 100644 --- a/tapdb/authmailbox_test.go +++ b/tapdb/authmailbox_test.go @@ -57,6 +57,14 @@ func TestStoreAndFetchMessage(t *testing.T) { t, msg.ArrivalTimestamp.Unix(), dbMsg.ArrivalTimestamp.Unix(), ) require.Equal(t, msg.ExpiryBlockHeight, dbMsg.ExpiryBlockHeight) + + // We should also be able to fetch the message by its outpoint. + dbMsgByOutPoint, err := mailboxStore.FetchMessageByOutPoint( + ctx, txProof.ClaimedOutPoint, + ) + require.NoError(t, err) + + require.Equal(t, dbMsg, dbMsgByOutPoint) } // TestQueryMessages tests querying messages with filters. diff --git a/tapdb/migrations.go b/tapdb/migrations.go index 43b9a045e..176ec1f85 100644 --- a/tapdb/migrations.go +++ b/tapdb/migrations.go @@ -24,7 +24,7 @@ const ( // daemon. // // NOTE: This MUST be updated when a new migration is added. - LatestMigrationVersion = 40 + LatestMigrationVersion = 41 ) // DatabaseBackend is an interface that contains all methods our different diff --git a/tapdb/sqlc/addrs.sql.go b/tapdb/sqlc/addrs.sql.go index a0d8436c4..fb7f43fed 100644 --- a/tapdb/sqlc/addrs.sql.go +++ b/tapdb/sqlc/addrs.sql.go @@ -13,13 +13,16 @@ import ( const FetchAddrEvent = `-- name: FetchAddrEvent :one SELECT - creation_time, status, asset_proof_id, asset_id, + creation_time, + status, chain_txns.txid as txid, chain_txns.block_height as confirmation_height, chain_txn_output_index as output_index, managed_utxos.amt_sats as amt_sats, managed_utxos.tapscript_sibling as tapscript_sibling, - internal_keys.raw_key as internal_key + internal_keys.raw_key as internal_key, + (SELECT count(*) FROM addr_event_proofs ap + WHERE ap.addr_event_id = addr_events.id) AS num_proofs FROM addr_events LEFT JOIN chain_txns ON addr_events.chain_txn_id = chain_txns.txn_id @@ -27,20 +30,19 @@ LEFT JOIN managed_utxos ON addr_events.managed_utxo_id = managed_utxos.utxo_id LEFT JOIN internal_keys ON managed_utxos.internal_key_id = internal_keys.key_id -WHERE id = $1 +WHERE addr_events.id = $1 ` type FetchAddrEventRow struct { CreationTime time.Time Status int16 - AssetProofID sql.NullInt64 - AssetID sql.NullInt64 Txid []byte ConfirmationHeight sql.NullInt32 OutputIndex int32 AmtSats sql.NullInt64 TapscriptSibling []byte InternalKey []byte + NumProofs int64 } func (q *Queries) FetchAddrEvent(ctx context.Context, id int64) (FetchAddrEventRow, error) { @@ -49,14 +51,13 @@ func (q *Queries) FetchAddrEvent(ctx context.Context, id int64) (FetchAddrEventR err := row.Scan( &i.CreationTime, &i.Status, - &i.AssetProofID, - &i.AssetID, &i.Txid, &i.ConfirmationHeight, &i.OutputIndex, &i.AmtSats, &i.TapscriptSibling, &i.InternalKey, + &i.NumProofs, ) return i, err } @@ -68,13 +69,17 @@ WITH target_addr(addr_id) AS ( WHERE addrs.taproot_output_key = $1 ) SELECT - addr_events.id, creation_time, status, asset_proof_id, asset_id, + addr_events.id, + creation_time, + status, chain_txns.txid as txid, chain_txns.block_height as confirmation_height, chain_txn_output_index as output_index, managed_utxos.amt_sats as amt_sats, managed_utxos.tapscript_sibling as tapscript_sibling, - internal_keys.raw_key as internal_key + internal_keys.raw_key as internal_key, + (SELECT count(*) FROM addr_event_proofs ap + WHERE ap.addr_event_id = addr_events.id) AS num_proofs FROM addr_events JOIN target_addr ON addr_events.addr_id = target_addr.addr_id @@ -98,14 +103,13 @@ type FetchAddrEventByAddrKeyAndOutpointRow struct { ID int64 CreationTime time.Time Status int16 - AssetProofID sql.NullInt64 - AssetID sql.NullInt64 Txid []byte ConfirmationHeight sql.NullInt32 OutputIndex int32 AmtSats sql.NullInt64 TapscriptSibling []byte InternalKey []byte + NumProofs int64 } func (q *Queries) FetchAddrEventByAddrKeyAndOutpoint(ctx context.Context, arg FetchAddrEventByAddrKeyAndOutpointParams) (FetchAddrEventByAddrKeyAndOutpointRow, error) { @@ -115,18 +119,114 @@ func (q *Queries) FetchAddrEventByAddrKeyAndOutpoint(ctx context.Context, arg Fe &i.ID, &i.CreationTime, &i.Status, - &i.AssetProofID, - &i.AssetID, &i.Txid, &i.ConfirmationHeight, &i.OutputIndex, &i.AmtSats, &i.TapscriptSibling, &i.InternalKey, + &i.NumProofs, ) return i, err } +const FetchAddrEventOutputs = `-- name: FetchAddrEventOutputs :many +SELECT + addr_event_outputs.amount, + addr_event_outputs.asset_id, + addr_event_outputs.script_key_id, + script_keys.script_key_id, script_keys.internal_key_id, script_keys.tweaked_script_key, script_keys.tweak, script_keys.key_type, + internal_keys.key_id, internal_keys.raw_key, internal_keys.key_family, internal_keys.key_index +FROM addr_event_outputs +JOIN script_keys + ON addr_event_outputs.script_key_id = script_keys.script_key_id +JOIN internal_keys + ON script_keys.internal_key_id = internal_keys.key_id +WHERE addr_event_outputs.addr_event_id = $1 +` + +type FetchAddrEventOutputsRow struct { + Amount int64 + AssetID []byte + ScriptKeyID int64 + ScriptKey ScriptKey + InternalKey InternalKey +} + +func (q *Queries) FetchAddrEventOutputs(ctx context.Context, addrEventID int64) ([]FetchAddrEventOutputsRow, error) { + rows, err := q.db.QueryContext(ctx, FetchAddrEventOutputs, addrEventID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FetchAddrEventOutputsRow + for rows.Next() { + var i FetchAddrEventOutputsRow + if err := rows.Scan( + &i.Amount, + &i.AssetID, + &i.ScriptKeyID, + &i.ScriptKey.ScriptKeyID, + &i.ScriptKey.InternalKeyID, + &i.ScriptKey.TweakedScriptKey, + &i.ScriptKey.Tweak, + &i.ScriptKey.KeyType, + &i.InternalKey.KeyID, + &i.InternalKey.RawKey, + &i.InternalKey.KeyFamily, + &i.InternalKey.KeyIndex, + ); 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 FetchAddrEventProofs = `-- name: FetchAddrEventProofs :many +SELECT + addr_event_proofs.asset_proof_id, + asset_proofs.proof_file +FROM addr_event_proofs +JOIN asset_proofs + ON addr_event_proofs.asset_proof_id = asset_proofs.proof_id +WHERE addr_event_proofs.addr_event_id = $1 +` + +type FetchAddrEventProofsRow struct { + AssetProofID int64 + ProofFile []byte +} + +func (q *Queries) FetchAddrEventProofs(ctx context.Context, addrEventID int64) ([]FetchAddrEventProofsRow, error) { + rows, err := q.db.QueryContext(ctx, FetchAddrEventProofs, addrEventID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []FetchAddrEventProofsRow + for rows.Next() { + var i FetchAddrEventProofsRow + if err := rows.Scan(&i.AssetProofID, &i.ProofFile); 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 FetchAddrs = `-- name: FetchAddrs :many SELECT version, asset_version, genesis_asset_id, group_key, tapscript_sibling, @@ -355,6 +455,23 @@ func (q *Queries) QueryEventIDs(ctx context.Context, arg QueryEventIDsParams) ([ return items, nil } +const QueryLastEventHeightByAddrVersion = `-- name: QueryLastEventHeightByAddrVersion :one +SELECT cast(coalesce(max(chain_txns.block_height), 0) AS BIGINT) AS last_height +FROM addr_events +JOIN chain_txns + ON addr_events.chain_txn_id = chain_txns.txn_id +JOIN addrs + ON addr_events.addr_id = addrs.id +WHERE addrs.version = $1 +` + +func (q *Queries) QueryLastEventHeightByAddrVersion(ctx context.Context, version int16) (int64, error) { + row := q.db.QueryRowContext(ctx, QueryLastEventHeightByAddrVersion, version) + var last_height int64 + err := row.Scan(&last_height) + return last_height, err +} + const SetAddrManaged = `-- name: SetAddrManaged :exec WITH target_addr(addr_id) AS ( SELECT id @@ -467,15 +584,13 @@ WITH target_addr(addr_id) AS ( ) INSERT INTO addr_events ( creation_time, addr_id, status, chain_txn_id, chain_txn_output_index, - managed_utxo_id, asset_proof_id, asset_id + managed_utxo_id ) VALUES ( $3, (SELECT addr_id FROM target_addr), $4, - (SELECT txn_id FROM target_chain_txn), $5, $6, $7, $8 + (SELECT txn_id FROM target_chain_txn), $5, $6 ) ON CONFLICT (addr_id, chain_txn_id, chain_txn_output_index) - DO UPDATE SET status = EXCLUDED.status, - asset_proof_id = COALESCE(EXCLUDED.asset_proof_id, addr_events.asset_proof_id), - asset_id = COALESCE(EXCLUDED.asset_id, addr_events.asset_id) + DO UPDATE SET status = EXCLUDED.status RETURNING id ` @@ -486,8 +601,6 @@ type UpsertAddrEventParams struct { Status int16 ChainTxnOutputIndex int32 ManagedUtxoID int64 - AssetProofID sql.NullInt64 - AssetID sql.NullInt64 } func (q *Queries) UpsertAddrEvent(ctx context.Context, arg UpsertAddrEventParams) (int64, error) { @@ -498,10 +611,67 @@ func (q *Queries) UpsertAddrEvent(ctx context.Context, arg UpsertAddrEventParams arg.Status, arg.ChainTxnOutputIndex, arg.ManagedUtxoID, - arg.AssetProofID, + ) + var id int64 + err := row.Scan(&id) + return id, err +} + +const UpsertAddrEventOutput = `-- name: UpsertAddrEventOutput :one +INSERT INTO addr_event_outputs ( + addr_event_id, amount, asset_id, script_key_id +) VALUES ( + $1, $2, $3, $4 +) +ON CONFLICT (addr_event_id, asset_id) DO UPDATE +SET + -- We allow the amount and script key to be updated. + amount = EXCLUDED.amount, + script_key_id = EXCLUDED.script_key_id +RETURNING id +` + +type UpsertAddrEventOutputParams struct { + AddrEventID int64 + Amount int64 + AssetID []byte + ScriptKeyID int64 +} + +func (q *Queries) UpsertAddrEventOutput(ctx context.Context, arg UpsertAddrEventOutputParams) (int64, error) { + row := q.db.QueryRowContext(ctx, UpsertAddrEventOutput, + arg.AddrEventID, + arg.Amount, arg.AssetID, + arg.ScriptKeyID, ) var id int64 err := row.Scan(&id) return id, err } + +const UpsertAddrEventProof = `-- name: UpsertAddrEventProof :one +INSERT INTO addr_event_proofs ( + addr_event_id, asset_proof_id, asset_id_fk +) VALUES ( + $1, $2, $3 +) +ON CONFLICT (addr_event_id, asset_proof_id) DO UPDATE +SET + -- We allow the asset_id_fk to be updated. + asset_id_fk = EXCLUDED.asset_id_fk +RETURNING id +` + +type UpsertAddrEventProofParams struct { + AddrEventID int64 + AssetProofID int64 + AssetIDFk sql.NullInt64 +} + +func (q *Queries) UpsertAddrEventProof(ctx context.Context, arg UpsertAddrEventProofParams) (int64, error) { + row := q.db.QueryRowContext(ctx, UpsertAddrEventProof, arg.AddrEventID, arg.AssetProofID, arg.AssetIDFk) + var id int64 + err := row.Scan(&id) + return id, err +} diff --git a/tapdb/sqlc/authmailbox.sql.go b/tapdb/sqlc/authmailbox.sql.go index bf96c87b0..af9d244dc 100644 --- a/tapdb/sqlc/authmailbox.sql.go +++ b/tapdb/sqlc/authmailbox.sql.go @@ -37,7 +37,7 @@ func (q *Queries) CountAuthMailboxMessages(ctx context.Context) (int64, error) { return count, err } -const FetchAuthMailboxMessages = `-- name: FetchAuthMailboxMessages :one +const FetchAuthMailboxMessage = `-- name: FetchAuthMailboxMessage :one SELECT m.id, m.claimed_outpoint, @@ -52,7 +52,7 @@ JOIN tx_proof_claimed_outpoints op WHERE id = $1 ` -type FetchAuthMailboxMessagesRow struct { +type FetchAuthMailboxMessageRow struct { ID int64 ClaimedOutpoint []byte ReceiverKey []byte @@ -62,9 +62,49 @@ type FetchAuthMailboxMessagesRow struct { BlockHeight int32 } -func (q *Queries) FetchAuthMailboxMessages(ctx context.Context, id int64) (FetchAuthMailboxMessagesRow, error) { - row := q.db.QueryRowContext(ctx, FetchAuthMailboxMessages, id) - var i FetchAuthMailboxMessagesRow +func (q *Queries) FetchAuthMailboxMessage(ctx context.Context, id int64) (FetchAuthMailboxMessageRow, error) { + row := q.db.QueryRowContext(ctx, FetchAuthMailboxMessage, id) + var i FetchAuthMailboxMessageRow + err := row.Scan( + &i.ID, + &i.ClaimedOutpoint, + &i.ReceiverKey, + &i.EncryptedPayload, + &i.ArrivalTimestamp, + &i.ExpiryBlockHeight, + &i.BlockHeight, + ) + return i, err +} + +const FetchAuthMailboxMessageByOutpoint = `-- name: FetchAuthMailboxMessageByOutpoint :one +SELECT + m.id, + m.claimed_outpoint, + m.receiver_key, + m.encrypted_payload, + m.arrival_timestamp, + m.expiry_block_height, + op.block_height +FROM authmailbox_messages m +JOIN tx_proof_claimed_outpoints op + ON m.claimed_outpoint = op.outpoint +WHERE m.claimed_outpoint = $1 +` + +type FetchAuthMailboxMessageByOutpointRow struct { + ID int64 + ClaimedOutpoint []byte + ReceiverKey []byte + EncryptedPayload []byte + ArrivalTimestamp int64 + ExpiryBlockHeight sql.NullInt32 + BlockHeight int32 +} + +func (q *Queries) FetchAuthMailboxMessageByOutpoint(ctx context.Context, claimedOutpoint []byte) (FetchAuthMailboxMessageByOutpointRow, error) { + row := q.db.QueryRowContext(ctx, FetchAuthMailboxMessageByOutpoint, claimedOutpoint) + var i FetchAuthMailboxMessageByOutpointRow err := row.Scan( &i.ID, &i.ClaimedOutpoint, diff --git a/tapdb/sqlc/migrations/000041_addr_event_outputs.down.sql b/tapdb/sqlc/migrations/000041_addr_event_outputs.down.sql new file mode 100644 index 000000000..e7a0d741c --- /dev/null +++ b/tapdb/sqlc/migrations/000041_addr_event_outputs.down.sql @@ -0,0 +1,18 @@ +DROP INDEX IF EXISTS addrs_script_key_version_2_uk; +DROP INDEX IF EXISTS addr_event_outputs_addr_event_id_asset_id_uk; +DROP INDEX IF EXISTS addr_event_outputs_addr_event_id_idx; +DROP INDEX IF EXISTS addr_event_proofs_addr_event_id_asset_proof_id_uk; +DROP INDEX IF EXISTS addr_event_proofs_addr_event_id_idx; + +DROP TABLE IF EXISTS addr_event_proofs; +DROP TABLE IF EXISTS addr_event_outputs; + +-- We don't allow downgrades, so we don't need a reverse migration for +-- the dropped column asset_proof_id in addr_events. We just add the column +-- back, so the schema is valid again (in case we ever need to downgrade in a +-- unit test or something). + +ALTER TABLE addr_events + ADD COLUMN asset_proof_id BIGINT REFERENCES asset_proofs(proof_id); +ALTER TABLE addr_events + ADD COLUMN asset_id BIGINT REFERENCES assets(asset_id); diff --git a/tapdb/sqlc/migrations/000041_addr_event_outputs.up.sql b/tapdb/sqlc/migrations/000041_addr_event_outputs.up.sql new file mode 100644 index 000000000..15862cc18 --- /dev/null +++ b/tapdb/sqlc/migrations/000041_addr_event_outputs.up.sql @@ -0,0 +1,106 @@ +-- Addresses with version 2 use the raw internal key as the script key. And we +-- need to be able to identify these addresses by script key, so we need a +-- unique index on the script_key_id and version columns to prevent users from +-- creating duplicate V2 addresses. +CREATE UNIQUE INDEX IF NOT EXISTS addrs_script_key_version_2_uk + ON addrs (script_key_id, version) WHERE version = 2; + +-- An event can now have multiple outputs, in case multiple tranches of a +-- grouped asset were sent as part of a V2 address transfer. +CREATE TABLE IF NOT EXISTS addr_event_outputs ( + id INTEGER PRIMARY KEY, + + -- addr_event_id is the reference to the address event this output belongs + -- to. + addr_event_id BIGINT NOT NULL REFERENCES addr_events(id), + + -- amount is the amount of the asset that this output represents. This might + -- only be part of the total amount of the address that is referenced by the + -- event. + amount BIGINT NOT NULL, + + -- asset_id is the ID of the asset that this output represents. + asset_id BLOB NOT NULL CHECK(length(asset_id) = 32), + + -- script_key_id points to the internal key that we created to serve as the + -- script key to be able to receive this asset. + script_key_id BIGINT NOT NULL REFERENCES script_keys(script_key_id) +); + +-- The same asset ID can only be used once per address event, so we add a +-- unique constraint on the combination of addr_event_id and asset_id. This will +-- allow us to upsert event outputs. +CREATE UNIQUE INDEX IF NOT EXISTS addr_event_outputs_addr_event_id_asset_id_uk + ON addr_event_outputs (addr_event_id, asset_id); + +-- We also make sure joins are fast by creating an index on addr_event_id. +CREATE INDEX IF NOT EXISTS addr_event_outputs_addr_event_id_idx + ON addr_event_outputs (addr_event_id); + +-- The data migration is quite simple, we just join the existing data from +-- multiple tables into the new addr_event_outputs table. +INSERT INTO addr_event_outputs ( + addr_event_id, amount, asset_id, script_key_id +) +SELECT + ae.id AS addr_event_id, + a.amount AS amount, + ga.asset_id AS asset_id, + a.script_key_id AS script_key_id +FROM addr_events AS ae +JOIN addrs AS a + ON a.id = ae.addr_id +JOIN genesis_assets AS ga + ON a.genesis_asset_id = ga.gen_asset_id; + +-- We'll also have multiple proofs associated with an address event, in case +-- multiple proofs were sent as part of a V2 address transfer. +CREATE TABLE IF NOT EXISTS addr_event_proofs ( + id INTEGER PRIMARY KEY, + + -- addr_event_id is the reference to the address event this proof belongs to. + addr_event_id BIGINT NOT NULL REFERENCES addr_events(id), + + -- asset_proof_id is a reference to the proof associated with this asset + -- event. + asset_proof_id BIGINT NOT NULL REFERENCES asset_proofs(proof_id), + + -- asset_id_fk is a reference to the asset once we have taken custody of it. + -- This will only be set once the proofs were imported successfully and the + -- event is in the status complete. + asset_id_fk BIGINT REFERENCES assets(asset_id) +); + +-- The same asset proof can only be used once per address event, so we add a +-- unique constraint on the combination of addr_event_id and asset_proof_id. +-- This will allow us to upsert event proofs. +CREATE UNIQUE INDEX IF NOT EXISTS + addr_event_proofs_addr_event_id_asset_proof_id_uk + ON addr_event_proofs (addr_event_id, asset_proof_id); + +-- We also make sure joins are fast by creating an index on addr_event_id. +CREATE INDEX IF NOT EXISTS addr_event_proofs_addr_event_id_idx + ON addr_event_proofs (addr_event_id); + +-- And again, we migrate the existing data from the 1:1 relationship to the new +-- 1:n relationship. +INSERT INTO addr_event_proofs ( + addr_event_id, asset_proof_id, asset_id_fk +) +SELECT + ae.id AS addr_event_id, + ae.asset_proof_id AS asset_proof_id, + ae.asset_id AS asset_id_fk +FROM addr_events AS ae +LEFT JOIN assets AS a + ON ae.asset_id = a.asset_id +WHERE ae.asset_proof_id IS NOT NULL; + +-- And now we can drop the old columns from the tables. +DROP INDEX IF EXISTS asset_proof_id_idx; +DROP INDEX IF EXISTS asset_id_idx; +ALTER TABLE addr_events + DROP COLUMN asset_id; + +ALTER TABLE addr_events + DROP COLUMN asset_proof_id; diff --git a/tapdb/sqlc/models.go b/tapdb/sqlc/models.go index e077c7948..f7fcd8cb3 100644 --- a/tapdb/sqlc/models.go +++ b/tapdb/sqlc/models.go @@ -34,8 +34,21 @@ type AddrEvent struct { ChainTxnID int64 ChainTxnOutputIndex int32 ManagedUtxoID int64 - AssetProofID sql.NullInt64 - AssetID sql.NullInt64 +} + +type AddrEventOutput struct { + ID int64 + AddrEventID int64 + Amount int64 + AssetID []byte + ScriptKeyID int64 +} + +type AddrEventProof struct { + ID int64 + AddrEventID int64 + AssetProofID int64 + AssetIDFk sql.NullInt64 } type Asset struct { diff --git a/tapdb/sqlc/querier.go b/tapdb/sqlc/querier.go index b605f72c6..8198f23ed 100644 --- a/tapdb/sqlc/querier.go +++ b/tapdb/sqlc/querier.go @@ -50,6 +50,8 @@ type Querier interface { DeleteUniverseSupplyRoot(ctx context.Context, namespaceRoot string) error FetchAddrEvent(ctx context.Context, id int64) (FetchAddrEventRow, error) FetchAddrEventByAddrKeyAndOutpoint(ctx context.Context, arg FetchAddrEventByAddrKeyAndOutpointParams) (FetchAddrEventByAddrKeyAndOutpointRow, error) + FetchAddrEventOutputs(ctx context.Context, addrEventID int64) ([]FetchAddrEventOutputsRow, error) + FetchAddrEventProofs(ctx context.Context, addrEventID int64) ([]FetchAddrEventProofsRow, error) FetchAddrs(ctx context.Context, arg FetchAddrsParams) ([]FetchAddrsRow, error) FetchAllNodes(ctx context.Context) ([]MssmtNode, error) FetchAssetID(ctx context.Context, arg FetchAssetIDParams) ([]int64, error) @@ -68,7 +70,8 @@ type Querier interface { // doesn't have a group key. See the comment in fetchAssetSprouts for a work // around that needs to be used with this query until a sqlc bug is fixed. FetchAssetsForBatch(ctx context.Context, rawKey []byte) ([]FetchAssetsForBatchRow, error) - FetchAuthMailboxMessages(ctx context.Context, id int64) (FetchAuthMailboxMessagesRow, error) + FetchAuthMailboxMessage(ctx context.Context, id int64) (FetchAuthMailboxMessageRow, error) + FetchAuthMailboxMessageByOutpoint(ctx context.Context, claimedOutpoint []byte) (FetchAuthMailboxMessageByOutpointRow, error) FetchChainTx(ctx context.Context, txid []byte) (ChainTxn, error) FetchChainTxByID(ctx context.Context, txnID int64) (FetchChainTxByIDRow, error) FetchChildren(ctx context.Context, arg FetchChildrenParams) ([]FetchChildrenRow, error) @@ -165,6 +168,7 @@ type Querier interface { // Join on genesis_info_view to get leaf related fields. QueryFederationProofSyncLog(ctx context.Context, arg QueryFederationProofSyncLogParams) ([]QueryFederationProofSyncLogRow, error) QueryFederationUniSyncConfigs(ctx context.Context) ([]QueryFederationUniSyncConfigsRow, error) + QueryLastEventHeightByAddrVersion(ctx context.Context, version int16) (int64, error) QueryMultiverseLeaves(ctx context.Context, arg QueryMultiverseLeavesParams) ([]QueryMultiverseLeavesRow, error) QueryPassiveAssets(ctx context.Context, transferID int64) ([]QueryPassiveAssetsRow, error) QueryPendingSupplyCommitTransition(ctx context.Context, groupKey []byte) (SupplyCommitTransition, error) @@ -193,6 +197,8 @@ type Querier interface { UpdateUTXOLease(ctx context.Context, arg UpdateUTXOLeaseParams) error UpsertAddr(ctx context.Context, arg UpsertAddrParams) (int64, error) UpsertAddrEvent(ctx context.Context, arg UpsertAddrEventParams) (int64, error) + UpsertAddrEventOutput(ctx context.Context, arg UpsertAddrEventOutputParams) (int64, error) + UpsertAddrEventProof(ctx context.Context, arg UpsertAddrEventProofParams) (int64, error) UpsertAsset(ctx context.Context, arg UpsertAssetParams) (int64, error) UpsertAssetGroupKey(ctx context.Context, arg UpsertAssetGroupKeyParams) (int64, error) UpsertAssetGroupWitness(ctx context.Context, arg UpsertAssetGroupWitnessParams) (int64, error) diff --git a/tapdb/sqlc/queries/addrs.sql b/tapdb/sqlc/queries/addrs.sql index 60a759b34..79af3641e 100644 --- a/tapdb/sqlc/queries/addrs.sql +++ b/tapdb/sqlc/queries/addrs.sql @@ -108,26 +108,52 @@ WITH target_addr(addr_id) AS ( ) INSERT INTO addr_events ( creation_time, addr_id, status, chain_txn_id, chain_txn_output_index, - managed_utxo_id, asset_proof_id, asset_id + managed_utxo_id ) VALUES ( $3, (SELECT addr_id FROM target_addr), $4, - (SELECT txn_id FROM target_chain_txn), $5, $6, $7, $8 + (SELECT txn_id FROM target_chain_txn), $5, $6 ) ON CONFLICT (addr_id, chain_txn_id, chain_txn_output_index) - DO UPDATE SET status = EXCLUDED.status, - asset_proof_id = COALESCE(EXCLUDED.asset_proof_id, addr_events.asset_proof_id), - asset_id = COALESCE(EXCLUDED.asset_id, addr_events.asset_id) + DO UPDATE SET status = EXCLUDED.status +RETURNING id; + +-- name: UpsertAddrEventOutput :one +INSERT INTO addr_event_outputs ( + addr_event_id, amount, asset_id, script_key_id +) VALUES ( + $1, $2, $3, $4 +) +ON CONFLICT (addr_event_id, asset_id) DO UPDATE +SET + -- We allow the amount and script key to be updated. + amount = EXCLUDED.amount, + script_key_id = EXCLUDED.script_key_id +RETURNING id; + +-- name: UpsertAddrEventProof :one +INSERT INTO addr_event_proofs ( + addr_event_id, asset_proof_id, asset_id_fk +) VALUES ( + $1, $2, $3 +) +ON CONFLICT (addr_event_id, asset_proof_id) DO UPDATE +SET + -- We allow the asset_id_fk to be updated. + asset_id_fk = EXCLUDED.asset_id_fk RETURNING id; -- name: FetchAddrEvent :one SELECT - creation_time, status, asset_proof_id, asset_id, + creation_time, + status, chain_txns.txid as txid, chain_txns.block_height as confirmation_height, chain_txn_output_index as output_index, managed_utxos.amt_sats as amt_sats, managed_utxos.tapscript_sibling as tapscript_sibling, - internal_keys.raw_key as internal_key + internal_keys.raw_key as internal_key, + (SELECT count(*) FROM addr_event_proofs ap + WHERE ap.addr_event_id = addr_events.id) AS num_proofs FROM addr_events LEFT JOIN chain_txns ON addr_events.chain_txn_id = chain_txns.txn_id @@ -135,7 +161,30 @@ LEFT JOIN managed_utxos ON addr_events.managed_utxo_id = managed_utxos.utxo_id LEFT JOIN internal_keys ON managed_utxos.internal_key_id = internal_keys.key_id -WHERE id = $1; +WHERE addr_events.id = $1; + +-- name: FetchAddrEventOutputs :many +SELECT + addr_event_outputs.amount, + addr_event_outputs.asset_id, + addr_event_outputs.script_key_id, + sqlc.embed(script_keys), + sqlc.embed(internal_keys) +FROM addr_event_outputs +JOIN script_keys + ON addr_event_outputs.script_key_id = script_keys.script_key_id +JOIN internal_keys + ON script_keys.internal_key_id = internal_keys.key_id +WHERE addr_event_outputs.addr_event_id = $1; + +-- name: FetchAddrEventProofs :many +SELECT + addr_event_proofs.asset_proof_id, + asset_proofs.proof_file +FROM addr_event_proofs +JOIN asset_proofs + ON addr_event_proofs.asset_proof_id = asset_proofs.proof_id +WHERE addr_event_proofs.addr_event_id = $1; -- name: FetchAddrEventByAddrKeyAndOutpoint :one WITH target_addr(addr_id) AS ( @@ -144,13 +193,17 @@ WITH target_addr(addr_id) AS ( WHERE addrs.taproot_output_key = $1 ) SELECT - addr_events.id, creation_time, status, asset_proof_id, asset_id, + addr_events.id, + creation_time, + status, chain_txns.txid as txid, chain_txns.block_height as confirmation_height, chain_txn_output_index as output_index, managed_utxos.amt_sats as amt_sats, managed_utxos.tapscript_sibling as tapscript_sibling, - internal_keys.raw_key as internal_key + internal_keys.raw_key as internal_key, + (SELECT count(*) FROM addr_event_proofs ap + WHERE ap.addr_event_id = addr_events.id) AS num_proofs FROM addr_events JOIN target_addr ON addr_events.addr_id = target_addr.addr_id @@ -174,3 +227,12 @@ WHERE addr_events.status >= @status_from AND COALESCE(@addr_taproot_key, addrs.taproot_output_key) = addrs.taproot_output_key AND addr_events.creation_time >= @created_after ORDER by addr_events.creation_time; + +-- name: QueryLastEventHeightByAddrVersion :one +SELECT cast(coalesce(max(chain_txns.block_height), 0) AS BIGINT) AS last_height +FROM addr_events +JOIN chain_txns + ON addr_events.chain_txn_id = chain_txns.txn_id +JOIN addrs + ON addr_events.addr_id = addrs.id +WHERE addrs.version = $1; diff --git a/tapdb/sqlc/queries/authmailbox.sql b/tapdb/sqlc/queries/authmailbox.sql index a2fce6c47..3f6abcb71 100644 --- a/tapdb/sqlc/queries/authmailbox.sql +++ b/tapdb/sqlc/queries/authmailbox.sql @@ -21,7 +21,7 @@ INSERT INTO authmailbox_messages ( ) RETURNING id; --- name: FetchAuthMailboxMessages :one +-- name: FetchAuthMailboxMessage :one SELECT m.id, m.claimed_outpoint, @@ -35,6 +35,20 @@ JOIN tx_proof_claimed_outpoints op ON m.claimed_outpoint = op.outpoint WHERE id = $1; +-- name: FetchAuthMailboxMessageByOutpoint :one +SELECT + m.id, + m.claimed_outpoint, + m.receiver_key, + m.encrypted_payload, + m.arrival_timestamp, + m.expiry_block_height, + op.block_height +FROM authmailbox_messages m +JOIN tx_proof_claimed_outpoints op + ON m.claimed_outpoint = op.outpoint +WHERE m.claimed_outpoint = $1; + -- name: QueryAuthMailboxMessages :many SELECT m.id, diff --git a/tapdb/sqlc/schemas/generated_schema.sql b/tapdb/sqlc/schemas/generated_schema.sql index 80b930b85..96e2c1001 100644 --- a/tapdb/sqlc/schemas/generated_schema.sql +++ b/tapdb/sqlc/schemas/generated_schema.sql @@ -2,6 +2,54 @@ CREATE INDEX addr_asset_genesis_ids ON addrs (genesis_asset_id); CREATE INDEX addr_creation_time ON addrs (creation_time); +CREATE TABLE addr_event_outputs ( + id INTEGER PRIMARY KEY, + + -- addr_event_id is the reference to the address event this output belongs + -- to. + addr_event_id BIGINT NOT NULL REFERENCES addr_events(id), + + -- amount is the amount of the asset that this output represents. This might + -- only be part of the total amount of the address that is referenced by the + -- event. + amount BIGINT NOT NULL, + + -- asset_id is the ID of the asset that this output represents. + asset_id BLOB NOT NULL CHECK(length(asset_id) = 32), + + -- script_key_id points to the internal key that we created to serve as the + -- script key to be able to receive this asset. + script_key_id BIGINT NOT NULL REFERENCES script_keys(script_key_id) +); + +CREATE UNIQUE INDEX addr_event_outputs_addr_event_id_asset_id_uk + ON addr_event_outputs (addr_event_id, asset_id); + +CREATE INDEX addr_event_outputs_addr_event_id_idx + ON addr_event_outputs (addr_event_id); + +CREATE TABLE addr_event_proofs ( + id INTEGER PRIMARY KEY, + + -- addr_event_id is the reference to the address event this proof belongs to. + addr_event_id BIGINT NOT NULL REFERENCES addr_events(id), + + -- asset_proof_id is a reference to the proof associated with this asset + -- event. + asset_proof_id BIGINT NOT NULL REFERENCES asset_proofs(proof_id), + + -- asset_id_fk is a reference to the asset once we have taken custody of it. + -- This will only be set once the proofs were imported successfully and the + -- event is in the status complete. + asset_id_fk BIGINT REFERENCES assets(asset_id) +); + +CREATE UNIQUE INDEX addr_event_proofs_addr_event_id_asset_proof_id_uk + ON addr_event_proofs (addr_event_id, asset_proof_id); + +CREATE INDEX addr_event_proofs_addr_event_id_idx + ON addr_event_proofs (addr_event_id); + CREATE TABLE addr_events ( id INTEGER PRIMARY KEY, @@ -26,15 +74,6 @@ CREATE TABLE addr_events ( -- managed_utxo_id is a reference to the managed UTXO the internal wallet -- tracks with on-chain funds that belong to us. managed_utxo_id BIGINT NOT NULL REFERENCES managed_utxos(utxo_id), - - -- asset_proof_id is a reference to the proof associated with this asset - -- event. - asset_proof_id BIGINT REFERENCES asset_proofs(proof_id), - - -- asset_id is a reference to the asset once we have taken custody of it. - -- This will only be set once the proofs were imported successfully and the - -- event is in the status complete. - asset_id BIGINT REFERENCES assets(asset_id), UNIQUE(addr_id, chain_txn_id, chain_txn_output_index) ); @@ -96,6 +135,9 @@ CREATE TABLE addrs ( proof_courier_addr BLOB NOT NULL ); +CREATE UNIQUE INDEX addrs_script_key_version_2_uk + ON addrs (script_key_id, version) WHERE version = 2; + CREATE TABLE "asset_burn_transfers" ( -- The auto-incrementing integer that identifies this burn transfer. burn_id INTEGER PRIMARY KEY, @@ -144,8 +186,6 @@ CREATE TABLE asset_groups ( , version INTEGER NOT NULL DEFAULT 0, custom_subtree_root_id INTEGER REFERENCES tapscript_roots(root_id)); -CREATE INDEX asset_id_idx ON addr_events(asset_id); - CREATE INDEX asset_ids on genesis_assets(asset_id); CREATE TABLE asset_minting_batches ( @@ -166,8 +206,6 @@ CREATE TABLE asset_minting_batches ( creation_time_unix TIMESTAMP NOT NULL , tapscript_sibling BLOB, assets_output_index INTEGER, universe_commitments BOOLEAN NOT NULL DEFAULT FALSE); -CREATE INDEX asset_proof_id_idx ON addr_events(asset_proof_id); - CREATE TABLE asset_proofs ( proof_id INTEGER PRIMARY KEY, diff --git a/tapfreighter/chain_porter.go b/tapfreighter/chain_porter.go index 9505dc6aa..65e446e98 100644 --- a/tapfreighter/chain_porter.go +++ b/tapfreighter/chain_porter.go @@ -28,6 +28,12 @@ import ( "github.com/lightningnetwork/lnd/lnwallet/chainfee" ) +const ( + // DefaultSendFragmentExpiryDelta is the default number of blocks that + // we expect a send fragment to be valid for. + DefaultSendFragmentExpiryDelta = 210_000 +) + // ProofImporter is used to import proofs into the local proof archive after we // complete a trransfer. type ProofImporter interface { @@ -611,6 +617,48 @@ func (p *ChainPorter) storeProofs(sendPkg *sendPackage) error { err) } } + + if len(sendPkg.SendManifests) == 0 { + // If there are no fragment manifests, then this is an + // old address or interactive/vPSBT flow transfer, and + // we don't need to create any submission TX proofs. + continue + } + + // Because we need to provide a TX proof for each message we + // upload to the auth mailbox server, we need to find the + // manifest that corresponds to this output, then create the + // TX proof from the transition proof that already contains all + // the data. + for outIdx := range sendPkg.SendManifests { + manifest := sendPkg.SendManifests[outIdx] + log.Debugf("Adding TX proof to manifest for output "+ + "index %d", outIdx) + + if outIdx != out.Anchor.OutPoint.Index { + continue + } + + if out.Anchor.InternalKey.PubKey == nil { + return fmt.Errorf("anchor internal key "+ + "not set for output %d", outIdx) + } + + manifest.ExpiryHeight = parsedSuffix.BlockHeight + + DefaultSendFragmentExpiryDelta + manifest.Fragment.OutPoint = out.Anchor.OutPoint + manifest.Fragment.BlockHeader = parsedSuffix.BlockHeader + manifest.Fragment.BlockHeight = parsedSuffix.BlockHeight + manifest.TxProof = proof.TxProof{ + MsgTx: parsedSuffix.AnchorTx, + BlockHeader: parsedSuffix.BlockHeader, + BlockHeight: parsedSuffix.BlockHeight, + MerkleProof: parsedSuffix.TxMerkleProof, + ClaimedOutPoint: out.Anchor.OutPoint, + InternalKey: *out.Anchor.InternalKey.PubKey, + MerkleRoot: out.Anchor.MerkleRoot, + } + } } sendPkg.SendState = SendStateTransferProofs @@ -901,10 +949,18 @@ func (p *ChainPorter) transferReceiverProof(pkg *sendPackage) error { "script key %x", scriptKeyBytes) } + // Is there a send fragment manifest for this output that we + // need to send first? + var sendManifest *proof.SendManifest + if len(pkg.SendManifests) > 0 { + anchorOutputIndex := out.Anchor.OutPoint.Index + sendManifest = pkg.SendManifests[anchorOutputIndex] + } + log.Debugf("Attempting to deliver proof (script_key=%x, "+ - "asset_id=%x, proof_courier_addr=%s)", + "asset_id=%x, proof_courier_addr=%s, has_manifest=%v)", scriptKeyBytes, receiverProof.AssetID[:], - out.ProofCourierAddr) + out.ProofCourierAddr, sendManifest != nil) proofCourierAddr, err := proof.ParseCourierAddress( string(out.ProofCourierAddr), @@ -938,7 +994,9 @@ func (p *ChainPorter) transferReceiverProof(pkg *sendPackage) error { AssetID: *receiverProof.AssetID, Amount: out.Amount, } - err = courier.DeliverProof(ctx, recipient, receiverProof) + err = courier.DeliverProof( + ctx, recipient, receiverProof, sendManifest, + ) // If the proof courier returned a backoff error, then // we'll just return nil here so that we can retry @@ -1238,7 +1296,8 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) { return nil, fmt.Errorf("unable to cast parcel to " + "address parcel") } - fundSendRes, err := p.cfg.AssetWallet.FundAddressSend( + wallet := p.cfg.AssetWallet + fundSendRes, err := wallet.FundAddressSend( ctx, fn.Some(asset.ScriptKeyBip86), nil, addrParcel.destAddrs..., ) @@ -1578,7 +1637,17 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) { // package state on disk to reflect this. This step frees up the change // outputs so that they can be used in future transactions. case SendStateStorePostAnchorTxConf: - err := p.storeProofs(¤tPkg) + // Before we store the proofs, we need to create the send + // fragment manifests for any address v2 sends. + manifests, err := createSendFragments(currentPkg.VirtualPackets) + if err != nil { + return nil, fmt.Errorf("unable to create send "+ + "fragments: %w", err) + } + + currentPkg.SendManifests = manifests + + err = p.storeProofs(¤tPkg) if err != nil { return nil, fmt.Errorf("unable to store proofs: %w", err) diff --git a/tapfreighter/parcel.go b/tapfreighter/parcel.go index cb40cc201..618745eef 100644 --- a/tapfreighter/parcel.go +++ b/tapfreighter/parcel.go @@ -178,8 +178,11 @@ func NewAddressParcel(feeRate *chainfee.SatPerKWeight, label string, // pkg returns the send package that should be delivered. func (p *AddressParcel) pkg() *sendPackage { + addrStrings := fn.Map(p.destAddrs, func(addr *address.Tap) string { + return fmt.Sprintf("%d:%s", addr.Amount, addr.String()) + }) log.Infof("Received to send request to %d addrs: %v", len(p.destAddrs), - p.destAddrs) + addrStrings) // Initialize a package with the destination address. return &sendPackage{ @@ -483,6 +486,11 @@ type sendPackage struct { // associated Taproot Asset commitment. InputCommitments tappsbt.InputCommitments + // SendManifests is a map of send manifests that need to be sent to the + // auth mailbox server to complete an address V2 transfer. It is keyed + // by the anchor output index. + SendManifests map[uint32]*proof.SendManifest + // PassiveAssets is the data used in re-anchoring passive assets. PassiveAssets []*tappsbt.VPacket diff --git a/tapfreighter/wallet.go b/tapfreighter/wallet.go index e14f26ced..f374642a1 100644 --- a/tapfreighter/wallet.go +++ b/tapfreighter/wallet.go @@ -274,12 +274,168 @@ func (f *AssetWallet) FundAddressSend(ctx context.Context, fundDesc.ScriptKeyType = scriptKeyType fundedVPkt, err := f.FundPacket(ctx, fundDesc, vPkt) if err != nil { - return nil, err + return nil, fmt.Errorf("error funding packet: %w", err) + } + + // If we're sending to a V2 address, we need to create the send fragment + // for the receiver later. For that we need to add the address to the + // virtual outputs and also derive a unique script key. + hasV2Addr := fn.Any( + receiverAddrs, func(a *address.Tap) bool { + return a.Version >= address.V2 + }, + ) + + // If there isn't a V2 address, we can return early, as we have + // everything we need. + if !hasV2Addr { + return fundedVPkt, nil + } + + return prepareV2Outputs(ctx, fundedVPkt) +} + +// prepareAddressV2Outputs prepares the outputs of a funded virtual packet +// for V2 addresses. It derives a unique script key for each output that has +// a V2 address set. +func prepareV2Outputs(ctx context.Context, + fundedVPkt *FundedVPacket) (*FundedVPacket, error) { + + for pktIdx := range fundedVPkt.VPackets { + vPkt := fundedVPkt.VPackets[pktIdx] + assetID, err := vPkt.AssetID() + if err != nil { + return nil, fmt.Errorf("unable to determine asset "+ + "specifier: %w", err) + } + + for outIdx := range vPkt.Outputs { + vOut := vPkt.Outputs[outIdx] + + // A send fragment can only be created for an output + // that has an address with version 2 set. + if vOut.Address == nil { + continue + } + if vOut.Address.Version < address.V2 { + continue + } + + receiverKey := vOut.Address.ScriptKey + scriptKey, err := asset.DeriveUniqueScriptKey( + receiverKey, assetID, + asset.ScriptKeyDerivationUniquePedersen, + ) + if err != nil { + return nil, fmt.Errorf("unable to derive "+ + "unique script key: %w", err) + } + + vOut.ScriptKey = scriptKey + if vOut.Asset != nil { + vOut.Asset.ScriptKey = scriptKey + } + } + + // We need to re-create the output assets because we potentially + // changed the script keys. + if err := tapsend.PrepareOutputAssets(ctx, vPkt); err != nil { + log.Errorf("Error preparing output assets: %v, "+ + "packets: %v", err, limitSpewer.Sdump(vPkt)) + return nil, fmt.Errorf("unable to prepare outputs: %w", + err) + } } return fundedVPkt, nil } +// createSendFragments creates the send fragments for the given funded virtual +// packets. The send fragments are used to reconstruct the information required +// to fetch proofs from the universe, and to materialize the asset outputs on +// the receiver's side. We assume that the receiver has access to the TAP +// address that was used to send the assets. +func createSendFragments( + packets []*tappsbt.VPacket) (map[uint32]*proof.SendManifest, error) { + + result := make(map[uint32]*proof.SendManifest) + addToFragment := func(addr *address.Tap, assetID asset.ID, + vOut *tappsbt.VOutput) error { + + receiverKey := addr.ScriptKey + + manifest, ok := result[vOut.AnchorOutputIndex] + if !ok { + manifest = &proof.SendManifest{ + Receiver: receiverKey, + CourierURL: *vOut.ProofDeliveryAddress, + Fragment: proof.SendFragment{ + Version: proof.SendFragmentV0, + Outputs: make( + map[asset.ID]proof.SendOutput, + ), + }, + } + result[vOut.AnchorOutputIndex] = manifest + } + + scriptKey, err := asset.DeriveUniqueScriptKey( + receiverKey, assetID, + asset.ScriptKeyDerivationUniquePedersen, + ) + if err != nil { + return fmt.Errorf("unable to derive unique script "+ + "key: %w", err) + } + + // As a sanity check, we make sure that the unique script key + // we just re-derived is the same that's already set on the + // virtual output. + if !scriptKey.PubKey.IsEqual(vOut.ScriptKey.PubKey) { + return fmt.Errorf("derived unique pedersen script key "+ + "%x doesn't match virtual output script key %x", + scriptKey.PubKey.SerializeCompressed(), + vOut.ScriptKey.PubKey.SerializeCompressed()) + } + + manifest.Fragment.Outputs[assetID] = proof.SendOutput{ + AssetVersion: vOut.AssetVersion, + Amount: vOut.Amount, + ScriptKey: asset.ToSerialized(scriptKey.PubKey), + } + + return nil + } + + for _, vPkt := range packets { + assetID, err := vPkt.AssetID() + if err != nil { + return nil, fmt.Errorf("unable to determine asset ID: "+ + "%w", err) + } + + for outIdx, vOut := range vPkt.Outputs { + // A send fragment can only be created for an output + // that has an address with version 2 set. + if vOut.Address == nil { + continue + } + if vOut.Address.Version < address.V2 { + continue + } + + log.Debugf("Adding send fregment for output %d", outIdx) + err := addToFragment(vOut.Address, assetID, vOut) + if err != nil { + return nil, fmt.Errorf("unable to add output "+ + "to send fragment: %w", err) + } + } + } + + return result, nil +} + // createPassivePacket creates a virtual packet for the given passive asset. func createPassivePacket(passiveAsset *asset.Asset, activePackets []*tappsbt.VPacket, anchorOutputIndex uint32, diff --git a/tapgarden/custodian.go b/tapgarden/custodian.go index 98e021708..c8bc84fb8 100644 --- a/tapgarden/custodian.go +++ b/tapgarden/custodian.go @@ -6,18 +6,34 @@ import ( "fmt" "strings" "sync" + "sync/atomic" "time" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcwallet/waddrmgr" "github.com/lightninglabs/lndclient" "github.com/lightninglabs/taproot-assets/address" "github.com/lightninglabs/taproot-assets/asset" + mbox "github.com/lightninglabs/taproot-assets/authmailbox" "github.com/lightninglabs/taproot-assets/fn" + "github.com/lightninglabs/taproot-assets/internal/ecies" "github.com/lightninglabs/taproot-assets/proof" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnrpc" ) +const ( + // defaultMboxInitialBackoff is the initial backoff time used for + // connecting to the auth mailbox service. + defaultMboxInitialBackoff = 100 * time.Millisecond + + // defaultMboxMaxBackoff is the maximum backoff time used for connecting + // to the auth mailbox service. + defaultMboxMaxBackoff = 10 * time.Second +) + // AssetReceiveEvent is an event that is sent to a subscriber once the // asset receive process has finished for a given address and outpoint. type AssetReceiveEvent struct { @@ -99,6 +115,10 @@ type CustodianConfig struct { // AddrBook is the storage backend for addresses. AddrBook *address.Book + // Signer is the lndclient.SignerClient that is used to sign challenges + // from the auth mailbox server when subscribing for messages. + Signer lndclient.SignerClient + // ProofArchive is the storage backend for proofs to which we store new // incoming proofs. ProofArchive proof.Archiver @@ -115,6 +135,10 @@ type CustodianConfig struct { // a proof courier address. ProofCourierDispatcher proof.CourierDispatch + // MboxBackoffCfg is the backoff configuration used for the auth + // mailbox service. + MboxBackoffCfg *proof.BackoffCfg + // ProofRetrievalDelay is the time duration the custodian waits having // identified an asset transfer on-chain and before retrieving the // corresponding proof via the proof courier service. @@ -159,6 +183,16 @@ type Custodian struct { // address events of inbound assets. events map[wire.OutPoint]*address.Event + // mboxSubscriptions is a helper that allows us to subscribe to multiple + // mailbox servers at once, using multiple different URLs and receiver + // keys. + mboxSubscriptions *mbox.MultiSubscription + + // mboxRequestStartHeight is the block height at which we start + // requesting messages from the auth mailbox. This is increased with + // each new message we receive. + mboxRequestStartHeight atomic.Uint32 + // ContextGuard provides a wait group and main quit channel that can be // used to create guarded contexts. *fn.ContextGuard @@ -172,12 +206,29 @@ func NewCustodian(cfg *CustodianConfig) *Custodian { ) proofSub := fn.NewEventReceiver[proof.Blob](fn.DefaultQueueSize) statusEventsSubs := make(map[uint64]*fn.EventReceiver[fn.Event]) + + backoffCfg := cfg.MboxBackoffCfg + if backoffCfg == nil { + backoffCfg = &proof.BackoffCfg{ + InitialBackoff: defaultMboxInitialBackoff, + MaxBackoff: defaultMboxMaxBackoff, + } + } + return &Custodian{ cfg: cfg, addrSubscription: addrSub, proofSubscription: proofSub, statusEventsSubs: statusEventsSubs, events: make(map[wire.OutPoint]*address.Event), + mboxSubscriptions: mbox.NewMultiSubscription( + mbox.ClientConfig{ + SkipTlsVerify: true, + Signer: cfg.Signer, + MinBackoff: backoffCfg.InitialBackoff, + MaxBackoff: backoffCfg.MaxBackoff, + }, + ), ContextGuard: &fn.ContextGuard{ DefaultTimeout: DefaultTimeout, Quit: make(chan struct{}), @@ -225,6 +276,8 @@ func (c *Custodian) Start() error { func (c *Custodian) Stop() error { var stopErr error c.stopOnce.Do(func() { + log.Info("Stopping asset custodian") + close(c.Quit) c.Wg.Wait() @@ -238,6 +291,12 @@ func (c *Custodian) Stop() error { stopErr = err } + err = c.mboxSubscriptions.Stop() + if err != nil { + stopErr = fmt.Errorf("unable to stop mailbox "+ + "subscriptions: %w", err) + } + // Remove all status event subscribers. c.statusEventsSubsMtx.Lock() defer c.statusEventsSubsMtx.Unlock() @@ -287,6 +346,25 @@ func (c *Custodian) watchInboundAssets() { return } + // Fetching start height for querying new auth mailbox messages. We + // always start at the last block height of the last event we processed, + // which will give us the events for that block again (the block height + // query is inclusive). But we can handle duplicate events, so this is + // not an issue. Only V2 addresses are using the auth mailbox, so we + // can query just for V2 address events. + log.Infof("Fetching last v2 address event height") + ctxt, cancel = c.WithCtxQuit() + lastHeight, err := c.cfg.AddrBook.LastEventHeightByVersion( + ctxt, address.V2, + ) + cancel() + if err != nil { + reportErr(err) + return + } + + c.mboxRequestStartHeight.Store(lastHeight) + // From the events we already know, we can now find out the last height // we detected an event at. log.Infof("Resuming %d pending inbound asset events", len(events)) @@ -333,8 +411,8 @@ func (c *Custodian) watchInboundAssets() { go func() { defer c.Wg.Done() - recErr := c.receiveProof( - event.Addr.Tap, event.Outpoint, + recErr := c.receiveProofs( + event.Addr.Tap, event.Outpoint, event.Outputs, event.ConfirmationHeight, ) if recErr != nil { @@ -383,7 +461,7 @@ func (c *Custodian) watchInboundAssets() { var err error select { case newAddr := <-c.addrSubscription.NewItemCreated.ChanOut(): - err = c.importAddrToWallet(newAddr) + err = c.importAddrToWallet(ctxStream, newAddr) case tx := <-newTxChan: err = c.inspectWalletTx(&tx) @@ -392,6 +470,13 @@ func (c *Custodian) watchInboundAssets() { log.Tracef("New proof received from notifier") err = c.mapProofToEvent(newProof) + case newMsg := <-c.mboxSubscriptions.MessageChan(): + log.Debugf("Received %d new mailbox message received "+ + "for %x", len(newMsg.Messages), + newMsg.Receiver.PubKey.SerializeCompressed()) + + err = c.handleMailboxMessages(newMsg) + case err = <-txErrChan: break @@ -438,17 +523,39 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error { op := wire.OutPoint{Hash: txHash, Index: uint32(idx)} event, ok := c.events[op] if ok { + // This code path is only for V0 and V1 + // addresses, which only have a single output. + scriptKey := asset.ScriptKey{ + PubKey: &event.Addr.ScriptKey, + TweakedScriptKey: &event.Addr.ScriptKeyTweak, + } + sendOutputs := map[asset.ID]address.SendOutput{ + event.Addr.AssetID: { + Amount: event.Addr.Amount, + ScriptKey: scriptKey, + }, + } + // Was this event previously unconfirmed, and we have // received a conf now? Let's bump the state then. if event.ConfirmationHeight == 0 && walletTx.Confirmations > 0 { - var err error + blockHash, err := chainhash.NewHashFromStr( + walletTx.BlockHash, + ) + if err != nil { + return fmt.Errorf("error parsing "+ + "block hash: %w", err) + } + ctxt, cancel := c.CtxBlocking() event, err = c.cfg.AddrBook.GetOrCreateEvent( ctxt, address.StatusTransactionConfirmed, - event.Addr, walletTx, uint32(idx), + event.Addr, walletTx.Tx, uint32(idx), + uint32(walletTx.BlockHeight), blockHash, + sendOutputs, ) cancel() if err != nil { @@ -466,8 +573,9 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error { go func() { defer c.Wg.Done() - recErr := c.receiveProof( + recErr := c.receiveProofs( event.Addr.Tap, op, + event.Outputs, event.ConfirmationHeight, ) if recErr != nil { @@ -523,8 +631,9 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error { go func() { defer c.Wg.Done() - recErr := c.receiveProof( - addr, op, event.ConfirmationHeight, + recErr := c.receiveProofs( + addr, op, event.Outputs, + event.ConfirmationHeight, ) if recErr != nil { c.publishSubscriberStatusEvent( @@ -544,23 +653,40 @@ func (c *Custodian) inspectWalletTx(walletTx *lndclient.Transaction) error { return nil } +// receiveProofs attempts to receive proofs for all outputs of the given +// address and outpoint via the proof courier service. It will iterate over +// the outputs and call receiveProof for each one. +func (c *Custodian) receiveProofs(addr *address.Tap, op wire.OutPoint, + outputs map[asset.ID]address.SendOutput, confHeight uint32) error { + + // We only want to send out the "transaction confirmed" event once, even + // if there are multiple outputs for the same address and outpoint. + c.publishSubscriberStatusEvent(NewAssetReceiveEvent( + *addr, op, confHeight, address.StatusTransactionConfirmed, + )) + + for assetID, output := range outputs { + err := c.receiveProof(addr, op, assetID, output.ScriptKey) + if err != nil { + return fmt.Errorf("unable to receive proof for output "+ + "%s in %s: %w", assetID, op.String(), err) + } + } + + return nil +} + // receiveProof attempts to receive a proof for the given address and outpoint // via the proof courier service. func (c *Custodian) receiveProof(addr *address.Tap, op wire.OutPoint, - confHeight uint32) error { + assetID asset.ID, scriptKey asset.ScriptKey) error { ctx, cancel := c.WithCtxQuitNoTimeout() defer cancel() - assetID := addr.AssetID - - scriptKeyBytes := addr.ScriptKey.SerializeCompressed() + scriptKeyBytes := scriptKey.PubKey.SerializeCompressed() log.Debugf("Waiting to receive proof for script key %x", scriptKeyBytes) - c.publishSubscriberStatusEvent(NewAssetReceiveEvent( - *addr, op, confHeight, address.StatusTransactionConfirmed, - )) - // Initiate proof courier service handle from the proof courier address // found in the Tap address. courier, err := c.cfg.ProofCourierDispatcher.NewCourier( @@ -583,22 +709,29 @@ func (c *Custodian) receiveProof(addr *address.Tap, op wire.OutPoint, // retrieval success before this delay. select { case <-time.After(c.cfg.ProofRetrievalDelay): + log.Trace("Done with initial delay, now attempting to " + + "retrieve proof") + case <-ctx.Done(): return nil } // Attempt to receive proof via proof courier service. recipient := proof.Recipient{ - ScriptKey: &addr.ScriptKey, + ScriptKey: scriptKey.PubKey, AssetID: assetID, Amount: addr.Amount, } loc := proof.Locator{ AssetID: &assetID, GroupKey: addr.GroupKey, - ScriptKey: addr.ScriptKey, + ScriptKey: *scriptKey.PubKey, OutPoint: &op, } + + log.Tracef("Attempting to receive proof for script key %x", + scriptKey.PubKey.SerializeCompressed()) + addrProof, err := courier.ReceiveProof(ctx, recipient, loc) if err != nil { return fmt.Errorf("unable to receive proof using courier: %w", @@ -685,15 +818,40 @@ func (c *Custodian) mapToTapAddr(walletTx *lndclient.Transaction, // a Taproot Asset address. log.Infof("Found inbound asset transfer (asset_id=%x) for Taproot "+ "Asset address %s in %s", addr.AssetID[:], addrStr, op.String()) - status := address.StatusTransactionDetected + + var ( + status = address.StatusTransactionDetected + blockHeight uint32 + blockHash *chainhash.Hash + ) if walletTx.Confirmations > 0 { status = address.StatusTransactionConfirmed + blockHeight = uint32(walletTx.BlockHeight) + + blockHash, err = chainhash.NewHashFromStr(walletTx.BlockHash) + if err != nil { + return nil, fmt.Errorf("error parsing block hash: %w", + err) + } + } + + // This code path is only for V0 and V1 addresses, which only have a + // single output. + sendOutputs := map[asset.ID]address.SendOutput{ + addr.AssetID: { + Amount: addr.Amount, + ScriptKey: asset.ScriptKey{ + PubKey: &addr.ScriptKey, + TweakedScriptKey: &addr.ScriptKeyTweak, + }, + }, } // Block here, a shutdown can wait on this operation. ctxt, cancel = c.CtxBlocking() event, err := c.cfg.AddrBook.GetOrCreateEvent( - ctxt, status, addr, walletTx, outputIdx, + ctxt, status, addr, walletTx.Tx, outputIdx, blockHeight, + blockHash, sendOutputs, ) cancel() if err != nil { @@ -714,12 +872,34 @@ func (c *Custodian) mapToTapAddr(walletTx *lndclient.Transaction, // importAddrToWallet imports the given Taproot Asset address into the // lnd-internal btcwallet instance by tracking the on-chain Taproot output key // the assets must be sent to in order to be received. -func (c *Custodian) importAddrToWallet(addr *address.AddrWithKeyInfo) error { +func (c *Custodian) importAddrToWallet(ctx context.Context, + addr *address.AddrWithKeyInfo) error { + addrStr, err := addr.EncodeAddress() if err != nil { return fmt.Errorf("unable to encode address: %w", err) } + // V2 addresses aren't added to the internal wallet as an on-chain + // address, they can't be detected by watching the chain at all. We'll + // not mark them as managed in the address book, that way we'll always + // receive the full list of V2 addresses at startup as well. + if addr.Version >= address.V2 { + startBlock := c.mboxRequestStartHeight.Load() + rawScriptKey := addr.ScriptKeyTweak.RawKey + log.Infof("Subscribing to mailbox updates for Taproot Asset "+ + "address receiver=%x (index=%d), startBlock=%d, "+ + "addr=%s", rawScriptKey.PubKey.SerializeCompressed(), + rawScriptKey.Index, startBlock, addrStr) + + return c.mboxSubscriptions.Subscribe( + ctx, addr.ProofCourierAddr, rawScriptKey, + mbox.MessageFilter{ + StartBlock: c.mboxRequestStartHeight.Load(), + }, + ) + } + // Let's not be interrupted by a shutdown. ctxt, cancel := c.CtxBlocking() defer cancel() @@ -749,6 +929,210 @@ func (c *Custodian) importAddrToWallet(addr *address.AddrWithKeyInfo) error { return c.cfg.AddrBook.SetAddrManaged(ctxt, addr, time.Now()) } +// handleMailboxMessages processes the received mailbox messages and attempts +// to decrypt them. If successful, it will then attempt to receive proofs for +// the contained SendFragment messages using the proof courier service. +func (c *Custodian) handleMailboxMessages(msgs *mbox.ReceivedMessages) error { + ctx, cancel := c.WithCtxQuitNoTimeout() + defer cancel() + + receiver := msgs.Receiver + tapAddr, err := c.cfg.AddrBook.AddrByScriptKeyAndVersion( + ctx, receiver.PubKey, address.V2, + ) + if err != nil { + if errors.Is(err, address.ErrNoAddr) { + return fmt.Errorf("no Taproot Asset address found for "+ + "receiver %x: %w", + receiver.PubKey.SerializeCompressed(), err) + } + return fmt.Errorf("error querying address by script key: %w", + err) + } + + var maxMsgBlockHeight uint32 + for _, mboxMsg := range msgs.Messages { + // Decrypt the mailbox message using the receiver's key. + log.Debugf("Decrypting mailbox message with ID %d for %x", + mboxMsg.MessageId, + receiver.PubKey.SerializeCompressed()) + + fragment, err := c.decryptMailboxMsg( + ctx, receiver, mboxMsg.EncryptedPayload, + ) + if err != nil { + return fmt.Errorf("unable to decrypt mailbox "+ + "message: %w", err) + } + + log.Debugf("Received fragment with %d outputs", + len(fragment.Outputs)) + + op := fragment.OutPoint + outputs := make(map[asset.ID]address.SendOutput) + for assetID, output := range fragment.Outputs { + scriptKey, err := asset.DeriveUniqueScriptKey( + *receiver.PubKey, assetID, + output.DerivationMethod, + ) + if err != nil { + return fmt.Errorf("unable to derive script "+ + "key for asset: %w", err) + } + + err = c.cfg.AddrBook.InsertScriptKey( + ctx, scriptKey, scriptKey.Type, + ) + if err != nil { + return fmt.Errorf("unable to insert script "+ + "key into address book: %w", err) + } + + log.Tracef("Expecting to fetch proof for outpoint %s "+ + "and script key %x", op.String(), + scriptKey.PubKey.SerializeCompressed()) + + outputs[assetID] = address.SendOutput{ + Amount: output.Amount, + ScriptKey: scriptKey, + } + } + + // Let's now make sure we can fetch the block mentioned in the + // fragment, so we can extract the transaction from it. + block, err := c.cfg.ChainBridge.GetBlock( + ctx, fragment.BlockHeader.BlockHash(), + ) + if err != nil { + return fmt.Errorf("unable to fetch block %s: %w", + fragment.BlockHeader.BlockHash(), err) + } + + var walletTx *wire.MsgTx + for _, tx := range block.Transactions { + if tx.TxHash() == fragment.OutPoint.Hash { + walletTx = tx + break + } + } + + if walletTx == nil { + return fmt.Errorf("unable to find transaction %s "+ + "in block %s", fragment.OutPoint.Hash, + fragment.BlockHeader.BlockHash()) + } + + // We have all the information we need to create a new address + // event for this fragment. + // Block here, a shutdown can wait on this operation. + ctxt, cancel := c.CtxBlocking() + event, err := c.cfg.AddrBook.GetOrCreateEvent( + ctxt, address.StatusTransactionConfirmed, tapAddr, + walletTx, op.Index, fragment.BlockHeight, &op.Hash, + outputs, + ) + cancel() + if err != nil { + return fmt.Errorf("error creating event: %w", err) + } + + // Let's update our cache of ongoing events. + c.events[op] = event + + // We'll want to ratchet forward the start block height for new + // mailbox queries, so we don't always receive the same events + // over and over again. We'll use the maximum block height + // from this set of messages. + if fragment.BlockHeight > maxMsgBlockHeight { + maxMsgBlockHeight = fragment.BlockHeight + } + + // Now that we've seen this output confirm on chain, we'll + // launch a goroutine to use the ProofCourier to import the + // proof into our local DB. + c.Wg.Add(1) + go func() { + defer c.Wg.Done() + + recErr := c.receiveProofs( + tapAddr.Tap, fragment.OutPoint, outputs, + fragment.BlockHeight, + ) + if recErr != nil { + c.publishSubscriberStatusEvent( + NewAssetReceiveErrorEvent( + recErr, *tapAddr.Tap, op, + fragment.BlockHeight, + event.Status, + ), + ) + + log.Errorf("Unable to receive proof: %v", + recErr) + } + }() + } + + if c.mboxRequestStartHeight.Load() < maxMsgBlockHeight { + log.Debugf("Updating mailbox request start height to %d", + maxMsgBlockHeight) + + // Update the start block height for new mailbox queries, so + // we don't always receive the same events over and over again. + c.mboxRequestStartHeight.Store(maxMsgBlockHeight) + } + + return nil +} + +// decryptMailboxMsg decrypts a mailbox message using the receiver's key and +// returns the decoded SendFragment message. +func (c *Custodian) decryptMailboxMsg(ctx context.Context, + receiverKey keychain.KeyDescriptor, msg []byte) (*proof.SendFragment, + error) { + + _, pubKeyBytes, _, err := ecies.ExtractAdditionalData(msg) + if err != nil { + return nil, fmt.Errorf("unable to extract additional data "+ + "from mailbox message: %w", err) + } + + senderPubKey, err := btcec.ParsePubKey(pubKeyBytes) + if err != nil { + return nil, fmt.Errorf("unable to parse sender public key: %w", + err) + } + + sharedKey, err := c.cfg.Signer.DeriveSharedKey( + ctx, senderPubKey, &receiverKey.KeyLocator, + ) + if err != nil { + return nil, fmt.Errorf("unable to derive shared key for "+ + "mailbox message: %w", err) + } + + // Decrypt the message using the ECIES decryption method. + decryptedMsg, err := ecies.DecryptSha256ChaCha20Poly1305(sharedKey, msg) + if err != nil { + return nil, fmt.Errorf("unable to decrypt mailbox message: %w", + err) + } + + // Decode the decrypted message into a mailbox message. + fragment, err := proof.DecodeSendFragment(decryptedMsg) + if err != nil { + return nil, fmt.Errorf("unable to decode send fragment: %w", + err) + } + + err = fragment.Validate() + if err != nil { + return nil, fmt.Errorf("invalid send fragment: %w", err) + } + + return fragment, nil +} + // checkProofAvailable checks the proof storage if a proof for the given event // is already available. If it is, and it checks out, the event is updated. func (c *Custodian) checkProofAvailable(event *address.Event) (bool, error) { @@ -821,7 +1205,7 @@ func (c *Custodian) checkProofAvailable(event *address.Event) (bool, error) { // The proof might be an old state, let's make sure it matches our event // before marking the inbound asset transfer as complete. if AddrMatchesAsset(event.Addr, &lastProof.Asset) { - return true, c.setReceiveCompleted(event, lastProof, file) + return true, c.setReceiveCompleted(event, file) } return false, nil @@ -926,31 +1310,36 @@ func (c *Custodian) mapProofToEvent(p proof.Blob) error { // Check if any of our in-flight events match the last proof's state. for _, event := range c.events { - if EventMatchesProof(event, lastProof) { - c.publishSubscriberStatusEvent(NewAssetReceiveEvent( - *event.Addr.Tap, event.Outpoint, - event.ConfirmationHeight, - address.StatusProofReceived, - )) - - // Importing a proof already creates the asset in the - // database. Therefore, all we need to do is update the - // state of the address event to mark it as completed - // successfully. - err = c.setReceiveCompleted(event, lastProof, file) - if err != nil { - c.publishSubscriberStatusEvent( - NewAssetReceiveErrorEvent( - err, *event.Addr.Tap, - event.Outpoint, - event.ConfirmationHeight, - event.Status, - ), - ) + matches := EventMatchesProof(event, lastProof) + if !matches { + log.Debugf("Proof with op %s doesn't match event with "+ + "op %s, skipping", lastProof.OutPoint(), + event.Outpoint) - return fmt.Errorf("error updating event: %w", - err) - } + continue + } + + c.publishSubscriberStatusEvent(NewAssetReceiveEvent( + *event.Addr.Tap, event.Outpoint, + event.ConfirmationHeight, address.StatusProofReceived, + )) + + log.Debugf("Proof received for event %s", event.Outpoint) + + // Importing a proof already creates the asset in the + // database. Therefore, all we need to do is update the + // state of the address event to mark it as completed + // successfully. + err = c.setReceiveCompleted(event, file) + if err != nil { + c.publishSubscriberStatusEvent( + NewAssetReceiveErrorEvent( + err, *event.Addr.Tap, event.Outpoint, + event.ConfirmationHeight, event.Status, + ), + ) + + return fmt.Errorf("error updating event: %w", err) } } @@ -987,7 +1376,7 @@ func (c *Custodian) assertProofInLocalArchive(p *proof.AnnotatedProof) error { // 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, - lastProof *proof.Proof, proofFile *proof.File) error { + proofFile *proof.File) error { // The proof is created after a single confirmation. To make sure we // notice if the anchor transaction is re-organized out of the chain, we @@ -1006,13 +1395,36 @@ func (c *Custodian) setReceiveCompleted(event *address.Event, ctxt, cancel := c.CtxBlocking() defer cancel() - anchorPoint := wire.OutPoint{ - Hash: lastProof.AnchorTx.TxHash(), - Index: lastProof.InclusionProof.OutputIndex, + // Do we have all proofs for all outputs of the event? If not, then we + // can't complete the event yet. We'll be called again here with more + // proofs once the sender sends them to us. + for assetID, output := range event.Outputs { + loc := proof.Locator{ + AssetID: &assetID, + GroupKey: event.Addr.GroupKey, + ScriptKey: *output.ScriptKey.PubKey, + OutPoint: &event.Outpoint, + } + haveProof, err := c.cfg.ProofArchive.HasProof(ctxt, loc) + if err != nil { + return fmt.Errorf("error checking if proof is "+ + "available for asset %s: %w", assetID, err) + } + + if !haveProof { + log.Debugf("Proof for output with script key %x not "+ + "yet available, can't complete event yet", + output.ScriptKey.PubKey.SerializeCompressed()) + + return nil + } } + log.Debugf("All proofs received for event %s, completing it", + event.Outpoint) + err = c.cfg.AddrBook.CompleteEvent( - ctxt, event, address.StatusCompleted, anchorPoint, + ctxt, event, address.StatusCompleted, event.Outpoint, ) if err != nil { return fmt.Errorf("error completing event: %w", err) @@ -1142,12 +1554,31 @@ func AddrMatchesAsset(addr *address.AddrWithKeyInfo, a *asset.Asset) bool { groupKeyEqual := groupKeyBothNil || addr.GroupKey.IsEqual(&a.GroupKey.GroupPubKey) - return addr.AssetID == a.ID() && groupKeyEqual && - addr.ScriptKey.IsEqual(a.ScriptKey.PubKey) + assetIDEqual := addr.AssetID == a.ID() + + scriptKeyEqual := addr.ScriptKey.IsEqual(a.ScriptKey.PubKey) + + pedersenScriptKey, err := addr.ScriptKeyForAssetID(a.ID()) + if err != nil { + // If we can't derive the Pedersen version, we'll just use the + // key in the address. + pedersenScriptKey = &addr.ScriptKey + } + pedersenScriptKeyEqual := pedersenScriptKey.IsEqual(a.ScriptKey.PubKey) + + log.Tracef("AddrMatchesAsset: id_equal=%v, group_key_equal=%v, "+ + "script_key_equal=%v, pedersen_script_key_equal=%v", + assetIDEqual, groupKeyEqual, scriptKeyEqual, + pedersenScriptKeyEqual) + + return (assetIDEqual || groupKeyEqual) && + (scriptKeyEqual || pedersenScriptKeyEqual) } // EventMatchesProof returns true if the given event matches the given proof. func EventMatchesProof(event *address.Event, p *proof.Proof) bool { + log.Tracef("EventMatchesProof: event_op=%s, proof_op=%s", + event.Outpoint, p.OutPoint()) return AddrMatchesAsset(event.Addr, &p.Asset) && event.Outpoint == p.OutPoint() } diff --git a/tapgarden/custodian_test.go b/tapgarden/custodian_test.go index bdf0c9ba9..fadb922a2 100644 --- a/tapgarden/custodian_test.go +++ b/tapgarden/custodian_test.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "math/rand" - "net/url" "testing" "time" @@ -351,11 +350,13 @@ func newHarness(t *testing.T, } } -func randAddr(h *custodianHarness) (*address.AddrWithKeyInfo, *asset.Genesis) { - addr, genesis, group := address.RandAddr( - h.t, &address.RegressionNetTap, url.URL{ - Scheme: "mock", - }, +func randAddrV1( + h *custodianHarness) (*address.AddrWithKeyInfo, *asset.Genesis) { + + version := test.RandFlip(address.V0, address.V1) + addr, genesis, group := address.RandAddrWithVersion( + h.t, &address.RegressionNetTap, + address.RandProofCourierAddrForVersion(h.t, version), version, ) err := h.tapdbBook.InsertAssetGen(context.Background(), genesis, group) @@ -526,7 +527,7 @@ func TestCustodianNewAddr(t *testing.T) { h.assertStartup() ctx := context.Background() - addr, _ := randAddr(h) + addr, _ := randAddrV1(h) proofCourierAddr := address.RandProofCourierAddr(t) addrVersion := test.RandFlip(address.V0, address.V1) dbAddr, err := h.addrBook.NewAddress( @@ -657,7 +658,7 @@ func TestTransactionHandling(t *testing.T) { addrs := make([]*address.AddrWithKeyInfo, numAddrs) genesis := make([]*asset.Genesis, numAddrs) for i := 0; i < numAddrs; i++ { - addrs[i], genesis[i] = randAddr(h) + addrs[i], genesis[i] = randAddrV1(h) err := h.tapdbBook.InsertAddrs(ctx, *addrs[i]) require.NoError(t, err) } @@ -668,7 +669,7 @@ func TestTransactionHandling(t *testing.T) { mockProof := randProof(t, outputIdx, tx.Tx, genesis[0], addrs[0]) recipient := proof.Recipient{} - err := h.courier.DeliverProof(nil, recipient, mockProof) + err := h.courier.DeliverProof(nil, recipient, mockProof, nil) require.NoError(t, err) require.NoError(t, h.c.Start()) @@ -712,7 +713,7 @@ func runTransactionConfirmedOnlyTest(t *testing.T, withRestart bool) { addrs := make([]*address.AddrWithKeyInfo, numAddrs) genesis := make([]*asset.Genesis, numAddrs) for i := 0; i < numAddrs; i++ { - addrs[i], genesis[i] = randAddr(h) + addrs[i], genesis[i] = randAddrV1(h) err := h.tapdbBook.InsertAddrs(ctx, *addrs[i]) require.NoError(t, err) } @@ -744,7 +745,7 @@ func runTransactionConfirmedOnlyTest(t *testing.T, withRestart bool) { mockProof := randProof( t, outputIndexes[idx], tx.Tx, genesis[idx], addrs[idx], ) - _ = h.courier.DeliverProof(nil, recipient, mockProof) + _ = h.courier.DeliverProof(nil, recipient, mockProof, nil) } // We want events to be created for each address, they should be in the @@ -795,7 +796,7 @@ func TestProofInMultiverseOnly(t *testing.T) { // corresponding wallet transaction. ctx := context.Background() - addr, genesis := randAddr(h) + addr, genesis := randAddrV1(h) err := h.tapdbBook.InsertAddrs(ctx, *addr) require.NoError(t, err) diff --git a/tappsbt/create.go b/tappsbt/create.go index 5e262144b..6e3b7329f 100644 --- a/tappsbt/create.go +++ b/tappsbt/create.go @@ -39,7 +39,7 @@ func FromAddresses(receiverAddrs []*address.Tap, switch firstAddr.Version { case address.V0: pkt.Version = V0 - case address.V1: + case address.V1, address.V2: pkt.Version = V1 default: return nil, address.ErrUnknownVersion @@ -80,6 +80,7 @@ func FromAddresses(receiverAddrs []*address.Tap, AnchorOutputInternalKey: &addr.InternalKey, AnchorOutputTapscriptSibling: addr.TapscriptSibling, ProofDeliveryAddress: &addr.ProofCourierAddr, + Address: addr, }) } diff --git a/tappsbt/decode.go b/tappsbt/decode.go index c32d828a5..2be131fc1 100644 --- a/tappsbt/decode.go +++ b/tappsbt/decode.go @@ -116,6 +116,7 @@ func NewFromPsbt(packet *psbt.Packet) (*VPacket, error) { vOut := &VOutput{} err = vOut.decode( packet.Outputs[idx], packet.UnsignedTx.TxOut[idx], + chainParams, ) if err != nil { return nil, fmt.Errorf("error decoding virtual output "+ @@ -212,7 +213,9 @@ func (i *VInput) decode(pIn psbt.PInput) error { } // decode decodes the given POutput and wire.TxOut into the current VOutput. -func (o *VOutput) decode(pOut psbt.POutput, txOut *wire.TxOut) error { +func (o *VOutput) decode(pOut psbt.POutput, txOut *wire.TxOut, + chainParams *address.ChainParams) error { + o.Amount = uint64(txOut.Value) if len(txOut.PkScript) != schnorr.PubKeyBytesLen+2 { @@ -305,6 +308,9 @@ func (o *VOutput) decode(pOut psbt.POutput, txOut *wire.TxOut) error { }, { key: PsbtKeyTypeOutputTapAltLeaves, decoder: altLeavesDecoder(&o.AltLeaves), + }, { + key: PsbtKeyTypeOutputTapAddress, + decoder: addressDecoder(&o.Address, chainParams), }} for idx := range mapping { @@ -524,3 +530,28 @@ func urlDecoder(u **url.URL) decoderFunc { return tlvDecoder(*u, asset.UrlDecoder)(key, byteVal) } } + +// addressDecoder returns a decoder function that can handle nil Taproot +// addresses. +func addressDecoder(a **address.Tap, + chainParams *address.ChainParams) decoderFunc { + + return func(key, byteVal []byte) error { + if len(byteVal) == 0 { + return nil + } + + addr := address.Tap{ + ChainParams: chainParams, + } + err := addr.Decode(bytes.NewReader(byteVal)) + if err != nil { + return fmt.Errorf("error decoding Taproot address: %w", + err) + } + + *a = &addr + + return nil + } +} diff --git a/tappsbt/decode_test.go b/tappsbt/decode_test.go index 7c2551f91..f51ff536f 100644 --- a/tappsbt/decode_test.go +++ b/tappsbt/decode_test.go @@ -193,14 +193,22 @@ func TestEncodingDecoding(t *testing.T) { assertEqualPackets(t, pkg, decoded) } + proofCourierAddr := address.RandProofCourierAddrForVersion( + t, address.V2, + ) testCases := []testCase{{ name: "minimal packet", pkg: func(t *testing.T) *VPacket { - proofCourierAddr := address.RandProofCourierAddr(t) addr, _, _ := address.RandAddr( t, testParams, proofCourierAddr, ) + // The address' genesis information isn't encoded, so it + // will be the empty genesis after decoding. To make + // sure we can directly compare before and after, we + // also attach an empty genesis to the address. + addr.AttachGenesis(asset.Genesis{}) + pkg, err := FromAddresses([]*address.Tap{addr.Tap}, 1) require.NoError(t, err) pkg.Outputs = append(pkg.Outputs, &VOutput{ diff --git a/tappsbt/encode.go b/tappsbt/encode.go index f5f23cc32..739477ce1 100644 --- a/tappsbt/encode.go +++ b/tappsbt/encode.go @@ -12,6 +12,7 @@ import ( "github.com/btcsuite/btcd/btcutil/psbt" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" + "github.com/lightninglabs/taproot-assets/address" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/commitment" "github.com/lightninglabs/taproot-assets/fn" @@ -301,6 +302,9 @@ func (o *VOutput) encode(coinType uint32) (psbt.POutput, *wire.TxOut, error) { }, { key: PsbtKeyTypeOutputTapAltLeaves, encoder: altLeavesEncoder(o.AltLeaves), + }, { + key: PsbtKeyTypeOutputTapAddress, + encoder: addressEncoder(o.Address), }, } @@ -527,3 +531,26 @@ func urlEncoder(val *url.URL) encoderFunc { }, nil } } + +// addressEncoder returns a function that encodes the given Taproot Asset +// address as a custom PSBT field. If the address is nil, it returns nil. +func addressEncoder(val *address.Tap) encoderFunc { + return func(key []byte) ([]*customPsbtField, error) { + if val == nil { + return nil, nil + } + + var b bytes.Buffer + if err := val.Encode(&b); err != nil { + return nil, fmt.Errorf("error encoding address: %w", + err) + } + + return []*customPsbtField{ + { + Key: fn.CopySlice(key), + Value: b.Bytes(), + }, + }, nil + } +} diff --git a/tappsbt/interface.go b/tappsbt/interface.go index 9c8ff17dd..a3023b3a6 100644 --- a/tappsbt/interface.go +++ b/tappsbt/interface.go @@ -59,6 +59,7 @@ var ( PsbtKeyTypeOutputTapAssetLockTime = []byte{0x7c} PsbtKeyTypeOutputTapAssetRelativeLockTime = []byte{0x7d} PsbtKeyTypeOutputTapAltLeaves = []byte{0x7e} + PsbtKeyTypeOutputTapAddress = []byte{0x7f} ) // The following keys are used as custom fields on the BTC level anchor @@ -597,6 +598,11 @@ type VOutput struct { // data-carrying leaves are used for a purpose distinct from // representing individual Taproot Assets. AltLeaves []asset.AltLeaf[asset.Asset] + + // Address is the Taproot Asset address that was used to create this + // output. This is only present for non-interactive outputs that were + // created from a Taproot Asset address. + Address *address.Tap } // Copy creates a deep copy of the VOutput. @@ -625,6 +631,7 @@ func (o *VOutput) Copy() *VOutput { ProofDeliveryAddress: o.ProofDeliveryAddress, ProofSuffix: o.ProofSuffix, AltLeaves: asset.CopyAltLeaves(o.AltLeaves), + Address: o.Address, } } diff --git a/tappsbt/mock.go b/tappsbt/mock.go index d196b9f67..ef80667a3 100644 --- a/tappsbt/mock.go +++ b/tappsbt/mock.go @@ -116,6 +116,17 @@ func RandPacket(t testing.TB, setVersion, altLeaves bool) *VPacket { courierAddress, err := url.Parse("https://example.com") require.NoError(t, err) + courierURL := address.RandProofCourierAddrForVersion(t, address.V2) + addr1, _, _ := address.RandAddr(t, testParams, courierURL) + addr2, _, _ := address.RandAddr(t, testParams, courierURL) + + // The address' genesis information isn't encoded, so it will be the + // empty genesis after decoding. To make sure we can directly compare + // before and after, we also attach an empty genesis to the two + // addresses. + addr1.AttachGenesis(asset.Genesis{}) + addr2.AttachGenesis(asset.Genesis{}) + randVInput := VInput{ PrevID: asset.PrevID{ OutPoint: op, @@ -154,6 +165,7 @@ func RandPacket(t testing.TB, setVersion, altLeaves bool) *VPacket { ProofSuffix: &inputProof, RelativeLockTime: 345, LockTime: 456, + Address: addr1.Tap, } randVOutput2 := VOutput{ @@ -170,6 +182,7 @@ func RandPacket(t testing.TB, setVersion, altLeaves bool) *VPacket { Asset: testOutputAsset, ScriptKey: testOutputAsset.ScriptKey, AnchorOutputTapscriptSibling: &testPreimage2, + Address: addr2.Tap, } if altLeaves { @@ -614,6 +627,11 @@ func NewTestFromVOutput(t testing.TB, v *VOutput, ) } } + + if v.Address != nil { + vo.Address = address.NewTestFromAddress(t, v.Address) + } + return vo } @@ -640,6 +658,7 @@ type TestVOutput struct { RelativeLockTime uint64 `json:"relative_lock_time"` LockTime uint64 `json:"lock_time"` AltLeaves []*asset.TestAsset `json:"alt_leaves"` + Address *address.TestAddress `json:"address"` } func (to *TestVOutput) ToVOutput(t testing.TB) *VOutput { @@ -741,5 +760,9 @@ func (to *TestVOutput) ToVOutput(t testing.TB) *VOutput { } } + if to.Address != nil { + v.Address = to.Address.ToAddress(t) + } + return v } diff --git a/tappsbt/testdata/psbt_encoding_generated.json b/tappsbt/testdata/psbt_encoding_generated.json index d7c50bbe2..c36a9af84 100644 --- a/tappsbt/testdata/psbt_encoding_generated.json +++ b/tappsbt/testdata/psbt_encoding_generated.json @@ -10,7 +10,7 @@ "tr_merkle_root": "", "prev_id": { "out_point": "0000000000000000000000000000000000000000000000000000000000000000:0", - "asset_id": "93aa785d48c3e0a0c7f82c83c2f15785351c93d6e5dd91e251eb79790067f46b", + "asset_id": "287caf88deaf7cc8548beb55d2633b9eb9b149cec77cc6af4592ec8eaac3c8bd", "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "anchor": { @@ -49,30 +49,44 @@ "proof_suffix": null, "relative_lock_time": 0, "lock_time": 0, - "alt_leaves": null + "alt_leaves": null, + "address": null }, { - "amount": 2703501726821866378, + "amount": 1, "type": 0, - "asset_version": 0, + "asset_version": 1, "interactive": false, "anchor_output_index": 1, - "anchor_output_internal_key": "03126685da09d16135881ca9762295a5a8399b0bd66eaa5863a0d7512eeec162fe", + "anchor_output_internal_key": "02daf785f20dcb5bb06bef717296c3894ed2564d5e3f8325d2f6bad1315aaad16c", "anchor_output_bip32_derivation": null, "anchor_output_tr_bip32_derivation": null, "anchor_output_tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", "asset": null, "split_asset": null, - "pk_script": "5120458a92cc12d01b8e8892da58ed511d398f2ce42b4d6295cf0c66346249f4d306", + "pk_script": "5120681804f878909a77ff81339141d1b55d36b76a2cd7f09c838a1eb67fea983700", "bip32_derivation": null, "tr_bip32_derivation": null, "tr_internal_key": "", "tr_merkle_root": "", - "proof_delivery_address": "hashmail://rand.hashmail.proof.courier:443", + "proof_delivery_address": "authmailbox+universerpc://foo.bar:10029", "proof_suffix": null, "relative_lock_time": 0, "lock_time": 0, - "alt_leaves": null + "alt_leaves": null, + "address": { + "version": 2, + "chain_params_hrp": "tapbc", + "asset_version": 1, + "asset_id": "287caf88deaf7cc8548beb55d2633b9eb9b149cec77cc6af4592ec8eaac3c8bd", + "group_key": "022f8037568677d1220c08e3525e8a2258da346da11df38b167b762ff08e6de0a1", + "script_key": "02681804f878909a77ff81339141d1b55d36b76a2cd7f09c838a1eb67fea983700", + "internal_key": "02daf785f20dcb5bb06bef717296c3894ed2564d5e3f8325d2f6bad1315aaad16c", + "tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", + "amount": 1, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", + "unknown_odd_types": null + } }, { "amount": 0, @@ -86,7 +100,7 @@ "anchor_output_tapscript_sibling": "", "asset": null, "split_asset": null, - "pk_script": "512098f9b76daedf00b6c4dfc25a045b320c8b81d4be9283105bc956895cc7f81a87", + "pk_script": "512063154e9e45e62a27c43f2b3342b0c49b8a2f49d0263dcc18f34172b66acfef09", "bip32_derivation": null, "tr_bip32_derivation": null, "tr_internal_key": "", @@ -95,13 +109,14 @@ "proof_suffix": null, "relative_lock_time": 0, "lock_time": 0, - "alt_leaves": null + "alt_leaves": null, + "address": null } ], "version": 1, "chain_params_hrp": "tapbc" }, - "expected": "cHNidP8BALQCAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAIlEgfHm5sm5GOJXu9WedhViULIbErSIzre8BvD5tVAs2U/6KW98sf8SEJSJRIEWKkswS0BuOiJLaWO1RHTmPLOQrTWKVzwxmNGJJ9NMGAAAAAAAAAAAiUSCY+bdtrt8AtsTfwloEWzIMi4HUvpKDEFvJVolcx/gahwAAAAABcAEBAXEFdGFwYmMBcgEBAAFwZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJOqeF1Iw+Cgx/gsg8LxV4U1HJPW5d2R4lHreXkAZ/RrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXEIAAAAAAAAAAABcgABcwgAAAAAAAAAAAF1AAF4AAABcAEBAXEBAAFyCAAAAAAAAAAAAXkBAAF8CAAAAAAAAAAAAX0IAAAAAAAAAAAAAXABAAFxAQABcggAAAAAAAAAAQFzIQMSZoXaCdFhNYgcqXYilaWoOZsL1m6qWGOg11Eu7sFi/gF4FQDAEm5vdCBhIHZhbGlkIHNjcmlwdAF5AQABeipoYXNobWFpbDovL3JhbmQuaGFzaG1haWwucHJvb2YuY291cmllcjo0NDMBfAgAAAAAAAAAAAF9CAAAAAAAAAAAAAFwAQABcQEAAXIIAAAAAAAAAAABeQEAAXwIAAAAAAAAAAABfQgAAAAAAAAAAAA=", + "expected": "cHNidP8BALQCAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAIlEgfHm5sm5GOJXu9WedhViULIbErSIzre8BvD5tVAs2U/4BAAAAAAAAACJRIGgYBPh4kJp3/4EzkUHRtV02t2os1/Ccg4oetn/qmDcAAAAAAAAAAAAiUSBjFU6eReYqJ8Q/KzNCsMSbii9J0CY9zBjzQXK2as/vCQAAAAABcAEBAXEFdGFwYmMBcgEBAAFwZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACh8r4jer3zIVIvrVdJjO565sUnOx3zGr0WS7I6qw8i9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXEIAAAAAAAAAAABcgABcwgAAAAAAAAAAAF1AAF4AAABcAEBAXEBAAFyCAAAAAAAAAAAAXkBAAF8CAAAAAAAAAAAAX0IAAAAAAAAAAAAAXABAAFxAQABcggAAAAAAAAAAQFzIQLa94XyDctbsGvvcXKWw4lO0lZNXj+DJdL2utExWqrRbAF4FQDAEm5vdCBhIHZhbGlkIHNjcmlwdAF5AQEBeidhdXRobWFpbGJveCt1bml2ZXJzZXJwYzovL2Zvby5iYXI6MTAwMjkBfAgAAAAAAAAAAAF9CAAAAAAAAAAAAX/UAAECAgEBBCAofK+I3q98yFSL61XSYzueubFJzsd8xq9FkuyOqsPIvQUhAi+AN1aGd9EiDAjjUl6KIljaNG2hHfOLFnt2L/CObeChBiECaBgE+HiQmnf/gTORQdG1XTa3aizX8JyDih62f+qYNwAIIQLa94XyDctbsGvvcXKWw4lO0lZNXj+DJdL2utExWqrRbAkVAMASbm90IGEgdmFsaWQgc2NyaXB0CgEBDCdhdXRobWFpbGJveCt1bml2ZXJzZXJwYzovL2Zvby5iYXI6MTAwMjkAAXABAAFxAQABcggAAAAAAAAAAAF5AQABfAgAAAAAAAAAAAF9CAAAAAAAAAAAAA==", "comment": "minimal packet" }, { @@ -139,8 +154,8 @@ "tr_merkle_root": "6d65726b6c6520726f6f74", "prev_id": { "out_point": "bc897d061b3ae419476c367403def63a5b6fea3b9393f93f3329d9f17d9e8fbc:2978395423", - "asset_id": "c00e09d6fc25640854c15dfcacaa8a2cecce5a3aba53ab705b18db94b4d338a5", - "script_key": "034f1cfb7d542874cbec5f024e48b1989fd7a3e8a9b65472ae6f99ace9502f0c51" + "asset_id": "0454b68312d5027ce15a4f0a58250d8fb50e77f2bf4f0152e5d49435807f9d4b", + "script_key": "029551c11cee58492ae9052e59f8197dffcd32cc9b648822e8e2ee8cc145edc2b0" }, "anchor": { "value": 777, @@ -424,7 +439,7 @@ { "amount": 123, "type": 1, - "asset_version": 1, + "asset_version": 0, "interactive": true, "anchor_output_index": 0, "anchor_output_internal_key": "0269792dd5313d26dfe944e01d6ad8a0e0c38db5af47deaf15981cf9ddbddeac1b", @@ -726,25 +741,8 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 29735, - "script_key": "02dd756e50caeef8caba0acf73db4e5b2e7f4c229644f01d538ec4427b7b194b23", - "group_key": null, - "unknown_odd_types": null - }, - { - "version": 0, - "genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0", - "genesis_tag": "", - "genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "genesis_output_index": 0, - "genesis_type": 0, - "amount": 0, - "lock_time": 0, - "relative_lock_time": 0, - "prev_witnesses": null, - "split_commitment_root": null, - "script_version": 57578, - "script_key": "02116adf7ccbf6ad3a10de4817ab7bd7b2d9c25f853203a79ca261fa98ce0dfd36", + "script_version": 2384, + "script_key": "0243d1129c376cd7be08cd11afc07dea9e5f9bd7b59f98d361cd8d4521fcf45243", "group_key": null, "unknown_odd_types": null }, @@ -760,12 +758,25 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 45968, - "script_key": "0230753a2f1ab5b025514d4fd233839e4d2a1932ec1b376754dc50d20475a51230", + "script_version": 23105, + "script_key": "02759989d69c3245db66ea1ed45eac1f4ea6ceacc695a39582706d36c23fa3275c", "group_key": null, "unknown_odd_types": null } - ] + ], + "address": { + "version": 2, + "chain_params_hrp": "tapbc", + "asset_version": 0, + "asset_id": "ba39b8af2bc742f8026696affc0ffe13427b459f5ae7493d877bf4657cb060b7", + "group_key": "", + "script_key": "021e75735bdbb3d21d70f64a5185faa9d4d8576c54221977ca374f2b163e2161b3", + "internal_key": "0275e5082b172fc2bc56530189dfce1ea4481b81732e94d2eb6149be31a82420bb", + "tapscript_sibling": "", + "amount": 3797840465501570741, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", + "unknown_odd_types": null + } }, { "amount": 345, @@ -856,8 +867,42 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 21434, - "script_key": "02b20fe0c0826121800688751f5d084a168fdc941702895b423da23b839ff55858", + "script_version": 16844, + "script_key": "02939293bf91bf9a844ad17c247c1e0d7dc6baad539813658bc2ecb87ba5b16e34", + "group_key": null, + "unknown_odd_types": null + }, + { + "version": 0, + "genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0", + "genesis_tag": "", + "genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "genesis_output_index": 0, + "genesis_type": 0, + "amount": 0, + "lock_time": 0, + "relative_lock_time": 0, + "prev_witnesses": null, + "split_commitment_root": null, + "script_version": 53986, + "script_key": "025a6d8581fcca9864804ed7767d489c81d23302d2d6dada7846ca750313d97cd5", + "group_key": null, + "unknown_odd_types": null + }, + { + "version": 0, + "genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0", + "genesis_tag": "", + "genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "genesis_output_index": 0, + "genesis_type": 0, + "amount": 0, + "lock_time": 0, + "relative_lock_time": 0, + "prev_witnesses": null, + "split_commitment_root": null, + "script_version": 47237, + "script_key": "02f56d92b2e69c4336f7f3cb296f498dbe1bedfd1bc2f50547d2c539f2d32458bc", "group_key": null, "unknown_odd_types": null }, @@ -873,18 +918,31 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 7255, - "script_key": "023a4301b480aa69e12c1c9aceee371b607110bae9969b7b502e5eb049c02e682a", + "script_version": 12559, + "script_key": "0290ad26294f05ff0f392bf82acb82521e5048a8a651b35ef386dbff68c923c37a", "group_key": null, "unknown_odd_types": null } - ] + ], + "address": { + "version": 1, + "chain_params_hrp": "tapbc", + "asset_version": 1, + "asset_id": "73f3e53abc31d63216fc53a98d55e15f833fd8f1c68ea29bda26519b71919a94", + "group_key": "036a2387e6a57d441dd879b32792e3dc0b4167d98d8beb701a4c40400bc4262458", + "script_key": "0274440806bd31111c581b6c0a91f51e06f556df41a34f300aac1a4a2f04d60b13", + "internal_key": "02e3e8caa7c8c999e39b147f8af31aafd5fd97db3fd2072fa17f75c7011e55d5ec", + "tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", + "amount": 5872006441185134428, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", + "unknown_odd_types": null + } } ], - "version": 1, + "version": 0, "chain_params_hrp": "tapbc" }, - "expected": "cHNidP8BALICAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACewAAAAAAAAAiUSA9L1ax/Ek3xCa1tlXhDqe89wMYb3zpU+aznVVCaOXsvVkBAAAAAAAAIlEgPS9WsfxJN8QmtbZV4Q6nvPcDGG986VPms51VQmjl7L0AAAAAAXABAQFxBXRhcGJjAXIBAQAiBgJpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGxgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhFml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABFyBpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGwEYC21lcmtsZSByb290AXBlvI+effHZKTM/+ZOTO+pvWzr23gN0NmxHGeQ6GwZ9ibyxhrUfwA4J1vwlZAhUwV38rKqKLOzOWjq6U6twWxjblLTTOKUDTxz7fVQodMvsXwJOSLGYn9ej6Km2VHKub5ms6VAvDFEBcQgAAAAAAAADCQFyD2FuY2hvciBwa3NjcmlwdAFzCAAAAAAAAAADAXQhAml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbAXULbWVya2xlIHJvb3QidgJpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGxgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhd2l5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABeAdzaWJsaW5nAXn9kgEAAQACipomb5dkeUs3OXARXoLtb0ElyPpzEeTX3vqSLarneGZnvo6ZgUA3ZjAxZjFmNTczOTgxNjU5YTQ0ZmYxN2E0YzcyMTVhM2I1MzllYjFlNTg0OWM2MDc3ZGJiNTcyMmY1NzE3YTI4fwHx9XOYFlmkT/F6THIVo7U56x5YScYHfbtXIvVxeigkT802AAQBAAYF/q9j5Y4LrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUCXji6DmoNhjnVEqRdRKkpv2+Ki239wRSh4P6fB7SRyjPGcLXJ6eGpLaFhPg1p8ZZ80hsn6D8BwZwis0a3DaldzDgIAABAhAzdb3PMLcpLE4s5/hRHGjP1Yu89chGEoKCW+I96gZ1IEESECaLjOzwxTHUrlltfXNBjf9ED1ANQg1mz9tA58Maebr0sBev3bBlRBUFAABAAAAAACJJomb5dkeUs3OXARXoLtb0ElyPpzEeTX3vqSLarneGZnvo6ZgQRQAQAAAJDwqfEQcC+Aghnr6hFzBWBCpxS61RuRbLaAAAAAAAAAUnUolVj1HJlmaZQEriKUcww8n5vaU1I85Q6bleVY2i/bJhtNTIYEGxqxv5MGnwEAAAABlmCMy6+harrakCeA2k3DXa/XrwX6DaCM+DNXX4z56DYAAAAASkkwRgIhANqySIkhPK9DrmrcQc8ck5bAgkDBmfUiWs9FQWMw/X29AiEA/jeQDgZEv1dEk6B/xe26BtvAfDEblHUgwtUUvFcl3LQB/////wEA8gUqAQAAABl2qRTxXRkh9S5AB7FG36YPNp7S/Dk84oisAAAAAAiCBKPzrGBdXkcn9Opy6TRqXVhvAjFGD9Uq2YlbyCQNhx3vUi2zOcGGwRSYQ6SEiZDm3bmmBl9LwUIq9T9LyG8bCEqJGJ/wMWzcEFEdpx2nV+VTytqfO1sUNPOSNnOttX2Dyqw5LDivFW1vwwtV+tQRLfK5VTHmgRTprRABHnL3t8/bDgr9AZYAAQACipomb5dkeUs3OXARXoLtb0ElyPpzEeTX3vqSLarneGZnvo6ZgUA3ZjAxZjFmNTczOTgxNjU5YTQ0ZmYxN2E0YzcyMTVhM2I1MzllYjFlNTg0OWM2MDc3ZGJiNTcyMmY1NzE3YTI4fwHx9XOYFlmkT/F6THIVo7U56x5YScYHfbtXIvVxeigkT802AAQBAAYBAQcD/QU5CQEGC60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAiSPLtHNohncvRWwoHQk/n7a8MULWAJb/GEUQz2aVU195KmdkhKuRntep5m+WMupCDc45iNjwaCchYvK7+IcOQw4CAAAQIQJfz4z3uiy5VzldF476bYAhPcAEeJY62tpFvtuRuEh0jxEhA2UTAl6KbpcUwff9S4huPQmJWEC1Px3/9/J106rt/TLoDKUABAAAAAACIQI3K/m5u8B9sw33y7+rryWSU8fMHe2lOCuLlVsPj3r3pgN6AUkAAQACIL+vqU644RS3UJXQrOaGM50+tQvgD4FKniYSXU0+uPAaBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQEN/QFOA6UABAAAAAICIQKdduJO68wj8q4t0El3US2r3Jv8RaCPKegGybH+dotn2AN6AUkAAQACIL+vqU644RS3UJXQrOaGM50+tQvgD4FKniYSXU0+uPAaBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQF3AAQAAAADAiECrlX4aHDxCYQOkF66cz+iW8Mbdj8klIK3zpN2KpsLjR4FTAFBARqsJUCKTSgjPNMl+u+t6e8Prnb8seNdCBQARbuqOBsw7vRuRjA1VmAu8TzvXS//Pcai7OZlf8keSwpbui3tTv8DBADAAQIEAQEuAAQAAAAEAiECNMRdtB31mzfE7bm6QkP7+dW0STw/tQdWi6dptA/0FrQFAwQBAQ+fAAQAAAAEAiEC3DSUSNywYyaZaAbttpBj5yJY+cEct5LWT8co3tD8+TwDdAFJAAEAAiC/r6lOuOEUt1CV0KzmhjOdPrUL4A+BSp4mEl1NPrjwGgQiAAD//////////////////////////////////////////wInAAEAAiIAAP//////////////////////////////////////////ER4AAQACGXF1b3RoIHRoZSByYXZlbiBuZXZlcm1vcmUVCQIDZm9vA2JhchYEAAAAKheKmiZvl2R5Szc5cBFegu1vQSXI+nMR5Nfe+pItqud4Zme+jpmBQDdmMDFmMWY1NzM5ODE2NTlhNDRmZjE3YTRjNzIxNWEzYjUzOWViMWU1ODQ5YzYwNzdkYmI1NzIyZjU3MTdhMjh/AfH1c5gWWaRP8XpMchWjtTnrHlhJxgd9u1ci9XF6KCRPzTYAGUEDZRMCXopulxTB9/1LiG49CYlYQLU/Hf/38nXTqu39MuhwOTS/UKKNoQKXXe2nfnWFeeo9/kE2q/dSs7gnHQPpRAABcGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxCAAAAAAAAAAAAXIAAXMIAAAAAAAAAAABdQABeAAAAXABAQFxAQEBcggAAAAAAAAAAAFzIQJpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGyJ0Aml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbGAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAACF1aXkt1TE9Jt/pROAdatig4MONta9H3q8VmBz53b3erBsZAAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAAAF2/ZIBAAEAAooPJmhtNUzeFgfuKUs58yt8eCK6ZPhKtDygxua5HB/Tvib78ptAYTBmM2NhOTkzNmU4NDYxZjEwZDc3Yzk2ZWE4MGE3YTY2NWY2MDZmNmE2M2I3ZjNkZmQyNTY3YzE4OTc5ZTRkNqDzypk26EYfENd8luqAp6Zl9gb2pjt/Pf0lZ8GJeeTWQUOQiQAEAQAGBf5snGS4C60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAZdwnwBq04DClxJWwvHBQ9EnY+3nD1MXHQYqLWDo2gjJpNZWsdZ9voCEBFy7wfX1nHcGRtaaEaDIucEFl+Ze80g4CAAAQIQI9L1ax/Ek3xCa1tlXhDqe89wMYb3zpU+aznVVCaOXsvREhAhPhdm67vBwYyGoCShzuCJXFtjScQ2WUbBKLJGhXDHcjAXf9kgEAAQACig8maG01TN4WB+4pSznzK3x4Irpk+Eq0PKDG5rkcH9O+Jvvym0BhMGYzY2E5OTM2ZTg0NjFmMTBkNzdjOTZlYTgwYTdhNjY1ZjYwNmY2YTYzYjdmM2RmZDI1NjdjMTg5NzllNGQ2oPPKmTboRh8Q13yW6oCnpmX2BvamO389/SVnwYl55NZBQ5CJAAQBAAYF/mycZLgLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUBl3CfAGrTgMKXElbC8cFD0Sdj7ecPUxcdBiotYOjaCMmk1lax1n2+gIQEXLvB9fWcdwZG1poRoMi5wQWX5l7zSDgIAABAhAj0vVrH8STfEJrW2VeEOp7z3AxhvfOlT5rOdVUJo5ey9ESECE+F2bru8HBjIagJKHO4IlcW2NJxDZZRsEoskaFcMdyMBeBUAwBJub3QgYSB2YWxpZCBzY3JpcHQBeQEBAXoTaHR0cHM6Ly9leGFtcGxlLmNvbQF7/dsGVEFQUAAEAAAAAAIkmiZvl2R5Szc5cBFegu1vQSXI+nMR5Nfe+pItqud4Zme+jpmBBFABAAAAkPCp8RBwL4CCGevqEXMFYEKnFLrVG5FstoAAAAAAAABSdSiVWPUcmWZplASuIpRzDDyfm9pTUjzlDpuV5VjaL9smG01MhgQbGrG/kwafAQAAAAGWYIzLr6FqutqQJ4DaTcNdr9evBfoNoIz4M1dfjPnoNgAAAABKSTBGAiEA2rJIiSE8r0OuatxBzxyTlsCCQMGZ9SJaz0VBYzD9fb0CIQD+N5AOBkS/V0SToH/F7boG28B8MRuUdSDC1RS8VyXctAH/////AQDyBSoBAAAAGXapFPFdGSH1LkAHsUbfpg82ntL8OTziiKwAAAAACIIEo/OsYF1eRyf06nLpNGpdWG8CMUYP1SrZiVvIJA2HHe9SLbM5wYbBFJhDpISJkObduaYGX0vBQir1P0vIbxsISokYn/AxbNwQUR2nHadX5VPK2p87WxQ085I2c621fYPKrDksOK8VbW/DC1X61BEt8rlVMeaBFOmtEAEecve3z9sOCv0BlgABAAKKmiZvl2R5Szc5cBFegu1vQSXI+nMR5Nfe+pItqud4Zme+jpmBQDdmMDFmMWY1NzM5ODE2NTlhNDRmZjE3YTRjNzIxNWEzYjUzOWViMWU1ODQ5YzYwNzdkYmI1NzIyZjU3MTdhMjh/AfH1c5gWWaRP8XpMchWjtTnrHlhJxgd9u1ci9XF6KCRPzTYABAEABgEBBwP9BTkJAQYLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUCJI8u0c2iGdy9FbCgdCT+ftrwxQtYAlv8YRRDPZpVTX3kqZ2SEq5Ge16nmb5Yy6kINzjmI2PBoJyFi8rv4hw5DDgIAABAhAl/PjPe6LLlXOV0XjvptgCE9wAR4ljra2kW+25G4SHSPESEDZRMCXopulxTB9/1LiG49CYlYQLU/Hf/38nXTqu39MugMpQAEAAAAAAIhAjcr+bm7wH2zDffLv6uvJZJTx8wd7aU4K4uVWw+PevemA3oBSQABAAIgv6+pTrjhFLdQldCs5oYznT61C+APgUqeJhJdTT648BoEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAQ39AU4DpQAEAAAAAgIhAp124k7rzCPyri3QSXdRLavcm/xFoI8p6AbJsf52i2fYA3oBSQABAAIgv6+pTrjhFLdQldCs5oYznT61C+APgUqeJhJdTT648BoEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAXcABAAAAAMCIQKuVfhocPEJhA6QXrpzP6Jbwxt2PySUgrfOk3YqmwuNHgVMAUEBGqwlQIpNKCM80yX6763p7w+udvyx410IFABFu6o4GzDu9G5GMDVWYC7xPO9dL/89xqLs5mV/yR5LClu6Le1O/wMEAMABAgQBAS4ABAAAAAQCIQI0xF20HfWbN8TtubpCQ/v51bRJPD+1B1aLp2m0D/QWtAUDBAEBD58ABAAAAAQCIQLcNJRI3LBjJploBu22kGPnIlj5wRy3ktZPxyje0Pz5PAN0AUkAAQACIL+vqU644RS3UJXQrOaGM50+tQvgD4FKniYSXU0+uPAaBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8RHgABAAIZcXVvdGggdGhlIHJhdmVuIG5ldmVybW9yZRUJAgNmb28DYmFyFgQAAAAqF4qaJm+XZHlLNzlwEV6C7W9BJcj6cxHk1976ki2q53hmZ76OmYFAN2YwMWYxZjU3Mzk4MTY1OWE0NGZmMTdhNGM3MjE1YTNiNTM5ZWIxZTU4NDljNjA3N2RiYjU3MjJmNTcxN2EyOH8B8fVzmBZZpE/xekxyFaO1OeseWEnGB327VyL1cXooJE/NNgAZQQNlEwJeim6XFMH3/UuIbj0JiVhAtT8d//fyddOq7f0y6HA5NL9Qoo2hApdd7ad+dYV56j3+QTar91KzuCcdA+lEAXwIAAAAAAAAAcgBfQgAAAAAAAABWQF+eQMnDgJ0JxAhAt11blDK7vjKugrPc9tOWy5/TCKWRPAdU47EQnt7GUsjJw4C4OoQIQIRat98y/atOhDeSBere9ey2cJfhTIDp5yiYfqYzg39NicOArOQECECMHU6Lxq1sCVRTU/SM4OeTSoZMuwbN2dU3FDSBHWlEjAAAXABAQFxAQABcggAAAAAAAAAAQFzIQJpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGyJ0Aml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbGAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAACF1aXkt1TE9Jt/pROAdatig4MONta9H3q8VmBz53b3erBsZAAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAAAF2/ZIBAAEAAooPJmhtNUzeFgfuKUs58yt8eCK6ZPhKtDygxua5HB/Tvib78ptAYTBmM2NhOTkzNmU4NDYxZjEwZDc3Yzk2ZWE4MGE3YTY2NWY2MDZmNmE2M2I3ZjNkZmQyNTY3YzE4OTc5ZTRkNqDzypk26EYfENd8luqAp6Zl9gb2pjt/Pf0lZ8GJeeTWQUOQiQAEAQAGBf5snGS4C60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAZdwnwBq04DClxJWwvHBQ9EnY+3nD1MXHQYqLWDo2gjJpNZWsdZ9voCEBFy7wfX1nHcGRtaaEaDIucEFl+Ze80g4CAAAQIQI9L1ax/Ek3xCa1tlXhDqe89wMYb3zpU+aznVVCaOXsvREhAhPhdm67vBwYyGoCShzuCJXFtjScQ2WUbBKLJGhXDHcjAXhBARl84i0SvFqZWHUzr0EWn6Hcn/hmwNTTAhFY1ikzZy0RGXziLRK8WplYdTOvQRafodyf+GbA1NMCEVjWKTNnLREBeQEAAXwIAAAAAAAAAAABfQgAAAAAAAAAAAF+UQInDgJTuhAhArIP4MCCYSGABoh1H10IShaP3JQXAolbQj2iO4Of9VhYJw4CHFcQIQI6QwG0gKpp4Swcms7uNxtgcRC66Zabe1AuXrBJwC5oKgA=", + "expected": "cHNidP8BALICAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACewAAAAAAAAAiUSA9L1ax/Ek3xCa1tlXhDqe89wMYb3zpU+aznVVCaOXsvVkBAAAAAAAAIlEgPS9WsfxJN8QmtbZV4Q6nvPcDGG986VPms51VQmjl7L0AAAAAAXABAQFxBXRhcGJjAXIBAAAiBgJpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGxgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhFml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABFyBpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGwEYC21lcmtsZSByb290AXBlvI+effHZKTM/+ZOTO+pvWzr23gN0NmxHGeQ6GwZ9ibyxhrUfBFS2gxLVAnzhWk8KWCUNj7UOd/K/TwFS5dSUNYB/nUsClVHBHO5YSSrpBS5Z+Bl9/80yzJtkiCLo4u6MwUXtwrABcQgAAAAAAAADCQFyD2FuY2hvciBwa3NjcmlwdAFzCAAAAAAAAAADAXQhAml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbAXULbWVya2xlIHJvb3QidgJpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGxgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhd2l5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABeAdzaWJsaW5nAXn9kgEAAQACipomb5dkeUs3OXARXoLtb0ElyPpzEeTX3vqSLarneGZnvo6ZgUA3ZjAxZjFmNTczOTgxNjU5YTQ0ZmYxN2E0YzcyMTVhM2I1MzllYjFlNTg0OWM2MDc3ZGJiNTcyMmY1NzE3YTI4fwHx9XOYFlmkT/F6THIVo7U56x5YScYHfbtXIvVxeigkT802AAQBAAYF/q9j5Y4LrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUCXji6DmoNhjnVEqRdRKkpv2+Ki239wRSh4P6fB7SRyjPGcLXJ6eGpLaFhPg1p8ZZ80hsn6D8BwZwis0a3DaldzDgIAABAhAzdb3PMLcpLE4s5/hRHGjP1Yu89chGEoKCW+I96gZ1IEESECaLjOzwxTHUrlltfXNBjf9ED1ANQg1mz9tA58Maebr0sBev3bBlRBUFAABAAAAAACJJomb5dkeUs3OXARXoLtb0ElyPpzEeTX3vqSLarneGZnvo6ZgQRQAQAAAJDwqfEQcC+Aghnr6hFzBWBCpxS61RuRbLaAAAAAAAAAUnUolVj1HJlmaZQEriKUcww8n5vaU1I85Q6bleVY2i/bJhtNTIYEGxqxv5MGnwEAAAABlmCMy6+harrakCeA2k3DXa/XrwX6DaCM+DNXX4z56DYAAAAASkkwRgIhANqySIkhPK9DrmrcQc8ck5bAgkDBmfUiWs9FQWMw/X29AiEA/jeQDgZEv1dEk6B/xe26BtvAfDEblHUgwtUUvFcl3LQB/////wEA8gUqAQAAABl2qRTxXRkh9S5AB7FG36YPNp7S/Dk84oisAAAAAAiCBKPzrGBdXkcn9Opy6TRqXVhvAjFGD9Uq2YlbyCQNhx3vUi2zOcGGwRSYQ6SEiZDm3bmmBl9LwUIq9T9LyG8bCEqJGJ/wMWzcEFEdpx2nV+VTytqfO1sUNPOSNnOttX2Dyqw5LDivFW1vwwtV+tQRLfK5VTHmgRTprRABHnL3t8/bDgr9AZYAAQACipomb5dkeUs3OXARXoLtb0ElyPpzEeTX3vqSLarneGZnvo6ZgUA3ZjAxZjFmNTczOTgxNjU5YTQ0ZmYxN2E0YzcyMTVhM2I1MzllYjFlNTg0OWM2MDc3ZGJiNTcyMmY1NzE3YTI4fwHx9XOYFlmkT/F6THIVo7U56x5YScYHfbtXIvVxeigkT802AAQBAAYBAQcD/QU5CQEGC60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAiSPLtHNohncvRWwoHQk/n7a8MULWAJb/GEUQz2aVU195KmdkhKuRntep5m+WMupCDc45iNjwaCchYvK7+IcOQw4CAAAQIQJfz4z3uiy5VzldF476bYAhPcAEeJY62tpFvtuRuEh0jxEhA2UTAl6KbpcUwff9S4huPQmJWEC1Px3/9/J106rt/TLoDKUABAAAAAACIQI3K/m5u8B9sw33y7+rryWSU8fMHe2lOCuLlVsPj3r3pgN6AUkAAQACIL+vqU644RS3UJXQrOaGM50+tQvgD4FKniYSXU0+uPAaBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQEN/QFOA6UABAAAAAICIQKdduJO68wj8q4t0El3US2r3Jv8RaCPKegGybH+dotn2AN6AUkAAQACIL+vqU644RS3UJXQrOaGM50+tQvgD4FKniYSXU0+uPAaBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQF3AAQAAAADAiECrlX4aHDxCYQOkF66cz+iW8Mbdj8klIK3zpN2KpsLjR4FTAFBARqsJUCKTSgjPNMl+u+t6e8Prnb8seNdCBQARbuqOBsw7vRuRjA1VmAu8TzvXS//Pcai7OZlf8keSwpbui3tTv8DBADAAQIEAQEuAAQAAAAEAiECNMRdtB31mzfE7bm6QkP7+dW0STw/tQdWi6dptA/0FrQFAwQBAQ+fAAQAAAAEAiEC3DSUSNywYyaZaAbttpBj5yJY+cEct5LWT8co3tD8+TwDdAFJAAEAAiC/r6lOuOEUt1CV0KzmhjOdPrUL4A+BSp4mEl1NPrjwGgQiAAD//////////////////////////////////////////wInAAEAAiIAAP//////////////////////////////////////////ER4AAQACGXF1b3RoIHRoZSByYXZlbiBuZXZlcm1vcmUVCQIDZm9vA2JhchYEAAAAKheKmiZvl2R5Szc5cBFegu1vQSXI+nMR5Nfe+pItqud4Zme+jpmBQDdmMDFmMWY1NzM5ODE2NTlhNDRmZjE3YTRjNzIxNWEzYjUzOWViMWU1ODQ5YzYwNzdkYmI1NzIyZjU3MTdhMjh/AfH1c5gWWaRP8XpMchWjtTnrHlhJxgd9u1ci9XF6KCRPzTYAGUEDZRMCXopulxTB9/1LiG49CYlYQLU/Hf/38nXTqu39MuhwOTS/UKKNoQKXXe2nfnWFeeo9/kE2q/dSs7gnHQPpRAABcGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxCAAAAAAAAAAAAXIAAXMIAAAAAAAAAAABdQABeAAAAXABAQFxAQEBcggAAAAAAAAAAAFzIQJpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGyJ0Aml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbGAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAACF1aXkt1TE9Jt/pROAdatig4MONta9H3q8VmBz53b3erBsZAAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAAAF2/ZIBAAEAAooPJmhtNUzeFgfuKUs58yt8eCK6ZPhKtDygxua5HB/Tvib78ptAYTBmM2NhOTkzNmU4NDYxZjEwZDc3Yzk2ZWE4MGE3YTY2NWY2MDZmNmE2M2I3ZjNkZmQyNTY3YzE4OTc5ZTRkNqDzypk26EYfENd8luqAp6Zl9gb2pjt/Pf0lZ8GJeeTWQUOQiQAEAQAGBf5snGS4C60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAZdwnwBq04DClxJWwvHBQ9EnY+3nD1MXHQYqLWDo2gjJpNZWsdZ9voCEBFy7wfX1nHcGRtaaEaDIucEFl+Ze80g4CAAAQIQI9L1ax/Ek3xCa1tlXhDqe89wMYb3zpU+aznVVCaOXsvREhAhPhdm67vBwYyGoCShzuCJXFtjScQ2WUbBKLJGhXDHcjAXf9kgEAAQACig8maG01TN4WB+4pSznzK3x4Irpk+Eq0PKDG5rkcH9O+Jvvym0BhMGYzY2E5OTM2ZTg0NjFmMTBkNzdjOTZlYTgwYTdhNjY1ZjYwNmY2YTYzYjdmM2RmZDI1NjdjMTg5NzllNGQ2oPPKmTboRh8Q13yW6oCnpmX2BvamO389/SVnwYl55NZBQ5CJAAQBAAYF/mycZLgLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUBl3CfAGrTgMKXElbC8cFD0Sdj7ecPUxcdBiotYOjaCMmk1lax1n2+gIQEXLvB9fWcdwZG1poRoMi5wQWX5l7zSDgIAABAhAj0vVrH8STfEJrW2VeEOp7z3AxhvfOlT5rOdVUJo5ey9ESECE+F2bru8HBjIagJKHO4IlcW2NJxDZZRsEoskaFcMdyMBeBUAwBJub3QgYSB2YWxpZCBzY3JpcHQBeQEAAXoTaHR0cHM6Ly9leGFtcGxlLmNvbQF7/dsGVEFQUAAEAAAAAAIkmiZvl2R5Szc5cBFegu1vQSXI+nMR5Nfe+pItqud4Zme+jpmBBFABAAAAkPCp8RBwL4CCGevqEXMFYEKnFLrVG5FstoAAAAAAAABSdSiVWPUcmWZplASuIpRzDDyfm9pTUjzlDpuV5VjaL9smG01MhgQbGrG/kwafAQAAAAGWYIzLr6FqutqQJ4DaTcNdr9evBfoNoIz4M1dfjPnoNgAAAABKSTBGAiEA2rJIiSE8r0OuatxBzxyTlsCCQMGZ9SJaz0VBYzD9fb0CIQD+N5AOBkS/V0SToH/F7boG28B8MRuUdSDC1RS8VyXctAH/////AQDyBSoBAAAAGXapFPFdGSH1LkAHsUbfpg82ntL8OTziiKwAAAAACIIEo/OsYF1eRyf06nLpNGpdWG8CMUYP1SrZiVvIJA2HHe9SLbM5wYbBFJhDpISJkObduaYGX0vBQir1P0vIbxsISokYn/AxbNwQUR2nHadX5VPK2p87WxQ085I2c621fYPKrDksOK8VbW/DC1X61BEt8rlVMeaBFOmtEAEecve3z9sOCv0BlgABAAKKmiZvl2R5Szc5cBFegu1vQSXI+nMR5Nfe+pItqud4Zme+jpmBQDdmMDFmMWY1NzM5ODE2NTlhNDRmZjE3YTRjNzIxNWEzYjUzOWViMWU1ODQ5YzYwNzdkYmI1NzIyZjU3MTdhMjh/AfH1c5gWWaRP8XpMchWjtTnrHlhJxgd9u1ci9XF6KCRPzTYABAEABgEBBwP9BTkJAQYLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUCJI8u0c2iGdy9FbCgdCT+ftrwxQtYAlv8YRRDPZpVTX3kqZ2SEq5Ge16nmb5Yy6kINzjmI2PBoJyFi8rv4hw5DDgIAABAhAl/PjPe6LLlXOV0XjvptgCE9wAR4ljra2kW+25G4SHSPESEDZRMCXopulxTB9/1LiG49CYlYQLU/Hf/38nXTqu39MugMpQAEAAAAAAIhAjcr+bm7wH2zDffLv6uvJZJTx8wd7aU4K4uVWw+PevemA3oBSQABAAIgv6+pTrjhFLdQldCs5oYznT61C+APgUqeJhJdTT648BoEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAQ39AU4DpQAEAAAAAgIhAp124k7rzCPyri3QSXdRLavcm/xFoI8p6AbJsf52i2fYA3oBSQABAAIgv6+pTrjhFLdQldCs5oYznT61C+APgUqeJhJdTT648BoEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAXcABAAAAAMCIQKuVfhocPEJhA6QXrpzP6Jbwxt2PySUgrfOk3YqmwuNHgVMAUEBGqwlQIpNKCM80yX6763p7w+udvyx410IFABFu6o4GzDu9G5GMDVWYC7xPO9dL/89xqLs5mV/yR5LClu6Le1O/wMEAMABAgQBAS4ABAAAAAQCIQI0xF20HfWbN8TtubpCQ/v51bRJPD+1B1aLp2m0D/QWtAUDBAEBD58ABAAAAAQCIQLcNJRI3LBjJploBu22kGPnIlj5wRy3ktZPxyje0Pz5PAN0AUkAAQACIL+vqU644RS3UJXQrOaGM50+tQvgD4FKniYSXU0+uPAaBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8RHgABAAIZcXVvdGggdGhlIHJhdmVuIG5ldmVybW9yZRUJAgNmb28DYmFyFgQAAAAqF4qaJm+XZHlLNzlwEV6C7W9BJcj6cxHk1976ki2q53hmZ76OmYFAN2YwMWYxZjU3Mzk4MTY1OWE0NGZmMTdhNGM3MjE1YTNiNTM5ZWIxZTU4NDljNjA3N2RiYjU3MjJmNTcxN2EyOH8B8fVzmBZZpE/xekxyFaO1OeseWEnGB327VyL1cXooJE/NNgAZQQNlEwJeim6XFMH3/UuIbj0JiVhAtT8d//fyddOq7f0y6HA5NL9Qoo2hApdd7ad+dYV56j3+QTar91KzuCcdA+lEAXwIAAAAAAAAAcgBfQgAAAAAAAABWQF+UQInDgIJUBAhAkPREpw3bNe+CM0Rr8B96p5fm9e1n5jTYc2NRSH89FJDJw4CWkEQIQJ1mYnWnDJF22bqHtRerB9Ops6sxpWjlYJwbTbCP6MnXAF/ogABAgIBAAQgujm4ryvHQvgCZpav/A/+E0J7RZ9a50k9h3v0ZXywYLcGIQIedXNb27PSHXD2SlGF+qnU2FdsVCIZd8o3TysWPiFhswghAnXlCCsXL8K8VlMBid/OHqRIG4FzLpTS62FJvjGoJCC7Cgn/NLSjyBPTRrUMJ2F1dGhtYWlsYm94K3VuaXZlcnNlcnBjOi8vZm9vLmJhcjoxMDAyOQABcAEBAXEBAAFyCAAAAAAAAAABAXMhAml5LdUxPSbf6UTgHWrYoODDjbWvR96vFZgc+d293qwbInQCaXkt1TE9Jt/pROAdatig4MONta9H3q8VmBz53b3erBsYAAAAAPkDAIAAAACAewAAgAAAAADIAQAAIXVpeS3VMT0m3+lE4B1q2KDgw421r0ferxWYHPndvd6sGxkAAAAAAPkDAIAAAACAewAAgAAAAADIAQAAAXb9kgEAAQACig8maG01TN4WB+4pSznzK3x4Irpk+Eq0PKDG5rkcH9O+Jvvym0BhMGYzY2E5OTM2ZTg0NjFmMTBkNzdjOTZlYTgwYTdhNjY1ZjYwNmY2YTYzYjdmM2RmZDI1NjdjMTg5NzllNGQ2oPPKmTboRh8Q13yW6oCnpmX2BvamO389/SVnwYl55NZBQ5CJAAQBAAYF/mycZLgLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUBl3CfAGrTgMKXElbC8cFD0Sdj7ecPUxcdBiotYOjaCMmk1lax1n2+gIQEXLvB9fWcdwZG1poRoMi5wQWX5l7zSDgIAABAhAj0vVrH8STfEJrW2VeEOp7z3AxhvfOlT5rOdVUJo5ey9ESECE+F2bru8HBjIagJKHO4IlcW2NJxDZZRsEoskaFcMdyMBeEEBGXziLRK8WplYdTOvQRafodyf+GbA1NMCEVjWKTNnLREZfOItErxamVh1M69BFp+h3J/4ZsDU0wIRWNYpM2ctEQF5AQABfAgAAAAAAAAAAAF9CAAAAAAAAAAAAX6hBCcOAkHMECECk5KTv5G/moRK0XwkfB4Nfca6rVOYE2WLwuy4e6WxbjQnDgLS4hAhAlpthYH8yphkgE7Xdn1InIHSMwLS1traeEbKdQMT2XzVJw4CuIUQIQL1bZKy5pxDNvfzyylvSY2+G+39G8L1BUfSxTny0yRYvCcOAjEPECECkK0mKU8F/w85K/gqy4JSHlBIqKZRs17zhtv/aMkjw3oBf9wAAQECAQEEIHPz5Tq8MdYyFvxTqY1V4V+DP9jxxo6im9omUZtxkZqUBSEDaiOH5qV9RB3YebMnkuPcC0Fn2Y2L63AaTEBAC8QmJFgGIQJ0RAgGvTERHFgbbAqR9R4G9VbfQaNPMAqsGkovBNYLEwghAuPoyqfIyZnjmxR/ivMar9X9l9s/0gcvoX91xwEeVdXsCRUAwBJub3QgYSB2YWxpZCBzY3JpcHQKCf9RfY6/PaVHXAwnYXV0aG1haWxib3grdW5pdmVyc2VycGM6Ly9mb28uYmFyOjEwMDI5AA==", "comment": "random packet" }, { @@ -893,7 +951,7 @@ { "bip32_derivation": [ { - "pub_key": "0252050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "022f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "fingerprint": 0, "bip32_path": [ 2147484665, @@ -906,7 +964,7 @@ ], "tr_bip32_derivation": [ { - "pub_key": "52050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "2f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "leaf_hashes": [], "fingerprint": 0, "bip32_path": [ @@ -918,23 +976,23 @@ ] } ], - "tr_internal_key": "52050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "tr_internal_key": "2f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "tr_merkle_root": "6d65726b6c6520726f6f74", "prev_id": { - "out_point": "251722cee10365790c96d24a03c6d982930cf840a79c3ba2d5288946f23d0064:681360684", - "asset_id": "23d728b45347eada650af24c56d0800a8691332088a805bd55c446e25eb07590", - "script_key": "0262a692930c4a1e5f9eb6333ab389a384955dccf0690bc0952a3dba8a99d0c5ba" + "out_point": "390908b802bdfc8df0dcf9f95edee4ae6d5c92e2b89ad1bdc176163db95e8cca:3240957262", + "asset_id": "2025a60c7dd3899d920e95f1c46d432f9b08e64d7f9b38965d5a77a7ac183c38", + "script_key": "02618217b26462653db545658335e95ebaf77511d00453f75633ab95690ad5c703" }, "anchor": { "value": 777, "pk_script": "616e63686f7220706b736372697074", "sig_hash_type": 3, - "internal_key": "0252050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "internal_key": "022f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "merkle_root": "6d65726b6c6520726f6f74", "tapscript_sibling": "7369626c696e67", "bip32_derivation": [ { - "pub_key": "0252050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "022f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "fingerprint": 0, "bip32_path": [ 2147484665, @@ -947,7 +1005,7 @@ ], "tr_bip32_derivation": [ { - "pub_key": "52050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "2f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "leaf_hashes": [], "fingerprint": 0, "bip32_path": [ @@ -961,13 +1019,13 @@ ] }, "asset": { - "version": 1, - "genesis_first_prev_out": "0a7f201283b654043a6680d58fe8ba8f22c93fb09f6c47ac3f0d6fb73c32eded:2773153607", - "genesis_tag": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "genesis_meta_hash": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "genesis_output_index": 3029492785, + "version": 0, + "genesis_first_prev_out": "0a80d0564cf20a65daea4753b428d723bc6fc8214b8a189b251dba77aecd00c4:1577903845", + "genesis_tag": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "genesis_meta_hash": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "genesis_output_index": 3293953285, "genesis_type": 0, - "amount": 2042064831, + "amount": 3312167364, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -978,22 +1036,22 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "ecf977951a991f4e80d604dbfae74cb0c1444b819d3fb4200eeeb0da58e4b6d2b8763b775eb1ab8601a4b58c6da79d88b7a7ebb42e74a359ac16b32cb0e35427" + "18fa7e2dfdf79dfa7b81da4baf9a88009ff5a1fbc8ca0f725a99e2b49270a30baab2ae4aaca5dc780e605bc21cd82f47a4eb3c2d69bfcbf52a016bd578cfa748" ], "split_commitment": null } ], "split_commitment_root": null, "script_version": 0, - "script_key": "02e9c55d4aa47773a3c3ddc9d2c9a94c9a37f0500d423f9e8a18d9481e765a0939", + "script_key": "03fbeac426a7a9b4cf33df9ecb157be2938c5d82bd0039493a28d777b57bafc94b", "group_key": { - "group_key": "027f5f3ecbb1bd1cfc0dc2b8fff9e052c6f3581934e12b5c85a6f52fc621a47b47" + "group_key": "02df17c8e7f1f6abab082af737b36fc425015ad30cf9b57d61089dd7618d3a268d" }, "unknown_odd_types": null }, "proof": { "version": 0, - "prev_out": "0a7f201283b654043a6680d58fe8ba8f22c93fb09f6c47ac3f0d6fb73c32eded:2773153607", + "prev_out": "0a80d0564cf20a65daea4753b428d723bc6fc8214b8a189b251dba77aecd00c4:1577903845", "block_header": { "version": 1, "prev_block": "00000000000080b66c911bd5ba14a74260057311eaeb1982802f7010f1a9f090", @@ -1020,10 +1078,10 @@ }, "asset": { "version": 0, - "genesis_first_prev_out": "0a7f201283b654043a6680d58fe8ba8f22c93fb09f6c47ac3f0d6fb73c32eded:2773153607", - "genesis_tag": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "genesis_meta_hash": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "genesis_output_index": 3029492785, + "genesis_first_prev_out": "0a80d0564cf20a65daea4753b428d723bc6fc8214b8a189b251dba77aecd00c4:1577903845", + "genesis_tag": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "genesis_meta_hash": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "genesis_output_index": 3293953285, "genesis_type": 0, "amount": 1, "lock_time": 1337, @@ -1036,28 +1094,28 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "65db9dcbaf343a25a00718c9f4171e332e77744b3de0ce0943a77770e0a974978aa0898b81f6824fc588c8bdfe635643ab4a334b624df521ca3462105bcb9428" + "d6504fc1e6b7c03d7f25f00aff13a62ea5ac17d9bbcdd5747aca52cf16fbf5e6fb30b55054e594baefdb39ca4c8c1271da72b2ca15ee7edd17a4c6ac33afa48d" ], "split_commitment": null } ], "split_commitment_root": null, "script_version": 0, - "script_key": "02ff17edcb1cf273f2fa15a6be722058dd2bec12f1105963de658ae20878008d08", + "script_key": "023ce2aab9a7c88afdbd44dcae1407991f8e1054dd0a1e03c354ec149d9196c330", "group_key": { - "group_key": "02b05dabff99aada76af4f67672b1e5464f85e72ec5dbd286e62586bba76d37cf0" + "group_key": "034d4d01c1faa3fbb3300865697516d5bf23c363cec7f7b957448cf2daee003174" }, "unknown_odd_types": null }, "inclusion_proof": { "output_index": 0, - "internal_key": "027d7a7a230360619b4e574b117c8acd818ad7215fa0b80bbd12d13531037fb0b0", + "internal_key": "02d0d3685b807ba9640c28380a45535b57e46c0fa213e94bbf344ca5fc79606451", "commitment_proof": { "proof": { "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "tap_key": "42aec58f851b38022040bb5e0d74b2ac99115ae9d77f718347fc1ecc23a3bdd6", + "tap_key": "25120f513a59c0a52b48d48dc7d45e7586e3c068dc2fd0be0b108d01814caa72", "unknown_odd_types": null }, "taproot_asset_proof": { @@ -1077,13 +1135,13 @@ "exclusion_proofs": [ { "output_index": 2, - "internal_key": "026d8ea41efa8ba84fd6fc5afaf026956182edc9bc1e12e9881ac5fc54cdd69667", + "internal_key": "0293bb3e5c187474e59ab2a893a8dcc0c0451b2513c62cefb24153c4c8b68131cd", "commitment_proof": { "proof": { "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "tap_key": "42aec58f851b38022040bb5e0d74b2ac99115ae9d77f718347fc1ecc23a3bdd6", + "tap_key": "25120f513a59c0a52b48d48dc7d45e7586e3c068dc2fd0be0b108d01814caa72", "unknown_odd_types": null }, "taproot_asset_proof": { @@ -1102,7 +1160,7 @@ }, { "output_index": 3, - "internal_key": "028d4fcfcffa206ee9c79e642d326283480d5b4a73e436ed8a8c99186f6907c796", + "internal_key": "0221bf569861add9bb9747bf2d576e89c958a69e2dde2440acf75b082839a65470", "commitment_proof": null, "tapscript_proof": { "tap_preimage_1": "011aac25408a4d28233cd325faefade9ef0fae76fcb1e35d08140045bbaa381b30eef46e46303556602ef13cef5d2fff3dc6a2ece6657fc91e4b0a5bba2ded4eff", @@ -1114,7 +1172,7 @@ }, { "output_index": 4, - "internal_key": "02d0589acec520c8c1ffb40672c1fcf506986a6062b264f90b521d55e6800592e9", + "internal_key": "027f8867d291453be43a581058c8c671eded569bf9a49f2db52a66ff2b11a19e2d", "commitment_proof": null, "tapscript_proof": { "tap_preimage_1": "", @@ -1127,13 +1185,13 @@ ], "split_root_proof": { "output_index": 4, - "internal_key": "0253a0339ebf6d2e16923ac7128299667cc88566282f8b19c35556749e0a9640e1", + "internal_key": "0229ca563abb1c5b4f08c94c84d89ab3403d1d8c3fa0a42ae9f5ff2f3dd805132b", "commitment_proof": { "proof": { "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "tap_key": "42aec58f851b38022040bb5e0d74b2ac99115ae9d77f718347fc1ecc23a3bdd6", + "tap_key": "25120f513a59c0a52b48d48dc7d45e7586e3c068dc2fd0be0b108d01814caa72", "unknown_odd_types": null }, "taproot_asset_proof": { @@ -1165,15 +1223,15 @@ "626172" ], "genesis_reveal": { - "first_prev_out": "0a7f201283b654043a6680d58fe8ba8f22c93fb09f6c47ac3f0d6fb73c32eded:2773153607", - "tag": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "meta_hash": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "output_index": 3029492785, + "first_prev_out": "0a80d0564cf20a65daea4753b428d723bc6fc8214b8a189b251dba77aecd00c4:1577903845", + "tag": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "meta_hash": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "output_index": 3293953285, "type": 0 }, "group_key_reveal": { - "raw_key": "02b05dabff99aada76af4f67672b1e5464f85e72ec5dbd286e62586bba76d37cf0", - "tapscript_root": "8406e877073ff08834e197a4034aa48afa3f85b8a62708caebbac880b5b89b93" + "raw_key": "034d4d01c1faa3fbb3300865697516d5bf23c363cec7f7b957448cf2daee003174", + "tapscript_root": "3022c1dfc579b99ed9d20d573ad53171c8fef7f1f4e4613bb365b2ebb44f0ffb" }, "alt_leaves": null, "unknown_odd_types": null @@ -1207,13 +1265,13 @@ { "amount": 123, "type": 1, - "asset_version": 1, + "asset_version": 0, "interactive": true, "anchor_output_index": 0, - "anchor_output_internal_key": "0252050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "anchor_output_internal_key": "022f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "anchor_output_bip32_derivation": [ { - "pub_key": "0252050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "022f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "fingerprint": 0, "bip32_path": [ 2147484665, @@ -1226,7 +1284,7 @@ ], "anchor_output_tr_bip32_derivation": [ { - "pub_key": "52050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "2f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "leaf_hashes": [], "fingerprint": 0, "bip32_path": [ @@ -1241,12 +1299,12 @@ "anchor_output_tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", "asset": { "version": 0, - "genesis_first_prev_out": "541c3b6bd9c19e7792417fc335327a49f6d261a82947a67e52b118fa6e04f9ce:3410233680", - "genesis_tag": "c05a4b13a1d5b2f5bfef5a6ed92da482caa9568e5b6fe9d8a9ddd9eb09277b92", - "genesis_meta_hash": "c05a4b13a1d5b2f5bfef5a6ed92da482caa9568e5b6fe9d8a9ddd9eb09277b92", - "genesis_output_index": 2955392992, + "genesis_first_prev_out": "4381075b1ccd2ab86ead7e74d4b80f63d487b8e5d22bd743cfb52e3298237ef1:378678736", + "genesis_tag": "d596e685a591121966e031650d510354aa845580ff560760fd36514ca197c875", + "genesis_meta_hash": "d596e685a591121966e031650d510354aa845580ff560760fd36514ca197c875", + "genesis_output_index": 2635277229, "genesis_type": 0, - "amount": 3819700043, + "amount": 571885926, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -1257,27 +1315,27 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "60e0ee8530cdfd6191a5d1be4cd143c6d11b914b448d1e3d7ad6765eb8212f2298a751a1c8651d456cc48716dd911055363f0612ec3f616469ae994e097242ea" + "4ca1c890aec103c3aab03acf94689ba02e810c61a789b8193e829b0ef1a05dae904719a85ce82ebc4ef60f32af3d8eb08f7275c544f0cf7dc37530f3d5e7e5a9" ], "split_commitment": null } ], "split_commitment_root": null, "script_version": 0, - "script_key": "02484a4f43cefb92fd22133d26c737b94fc50ae8192d668c820afdf6428d51099c", + "script_key": "02c5cd3c536e102742945f3ec6ba3d28a46754f58c93a5cd63abf35749e852dea1", "group_key": { - "group_key": "03dffff1117719feb3a414b7b24b27f2da96be03b6f5d84c1eec8c73f1d8007640" + "group_key": "02e37fa9e3b1d3e722448a08969d7e7469f95d0820d67e3de737ce6c92c252a5f5" }, "unknown_odd_types": null }, "split_asset": { "version": 0, - "genesis_first_prev_out": "541c3b6bd9c19e7792417fc335327a49f6d261a82947a67e52b118fa6e04f9ce:3410233680", - "genesis_tag": "c05a4b13a1d5b2f5bfef5a6ed92da482caa9568e5b6fe9d8a9ddd9eb09277b92", - "genesis_meta_hash": "c05a4b13a1d5b2f5bfef5a6ed92da482caa9568e5b6fe9d8a9ddd9eb09277b92", - "genesis_output_index": 2955392992, + "genesis_first_prev_out": "4381075b1ccd2ab86ead7e74d4b80f63d487b8e5d22bd743cfb52e3298237ef1:378678736", + "genesis_tag": "d596e685a591121966e031650d510354aa845580ff560760fd36514ca197c875", + "genesis_meta_hash": "d596e685a591121966e031650d510354aa845580ff560760fd36514ca197c875", + "genesis_output_index": 2635277229, "genesis_type": 0, - "amount": 3819700043, + "amount": 571885926, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -1288,20 +1346,20 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "60e0ee8530cdfd6191a5d1be4cd143c6d11b914b448d1e3d7ad6765eb8212f2298a751a1c8651d456cc48716dd911055363f0612ec3f616469ae994e097242ea" + "4ca1c890aec103c3aab03acf94689ba02e810c61a789b8193e829b0ef1a05dae904719a85ce82ebc4ef60f32af3d8eb08f7275c544f0cf7dc37530f3d5e7e5a9" ], "split_commitment": null } ], "split_commitment_root": null, "script_version": 0, - "script_key": "02484a4f43cefb92fd22133d26c737b94fc50ae8192d668c820afdf6428d51099c", + "script_key": "02c5cd3c536e102742945f3ec6ba3d28a46754f58c93a5cd63abf35749e852dea1", "group_key": { - "group_key": "03dffff1117719feb3a414b7b24b27f2da96be03b6f5d84c1eec8c73f1d8007640" + "group_key": "02e37fa9e3b1d3e722448a08969d7e7469f95d0820d67e3de737ce6c92c252a5f5" }, "unknown_odd_types": null }, - "pk_script": "5120484a4f43cefb92fd22133d26c737b94fc50ae8192d668c820afdf6428d51099c", + "pk_script": "5120c5cd3c536e102742945f3ec6ba3d28a46754f58c93a5cd63abf35749e852dea1", "bip32_derivation": null, "tr_bip32_derivation": null, "tr_internal_key": "", @@ -1309,7 +1367,7 @@ "proof_delivery_address": "https://example.com", "proof_suffix": { "version": 0, - "prev_out": "0a7f201283b654043a6680d58fe8ba8f22c93fb09f6c47ac3f0d6fb73c32eded:2773153607", + "prev_out": "0a80d0564cf20a65daea4753b428d723bc6fc8214b8a189b251dba77aecd00c4:1577903845", "block_header": { "version": 1, "prev_block": "00000000000080b66c911bd5ba14a74260057311eaeb1982802f7010f1a9f090", @@ -1336,10 +1394,10 @@ }, "asset": { "version": 0, - "genesis_first_prev_out": "0a7f201283b654043a6680d58fe8ba8f22c93fb09f6c47ac3f0d6fb73c32eded:2773153607", - "genesis_tag": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "genesis_meta_hash": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "genesis_output_index": 3029492785, + "genesis_first_prev_out": "0a80d0564cf20a65daea4753b428d723bc6fc8214b8a189b251dba77aecd00c4:1577903845", + "genesis_tag": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "genesis_meta_hash": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "genesis_output_index": 3293953285, "genesis_type": 0, "amount": 1, "lock_time": 1337, @@ -1352,28 +1410,28 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "65db9dcbaf343a25a00718c9f4171e332e77744b3de0ce0943a77770e0a974978aa0898b81f6824fc588c8bdfe635643ab4a334b624df521ca3462105bcb9428" + "d6504fc1e6b7c03d7f25f00aff13a62ea5ac17d9bbcdd5747aca52cf16fbf5e6fb30b55054e594baefdb39ca4c8c1271da72b2ca15ee7edd17a4c6ac33afa48d" ], "split_commitment": null } ], "split_commitment_root": null, "script_version": 0, - "script_key": "02ff17edcb1cf273f2fa15a6be722058dd2bec12f1105963de658ae20878008d08", + "script_key": "023ce2aab9a7c88afdbd44dcae1407991f8e1054dd0a1e03c354ec149d9196c330", "group_key": { - "group_key": "02b05dabff99aada76af4f67672b1e5464f85e72ec5dbd286e62586bba76d37cf0" + "group_key": "034d4d01c1faa3fbb3300865697516d5bf23c363cec7f7b957448cf2daee003174" }, "unknown_odd_types": null }, "inclusion_proof": { "output_index": 0, - "internal_key": "027d7a7a230360619b4e574b117c8acd818ad7215fa0b80bbd12d13531037fb0b0", + "internal_key": "02d0d3685b807ba9640c28380a45535b57e46c0fa213e94bbf344ca5fc79606451", "commitment_proof": { "proof": { "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "tap_key": "42aec58f851b38022040bb5e0d74b2ac99115ae9d77f718347fc1ecc23a3bdd6", + "tap_key": "25120f513a59c0a52b48d48dc7d45e7586e3c068dc2fd0be0b108d01814caa72", "unknown_odd_types": null }, "taproot_asset_proof": { @@ -1393,13 +1451,13 @@ "exclusion_proofs": [ { "output_index": 2, - "internal_key": "026d8ea41efa8ba84fd6fc5afaf026956182edc9bc1e12e9881ac5fc54cdd69667", + "internal_key": "0293bb3e5c187474e59ab2a893a8dcc0c0451b2513c62cefb24153c4c8b68131cd", "commitment_proof": { "proof": { "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "tap_key": "42aec58f851b38022040bb5e0d74b2ac99115ae9d77f718347fc1ecc23a3bdd6", + "tap_key": "25120f513a59c0a52b48d48dc7d45e7586e3c068dc2fd0be0b108d01814caa72", "unknown_odd_types": null }, "taproot_asset_proof": { @@ -1418,7 +1476,7 @@ }, { "output_index": 3, - "internal_key": "028d4fcfcffa206ee9c79e642d326283480d5b4a73e436ed8a8c99186f6907c796", + "internal_key": "0221bf569861add9bb9747bf2d576e89c958a69e2dde2440acf75b082839a65470", "commitment_proof": null, "tapscript_proof": { "tap_preimage_1": "011aac25408a4d28233cd325faefade9ef0fae76fcb1e35d08140045bbaa381b30eef46e46303556602ef13cef5d2fff3dc6a2ece6657fc91e4b0a5bba2ded4eff", @@ -1430,7 +1488,7 @@ }, { "output_index": 4, - "internal_key": "02d0589acec520c8c1ffb40672c1fcf506986a6062b264f90b521d55e6800592e9", + "internal_key": "027f8867d291453be43a581058c8c671eded569bf9a49f2db52a66ff2b11a19e2d", "commitment_proof": null, "tapscript_proof": { "tap_preimage_1": "", @@ -1443,13 +1501,13 @@ ], "split_root_proof": { "output_index": 4, - "internal_key": "0253a0339ebf6d2e16923ac7128299667cc88566282f8b19c35556749e0a9640e1", + "internal_key": "0229ca563abb1c5b4f08c94c84d89ab3403d1d8c3fa0a42ae9f5ff2f3dd805132b", "commitment_proof": { "proof": { "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "tap_key": "42aec58f851b38022040bb5e0d74b2ac99115ae9d77f718347fc1ecc23a3bdd6", + "tap_key": "25120f513a59c0a52b48d48dc7d45e7586e3c068dc2fd0be0b108d01814caa72", "unknown_odd_types": null }, "taproot_asset_proof": { @@ -1481,15 +1539,15 @@ "626172" ], "genesis_reveal": { - "first_prev_out": "0a7f201283b654043a6680d58fe8ba8f22c93fb09f6c47ac3f0d6fb73c32eded:2773153607", - "tag": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "meta_hash": "f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e138647a4b44ed4bce964", - "output_index": 3029492785, + "first_prev_out": "0a80d0564cf20a65daea4753b428d723bc6fc8214b8a189b251dba77aecd00c4:1577903845", + "tag": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "meta_hash": "8585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c918bba3e933e5", + "output_index": 3293953285, "type": 0 }, "group_key_reveal": { - "raw_key": "02b05dabff99aada76af4f67672b1e5464f85e72ec5dbd286e62586bba76d37cf0", - "tapscript_root": "8406e877073ff08834e197a4034aa48afa3f85b8a62708caebbac880b5b89b93" + "raw_key": "034d4d01c1faa3fbb3300865697516d5bf23c363cec7f7b957448cf2daee003174", + "tapscript_root": "3022c1dfc579b99ed9d20d573ad53171c8fef7f1f4e4613bb365b2ebb44f0ffb" }, "alt_leaves": null, "unknown_odd_types": null @@ -1509,8 +1567,8 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 65408, - "script_key": "021cc80a15b715539063341dfbacd661eafdd2db318701ba97eb4ee897ef17e6f4", + "script_version": 54179, + "script_key": "02c26cec6f98aa274613c71c82ba7587ece74021ee5a19fb89887d11cec0dabd6b", "group_key": null, "unknown_odd_types": null }, @@ -1526,8 +1584,8 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 28333, - "script_key": "02773bdcf43714bb150e7a6de49d8f2061aceeef229d79f9cad38edd1e7299cd6c", + "script_version": 11, + "script_key": "0295ada4bfb469dd9941b5ca7b0eff9001c6ce5628b17119b17cfe8be5fdd206b8", "group_key": null, "unknown_odd_types": null }, @@ -1543,12 +1601,25 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 39423, - "script_key": "02f9ecd60d652bdfb86737ee52805a2389afb474f16cf6ca12911e71f874250236", + "script_version": 20993, + "script_key": "02aeeed1abb72bc7244e4e67c3cd89aca846eca0e3fd7e17173225685822e279cc", "group_key": null, "unknown_odd_types": null } - ] + ], + "address": { + "version": 2, + "chain_params_hrp": "tapbc", + "asset_version": 0, + "asset_id": "c73aa971902cbd9cfe0afa0ec8174823f53f1730aa0f7d5b3310273beb245d33", + "group_key": "037611a80c011704386dd3ffc063f01b6a531718a928e3ab432c082fdffd7736d3", + "script_key": "029d189748b1efb83b8244141e2d82fe6caf056edfe3106936fe16790c002e3bcf", + "internal_key": "0387d8b454acbddaa773bc216518a430990ee8a57dbc928f732d010c1889f578c9", + "tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", + "amount": 6848489594515705305, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", + "unknown_odd_types": null + } }, { "amount": 345, @@ -1556,10 +1627,10 @@ "asset_version": 1, "interactive": false, "anchor_output_index": 1, - "anchor_output_internal_key": "0252050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "anchor_output_internal_key": "022f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "anchor_output_bip32_derivation": [ { - "pub_key": "0252050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "022f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "fingerprint": 0, "bip32_path": [ 2147484665, @@ -1572,7 +1643,7 @@ ], "anchor_output_tr_bip32_derivation": [ { - "pub_key": "52050ff1a0732e70709b424af5172f9a9cab982a07a000b4f140c75a0430951f", + "pub_key": "2f0cf11d2fd0d88576d795a60e2953d6ac63f3b041c3ec44d6998711075c1cf6", "leaf_hashes": [], "fingerprint": 0, "bip32_path": [ @@ -1587,12 +1658,12 @@ "anchor_output_tapscript_sibling": "01197ce22d12bc5a99587533af41169fa1dc9ff866c0d4d3021158d62933672d11197ce22d12bc5a99587533af41169fa1dc9ff866c0d4d3021158d62933672d11", "asset": { "version": 0, - "genesis_first_prev_out": "541c3b6bd9c19e7792417fc335327a49f6d261a82947a67e52b118fa6e04f9ce:3410233680", - "genesis_tag": "c05a4b13a1d5b2f5bfef5a6ed92da482caa9568e5b6fe9d8a9ddd9eb09277b92", - "genesis_meta_hash": "c05a4b13a1d5b2f5bfef5a6ed92da482caa9568e5b6fe9d8a9ddd9eb09277b92", - "genesis_output_index": 2955392992, + "genesis_first_prev_out": "4381075b1ccd2ab86ead7e74d4b80f63d487b8e5d22bd743cfb52e3298237ef1:378678736", + "genesis_tag": "d596e685a591121966e031650d510354aa845580ff560760fd36514ca197c875", + "genesis_meta_hash": "d596e685a591121966e031650d510354aa845580ff560760fd36514ca197c875", + "genesis_output_index": 2635277229, "genesis_type": 0, - "amount": 3819700043, + "amount": 571885926, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -1603,21 +1674,21 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "60e0ee8530cdfd6191a5d1be4cd143c6d11b914b448d1e3d7ad6765eb8212f2298a751a1c8651d456cc48716dd911055363f0612ec3f616469ae994e097242ea" + "4ca1c890aec103c3aab03acf94689ba02e810c61a789b8193e829b0ef1a05dae904719a85ce82ebc4ef60f32af3d8eb08f7275c544f0cf7dc37530f3d5e7e5a9" ], "split_commitment": null } ], "split_commitment_root": null, "script_version": 0, - "script_key": "02484a4f43cefb92fd22133d26c737b94fc50ae8192d668c820afdf6428d51099c", + "script_key": "02c5cd3c536e102742945f3ec6ba3d28a46754f58c93a5cd63abf35749e852dea1", "group_key": { - "group_key": "03dffff1117719feb3a414b7b24b27f2da96be03b6f5d84c1eec8c73f1d8007640" + "group_key": "02e37fa9e3b1d3e722448a08969d7e7469f95d0820d67e3de737ce6c92c252a5f5" }, "unknown_odd_types": null }, "split_asset": null, - "pk_script": "5120484a4f43cefb92fd22133d26c737b94fc50ae8192d668c820afdf6428d51099c", + "pk_script": "5120c5cd3c536e102742945f3ec6ba3d28a46754f58c93a5cd63abf35749e852dea1", "bip32_derivation": null, "tr_bip32_derivation": null, "tr_internal_key": "", @@ -1639,8 +1710,8 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 2189, - "script_key": "02bfe47b76305b0b88d1e616278a25b2d6b52c8345e0995e8629c083f376b334e9", + "script_version": 32954, + "script_key": "02ee2afa1c5726cde276e5b9929212ac288a82daf78af86a362f31f9916165f404", "group_key": null, "unknown_odd_types": null }, @@ -1656,52 +1727,31 @@ "relative_lock_time": 0, "prev_witnesses": null, "split_commitment_root": null, - "script_version": 18714, - "script_key": "02b90d4aed8bfeb0df3e72df00b59a79fd3a84c3ef05eb884bbe46741db9f60867", - "group_key": null, - "unknown_odd_types": null - }, - { - "version": 0, - "genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0", - "genesis_tag": "", - "genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "genesis_output_index": 0, - "genesis_type": 0, - "amount": 0, - "lock_time": 0, - "relative_lock_time": 0, - "prev_witnesses": null, - "split_commitment_root": null, - "script_version": 25363, - "script_key": "02d8e759976a5a65c7d32a1130fdc595448720a248535cd8daa4991bacaf37e1a3", - "group_key": null, - "unknown_odd_types": null - }, - { - "version": 0, - "genesis_first_prev_out": "0000000000000000000000000000000000000000000000000000000000000000:0", - "genesis_tag": "", - "genesis_meta_hash": "0000000000000000000000000000000000000000000000000000000000000000", - "genesis_output_index": 0, - "genesis_type": 0, - "amount": 0, - "lock_time": 0, - "relative_lock_time": 0, - "prev_witnesses": null, - "split_commitment_root": null, - "script_version": 43751, - "script_key": "024a57bca43e2374f69dc13049b5fcb189d15151e3d1bb55d050b6a711e7d1c617", + "script_version": 7386, + "script_key": "0225025c1701d27f2855a36a2a45c088e44d6739dc6452e2f8cb7e816d9cf36cf1", "group_key": null, "unknown_odd_types": null } - ] + ], + "address": { + "version": 1, + "chain_params_hrp": "tapbc", + "asset_version": 0, + "asset_id": "cc6fc2f8b425f1b3c402fa41df82b484088df33cdf41087cab7fea57c2b1c55b", + "group_key": "03f8cc5d06497f237cab245a524c8c63c35254ea24870b6ed45f104b687571f12c", + "script_key": "02efb7e5438142d2b71466927d03a2a53f75202bd1a7cc4555cc31eff7f5c87fe1", + "internal_key": "0257849e169f0f7383d756a38917f37b0635ca4d84fc257c8ed66a5fe79c4dc41e", + "tapscript_sibling": "00c0126e6f7420612076616c696420736372697074", + "amount": 396608336029707725, + "proof_courier_addr": "authmailbox+universerpc://foo.bar:10029", + "unknown_odd_types": null + } } ], "version": 0, "chain_params_hrp": "tapbc" }, - "expected": "cHNidP8BALICAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACewAAAAAAAAAiUSBISk9DzvuS/SITPSbHN7lPxQroGS1mjIIK/fZCjVEJnFkBAAAAAAAAIlEgSEpPQ877kv0iEz0mxze5T8UK6BktZoyCCv32Qo1RCZwAAAAAAXABAQFxBXRhcGJjAXIBAAAiBgJSBQ/xoHMucHCbQkr1Fy+anKuYKgegALTxQMdaBDCVHxgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhFlIFD/Ggcy5wcJtCSvUXL5qcq5gqB6AAtPFAx1oEMJUfGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABFyBSBQ/xoHMucHCbQkr1Fy+anKuYKgegALTxQMdaBDCVHwEYC21lcmtsZSByb290AXBlZAA98kaJKNWiO5ynQPgMk4LZxgNK0pYMeWUD4c4iFyUonL0sI9cotFNH6tplCvJMVtCACoaRMyCIqAW9VcRG4l6wdZACYqaSkwxKHl+etjM6s4mjhJVdzPBpC8CVKj26ipnQxboBcQgAAAAAAAADCQFyD2FuY2hvciBwa3NjcmlwdAFzCAAAAAAAAAADAXQhAlIFD/Ggcy5wcJtCSvUXL5qcq5gqB6AAtPFAx1oEMJUfAXULbWVya2xlIHJvb3QidgJSBQ/xoHMucHCbQkr1Fy+anKuYKgegALTxQMdaBDCVHxgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhd1IFD/Ggcy5wcJtCSvUXL5qcq5gqB6AAtPFAx1oEMJUfGQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABeAdzaWJsaW5nAXn9kgEAAQECiu3tMjy3bw0/rEdsn7A/ySKPuuiP1YBmOgRUtoMSIH8KpUr3R0BmNTBjYWYxZmJmZTgzMWIxMGI3YmY1YjE1YzQ3YTUzZGJmOGU3ZGNhZmM5ZTEzODY0N2E0YjQ0ZWQ0YmNlOTY09QyvH7/oMbELe/WxXEelPb+Ofcr8nhOGR6S0TtS86WS0kmQxAAQBAAYF/nm3b78LrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUDs+XeVGpkfToDWBNv650ywwURLgZ0/tCAO7rDaWOS20rh2O3desauGAaS1jG2nnYi3p+u0LnSjWawWsyyw41QnDgIAABAhAunFXUqkd3Ojw93J0smpTJo38FANQj+eihjZSB52Wgk5ESECf18+y7G9HPwNwrj/+eBSxvNYGTThK1yFpvUvxiGke0cBev3bBlRBUFAABAAAAAACJO3tMjy3bw0/rEdsn7A/ySKPuuiP1YBmOgRUtoMSIH8KpUr3RwRQAQAAAJDwqfEQcC+Aghnr6hFzBWBCpxS61RuRbLaAAAAAAAAAUnUolVj1HJlmaZQEriKUcww8n5vaU1I85Q6bleVY2i/bJhtNTIYEGxqxv5MGnwEAAAABlmCMy6+harrakCeA2k3DXa/XrwX6DaCM+DNXX4z56DYAAAAASkkwRgIhANqySIkhPK9DrmrcQc8ck5bAgkDBmfUiWs9FQWMw/X29AiEA/jeQDgZEv1dEk6B/xe26BtvAfDEblHUgwtUUvFcl3LQB/////wEA8gUqAQAAABl2qRTxXRkh9S5AB7FG36YPNp7S/Dk84oisAAAAAAiCBKPzrGBdXkcn9Opy6TRqXVhvAjFGD9Uq2YlbyCQNhx3vUi2zOcGGwRSYQ6SEiZDm3bmmBl9LwUIq9T9LyG8bCEqJGJ/wMWzcEFEdpx2nV+VTytqfO1sUNPOSNnOttX2Dyqw5LDivFW1vwwtV+tQRLfK5VTHmgRTprRABHnL3t8/bDgr9AZYAAQACiu3tMjy3bw0/rEdsn7A/ySKPuuiP1YBmOgRUtoMSIH8KpUr3R0BmNTBjYWYxZmJmZTgzMWIxMGI3YmY1YjE1YzQ3YTUzZGJmOGU3ZGNhZmM5ZTEzODY0N2E0YjQ0ZWQ0YmNlOTY09QyvH7/oMbELe/WxXEelPb+Ofcr8nhOGR6S0TtS86WS0kmQxAAQBAAYBAQcD/QU5CQEGC60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAZdudy680OiWgBxjJ9BceMy53dEs94M4JQ6d3cOCpdJeKoImLgfaCT8WIyL3+Y1ZDq0ozS2JN9SHKNGIQW8uUKA4CAAAQIQL/F+3LHPJz8voVpr5yIFjdK+wS8RBZY95liuIIeACNCBEhArBdq/+Zqtp2r09nZyseVGT4XnLsXb0obmJYa7p203zwDKUABAAAAAACIQJ9enojA2Bhm05XSxF8is2BitchX6C4C70S0TUxA3+wsAN6AUkAAQACIEKuxY+FGzgCIEC7Xg10sqyZEVrp139xg0f8Hswjo73WBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQEN/QFOA6UABAAAAAICIQJtjqQe+ouoT9b8WvrwJpVhgu3JvB4S6YgaxfxUzdaWZwN6AUkAAQACIEKuxY+FGzgCIEC7Xg10sqyZEVrp139xg0f8Hswjo73WBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQF3AAQAAAADAiECjU/Pz/ogbunHnmQtMmKDSA1bSnPkNu2KjJkYb2kHx5YFTAFBARqsJUCKTSgjPNMl+u+t6e8Prnb8seNdCBQARbuqOBsw7vRuRjA1VmAu8TzvXS//Pcai7OZlf8keSwpbui3tTv8DBADAAQIEAQEuAAQAAAAEAiEC0FiazsUgyMH/tAZywfz1BphqYGKyZPkLUh1V5oAFkukFAwQBAQ+fAAQAAAAEAiECU6Aznr9tLhaSOscSgplmfMiFZigvixnDVVZ0ngqWQOEDdAFJAAEAAiBCrsWPhRs4AiBAu14NdLKsmRFa6dd/cYNH/B7MI6O91gQiAAD//////////////////////////////////////////wInAAEAAiIAAP//////////////////////////////////////////ER4AAQACGXF1b3RoIHRoZSByYXZlbiBuZXZlcm1vcmUVCQIDZm9vA2JhchYEAAAAKheK7e0yPLdvDT+sR2yfsD/JIo+66I/VgGY6BFS2gxIgfwqlSvdHQGY1MGNhZjFmYmZlODMxYjEwYjdiZjViMTVjNDdhNTNkYmY4ZTdkY2FmYzllMTM4NjQ3YTRiNDRlZDRiY2U5NjT1DK8fv+gxsQt79bFcR6U9v459yvyeE4ZHpLRO1LzpZLSSZDEAGUECsF2r/5mq2navT2dnKx5UZPhecuxdvShuYlhrunbTfPCEBuh3Bz/wiDThl6QDSqSK+j+FuKYnCMrrusiAtbibkwABcGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxCAAAAAAAAAAAAXIAAXMIAAAAAAAAAAABdQABeAAAAXABAQFxAQEBcggAAAAAAAAAAAFzIQJSBQ/xoHMucHCbQkr1Fy+anKuYKgegALTxQMdaBDCVHyJ0AlIFD/Ggcy5wcJtCSvUXL5qcq5gqB6AAtPFAx1oEMJUfGAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAACF1UgUP8aBzLnBwm0JK9RcvmpyrmCoHoAC08UDHWgQwlR8ZAAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAAAF2/ZIBAAEAAorO+QRu+hixUn6mRymoYdL2SXoyNcN/QZJ3nsHZazscVMtECVBAYzA1YTRiMTNhMWQ1YjJmNWJmZWY1YTZlZDkyZGE0ODJjYWE5NTY4ZTViNmZlOWQ4YTlkZGQ5ZWIwOTI3N2I5MsBaSxOh1bL1v+9abtktpILKqVaOW2/p2Knd2esJJ3uSsCe34AAEAQAGBf7jq/9LC60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAYODuhTDN/WGRpdG+TNFDxtEbkUtEjR49etZ2XrghLyKYp1GhyGUdRWzEhxbdkRBVNj8GEuw/YWRprplOCXJC6g4CAAAQIQJISk9DzvuS/SITPSbHN7lPxQroGS1mjIIK/fZCjVEJnBEhA9//8RF3Gf6zpBS3sksn8tqWvgO29dhMHuyMc/HYAHZAAXf9kgEAAQACis75BG76GLFSfqZHKahh0vZJejI1w39BkneewdlrOxxUy0QJUEBjMDVhNGIxM2ExZDViMmY1YmZlZjVhNmVkOTJkYTQ4MmNhYTk1NjhlNWI2ZmU5ZDhhOWRkZDllYjA5Mjc3YjkywFpLE6HVsvW/71pu2S2kgsqpVo5bb+nYqd3Z6wkne5KwJ7fgAAQBAAYF/uOr/0sLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUBg4O6FMM39YZGl0b5M0UPG0RuRS0SNHj161nZeuCEvIpinUaHIZR1FbMSHFt2REFU2PwYS7D9hZGmumU4JckLqDgIAABAhAkhKT0PO+5L9IhM9Jsc3uU/FCugZLWaMggr99kKNUQmcESED3//xEXcZ/rOkFLeySyfy2pa+A7b12Ewe7Ixz8dgAdkABeBUAwBJub3QgYSB2YWxpZCBzY3JpcHQBeQEBAXoTaHR0cHM6Ly9leGFtcGxlLmNvbQF7/dsGVEFQUAAEAAAAAAIk7e0yPLdvDT+sR2yfsD/JIo+66I/VgGY6BFS2gxIgfwqlSvdHBFABAAAAkPCp8RBwL4CCGevqEXMFYEKnFLrVG5FstoAAAAAAAABSdSiVWPUcmWZplASuIpRzDDyfm9pTUjzlDpuV5VjaL9smG01MhgQbGrG/kwafAQAAAAGWYIzLr6FqutqQJ4DaTcNdr9evBfoNoIz4M1dfjPnoNgAAAABKSTBGAiEA2rJIiSE8r0OuatxBzxyTlsCCQMGZ9SJaz0VBYzD9fb0CIQD+N5AOBkS/V0SToH/F7boG28B8MRuUdSDC1RS8VyXctAH/////AQDyBSoBAAAAGXapFPFdGSH1LkAHsUbfpg82ntL8OTziiKwAAAAACIIEo/OsYF1eRyf06nLpNGpdWG8CMUYP1SrZiVvIJA2HHe9SLbM5wYbBFJhDpISJkObduaYGX0vBQir1P0vIbxsISokYn/AxbNwQUR2nHadX5VPK2p87WxQ085I2c621fYPKrDksOK8VbW/DC1X61BEt8rlVMeaBFOmtEAEecve3z9sOCv0BlgABAAKK7e0yPLdvDT+sR2yfsD/JIo+66I/VgGY6BFS2gxIgfwqlSvdHQGY1MGNhZjFmYmZlODMxYjEwYjdiZjViMTVjNDdhNTNkYmY4ZTdkY2FmYzllMTM4NjQ3YTRiNDRlZDRiY2U5NjT1DK8fv+gxsQt79bFcR6U9v459yvyeE4ZHpLRO1LzpZLSSZDEABAEABgEBBwP9BTkJAQYLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUBl253LrzQ6JaAHGMn0Fx4zLnd0Sz3gzglDp3dw4Kl0l4qgiYuB9oJPxYjIvf5jVkOrSjNLYk31Ico0YhBby5QoDgIAABAhAv8X7csc8nPy+hWmvnIgWN0r7BLxEFlj3mWK4gh4AI0IESECsF2r/5mq2navT2dnKx5UZPhecuxdvShuYlhrunbTfPAMpQAEAAAAAAIhAn16eiMDYGGbTldLEXyKzYGK1yFfoLgLvRLRNTEDf7CwA3oBSQABAAIgQq7Fj4UbOAIgQLteDXSyrJkRWunXf3GDR/wezCOjvdYEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAQ39AU4DpQAEAAAAAgIhAm2OpB76i6hP1vxa+vAmlWGC7cm8HhLpiBrF/FTN1pZnA3oBSQABAAIgQq7Fj4UbOAIgQLteDXSyrJkRWunXf3GDR/wezCOjvdYEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAXcABAAAAAMCIQKNT8/P+iBu6ceeZC0yYoNIDVtKc+Q27YqMmRhvaQfHlgVMAUEBGqwlQIpNKCM80yX6763p7w+udvyx410IFABFu6o4GzDu9G5GMDVWYC7xPO9dL/89xqLs5mV/yR5LClu6Le1O/wMEAMABAgQBAS4ABAAAAAQCIQLQWJrOxSDIwf+0BnLB/PUGmGpgYrJk+QtSHVXmgAWS6QUDBAEBD58ABAAAAAQCIQJToDOev20uFpI6xxKCmWZ8yIVmKC+LGcNVVnSeCpZA4QN0AUkAAQACIEKuxY+FGzgCIEC7Xg10sqyZEVrp139xg0f8Hswjo73WBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8RHgABAAIZcXVvdGggdGhlIHJhdmVuIG5ldmVybW9yZRUJAgNmb28DYmFyFgQAAAAqF4rt7TI8t28NP6xHbJ+wP8kij7roj9WAZjoEVLaDEiB/CqVK90dAZjUwY2FmMWZiZmU4MzFiMTBiN2JmNWIxNWM0N2E1M2RiZjhlN2RjYWZjOWUxMzg2NDdhNGI0NGVkNGJjZTk2NPUMrx+/6DGxC3v1sVxHpT2/jn3K/J4ThkektE7UvOlktJJkMQAZQQKwXav/maradq9PZ2crHlRk+F5y7F29KG5iWGu6dtN88IQG6HcHP/CINOGXpANKpIr6P4W4picIyuu6yIC1uJuTAXwIAAAAAAAAAcgBfQgAAAAAAAABWQF+eQMnDgL/gBAhAhzIChW3FVOQYzQd+6zWYer90tsxhwG6l+tO6JfvF+b0Jw4Cbq0QIQJ3O9z0NxS7FQ56beSdjyBhrO7vIp15+crTjt0ecpnNbCcOApn/ECEC+ezWDWUr37hnN+5SgFojia+0dPFs9soSkR5x+HQlAjYAAXABAQFxAQABcggAAAAAAAAAAQFzIQJSBQ/xoHMucHCbQkr1Fy+anKuYKgegALTxQMdaBDCVHyJ0AlIFD/Ggcy5wcJtCSvUXL5qcq5gqB6AAtPFAx1oEMJUfGAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAACF1UgUP8aBzLnBwm0JK9RcvmpyrmCoHoAC08UDHWgQwlR8ZAAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAAAF2/ZIBAAEAAorO+QRu+hixUn6mRymoYdL2SXoyNcN/QZJ3nsHZazscVMtECVBAYzA1YTRiMTNhMWQ1YjJmNWJmZWY1YTZlZDkyZGE0ODJjYWE5NTY4ZTViNmZlOWQ4YTlkZGQ5ZWIwOTI3N2I5MsBaSxOh1bL1v+9abtktpILKqVaOW2/p2Knd2esJJ3uSsCe34AAEAQAGBf7jq/9LC60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFAYODuhTDN/WGRpdG+TNFDxtEbkUtEjR49etZ2XrghLyKYp1GhyGUdRWzEhxbdkRBVNj8GEuw/YWRprplOCXJC6g4CAAAQIQJISk9DzvuS/SITPSbHN7lPxQroGS1mjIIK/fZCjVEJnBEhA9//8RF3Gf6zpBS3sksn8tqWvgO29dhMHuyMc/HYAHZAAXhBARl84i0SvFqZWHUzr0EWn6Hcn/hmwNTTAhFY1ikzZy0RGXziLRK8WplYdTOvQRafodyf+GbA1NMCEVjWKTNnLREBeQEBAXwIAAAAAAAAAAABfQgAAAAAAAAAAAF+oQQnDgIIjRAhAr/ke3YwWwuI0eYWJ4olsta1LINF4JlehinAg/N2szTpJw4CSRoQIQK5DUrti/6w3z5y3wC1mnn9OoTD7wXriEu+RnQdufYIZycOAmMTECEC2OdZl2paZcfTKhEw/cWVRIcgokhTXNjapJkbrK834aMnDgKq5xAhAkpXvKQ+I3T2ncEwSbX8sYnRUVHj0btV0FC2pxHn0cYXAA==", + "expected": "cHNidP8BALICAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACewAAAAAAAAAiUSDFzTxTbhAnQpRfPsa6PSikZ1T1jJOlzWOr81dJ6FLeoVkBAAAAAAAAIlEgxc08U24QJ0KUXz7Guj0opGdU9YyTpc1jq/NXSehS3qEAAAAAAXABAQFxBXRhcGJjAXIBAAAiBgIvDPEdL9DYhXbXlaYOKVPWrGPzsEHD7ETWmYcRB1wc9hgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhFi8M8R0v0NiFdteVpg4pU9asY/OwQcPsRNaZhxEHXBz2GQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABFyAvDPEdL9DYhXbXlaYOKVPWrGPzsEHD7ETWmYcRB1wc9gEYC21lcmtsZSByb290AXBlyoxeuT0WdsG90Zq44pJcba7k3l75+dzwjfy9ArgICTnBLRVOICWmDH3TiZ2SDpXxxG1DL5sI5k1/mziWXVp3p6wYPDgCYYIXsmRiZT21RWWDNeleuvd1EdAEU/dWM6uVaQrVxwMBcQgAAAAAAAADCQFyD2FuY2hvciBwa3NjcmlwdAFzCAAAAAAAAAADAXQhAi8M8R0v0NiFdteVpg4pU9asY/OwQcPsRNaZhxEHXBz2AXULbWVya2xlIHJvb3QidgIvDPEdL9DYhXbXlaYOKVPWrGPzsEHD7ETWmYcRB1wc9hgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhdy8M8R0v0NiFdteVpg4pU9asY/OwQcPsRNaZhxEHXBz2GQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABeAdzaWJsaW5nAXn9kgEAAQACisQAza53uh0lmxiKSyHIb7wj1yi0U0fq2mUK8kxW0IAKXgzm5UA4NTg1OTI4YTBmN2RlNTBiZTFhNmRjMWQ1NzY4ZTg1Mzc5ODhmZGRjZTU2MmU5Yjk0OGM5MThiYmEzZTkzM2U1hYWSig995QvhptwdV2joU3mI/dzlYum5SMkYu6PpM+XEVb0FAAQBAAYF/sVrqcQLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUAY+n4t/fed+nuB2kuvmogAn/Wh+8jKD3JameK0knCjC6qyrkqspdx4DmBbwhzYL0ek6zwtab/L9SoBa9V4z6dIDgIAABAhA/vqxCanqbTPM9+eyxV74pOMXYK9ADlJOijXd7V7r8lLESEC3xfI5/H2q6sIKvc3s2/EJQFa0wz5tX1hCJ3XYY06Jo0Bev3bBlRBUFAABAAAAAACJMQAza53uh0lmxiKSyHIb7wj1yi0U0fq2mUK8kxW0IAKXgzm5QRQAQAAAJDwqfEQcC+Aghnr6hFzBWBCpxS61RuRbLaAAAAAAAAAUnUolVj1HJlmaZQEriKUcww8n5vaU1I85Q6bleVY2i/bJhtNTIYEGxqxv5MGnwEAAAABlmCMy6+harrakCeA2k3DXa/XrwX6DaCM+DNXX4z56DYAAAAASkkwRgIhANqySIkhPK9DrmrcQc8ck5bAgkDBmfUiWs9FQWMw/X29AiEA/jeQDgZEv1dEk6B/xe26BtvAfDEblHUgwtUUvFcl3LQB/////wEA8gUqAQAAABl2qRTxXRkh9S5AB7FG36YPNp7S/Dk84oisAAAAAAiCBKPzrGBdXkcn9Opy6TRqXVhvAjFGD9Uq2YlbyCQNhx3vUi2zOcGGwRSYQ6SEiZDm3bmmBl9LwUIq9T9LyG8bCEqJGJ/wMWzcEFEdpx2nV+VTytqfO1sUNPOSNnOttX2Dyqw5LDivFW1vwwtV+tQRLfK5VTHmgRTprRABHnL3t8/bDgr9AZYAAQACisQAza53uh0lmxiKSyHIb7wj1yi0U0fq2mUK8kxW0IAKXgzm5UA4NTg1OTI4YTBmN2RlNTBiZTFhNmRjMWQ1NzY4ZTg1Mzc5ODhmZGRjZTU2MmU5Yjk0OGM5MThiYmEzZTkzM2U1hYWSig995QvhptwdV2joU3mI/dzlYum5SMkYu6PpM+XEVb0FAAQBAAYBAQcD/QU5CQEGC60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFA1lBPwea3wD1/JfAK/xOmLqWsF9m7zdV0espSzxb79eb7MLVQVOWUuu/bOcpMjBJx2nKyyhXuft0XpMasM6+kjQ4CAAAQIQI84qq5p8iK/b1E3K4UB5kfjhBU3QoeA8NU7BSdkZbDMBEhA01NAcH6o/uzMAhlaXUW1b8jw2POx/e5V0SM8truADF0DKUABAAAAAACIQLQ02hbgHupZAwoOApFU1tX5GwPohPpS780TKX8eWBkUQN6AUkAAQACICUSD1E6WcClK0jUjcfUXnWG48Bo3C/QvgsQjQGBTKpyBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQEN/QFOA6UABAAAAAICIQKTuz5cGHR05ZqyqJOo3MDARRslE8Ys77JBU8TItoExzQN6AUkAAQACICUSD1E6WcClK0jUjcfUXnWG48Bo3C/QvgsQjQGBTKpyBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8FBADAAQF3AAQAAAADAiECIb9WmGGt2buXR78tV26JyVimni3eJECs91sIKDmmVHAFTAFBARqsJUCKTSgjPNMl+u+t6e8Prnb8seNdCBQARbuqOBsw7vRuRjA1VmAu8TzvXS//Pcai7OZlf8keSwpbui3tTv8DBADAAQIEAQEuAAQAAAAEAiECf4hn0pFFO+Q6WBBYyMZx7e1Wm/mkny21Kmb/KxGhni0FAwQBAQ+fAAQAAAAEAiECKcpWOrscW08IyUyE2JqzQD0djD+gpCrp9f8vPdgFEysDdAFJAAEAAiAlEg9ROlnApStI1I3H1F51huPAaNwv0L4LEI0BgUyqcgQiAAD//////////////////////////////////////////wInAAEAAiIAAP//////////////////////////////////////////ER4AAQACGXF1b3RoIHRoZSByYXZlbiBuZXZlcm1vcmUVCQIDZm9vA2JhchYEAAAAKheKxADNrne6HSWbGIpLIchvvCPXKLRTR+raZQryTFbQgApeDOblQDg1ODU5MjhhMGY3ZGU1MGJlMWE2ZGMxZDU3NjhlODUzNzk4OGZkZGNlNTYyZTliOTQ4YzkxOGJiYTNlOTMzZTWFhZKKD33lC+Gm3B1XaOhTeYj93OVi6blIyRi7o+kz5cRVvQUAGUEDTU0Bwfqj+7MwCGVpdRbVvyPDY87H97lXRIzy2u4AMXQwIsHfxXm5ntnSDVc61TFxyP738fTkYTuzZbLrtE8P+wABcGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFxCAAAAAAAAAAAAXIAAXMIAAAAAAAAAAABdQABeAAAAXABAQFxAQEBcggAAAAAAAAAAAFzIQIvDPEdL9DYhXbXlaYOKVPWrGPzsEHD7ETWmYcRB1wc9iJ0Ai8M8R0v0NiFdteVpg4pU9asY/OwQcPsRNaZhxEHXBz2GAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAACF1LwzxHS/Q2IV215WmDilT1qxj87BBw+xE1pmHEQdcHPYZAAAAAAD5AwCAAAAAgHsAAIAAAAAAyAEAAAF2/ZIBAAEAAorxfiOYMi61z0PXK9LluIfUYw+41HR+rW64Ks0cWweBQxaSLdBAZDU5NmU2ODVhNTkxMTIxOTY2ZTAzMTY1MGQ1MTAzNTRhYTg0NTU4MGZmNTYwNzYwZmQzNjUxNGNhMTk3Yzg3NdWW5oWlkRIZZuAxZQ1RA1SqhFWA/1YHYP02UUyhl8h1nRMjrQAEAQAGBf4iFklmC60BqwFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQgFATKHIkK7BA8OqsDrPlGiboC6BDGGnibgZPoKbDvGgXa6QRxmoXOguvE72DzKvPY6wj3J1xUTwz33DdTDz1eflqQ4CAAAQIQLFzTxTbhAnQpRfPsa6PSikZ1T1jJOlzWOr81dJ6FLeoREhAuN/qeOx0+ciRIoIlp1+dGn5XQgg1n495zfObJLCUqX1AXf9kgEAAQACivF+I5gyLrXPQ9cr0uW4h9RjD7jUdH6tbrgqzRxbB4FDFpIt0EBkNTk2ZTY4NWE1OTExMjE5NjZlMDMxNjUwZDUxMDM1NGFhODQ1NTgwZmY1NjA3NjBmZDM2NTE0Y2ExOTdjODc11ZbmhaWREhlm4DFlDVEDVKqEVYD/Vgdg/TZRTKGXyHWdEyOtAAQBAAYF/iIWSWYLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUBMociQrsEDw6qwOs+UaJugLoEMYaeJuBk+gpsO8aBdrpBHGahc6C68TvYPMq89jrCPcnXFRPDPfcN1MPPV5+WpDgIAABAhAsXNPFNuECdClF8+xro9KKRnVPWMk6XNY6vzV0noUt6hESEC43+p47HT5yJEigiWnX50afldCCDWfj3nN85sksJSpfUBeBUAwBJub3QgYSB2YWxpZCBzY3JpcHQBeQEAAXoTaHR0cHM6Ly9leGFtcGxlLmNvbQF7/dsGVEFQUAAEAAAAAAIkxADNrne6HSWbGIpLIchvvCPXKLRTR+raZQryTFbQgApeDOblBFABAAAAkPCp8RBwL4CCGevqEXMFYEKnFLrVG5FstoAAAAAAAABSdSiVWPUcmWZplASuIpRzDDyfm9pTUjzlDpuV5VjaL9smG01MhgQbGrG/kwafAQAAAAGWYIzLr6FqutqQJ4DaTcNdr9evBfoNoIz4M1dfjPnoNgAAAABKSTBGAiEA2rJIiSE8r0OuatxBzxyTlsCCQMGZ9SJaz0VBYzD9fb0CIQD+N5AOBkS/V0SToH/F7boG28B8MRuUdSDC1RS8VyXctAH/////AQDyBSoBAAAAGXapFPFdGSH1LkAHsUbfpg82ntL8OTziiKwAAAAACIIEo/OsYF1eRyf06nLpNGpdWG8CMUYP1SrZiVvIJA2HHe9SLbM5wYbBFJhDpISJkObduaYGX0vBQir1P0vIbxsISokYn/AxbNwQUR2nHadX5VPK2p87WxQ085I2c621fYPKrDksOK8VbW/DC1X61BEt8rlVMeaBFOmtEAEecve3z9sOCv0BlgABAAKKxADNrne6HSWbGIpLIchvvCPXKLRTR+raZQryTFbQgApeDOblQDg1ODU5MjhhMGY3ZGU1MGJlMWE2ZGMxZDU3NjhlODUzNzk4OGZkZGNlNTYyZTliOTQ4YzkxOGJiYTNlOTMzZTWFhZKKD33lC+Gm3B1XaOhTeYj93OVi6blIyRi7o+kz5cRVvQUABAEABgEBBwP9BTkJAQYLrQGrAWUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANCAUDWUE/B5rfAPX8l8Ar/E6YupawX2bvN1XR6ylLPFvv15vswtVBU5ZS679s5ykyMEnHacrLKFe5+3Rekxqwzr6SNDgIAABAhAjziqrmnyIr9vUTcrhQHmR+OEFTdCh4Dw1TsFJ2RlsMwESEDTU0Bwfqj+7MwCGVpdRbVvyPDY87H97lXRIzy2u4AMXQMpQAEAAAAAAIhAtDTaFuAe6lkDCg4CkVTW1fkbA+iE+lLvzRMpfx5YGRRA3oBSQABAAIgJRIPUTpZwKUrSNSNx9RedYbjwGjcL9C+CxCNAYFMqnIEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAQ39AU4DpQAEAAAAAgIhApO7PlwYdHTlmrKok6jcwMBFGyUTxizvskFTxMi2gTHNA3oBSQABAAIgJRIPUTpZwKUrSNSNx9RedYbjwGjcL9C+CxCNAYFMqnIEIgAA//////////////////////////////////////////8CJwABAAIiAAD//////////////////////////////////////////wUEAMABAXcABAAAAAMCIQIhv1aYYa3Zu5dHvy1XbonJWKaeLd4kQKz3WwgoOaZUcAVMAUEBGqwlQIpNKCM80yX6763p7w+udvyx410IFABFu6o4GzDu9G5GMDVWYC7xPO9dL/89xqLs5mV/yR5LClu6Le1O/wMEAMABAgQBAS4ABAAAAAQCIQJ/iGfSkUU75DpYEFjIxnHt7Vab+aSfLbUqZv8rEaGeLQUDBAEBD58ABAAAAAQCIQIpylY6uxxbTwjJTITYmrNAPR2MP6CkKun1/y892AUTKwN0AUkAAQACICUSD1E6WcClK0jUjcfUXnWG48Bo3C/QvgsQjQGBTKpyBCIAAP//////////////////////////////////////////AicAAQACIgAA//////////////////////////////////////////8RHgABAAIZcXVvdGggdGhlIHJhdmVuIG5ldmVybW9yZRUJAgNmb28DYmFyFgQAAAAqF4rEAM2ud7odJZsYikshyG+8I9cotFNH6tplCvJMVtCACl4M5uVAODU4NTkyOGEwZjdkZTUwYmUxYTZkYzFkNTc2OGU4NTM3OTg4ZmRkY2U1NjJlOWI5NDhjOTE4YmJhM2U5MzNlNYWFkooPfeUL4abcHVdo6FN5iP3c5WLpuUjJGLuj6TPlxFW9BQAZQQNNTQHB+qP7szAIZWl1FtW/I8Njzsf3uVdEjPLa7gAxdDAiwd/Febme2dINVzrVMXHI/vfx9ORhO7Nlsuu0Tw/7AXwIAAAAAAAAAcgBfQgAAAAAAAABWQF+eQMnDgLToxAhAsJs7G+YqidGE8ccgrp1h+znQCHuWhn7iYh9Ec7A2r1rJw4CAAsQIQKVraS/tGndmUG1ynsO/5ABxs5WKLFxGbF8/ovl/dIGuCcOAlIBECECru7Rq7crxyROTmfDzYmsqEbsoOP9fhcXMiVoWCLiecwBf9wAAQICAQAEIMc6qXGQLL2c/gr6DsgXSCP1Pxcwqg99WzMQJzvrJF0zBSEDdhGoDAEXBDht0//AY/AbalMXGKko46tDLAgv3/13NtMGIQKdGJdIse+4O4JEFB4tgv5srwVu3+MQaTb+FnkMAC47zwghA4fYtFSsvdqnc7whZRikMJkO6KV9vJKPcy0BDBiJ9XjJCRUAwBJub3QgYSB2YWxpZCBzY3JpcHQKCf9fCrkAWRFN2QwnYXV0aG1haWxib3grdW5pdmVyc2VycGM6Ly9mb28uYmFyOjEwMDI5AAFwAQEBcQEAAXIIAAAAAAAAAAEBcyECLwzxHS/Q2IV215WmDilT1qxj87BBw+xE1pmHEQdcHPYidAIvDPEdL9DYhXbXlaYOKVPWrGPzsEHD7ETWmYcRB1wc9hgAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAAhdS8M8R0v0NiFdteVpg4pU9asY/OwQcPsRNaZhxEHXBz2GQAAAAAA+QMAgAAAAIB7AACAAAAAAMgBAAABdv2SAQABAAKK8X4jmDIutc9D1yvS5biH1GMPuNR0fq1uuCrNHFsHgUMWki3QQGQ1OTZlNjg1YTU5MTEyMTk2NmUwMzE2NTBkNTEwMzU0YWE4NDU1ODBmZjU2MDc2MGZkMzY1MTRjYTE5N2M4NzXVluaFpZESGWbgMWUNUQNUqoRVgP9WB2D9NlFMoZfIdZ0TI60ABAEABgX+IhZJZgutAasBZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0IBQEyhyJCuwQPDqrA6z5Rom6AugQxhp4m4GT6Cmw7xoF2ukEcZqFzoLrxO9g8yrz2OsI9ydcVE8M99w3Uw89Xn5akOAgAAECECxc08U24QJ0KUXz7Guj0opGdU9YyTpc1jq/NXSehS3qERIQLjf6njsdPnIkSKCJadfnRp+V0IINZ+Pec3zmySwlKl9QF4QQEZfOItErxamVh1M69BFp+h3J/4ZsDU0wIRWNYpM2ctERl84i0SvFqZWHUzr0EWn6Hcn/hmwNTTAhFY1ikzZy0RAXkBAQF8CAAAAAAAAAAAAX0IAAAAAAAAAAABflECJw4CgLoQIQLuKvocVybN4nbluZKSEqwoioLa94r4ajYvMfmRYWX0BCcOAhzaECECJQJcFwHSfyhVo2oqRcCI5E1nOdxkUuL4y36BbZzzbPEBf9wAAQECAQAEIMxvwvi0JfGzxAL6Qd+CtIQIjfM830EIfKt/6lfCscVbBSED+MxdBkl/I3yrJFpSTIxjw1JU6iSHC27UXxBLaHVx8SwGIQLvt+VDgULStxRmkn0DoqU/dSAr0afMRVXMMe/39ch/4QghAleEnhafD3OD11ajiRfzewY1yk2E/CV8jtZqX+ecTcQeCRUAwBJub3QgYSB2YWxpZCBzY3JpcHQKCf8FgQkuKAJtzQwnYXV0aG1haWxib3grdW5pdmVyc2VycGM6Ly9mb28uYmFyOjEwMDI5AA==", "comment": "random packet with no explicit version" } ], diff --git a/taprpc/assetwalletrpc/assetwallet.pb.go b/taprpc/assetwalletrpc/assetwallet.pb.go index f73bb7252..b50b2fd91 100644 --- a/taprpc/assetwalletrpc/assetwallet.pb.go +++ b/taprpc/assetwalletrpc/assetwallet.pb.go @@ -256,9 +256,20 @@ type TxTemplate struct { // If no inputs are specified, asset coin selection will be performed instead // and inputs of sufficient value will be added to the resulting PSBT. Inputs []*PrevId `protobuf:"bytes,1,rep,name=inputs,proto3" json:"inputs,omitempty"` - // A map of all Taproot Asset addresses mapped to the anchor transaction's - // output index that should be sent to. + // DEPRECATED: A map of all Taproot Asset addresses that should be sent to. + // The keys are the Taproot Asset addresses in human-readable form, and the + // values are IGNORED and should not be set (use the addresses_with_amounts + // field below instead). The recipients map and addresses_with_amounts list + // are mutually exclusive, meaning that if addresses_with_amounts is set, then + // recipients must be empty, and vice versa. Recipients map[string]uint64 `protobuf:"bytes,2,rep,name=recipients,proto3" json:"recipients,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + // A list of addresses and the amounts of asset units to send to them. This + // must be used for V2 TAP addresses that don't specify an amount in the + // address itself and allow the sender to choose the amount to send. The + // recipients and addresses_with_amounts lists are mutually exclusive, + // meaning that if addresses_with_amounts is set, then recipients must be + // empty, and vice versa. + AddressesWithAmounts []*taprpc.AddressWithAmount `protobuf:"bytes,3,rep,name=addresses_with_amounts,json=addressesWithAmounts,proto3" json:"addresses_with_amounts,omitempty"` } func (x *TxTemplate) Reset() { @@ -307,6 +318,13 @@ func (x *TxTemplate) GetRecipients() map[string]uint64 { return nil } +func (x *TxTemplate) GetAddressesWithAmounts() []*taprpc.AddressWithAmount { + if x != nil { + return x.AddressesWithAmounts + } + return nil +} + type PrevId struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1809,7 +1827,7 @@ var file_assetwalletrpc_assetwallet_proto_rawDesc = []byte{ 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x69, - 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x50, 0x73, 0x62, 0x74, 0x73, 0x22, 0xc7, 0x01, 0x0a, + 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x50, 0x73, 0x62, 0x74, 0x73, 0x22, 0x98, 0x02, 0x0a, 0x0a, 0x54, 0x78, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x72, 0x65, @@ -1818,280 +1836,285 @@ var file_assetwalletrpc_assetwallet_proto_rawDesc = []byte{ 0x2a, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x78, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x72, 0x65, 0x63, - 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x52, 0x65, 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, 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, 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, 0xc5, 0x03, 0x0a, 0x19, - 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 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, 0x12, 0x2e, - 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, - 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x70, 0x61, 0x73, - 0x73, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x50, 0x73, 0x62, 0x74, 0x73, 0x12, 0x1f, - 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x03, 0x20, + 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x4f, 0x0a, 0x16, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x57, 0x69, 0x74, 0x68, 0x41, 0x6d, 0x6f, 0x75, + 0x6e, 0x74, 0x52, 0x14, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x57, 0x69, 0x74, + 0x68, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x52, 0x65, 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, 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, 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, 0xc5, 0x03, 0x0a, + 0x19, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 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, 0x12, + 0x2e, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, + 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x70, 0x61, + 0x73, 0x73, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x50, 0x73, 0x62, 0x74, 0x73, 0x12, + 0x1f, 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, + 0x12, 0x34, 0x0a, 0x15, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, + 0x00, 0x52, 0x13, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, + 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x64, 0x64, 0x12, 0x21, 0x0a, 0x0b, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x48, + 0x01, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x24, 0x0a, + 0x0d, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, + 0x79, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6c, 0x6f, + 0x63, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x4c, 0x6f, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x6c, 0x6f, 0x63, 0x6b, + 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x75, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x42, 0x16, 0x0a, 0x14, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x06, 0x0a, 0x04, + 0x66, 0x65, 0x65, 0x73, 0x22, 0xfe, 0x01, 0x0a, 0x1a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x56, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x73, + 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, + 0x50, 0x73, 0x62, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, + 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x61, 0x73, + 0x73, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x50, 0x73, 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3a, 0x0a, 0x10, 0x6c, 0x6e, 0x64, + 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, + 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0e, 0x6c, 0x6e, 0x64, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x55, 0x74, 0x78, 0x6f, 0x73, 0x22, 0xc7, 0x02, 0x0a, 0x14, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x41, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, + 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, 0x12, - 0x34, 0x0a, 0x15, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, - 0x52, 0x13, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x48, 0x00, 0x52, 0x03, 0x61, 0x64, 0x64, 0x12, 0x21, 0x0a, 0x0b, 0x74, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x01, - 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x24, 0x0a, 0x0d, - 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x62, 0x79, 0x74, 0x65, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x0b, 0x73, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x62, 0x79, - 0x74, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6c, 0x6f, 0x63, - 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x4c, 0x6f, 0x63, 0x6b, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x17, 0x6c, 0x6f, 0x63, 0x6b, - 0x5f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x63, 0x6f, - 0x6e, 0x64, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x6c, 0x6f, 0x63, 0x6b, 0x45, - 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, - 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x66, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x6b, 0x69, 0x70, 0x46, 0x75, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x42, 0x16, 0x0a, 0x14, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x06, 0x0a, 0x04, 0x66, - 0x65, 0x65, 0x73, 0x22, 0xfe, 0x01, 0x0a, 0x1a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x56, 0x69, - 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x73, 0x62, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x50, - 0x73, 0x62, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x70, - 0x73, 0x62, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, - 0x69, 0x76, 0x65, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x50, 0x73, 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3a, 0x0a, 0x10, 0x6c, 0x6e, 0x64, 0x5f, - 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, - 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0e, 0x6c, 0x6e, 0x64, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x55, - 0x74, 0x78, 0x6f, 0x73, 0x22, 0xc7, 0x02, 0x0a, 0x14, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, - 0x41, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, 0x12, 0x23, - 0x0a, 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, - 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x61, - 0x73, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, - 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x50, 0x73, - 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x3a, 0x0a, 0x10, 0x6c, 0x6e, 0x64, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x65, - 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, - 0x0e, 0x6c, 0x6e, 0x64, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x12, - 0x37, 0x0a, 0x18, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x74, - 0x78, 0x5f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x15, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x54, 0x78, 0x42, - 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, - 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 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, + 0x23, 0x0a, 0x0d, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, + 0x73, 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x5f, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x11, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x50, + 0x73, 0x62, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3a, 0x0a, 0x10, 0x6c, 0x6e, 0x64, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, + 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, + 0x52, 0x0e, 0x6c, 0x6e, 0x64, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x73, + 0x12, 0x37, 0x0a, 0x18, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, + 0x74, 0x78, 0x5f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x15, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x54, 0x78, + 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 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, + 0x3c, 0x0a, 0x17, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x22, 0x54, 0x0a, + 0x18, 0x51, 0x75, 0x65, 0x72, 0x79, 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, 0x45, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, + 0x74, 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x74, 0x77, 0x65, 0x61, 0x6b, 0x65, + 0x64, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x4a, 0x0a, 0x16, 0x51, 0x75, + 0x65, 0x72, 0x79, 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, 0xa2, 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, 0x12, 0x1c, 0x0a, + 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 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, 0x69, 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, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, + 0x6e, 0x67, 0x65, 0x22, 0xf8, 0x01, 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, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x02, 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, 0x21, 0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, + 0x73, 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, + 0x61, 0x73, 0x68, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, + 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x53, 0x74, 0x72, 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, 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, 0x22, 0x4b, 0x0a, 0x17, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 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, 0x3c, - 0x0a, 0x17, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, - 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x22, 0x54, 0x0a, 0x18, - 0x51, 0x75, 0x65, 0x72, 0x79, 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, 0x45, 0x0a, 0x15, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x74, - 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x74, 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x4a, 0x0a, 0x16, 0x51, 0x75, 0x65, - 0x72, 0x79, 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, 0xa2, 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, 0x12, 0x1c, 0x0a, 0x09, - 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 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, 0x69, 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, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, - 0x67, 0x65, 0x22, 0xf8, 0x01, 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, 0x12, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x18, 0x02, 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, 0x21, 0x0a, 0x0c, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x73, - 0x74, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x53, 0x74, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x5f, 0x73, 0x74, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x53, 0x74, 0x72, 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, 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, - 0x22, 0x4b, 0x0a, 0x17, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 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, 0x4c, 0x0a, - 0x18, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 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, 0x2a, 0x6b, 0x0a, 0x0e, 0x43, - 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, - 0x13, 0x43, 0x4f, 0x49, 0x4e, 0x5f, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, 0x44, 0x45, 0x46, - 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x49, 0x4e, 0x5f, 0x53, - 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, 0x42, 0x49, 0x50, 0x38, 0x36, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, - 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x43, 0x4f, 0x49, 0x4e, 0x5f, 0x53, 0x45, 0x4c, 0x45, 0x43, - 0x54, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x52, 0x45, 0x45, 0x53, 0x5f, 0x41, - 0x4c, 0x4c, 0x4f, 0x57, 0x45, 0x44, 0x10, 0x02, 0x32, 0xb0, 0x0a, 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, 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, 0x6b, 0x0a, 0x12, - 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 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, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, - 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x15, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x41, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, - 0x65, 0x72, 0x12, 0x24, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x41, 0x6e, 0x64, 0x4c, 0x6f, - 0x67, 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, + 0x4b, 0x65, 0x79, 0x52, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x4c, + 0x0a, 0x18, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 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, 0x2a, 0x6b, 0x0a, 0x0e, + 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, + 0x0a, 0x13, 0x43, 0x4f, 0x49, 0x4e, 0x5f, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, 0x44, 0x45, + 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x4f, 0x49, 0x4e, 0x5f, + 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x5f, 0x42, 0x49, 0x50, 0x38, 0x36, 0x5f, 0x4f, 0x4e, 0x4c, + 0x59, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x43, 0x4f, 0x49, 0x4e, 0x5f, 0x53, 0x45, 0x4c, 0x45, + 0x43, 0x54, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x54, 0x52, 0x45, 0x45, 0x53, 0x5f, + 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x45, 0x44, 0x10, 0x02, 0x32, 0xb0, 0x0a, 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, 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, 0x6b, 0x0a, + 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 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, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, + 0x61, 0x6c, 0x50, 0x73, 0x62, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 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, 0x65, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, - 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x73, 0x62, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x58, 0x0a, 0x15, 0x50, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x68, 0x41, 0x6e, 0x64, 0x4c, 0x6f, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x41, 0x6e, 0x64, 0x4c, + 0x6f, 0x67, 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, 0x65, 0x0a, 0x10, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x2e, 0x61, 0x73, 0x73, + 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, + 0x0e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, + 0x25, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, + 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 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, 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, 0x12, 0x65, 0x0a, 0x10, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, + 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6c, 0x61, + 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x25, - 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, - 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 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, - 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, 0x12, 0x65, 0x0a, 0x10, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x53, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x27, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, - 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x28, 0x2e, 0x61, 0x73, 0x73, 0x65, 0x74, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x4b, 0x65, 0x79, 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, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x65, 0x53, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x4b, 0x65, 0x79, 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 ( @@ -2137,59 +2160,61 @@ var file_assetwalletrpc_assetwallet_proto_goTypes = []any{ (*DeclareScriptKeyRequest)(nil), // 25: assetwalletrpc.DeclareScriptKeyRequest (*DeclareScriptKeyResponse)(nil), // 26: assetwalletrpc.DeclareScriptKeyResponse nil, // 27: assetwalletrpc.TxTemplate.RecipientsEntry - (*taprpc.OutPoint)(nil), // 28: taprpc.OutPoint - (*taprpc.KeyDescriptor)(nil), // 29: taprpc.KeyDescriptor - (*taprpc.ScriptKey)(nil), // 30: taprpc.ScriptKey - (*taprpc.SendAssetResponse)(nil), // 31: taprpc.SendAssetResponse + (*taprpc.AddressWithAmount)(nil), // 28: taprpc.AddressWithAmount + (*taprpc.OutPoint)(nil), // 29: taprpc.OutPoint + (*taprpc.KeyDescriptor)(nil), // 30: taprpc.KeyDescriptor + (*taprpc.ScriptKey)(nil), // 31: taprpc.ScriptKey + (*taprpc.SendAssetResponse)(nil), // 32: taprpc.SendAssetResponse } var file_assetwalletrpc_assetwallet_proto_depIdxs = []int32{ 3, // 0: assetwalletrpc.FundVirtualPsbtRequest.raw:type_name -> assetwalletrpc.TxTemplate 0, // 1: assetwalletrpc.FundVirtualPsbtRequest.coin_select_type:type_name -> assetwalletrpc.CoinSelectType 4, // 2: assetwalletrpc.TxTemplate.inputs:type_name -> assetwalletrpc.PrevId 27, // 3: assetwalletrpc.TxTemplate.recipients:type_name -> assetwalletrpc.TxTemplate.RecipientsEntry - 28, // 4: assetwalletrpc.PrevId.outpoint:type_name -> taprpc.OutPoint - 28, // 5: assetwalletrpc.CommitVirtualPsbtsResponse.lnd_locked_utxos:type_name -> taprpc.OutPoint - 28, // 6: assetwalletrpc.PublishAndLogRequest.lnd_locked_utxos:type_name -> taprpc.OutPoint - 29, // 7: assetwalletrpc.NextInternalKeyResponse.internal_key:type_name -> taprpc.KeyDescriptor - 30, // 8: assetwalletrpc.NextScriptKeyResponse.script_key:type_name -> taprpc.ScriptKey - 29, // 9: assetwalletrpc.QueryInternalKeyResponse.internal_key:type_name -> taprpc.KeyDescriptor - 30, // 10: assetwalletrpc.QueryScriptKeyResponse.script_key:type_name -> taprpc.ScriptKey - 28, // 11: assetwalletrpc.ProveAssetOwnershipRequest.outpoint:type_name -> taprpc.OutPoint - 28, // 12: assetwalletrpc.VerifyAssetOwnershipResponse.outpoint:type_name -> taprpc.OutPoint - 28, // 13: assetwalletrpc.RemoveUTXOLeaseRequest.outpoint:type_name -> taprpc.OutPoint - 30, // 14: assetwalletrpc.DeclareScriptKeyRequest.script_key:type_name -> taprpc.ScriptKey - 30, // 15: assetwalletrpc.DeclareScriptKeyResponse.script_key:type_name -> taprpc.ScriptKey - 1, // 16: assetwalletrpc.AssetWallet.FundVirtualPsbt:input_type -> assetwalletrpc.FundVirtualPsbtRequest - 5, // 17: assetwalletrpc.AssetWallet.SignVirtualPsbt:input_type -> assetwalletrpc.SignVirtualPsbtRequest - 7, // 18: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:input_type -> assetwalletrpc.AnchorVirtualPsbtsRequest - 8, // 19: assetwalletrpc.AssetWallet.CommitVirtualPsbts:input_type -> assetwalletrpc.CommitVirtualPsbtsRequest - 10, // 20: assetwalletrpc.AssetWallet.PublishAndLogTransfer:input_type -> assetwalletrpc.PublishAndLogRequest - 11, // 21: assetwalletrpc.AssetWallet.NextInternalKey:input_type -> assetwalletrpc.NextInternalKeyRequest - 13, // 22: assetwalletrpc.AssetWallet.NextScriptKey:input_type -> assetwalletrpc.NextScriptKeyRequest - 15, // 23: assetwalletrpc.AssetWallet.QueryInternalKey:input_type -> assetwalletrpc.QueryInternalKeyRequest - 17, // 24: assetwalletrpc.AssetWallet.QueryScriptKey:input_type -> assetwalletrpc.QueryScriptKeyRequest - 19, // 25: assetwalletrpc.AssetWallet.ProveAssetOwnership:input_type -> assetwalletrpc.ProveAssetOwnershipRequest - 21, // 26: assetwalletrpc.AssetWallet.VerifyAssetOwnership:input_type -> assetwalletrpc.VerifyAssetOwnershipRequest - 23, // 27: assetwalletrpc.AssetWallet.RemoveUTXOLease:input_type -> assetwalletrpc.RemoveUTXOLeaseRequest - 25, // 28: assetwalletrpc.AssetWallet.DeclareScriptKey:input_type -> assetwalletrpc.DeclareScriptKeyRequest - 2, // 29: assetwalletrpc.AssetWallet.FundVirtualPsbt:output_type -> assetwalletrpc.FundVirtualPsbtResponse - 6, // 30: assetwalletrpc.AssetWallet.SignVirtualPsbt:output_type -> assetwalletrpc.SignVirtualPsbtResponse - 31, // 31: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:output_type -> taprpc.SendAssetResponse - 9, // 32: assetwalletrpc.AssetWallet.CommitVirtualPsbts:output_type -> assetwalletrpc.CommitVirtualPsbtsResponse - 31, // 33: assetwalletrpc.AssetWallet.PublishAndLogTransfer:output_type -> taprpc.SendAssetResponse - 12, // 34: assetwalletrpc.AssetWallet.NextInternalKey:output_type -> assetwalletrpc.NextInternalKeyResponse - 14, // 35: assetwalletrpc.AssetWallet.NextScriptKey:output_type -> assetwalletrpc.NextScriptKeyResponse - 16, // 36: assetwalletrpc.AssetWallet.QueryInternalKey:output_type -> assetwalletrpc.QueryInternalKeyResponse - 18, // 37: assetwalletrpc.AssetWallet.QueryScriptKey:output_type -> assetwalletrpc.QueryScriptKeyResponse - 20, // 38: assetwalletrpc.AssetWallet.ProveAssetOwnership:output_type -> assetwalletrpc.ProveAssetOwnershipResponse - 22, // 39: assetwalletrpc.AssetWallet.VerifyAssetOwnership:output_type -> assetwalletrpc.VerifyAssetOwnershipResponse - 24, // 40: assetwalletrpc.AssetWallet.RemoveUTXOLease:output_type -> assetwalletrpc.RemoveUTXOLeaseResponse - 26, // 41: assetwalletrpc.AssetWallet.DeclareScriptKey:output_type -> assetwalletrpc.DeclareScriptKeyResponse - 29, // [29:42] is the sub-list for method output_type - 16, // [16:29] is the sub-list for method input_type - 16, // [16:16] is the sub-list for extension type_name - 16, // [16:16] is the sub-list for extension extendee - 0, // [0:16] is the sub-list for field type_name + 28, // 4: assetwalletrpc.TxTemplate.addresses_with_amounts:type_name -> taprpc.AddressWithAmount + 29, // 5: assetwalletrpc.PrevId.outpoint:type_name -> taprpc.OutPoint + 29, // 6: assetwalletrpc.CommitVirtualPsbtsResponse.lnd_locked_utxos:type_name -> taprpc.OutPoint + 29, // 7: assetwalletrpc.PublishAndLogRequest.lnd_locked_utxos:type_name -> taprpc.OutPoint + 30, // 8: assetwalletrpc.NextInternalKeyResponse.internal_key:type_name -> taprpc.KeyDescriptor + 31, // 9: assetwalletrpc.NextScriptKeyResponse.script_key:type_name -> taprpc.ScriptKey + 30, // 10: assetwalletrpc.QueryInternalKeyResponse.internal_key:type_name -> taprpc.KeyDescriptor + 31, // 11: assetwalletrpc.QueryScriptKeyResponse.script_key:type_name -> taprpc.ScriptKey + 29, // 12: assetwalletrpc.ProveAssetOwnershipRequest.outpoint:type_name -> taprpc.OutPoint + 29, // 13: assetwalletrpc.VerifyAssetOwnershipResponse.outpoint:type_name -> taprpc.OutPoint + 29, // 14: assetwalletrpc.RemoveUTXOLeaseRequest.outpoint:type_name -> taprpc.OutPoint + 31, // 15: assetwalletrpc.DeclareScriptKeyRequest.script_key:type_name -> taprpc.ScriptKey + 31, // 16: assetwalletrpc.DeclareScriptKeyResponse.script_key:type_name -> taprpc.ScriptKey + 1, // 17: assetwalletrpc.AssetWallet.FundVirtualPsbt:input_type -> assetwalletrpc.FundVirtualPsbtRequest + 5, // 18: assetwalletrpc.AssetWallet.SignVirtualPsbt:input_type -> assetwalletrpc.SignVirtualPsbtRequest + 7, // 19: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:input_type -> assetwalletrpc.AnchorVirtualPsbtsRequest + 8, // 20: assetwalletrpc.AssetWallet.CommitVirtualPsbts:input_type -> assetwalletrpc.CommitVirtualPsbtsRequest + 10, // 21: assetwalletrpc.AssetWallet.PublishAndLogTransfer:input_type -> assetwalletrpc.PublishAndLogRequest + 11, // 22: assetwalletrpc.AssetWallet.NextInternalKey:input_type -> assetwalletrpc.NextInternalKeyRequest + 13, // 23: assetwalletrpc.AssetWallet.NextScriptKey:input_type -> assetwalletrpc.NextScriptKeyRequest + 15, // 24: assetwalletrpc.AssetWallet.QueryInternalKey:input_type -> assetwalletrpc.QueryInternalKeyRequest + 17, // 25: assetwalletrpc.AssetWallet.QueryScriptKey:input_type -> assetwalletrpc.QueryScriptKeyRequest + 19, // 26: assetwalletrpc.AssetWallet.ProveAssetOwnership:input_type -> assetwalletrpc.ProveAssetOwnershipRequest + 21, // 27: assetwalletrpc.AssetWallet.VerifyAssetOwnership:input_type -> assetwalletrpc.VerifyAssetOwnershipRequest + 23, // 28: assetwalletrpc.AssetWallet.RemoveUTXOLease:input_type -> assetwalletrpc.RemoveUTXOLeaseRequest + 25, // 29: assetwalletrpc.AssetWallet.DeclareScriptKey:input_type -> assetwalletrpc.DeclareScriptKeyRequest + 2, // 30: assetwalletrpc.AssetWallet.FundVirtualPsbt:output_type -> assetwalletrpc.FundVirtualPsbtResponse + 6, // 31: assetwalletrpc.AssetWallet.SignVirtualPsbt:output_type -> assetwalletrpc.SignVirtualPsbtResponse + 32, // 32: assetwalletrpc.AssetWallet.AnchorVirtualPsbts:output_type -> taprpc.SendAssetResponse + 9, // 33: assetwalletrpc.AssetWallet.CommitVirtualPsbts:output_type -> assetwalletrpc.CommitVirtualPsbtsResponse + 32, // 34: assetwalletrpc.AssetWallet.PublishAndLogTransfer:output_type -> taprpc.SendAssetResponse + 12, // 35: assetwalletrpc.AssetWallet.NextInternalKey:output_type -> assetwalletrpc.NextInternalKeyResponse + 14, // 36: assetwalletrpc.AssetWallet.NextScriptKey:output_type -> assetwalletrpc.NextScriptKeyResponse + 16, // 37: assetwalletrpc.AssetWallet.QueryInternalKey:output_type -> assetwalletrpc.QueryInternalKeyResponse + 18, // 38: assetwalletrpc.AssetWallet.QueryScriptKey:output_type -> assetwalletrpc.QueryScriptKeyResponse + 20, // 39: assetwalletrpc.AssetWallet.ProveAssetOwnership:output_type -> assetwalletrpc.ProveAssetOwnershipResponse + 22, // 40: assetwalletrpc.AssetWallet.VerifyAssetOwnership:output_type -> assetwalletrpc.VerifyAssetOwnershipResponse + 24, // 41: assetwalletrpc.AssetWallet.RemoveUTXOLease:output_type -> assetwalletrpc.RemoveUTXOLeaseResponse + 26, // 42: assetwalletrpc.AssetWallet.DeclareScriptKey:output_type -> assetwalletrpc.DeclareScriptKeyResponse + 30, // [30:43] is the sub-list for method output_type + 17, // [17:30] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_assetwalletrpc_assetwallet_proto_init() } diff --git a/taprpc/assetwalletrpc/assetwallet.proto b/taprpc/assetwalletrpc/assetwallet.proto index 9a83dde32..aeec99bc4 100644 --- a/taprpc/assetwalletrpc/assetwallet.proto +++ b/taprpc/assetwalletrpc/assetwallet.proto @@ -193,10 +193,24 @@ message TxTemplate { repeated PrevId inputs = 1; /* - A map of all Taproot Asset addresses mapped to the anchor transaction's - output index that should be sent to. + DEPRECATED: A map of all Taproot Asset addresses that should be sent to. + The keys are the Taproot Asset addresses in human-readable form, and the + values are IGNORED and should not be set (use the addresses_with_amounts + field below instead). The recipients map and addresses_with_amounts list + are mutually exclusive, meaning that if addresses_with_amounts is set, then + recipients must be empty, and vice versa. */ map recipients = 2; + + /* + A list of addresses and the amounts of asset units to send to them. This + must be used for V2 TAP addresses that don't specify an amount in the + address itself and allow the sender to choose the amount to send. The + recipients and addresses_with_amounts lists are mutually exclusive, + meaning that if addresses_with_amounts is set, then recipients must be + empty, and vice versa. + */ + repeated taprpc.AddressWithAmount addresses_with_amounts = 3; } message PrevId { diff --git a/taprpc/assetwalletrpc/assetwallet.swagger.json b/taprpc/assetwalletrpc/assetwallet.swagger.json index 56adde2d2..1de5f5373 100644 --- a/taprpc/assetwalletrpc/assetwallet.swagger.json +++ b/taprpc/assetwalletrpc/assetwallet.swagger.json @@ -828,7 +828,15 @@ "type": "string", "format": "uint64" }, - "description": "A map of all Taproot Asset addresses mapped to the anchor transaction's\noutput index that should be sent to." + "description": "DEPRECATED: A map of all Taproot Asset addresses that should be sent to.\nThe keys are the Taproot Asset addresses in human-readable form, and the\nvalues are IGNORED and should not be set (use the addresses_with_amounts\nfield below instead). The recipients map and addresses_with_amounts list\nare mutually exclusive, meaning that if addresses_with_amounts is set, then\nrecipients must be empty, and vice versa." + }, + "addresses_with_amounts": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/taprpcAddressWithAmount" + }, + "description": "A list of addresses and the amounts of asset units to send to them. This\nmust be used for V2 TAP addresses that don't specify an amount in the\naddress itself and allow the sender to choose the amount to send. The\nrecipients and addresses_with_amounts lists are mutually exclusive,\nmeaning that if addresses_with_amounts is set, then recipients must be\nempty, and vice versa." } } }, @@ -904,6 +912,20 @@ } } }, + "taprpcAddressWithAmount": { + "type": "object", + "properties": { + "tap_addr": { + "type": "string", + "description": "The TAP address to send assets to." + }, + "amount": { + "type": "string", + "format": "uint64", + "description": "The amount of asset units to send to the address. This is only used for\nre-usable V2 addresses that don't specify an amount in the address itself\nand allow the sender to specify the amount on each send attempt. For V0\nor V1 addresses, this can be left empty (zero) as the amount is taken\nfrom the address itself." + } + } + }, "taprpcAssetTransfer": { "type": "object", "properties": { diff --git a/taprpc/tapdevrpc/tapdev.swagger.json b/taprpc/tapdevrpc/tapdev.swagger.json index 6ff727a61..7c783dbde 100644 --- a/taprpc/tapdevrpc/tapdev.swagger.json +++ b/taprpc/tapdevrpc/tapdev.swagger.json @@ -149,7 +149,7 @@ "asset_id": { "type": "string", "format": "byte", - "description": "The asset ID that uniquely identifies the asset." + "description": "The asset ID that uniquely identifies the asset. This can be all zeroes\nfor V2 addresses that have a group key set." }, "asset_type": { "$ref": "#/definitions/taprpcAssetType", @@ -158,7 +158,7 @@ "amount": { "type": "string", "format": "uint64", - "description": "The total amount of the asset stored in this Taproot Asset UTXO." + "description": "The total amount of the asset stored in this Taproot Asset UTXO. The\namount is allowed to be unset for V2 addresses, where the sender will\npost a fragment containing the asset IDs and amounts to the proof\ncourier's auth mailbox." }, "group_key": { "type": "string", @@ -187,7 +187,7 @@ }, "proof_courier_addr": { "type": "string", - "description": "The address of the proof courier service used in proof transfer." + "description": "The address of the proof courier service used in proof transfer. For V2\naddresses the proof courier address is mandatory and must be a valid auth\nmailbox address (authmailbox+universerpc://host:port)." }, "asset_version": { "$ref": "#/definitions/taprpcAssetVersion", @@ -204,10 +204,11 @@ "enum": [ "ADDR_VERSION_UNSPECIFIED", "ADDR_VERSION_V0", - "ADDR_VERSION_V1" + "ADDR_VERSION_V1", + "ADDR_VERSION_V2" ], "default": "ADDR_VERSION_UNSPECIFIED", - "description": " - ADDR_VERSION_UNSPECIFIED: ADDR_VERSION_UNSPECIFIED is the default value for an address version in\nan RPC message. It is unmarshalled to the latest address version.\n - ADDR_VERSION_V0: ADDR_VERSION_V0 is the initial address version.\n - ADDR_VERSION_V1: ADDR_VERSION_V1 is the address version that uses V2 Taproot Asset\ncommitments." + "description": " - ADDR_VERSION_UNSPECIFIED: ADDR_VERSION_UNSPECIFIED is the default value for an address version in\nan RPC message. It is unmarshalled to the latest address version.\n - ADDR_VERSION_V0: ADDR_VERSION_V0 is the initial address version.\n - ADDR_VERSION_V1: ADDR_VERSION_V1 is the address version that uses V2 Taproot Asset\ncommitments.\n - ADDR_VERSION_V2: ADDR_VERSION_V2 is the address version that supports sending grouped\nassets and require the new auth mailbox proof courier address format." }, "taprpcAssetType": { "type": "string", diff --git a/taprpc/taprootassets.pb.go b/taprpc/taprootassets.pb.go index 0183911b2..a97f2046b 100644 --- a/taprpc/taprootassets.pb.go +++ b/taprpc/taprootassets.pb.go @@ -291,6 +291,9 @@ const ( // ADDR_VERSION_V1 is the address version that uses V2 Taproot Asset // commitments. AddrVersion_ADDR_VERSION_V1 AddrVersion = 2 + // ADDR_VERSION_V2 is the address version that supports sending grouped + // assets and require the new auth mailbox proof courier address format. + AddrVersion_ADDR_VERSION_V2 AddrVersion = 3 ) // Enum value maps for AddrVersion. @@ -299,11 +302,13 @@ var ( 0: "ADDR_VERSION_UNSPECIFIED", 1: "ADDR_VERSION_V0", 2: "ADDR_VERSION_V1", + 3: "ADDR_VERSION_V2", } AddrVersion_value = map[string]int32{ "ADDR_VERSION_UNSPECIFIED": 0, "ADDR_VERSION_V0": 1, "ADDR_VERSION_V1": 2, + "ADDR_VERSION_V2": 3, } ) @@ -3627,11 +3632,15 @@ type Addr struct { // The bech32 encoded Taproot Asset address. Encoded string `protobuf:"bytes,1,opt,name=encoded,proto3" json:"encoded,omitempty"` - // The asset ID that uniquely identifies the asset. + // The asset ID that uniquely identifies the asset. This can be all zeroes + // for V2 addresses that have a group key set. AssetId []byte `protobuf:"bytes,2,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` // The type of the asset. AssetType AssetType `protobuf:"varint,3,opt,name=asset_type,json=assetType,proto3,enum=taprpc.AssetType" json:"asset_type,omitempty"` - // The total amount of the asset stored in this Taproot Asset UTXO. + // The total amount of the asset stored in this Taproot Asset UTXO. The + // amount is allowed to be unset for V2 addresses, where the sender will + // post a fragment containing the asset IDs and amounts to the proof + // courier's auth mailbox. Amount uint64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` // The group key of the asset (if it exists) GroupKey []byte `protobuf:"bytes,5,opt,name=group_key,json=groupKey,proto3" json:"group_key,omitempty"` @@ -3649,7 +3658,9 @@ type Addr struct { // on-chain output key the Bitcoin transaction must send to in order to // transfer assets described in this address. TaprootOutputKey []byte `protobuf:"bytes,9,opt,name=taproot_output_key,json=taprootOutputKey,proto3" json:"taproot_output_key,omitempty"` - // The address of the proof courier service used in proof transfer. + // The address of the proof courier service used in proof transfer. For V2 + // addresses the proof courier address is mandatory and must be a valid auth + // mailbox address (authmailbox+universerpc://host:port). ProofCourierAddr string `protobuf:"bytes,10,opt,name=proof_courier_addr,json=proofCourierAddr,proto3" json:"proof_courier_addr,omitempty"` // The asset version of the address. AssetVersion AssetVersion `protobuf:"varint,11,opt,name=asset_version,json=assetVersion,proto3,enum=taprpc.AssetVersion" json:"asset_version,omitempty"` @@ -3902,8 +3913,14 @@ type NewAddrRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // The asset ID to create the address for. This is required for V0 and V1 + // addresses. For V2 addresses, this field is optional and must be empty if the + // group key is set. AssetId []byte `protobuf:"bytes,1,opt,name=asset_id,json=assetId,proto3" json:"asset_id,omitempty"` - Amt uint64 `protobuf:"varint,2,opt,name=amt,proto3" json:"amt,omitempty"` + // The number of asset units to be sent to the address. This is required for V0 + // and V1 addresses. For V2 addresses, this field is optional and can be left + // at 0 to indicate that the sender can choose the amount of assets to send. + Amt uint64 `protobuf:"varint,2,opt,name=amt,proto3" json:"amt,omitempty"` // The optional script key that the receiving asset should be locked to. If no // script key is provided, a normal BIP-86 key will be derived from the // underlying wallet. @@ -3930,6 +3947,9 @@ type NewAddrRequest struct { AssetVersion AssetVersion `protobuf:"varint,7,opt,name=asset_version,json=assetVersion,proto3,enum=taprpc.AssetVersion" json:"asset_version,omitempty"` // The version of this address. AddressVersion AddrVersion `protobuf:"varint,8,opt,name=address_version,json=addressVersion,proto3,enum=taprpc.AddrVersion" json:"address_version,omitempty"` + // The group key to receive assets for. This can only be specified for V2 + // addresses. If this field is set, the asset_id field must be empty. + GroupKey []byte `protobuf:"bytes,9,opt,name=group_key,json=groupKey,proto3" json:"group_key,omitempty"` } func (x *NewAddrRequest) Reset() { @@ -4020,6 +4040,13 @@ func (x *NewAddrRequest) GetAddressVersion() AddrVersion { return AddrVersion_ADDR_VERSION_UNSPECIFIED } +func (x *NewAddrRequest) GetGroupKey() []byte { + if x != nil { + return x.GroupKey + } + return nil +} + type ScriptKeyTypeQuery struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5310,6 +5337,13 @@ type SendAssetRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // The list of TAP addresses to send assets to. The amount to send to each + // address is determined by the amount specified in the address itself. For + // V2 addresses that are allowed to not specify an amount, use the + // addresses_with_amounts list to specify the amount to send to each + // address. The tap_addrs and addresses_with_amounts lists are mutually + // exclusive, meaning that if addresses_with_amounts is set, then tap_addrs + // must be empty, and vice versa. TapAddrs []string `protobuf:"bytes,1,rep,name=tap_addrs,json=tapAddrs,proto3" json:"tap_addrs,omitempty"` // The optional fee rate to use for the minting transaction, in sat/kw. FeeRate uint32 `protobuf:"varint,2,opt,name=fee_rate,json=feeRate,proto3" json:"fee_rate,omitempty"` @@ -5321,6 +5355,13 @@ type SendAssetRequest struct { // testing purposes and for forced transfers when the proof courier // is not immediately available. SkipProofCourierPingCheck bool `protobuf:"varint,4,opt,name=skip_proof_courier_ping_check,json=skipProofCourierPingCheck,proto3" json:"skip_proof_courier_ping_check,omitempty"` + // A list of addresses and the amounts of asset units to send to them. This + // must be used for V2 TAP addresses that don't specify an amount in the + // address itself and allow the sender to choose the amount to send. The + // tap_addrs and addresses_with_amounts lists are mutually exclusive, + // meaning that if addresses_with_amounts is set, then tap_addrs must be + // empty, and vice versa. + AddressesWithAmounts []*AddressWithAmount `protobuf:"bytes,5,rep,name=addresses_with_amounts,json=addressesWithAmounts,proto3" json:"addresses_with_amounts,omitempty"` } func (x *SendAssetRequest) Reset() { @@ -5383,6 +5424,74 @@ func (x *SendAssetRequest) GetSkipProofCourierPingCheck() bool { return false } +func (x *SendAssetRequest) GetAddressesWithAmounts() []*AddressWithAmount { + if x != nil { + return x.AddressesWithAmounts + } + return nil +} + +type AddressWithAmount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The TAP address to send assets to. + TapAddr string `protobuf:"bytes,1,opt,name=tap_addr,json=tapAddr,proto3" json:"tap_addr,omitempty"` + // The amount of asset units to send to the address. This is only used for + // re-usable V2 addresses that don't specify an amount in the address itself + // and allow the sender to specify the amount on each send attempt. For V0 + // or V1 addresses, this can be left empty (zero) as the amount is taken + // from the address itself. + Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (x *AddressWithAmount) Reset() { + *x = AddressWithAmount{} + if protoimpl.UnsafeEnabled { + mi := &file_taprootassets_proto_msgTypes[63] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddressWithAmount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddressWithAmount) ProtoMessage() {} + +func (x *AddressWithAmount) ProtoReflect() protoreflect.Message { + mi := &file_taprootassets_proto_msgTypes[63] + 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 AddressWithAmount.ProtoReflect.Descriptor instead. +func (*AddressWithAmount) Descriptor() ([]byte, []int) { + return file_taprootassets_proto_rawDescGZIP(), []int{63} +} + +func (x *AddressWithAmount) GetTapAddr() string { + if x != nil { + return x.TapAddr + } + return "" +} + +func (x *AddressWithAmount) GetAmount() uint64 { + if x != nil { + return x.Amount + } + return 0 +} + type PrevInputAsset struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5397,7 +5506,7 @@ type PrevInputAsset struct { func (x *PrevInputAsset) Reset() { *x = PrevInputAsset{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[63] + mi := &file_taprootassets_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5410,7 +5519,7 @@ func (x *PrevInputAsset) String() string { func (*PrevInputAsset) ProtoMessage() {} func (x *PrevInputAsset) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[63] + mi := &file_taprootassets_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5423,7 +5532,7 @@ func (x *PrevInputAsset) ProtoReflect() protoreflect.Message { // Deprecated: Use PrevInputAsset.ProtoReflect.Descriptor instead. func (*PrevInputAsset) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{63} + return file_taprootassets_proto_rawDescGZIP(), []int{64} } func (x *PrevInputAsset) GetAnchorPoint() string { @@ -5465,7 +5574,7 @@ type SendAssetResponse struct { func (x *SendAssetResponse) Reset() { *x = SendAssetResponse{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[64] + mi := &file_taprootassets_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5478,7 +5587,7 @@ func (x *SendAssetResponse) String() string { func (*SendAssetResponse) ProtoMessage() {} func (x *SendAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[64] + mi := &file_taprootassets_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5491,7 +5600,7 @@ func (x *SendAssetResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SendAssetResponse.ProtoReflect.Descriptor instead. func (*SendAssetResponse) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{64} + return file_taprootassets_proto_rawDescGZIP(), []int{65} } func (x *SendAssetResponse) GetTransfer() *AssetTransfer { @@ -5510,7 +5619,7 @@ type GetInfoRequest struct { func (x *GetInfoRequest) Reset() { *x = GetInfoRequest{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[65] + mi := &file_taprootassets_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5523,7 +5632,7 @@ func (x *GetInfoRequest) String() string { func (*GetInfoRequest) ProtoMessage() {} func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[65] + mi := &file_taprootassets_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5536,7 +5645,7 @@ func (x *GetInfoRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoRequest.ProtoReflect.Descriptor instead. func (*GetInfoRequest) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{65} + return file_taprootassets_proto_rawDescGZIP(), []int{66} } type GetInfoResponse struct { @@ -5557,7 +5666,7 @@ type GetInfoResponse struct { func (x *GetInfoResponse) Reset() { *x = GetInfoResponse{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[66] + mi := &file_taprootassets_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5570,7 +5679,7 @@ func (x *GetInfoResponse) String() string { func (*GetInfoResponse) ProtoMessage() {} func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[66] + mi := &file_taprootassets_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5583,7 +5692,7 @@ func (x *GetInfoResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetInfoResponse.ProtoReflect.Descriptor instead. func (*GetInfoResponse) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{66} + return file_taprootassets_proto_rawDescGZIP(), []int{67} } func (x *GetInfoResponse) GetVersion() string { @@ -5659,7 +5768,7 @@ type FetchAssetMetaRequest struct { func (x *FetchAssetMetaRequest) Reset() { *x = FetchAssetMetaRequest{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[67] + mi := &file_taprootassets_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5672,7 +5781,7 @@ func (x *FetchAssetMetaRequest) String() string { func (*FetchAssetMetaRequest) ProtoMessage() {} func (x *FetchAssetMetaRequest) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[67] + mi := &file_taprootassets_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5685,7 +5794,7 @@ func (x *FetchAssetMetaRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use FetchAssetMetaRequest.ProtoReflect.Descriptor instead. func (*FetchAssetMetaRequest) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{67} + return file_taprootassets_proto_rawDescGZIP(), []int{68} } func (m *FetchAssetMetaRequest) GetAsset() isFetchAssetMetaRequest_Asset { @@ -5789,7 +5898,7 @@ type FetchAssetMetaResponse struct { func (x *FetchAssetMetaResponse) Reset() { *x = FetchAssetMetaResponse{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[68] + mi := &file_taprootassets_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5802,7 +5911,7 @@ func (x *FetchAssetMetaResponse) String() string { func (*FetchAssetMetaResponse) ProtoMessage() {} func (x *FetchAssetMetaResponse) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[68] + mi := &file_taprootassets_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5815,7 +5924,7 @@ func (x *FetchAssetMetaResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use FetchAssetMetaResponse.ProtoReflect.Descriptor instead. func (*FetchAssetMetaResponse) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{68} + return file_taprootassets_proto_rawDescGZIP(), []int{69} } func (x *FetchAssetMetaResponse) GetData() []byte { @@ -5896,7 +6005,7 @@ type BurnAssetRequest struct { func (x *BurnAssetRequest) Reset() { *x = BurnAssetRequest{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[69] + mi := &file_taprootassets_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5909,7 +6018,7 @@ func (x *BurnAssetRequest) String() string { func (*BurnAssetRequest) ProtoMessage() {} func (x *BurnAssetRequest) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[69] + mi := &file_taprootassets_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5922,7 +6031,7 @@ func (x *BurnAssetRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BurnAssetRequest.ProtoReflect.Descriptor instead. func (*BurnAssetRequest) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{69} + return file_taprootassets_proto_rawDescGZIP(), []int{70} } func (m *BurnAssetRequest) GetAsset() isBurnAssetRequest_Asset { @@ -5999,7 +6108,7 @@ type BurnAssetResponse struct { func (x *BurnAssetResponse) Reset() { *x = BurnAssetResponse{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[70] + mi := &file_taprootassets_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6012,7 +6121,7 @@ func (x *BurnAssetResponse) String() string { func (*BurnAssetResponse) ProtoMessage() {} func (x *BurnAssetResponse) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[70] + mi := &file_taprootassets_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6025,7 +6134,7 @@ func (x *BurnAssetResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BurnAssetResponse.ProtoReflect.Descriptor instead. func (*BurnAssetResponse) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{70} + return file_taprootassets_proto_rawDescGZIP(), []int{71} } func (x *BurnAssetResponse) GetBurnTransfer() *AssetTransfer { @@ -6058,7 +6167,7 @@ type ListBurnsRequest struct { func (x *ListBurnsRequest) Reset() { *x = ListBurnsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[71] + mi := &file_taprootassets_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6071,7 +6180,7 @@ func (x *ListBurnsRequest) String() string { func (*ListBurnsRequest) ProtoMessage() {} func (x *ListBurnsRequest) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[71] + mi := &file_taprootassets_proto_msgTypes[72] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6084,7 +6193,7 @@ func (x *ListBurnsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListBurnsRequest.ProtoReflect.Descriptor instead. func (*ListBurnsRequest) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{71} + return file_taprootassets_proto_rawDescGZIP(), []int{72} } func (x *ListBurnsRequest) GetAssetId() []byte { @@ -6128,7 +6237,7 @@ type AssetBurn struct { func (x *AssetBurn) Reset() { *x = AssetBurn{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[72] + mi := &file_taprootassets_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6141,7 +6250,7 @@ func (x *AssetBurn) String() string { func (*AssetBurn) ProtoMessage() {} func (x *AssetBurn) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[72] + mi := &file_taprootassets_proto_msgTypes[73] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6154,7 +6263,7 @@ func (x *AssetBurn) ProtoReflect() protoreflect.Message { // Deprecated: Use AssetBurn.ProtoReflect.Descriptor instead. func (*AssetBurn) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{72} + return file_taprootassets_proto_rawDescGZIP(), []int{73} } func (x *AssetBurn) GetNote() string { @@ -6203,7 +6312,7 @@ type ListBurnsResponse struct { func (x *ListBurnsResponse) Reset() { *x = ListBurnsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[73] + mi := &file_taprootassets_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6216,7 +6325,7 @@ func (x *ListBurnsResponse) String() string { func (*ListBurnsResponse) ProtoMessage() {} func (x *ListBurnsResponse) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[73] + mi := &file_taprootassets_proto_msgTypes[74] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6229,7 +6338,7 @@ func (x *ListBurnsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListBurnsResponse.ProtoReflect.Descriptor instead. func (*ListBurnsResponse) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{73} + return file_taprootassets_proto_rawDescGZIP(), []int{74} } func (x *ListBurnsResponse) GetBurns() []*AssetBurn { @@ -6255,7 +6364,7 @@ type SubscribeReceiveEventsRequest struct { func (x *SubscribeReceiveEventsRequest) Reset() { *x = SubscribeReceiveEventsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[74] + mi := &file_taprootassets_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6268,7 +6377,7 @@ func (x *SubscribeReceiveEventsRequest) String() string { func (*SubscribeReceiveEventsRequest) ProtoMessage() {} func (x *SubscribeReceiveEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[74] + mi := &file_taprootassets_proto_msgTypes[75] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6281,7 +6390,7 @@ func (x *SubscribeReceiveEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubscribeReceiveEventsRequest.ProtoReflect.Descriptor instead. func (*SubscribeReceiveEventsRequest) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{74} + return file_taprootassets_proto_rawDescGZIP(), []int{75} } func (x *SubscribeReceiveEventsRequest) GetFilterAddr() string { @@ -6323,7 +6432,7 @@ type ReceiveEvent struct { func (x *ReceiveEvent) Reset() { *x = ReceiveEvent{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[75] + mi := &file_taprootassets_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6336,7 +6445,7 @@ func (x *ReceiveEvent) String() string { func (*ReceiveEvent) ProtoMessage() {} func (x *ReceiveEvent) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[75] + mi := &file_taprootassets_proto_msgTypes[76] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6349,7 +6458,7 @@ func (x *ReceiveEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use ReceiveEvent.ProtoReflect.Descriptor instead. func (*ReceiveEvent) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{75} + return file_taprootassets_proto_rawDescGZIP(), []int{76} } func (x *ReceiveEvent) GetTimestamp() int64 { @@ -6410,7 +6519,7 @@ type SubscribeSendEventsRequest struct { func (x *SubscribeSendEventsRequest) Reset() { *x = SubscribeSendEventsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[76] + mi := &file_taprootassets_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6423,7 +6532,7 @@ func (x *SubscribeSendEventsRequest) String() string { func (*SubscribeSendEventsRequest) ProtoMessage() {} func (x *SubscribeSendEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[76] + mi := &file_taprootassets_proto_msgTypes[77] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6436,7 +6545,7 @@ func (x *SubscribeSendEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubscribeSendEventsRequest.ProtoReflect.Descriptor instead. func (*SubscribeSendEventsRequest) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{76} + return file_taprootassets_proto_rawDescGZIP(), []int{77} } func (x *SubscribeSendEventsRequest) GetFilterScriptKey() []byte { @@ -6493,7 +6602,7 @@ type SendEvent struct { func (x *SendEvent) Reset() { *x = SendEvent{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[77] + mi := &file_taprootassets_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6506,7 +6615,7 @@ func (x *SendEvent) String() string { func (*SendEvent) ProtoMessage() {} func (x *SendEvent) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[77] + mi := &file_taprootassets_proto_msgTypes[78] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6519,7 +6628,7 @@ func (x *SendEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use SendEvent.ProtoReflect.Descriptor instead. func (*SendEvent) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{77} + return file_taprootassets_proto_rawDescGZIP(), []int{78} } func (x *SendEvent) GetTimestamp() int64 { @@ -6623,7 +6732,7 @@ type AnchorTransaction struct { func (x *AnchorTransaction) Reset() { *x = AnchorTransaction{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[78] + mi := &file_taprootassets_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6636,7 +6745,7 @@ func (x *AnchorTransaction) String() string { func (*AnchorTransaction) ProtoMessage() {} func (x *AnchorTransaction) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[78] + mi := &file_taprootassets_proto_msgTypes[79] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6649,7 +6758,7 @@ func (x *AnchorTransaction) ProtoReflect() protoreflect.Message { // Deprecated: Use AnchorTransaction.ProtoReflect.Descriptor instead. func (*AnchorTransaction) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{78} + return file_taprootassets_proto_rawDescGZIP(), []int{79} } func (x *AnchorTransaction) GetAnchorPsbt() []byte { @@ -6712,7 +6821,7 @@ type RegisterTransferRequest struct { func (x *RegisterTransferRequest) Reset() { *x = RegisterTransferRequest{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[79] + mi := &file_taprootassets_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6725,7 +6834,7 @@ func (x *RegisterTransferRequest) String() string { func (*RegisterTransferRequest) ProtoMessage() {} func (x *RegisterTransferRequest) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[79] + mi := &file_taprootassets_proto_msgTypes[80] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6738,7 +6847,7 @@ func (x *RegisterTransferRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterTransferRequest.ProtoReflect.Descriptor instead. func (*RegisterTransferRequest) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{79} + return file_taprootassets_proto_rawDescGZIP(), []int{80} } func (x *RegisterTransferRequest) GetAssetId() []byte { @@ -6780,7 +6889,7 @@ type RegisterTransferResponse struct { func (x *RegisterTransferResponse) Reset() { *x = RegisterTransferResponse{} if protoimpl.UnsafeEnabled { - mi := &file_taprootassets_proto_msgTypes[80] + mi := &file_taprootassets_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6793,7 +6902,7 @@ func (x *RegisterTransferResponse) String() string { func (*RegisterTransferResponse) ProtoMessage() {} func (x *RegisterTransferResponse) ProtoReflect() protoreflect.Message { - mi := &file_taprootassets_proto_msgTypes[80] + mi := &file_taprootassets_proto_msgTypes[81] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6806,7 +6915,7 @@ func (x *RegisterTransferResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterTransferResponse.ProtoReflect.Descriptor instead. func (*RegisterTransferResponse) Descriptor() ([]byte, []int) { - return file_taprootassets_proto_rawDescGZIP(), []int{80} + return file_taprootassets_proto_rawDescGZIP(), []int{81} } func (x *RegisterTransferResponse) GetRegisteredAsset() *Asset { @@ -7319,7 +7428,7 @@ var file_taprootassets_proto_rawDesc = []byte{ 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x05, 0x61, 0x64, 0x64, 0x72, 0x73, - 0x22, 0xfd, 0x02, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x22, 0x9a, 0x03, 0x0a, 0x0e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 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, 0x10, 0x0a, 0x03, 0x61, 0x6d, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x61, 0x6d, 0x74, @@ -7343,568 +7452,581 @@ var file_taprootassets_proto_rawDesc = []byte{ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x22, 0x79, 0x0a, 0x12, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, - 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x3c, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, - 0x69, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, - 0x54, 0x79, 0x70, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x61, 0x6c, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x61, 0x6c, 0x6c, 0x54, 0x79, - 0x70, 0x65, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x09, - 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, - 0x65, 0x79, 0x12, 0x30, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, - 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, 0x07, 0x6b, 0x65, 0x79, - 0x44, 0x65, 0x73, 0x63, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x70, 0x5f, 0x74, 0x77, 0x65, 0x61, - 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x74, 0x61, 0x70, 0x54, 0x77, 0x65, 0x61, - 0x6b, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x15, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, - 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x48, 0x0a, 0x0a, - 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, - 0x79, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, - 0x6b, 0x65, 0x79, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6b, 0x65, - 0x79, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x60, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x61, 0x77, 0x5f, 0x6b, - 0x65, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, - 0x72, 0x61, 0x77, 0x4b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x07, 0x6b, - 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, - 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, - 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x22, 0x43, 0x0a, 0x11, 0x54, 0x61, 0x70, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x12, 0x2e, 0x0a, - 0x0a, 0x61, 0x6c, 0x6c, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x61, 0x70, 0x4c, 0x65, - 0x61, 0x66, 0x52, 0x09, 0x61, 0x6c, 0x6c, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x22, 0x21, 0x0a, - 0x07, 0x54, 0x61, 0x70, 0x4c, 0x65, 0x61, 0x66, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x22, 0x53, 0x0a, 0x09, 0x54, 0x61, 0x70, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x21, 0x0a, - 0x0c, 0x6c, 0x65, 0x66, 0x74, 0x5f, 0x74, 0x61, 0x70, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6c, 0x65, 0x66, 0x74, 0x54, 0x61, 0x70, 0x68, 0x61, 0x73, 0x68, - 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x74, 0x61, 0x70, 0x68, 0x61, 0x73, - 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x69, 0x67, 0x68, 0x74, 0x54, 0x61, - 0x70, 0x68, 0x61, 0x73, 0x68, 0x22, 0x27, 0x0a, 0x11, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x41, - 0x64, 0x64, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, - 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x22, 0x56, - 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x72, - 0x61, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x61, 0x77, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, - 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, - 0x73, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0xf6, 0x04, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6f, 0x66, - 0x5f, 0x61, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0c, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x41, 0x74, 0x44, 0x65, 0x70, 0x74, 0x68, 0x12, 0x28, 0x0a, - 0x10, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x4f, - 0x66, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x23, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x12, 0x32, 0x0a, 0x0b, - 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, - 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x78, 0x5f, 0x6d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x70, 0x72, - 0x6f, 0x6f, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x78, 0x4d, 0x65, 0x72, - 0x6b, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x78, 0x63, - 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x28, 0x0a, 0x10, - 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x52, 0x6f, 0x6f, - 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x32, 0x0a, 0x15, 0x6e, 0x75, 0x6d, 0x5f, 0x61, 0x64, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x68, - 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x18, - 0x0a, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x10, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, - 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x62, 0x75, - 0x72, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x42, 0x75, 0x72, 0x6e, - 0x12, 0x3c, 0x0a, 0x0e, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x76, 0x65, - 0x61, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x52, - 0x0d, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x12, 0x40, - 0x0a, 0x10, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x65, 0x76, 0x65, - 0x61, 0x6c, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, - 0x63, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, - 0x52, 0x0e, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, - 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x6c, 0x74, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x6c, 0x74, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x22, - 0x66, 0x0a, 0x13, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0d, - 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 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, 0x0c, 0x64, 0x65, 0x63, 0x6f, 0x64, - 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xb1, 0x01, 0x0a, 0x12, 0x44, 0x65, 0x63, 0x6f, - 0x64, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, - 0x0a, 0x09, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x08, 0x72, 0x61, 0x77, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x24, 0x0a, 0x0e, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x61, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x41, 0x74, 0x44, 0x65, 0x70, 0x74, - 0x68, 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x77, - 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, - 0x77, 0x69, 0x74, 0x68, 0x50, 0x72, 0x65, 0x76, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x12, 0x28, 0x0a, 0x10, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x72, - 0x65, 0x76, 0x65, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x77, 0x69, 0x74, - 0x68, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x22, 0x50, 0x0a, 0x13, 0x44, - 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0d, 0x64, 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, 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, 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, 0x3e, 0x0a, 0x16, 0x55, - 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, - 0x61, 0x77, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x38, 0x0a, 0x17, 0x55, - 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x72, - 0x6f, 0x6f, 0x66, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 0x77, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x73, 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, 0xa2, 0x01, 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, 0x12, 0x14, - 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x12, 0x40, 0x0a, 0x1d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0x5f, 0x63, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, - 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x6b, 0x69, - 0x70, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x43, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x50, 0x69, 0x6e, - 0x67, 0x43, 0x68, 0x65, 0x63, 0x6b, 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, 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, - 0xd4, 0x03, 0x0a, 0x16, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, - 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x29, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, - 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x74, - 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x12, 0x5f, 0x0a, 0x11, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, - 0x6e, 0x5f, 0x6f, 0x64, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x2e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x4f, 0x64, 0x64, 0x54, 0x79, 0x70, 0x65, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x4f, - 0x64, 0x64, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x63, 0x69, 0x6d, - 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0e, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x12, 0x31, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, - 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, - 0x5f, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x55, - 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x65, 0x55, 0x72, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, - 0x65, 0x79, 0x1a, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x4f, 0x64, 0x64, - 0x54, 0x79, 0x70, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc3, 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, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x6f, 0x74, 0x65, 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, 0x7a, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x73, - 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, + 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x22, 0x79, 0x0a, + 0x12, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x12, 0x3c, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x61, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, + 0x65, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1d, 0x0a, 0x09, 0x61, 0x6c, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x61, 0x6c, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x73, + 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x09, 0x53, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, + 0x30, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x02, 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, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, + 0x63, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x70, 0x5f, 0x74, 0x77, 0x65, 0x61, 0x6b, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x74, 0x61, 0x70, 0x54, 0x77, 0x65, 0x61, 0x6b, 0x12, 0x29, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, + 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x48, 0x0a, 0x0a, 0x4b, 0x65, 0x79, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x66, + 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x79, + 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x22, 0x60, 0x0a, 0x0d, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x61, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, + 0x4b, 0x65, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, + 0x6c, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x61, 0x70, 0x72, + 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x6b, + 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x22, 0x43, 0x0a, 0x11, 0x54, 0x61, 0x70, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x12, 0x2e, 0x0a, 0x0a, 0x61, 0x6c, + 0x6c, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x61, 0x70, 0x4c, 0x65, 0x61, 0x66, 0x52, + 0x09, 0x61, 0x6c, 0x6c, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x22, 0x21, 0x0a, 0x07, 0x54, 0x61, + 0x70, 0x4c, 0x65, 0x61, 0x66, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x22, 0x53, 0x0a, + 0x09, 0x54, 0x61, 0x70, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x65, + 0x66, 0x74, 0x5f, 0x74, 0x61, 0x70, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x6c, 0x65, 0x66, 0x74, 0x54, 0x61, 0x70, 0x68, 0x61, 0x73, 0x68, 0x12, 0x23, 0x0a, + 0x0d, 0x72, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x74, 0x61, 0x70, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x69, 0x67, 0x68, 0x74, 0x54, 0x61, 0x70, 0x68, 0x61, + 0x73, 0x68, 0x22, 0x27, 0x0a, 0x11, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x22, 0x56, 0x0a, 0x09, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x61, 0x77, 0x5f, + 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0c, 0x72, 0x61, 0x77, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x50, 0x6f, + 0x69, 0x6e, 0x74, 0x22, 0xf6, 0x04, 0x0a, 0x0c, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x61, 0x74, + 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x70, 0x72, + 0x6f, 0x6f, 0x66, 0x41, 0x74, 0x44, 0x65, 0x70, 0x74, 0x68, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x66, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x23, 0x0a, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x52, 0x05, 0x61, 0x73, 0x73, 0x65, 0x74, 0x12, 0x32, 0x0a, 0x0b, 0x6d, 0x65, 0x74, + 0x61, 0x5f, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, + 0x61, 0x52, 0x0a, 0x6d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x12, 0x26, 0x0a, + 0x0f, 0x74, 0x78, 0x5f, 0x6d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x74, 0x78, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, + 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x29, + 0x0a, 0x10, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x6f, + 0x66, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x70, 0x6c, + 0x69, 0x74, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x12, 0x32, 0x0a, 0x15, 0x6e, 0x75, 0x6d, 0x5f, 0x61, 0x64, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x13, 0x6e, 0x75, 0x6d, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x6c, 0x6c, + 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x77, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x03, + 0x28, 0x0c, 0x52, 0x10, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x57, 0x69, 0x74, + 0x6e, 0x65, 0x73, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x62, 0x75, 0x72, 0x6e, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x3c, 0x0a, + 0x0e, 0x67, 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x65, 0x6e, 0x65, 0x73, 0x69, 0x73, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x52, 0x0d, 0x67, 0x65, + 0x6e, 0x65, 0x73, 0x69, 0x73, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x12, 0x40, 0x0a, 0x10, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x47, + 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x52, 0x0e, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x12, 0x1d, 0x0a, + 0x0a, 0x61, 0x6c, 0x74, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x61, 0x6c, 0x74, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x22, 0x66, 0x0a, 0x13, + 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0d, 0x64, 0x65, 0x63, + 0x6f, 0x64, 0x65, 0x64, 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, 0x0c, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xb1, 0x01, 0x0a, 0x12, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x72, + 0x61, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, + 0x72, 0x61, 0x77, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6f, + 0x66, 0x5f, 0x61, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x41, 0x74, 0x44, 0x65, 0x70, 0x74, 0x68, 0x12, 0x2e, + 0x0a, 0x13, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x77, 0x69, 0x74, 0x6e, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x77, 0x69, 0x74, + 0x68, 0x50, 0x72, 0x65, 0x76, 0x57, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x28, + 0x0a, 0x10, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x76, 0x65, + 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x77, 0x69, 0x74, 0x68, 0x4d, 0x65, + 0x74, 0x61, 0x52, 0x65, 0x76, 0x65, 0x61, 0x6c, 0x22, 0x50, 0x0a, 0x13, 0x44, 0x65, 0x63, 0x6f, + 0x64, 0x65, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x39, 0x0a, 0x0d, 0x64, 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, 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, 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, 0x3e, 0x0a, 0x16, 0x55, 0x6e, 0x70, 0x61, + 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, + 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x72, 0x61, 0x77, 0x50, + 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x38, 0x0a, 0x17, 0x55, 0x6e, 0x70, 0x61, + 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x72, 0x61, 0x77, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0x73, 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, 0xf3, + 0x01, 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, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x12, 0x40, 0x0a, 0x1d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, + 0x63, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x68, 0x65, + 0x63, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x43, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x50, 0x69, 0x6e, 0x67, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x12, 0x4f, 0x0a, 0x16, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, + 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x57, 0x69, 0x74, 0x68, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x14, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x57, 0x69, 0x74, 0x68, 0x41, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x73, 0x22, 0x46, 0x0a, 0x11, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x57, + 0x69, 0x74, 0x68, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x61, 0x70, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x70, + 0x41, 0x64, 0x64, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 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, 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, 0xd4, 0x03, 0x0a, 0x16, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x29, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x12, 0x5f, 0x0a, 0x11, + 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x5f, 0x6f, 0x64, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, + 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x4f, + 0x64, 0x64, 0x54, 0x79, 0x70, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0f, 0x75, 0x6e, + 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x4f, 0x64, 0x64, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x27, 0x0a, + 0x0f, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x6c, 0x44, + 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x12, 0x31, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, + 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x65, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x61, 0x6e, + 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x65, 0x5f, + 0x75, 0x72, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x15, 0x63, 0x61, 0x6e, 0x6f, + 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x65, 0x55, 0x72, 0x6c, + 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x1a, 0x42, 0x0a, 0x14, 0x55, 0x6e, 0x6b, 0x6e, + 0x6f, 0x77, 0x6e, 0x4f, 0x64, 0x64, 0x54, 0x79, 0x70, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc3, 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, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 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, 0x7a, 0x0a, 0x10, 0x4c, 0x69, 0x73, + 0x74, 0x42, 0x75, 0x72, 0x6e, 0x73, 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, 0x2a, 0x0a, 0x11, 0x74, 0x77, 0x65, 0x61, + 0x6b, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x74, 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x4b, 0x65, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x74, + 0x78, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, + 0x72, 0x54, 0x78, 0x69, 0x64, 0x22, 0x9f, 0x01, 0x0a, 0x09, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, + 0x75, 0x72, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, 0x65, 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, 0x2a, 0x0a, 0x11, 0x74, 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x74, - 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 0x12, 0x1f, - 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x54, 0x78, 0x69, 0x64, 0x22, - 0x9f, 0x01, 0x0a, 0x09, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x74, - 0x65, 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, 0x2a, 0x0a, 0x11, - 0x74, 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x74, 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, - 0x47, 0x72, 0x6f, 0x75, 0x70, 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, - 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x54, 0x78, 0x69, - 0x64, 0x22, 0x3c, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x05, 0x62, 0x75, 0x72, 0x6e, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, - 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x52, 0x05, 0x62, 0x75, 0x72, 0x6e, 0x73, 0x22, - 0x69, 0x0a, 0x1d, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 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, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xe8, 0x01, 0x0a, 0x0c, 0x52, - 0x65, 0x63, 0x65, 0x69, 0x76, 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, 0x12, 0x2f, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 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, 0x2f, - 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, - 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 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, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x6b, 0x0a, 0x1a, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, - 0x21, 0x0a, 0x0c, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x22, 0xec, 0x03, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 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, 0x12, 0x33, 0x0a, - 0x0b, 0x70, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x72, 0x63, - 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, - 0x64, 0x64, 0x72, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x27, - 0x0a, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, - 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, - 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x70, 0x61, 0x73, 0x73, 0x69, - 0x76, 0x65, 0x5f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, - 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x15, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, - 0x65, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, - 0x48, 0x0a, 0x12, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x61, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x08, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x08, 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, 0x12, 0x14, 0x0a, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x5f, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x66, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, - 0x74, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x22, 0x97, 0x02, 0x0a, 0x11, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, - 0x72, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, - 0x63, 0x68, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x5f, 0x73, 0x61, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x65, 0x65, 0x73, 0x53, 0x61, 0x74, 0x73, - 0x12, 0x32, 0x0a, 0x16, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, - 0x61, 0x74, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x6b, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x12, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x46, 0x65, 0x65, 0x52, 0x61, 0x74, 0x65, 0x53, - 0x61, 0x74, 0x4b, 0x77, 0x12, 0x3a, 0x0a, 0x10, 0x6c, 0x6e, 0x64, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, - 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, - 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x52, 0x0e, 0x6c, 0x6e, 0x64, 0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x55, 0x74, 0x78, 0x6f, 0x73, - 0x12, 0x19, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x74, 0x78, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x07, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x54, 0x78, 0x22, 0x9e, 0x01, 0x0a, 0x17, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, - 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, 0x1b, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4b, 0x65, 0x79, 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, 0x2c, - 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x04, 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, 0x54, 0x0a, 0x18, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x10, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, - 0x74, 0x52, 0x0f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x41, 0x73, 0x73, - 0x65, 0x74, 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, 0x39, 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, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x45, 0x54, 0x41, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x01, 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, + 0x77, 0x65, 0x61, 0x6b, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 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, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, + 0x5f, 0x74, 0x78, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, + 0x68, 0x6f, 0x72, 0x54, 0x78, 0x69, 0x64, 0x22, 0x3c, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x42, + 0x75, 0x72, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x05, + 0x62, 0x75, 0x72, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x52, 0x05, + 0x62, 0x75, 0x72, 0x6e, 0x73, 0x22, 0x69, 0x0a, 0x1d, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 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, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x22, 0xe8, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 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, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 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, 0x2f, 0x0a, 0x13, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x05, 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, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x6b, 0x0a, 0x1a, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x53, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x22, 0xec, 0x03, 0x0a, 0x09, 0x53, 0x65, 0x6e, + 0x64, 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, 0x12, 0x33, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x50, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x70, 0x61, + 0x72, 0x63, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, + 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x76, + 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, + 0x17, 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x15, + 0x70, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x48, 0x0a, 0x12, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x6e, 0x63, 0x68, 0x6f, + 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x61, 0x6e, + 0x63, 0x68, 0x6f, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x31, 0x0a, 0x08, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x08, 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, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x66, 0x65, 0x72, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, + 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x53, 0x65, + 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x97, 0x02, 0x0a, 0x11, 0x41, 0x6e, 0x63, 0x68, + 0x6f, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, + 0x0b, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x5f, 0x70, 0x73, 0x62, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x50, 0x73, 0x62, 0x74, 0x12, 0x2e, + 0x0a, 0x13, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, + 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x5f, 0x73, 0x61, 0x74, + 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x65, + 0x65, 0x73, 0x53, 0x61, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x16, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x5f, 0x66, 0x65, 0x65, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x6b, 0x77, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x46, 0x65, + 0x65, 0x52, 0x61, 0x74, 0x65, 0x53, 0x61, 0x74, 0x4b, 0x77, 0x12, 0x3a, 0x0a, 0x10, 0x6c, 0x6e, + 0x64, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x5f, 0x75, 0x74, 0x78, 0x6f, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x75, + 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x0e, 0x6c, 0x6e, 0x64, 0x4c, 0x6f, 0x63, 0x6b, 0x65, + 0x64, 0x55, 0x74, 0x78, 0x6f, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x5f, + 0x74, 0x78, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x54, + 0x78, 0x22, 0x9e, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 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, 0x1b, 0x0a, 0x09, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x4b, 0x65, 0x79, 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, 0x2c, 0x0a, 0x08, 0x6f, 0x75, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x04, 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, 0x54, 0x0a, 0x18, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, + 0x0a, 0x10, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x61, 0x73, 0x73, + 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x0f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x65, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 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, 0x39, 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, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x45, 0x54, + 0x41, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x01, 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, - 0x31, 0x10, 0x01, 0x2a, 0x52, 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, 0x22, 0x04, 0x08, 0x02, 0x10, 0x02, 0x22, 0x04, 0x08, 0x03, 0x10, - 0x03, 0x22, 0x04, 0x08, 0x04, 0x10, 0x04, 0x2a, 0x86, 0x01, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x28, 0x0a, 0x24, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, - 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x41, 0x50, 0x50, - 0x4c, 0x49, 0x43, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, 0x50, 0x52, 0x4f, - 0x4f, 0x46, 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x01, 0x12, 0x21, 0x0a, - 0x1d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, - 0x2a, 0x55, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x1c, 0x0a, 0x18, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, - 0x0f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x30, - 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, - 0x4f, 0x4e, 0x5f, 0x56, 0x31, 0x10, 0x02, 0x2a, 0xc9, 0x01, 0x0a, 0x0d, 0x53, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x43, 0x52, - 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, - 0x42, 0x49, 0x50, 0x38, 0x36, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x43, 0x52, 0x49, 0x50, - 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x50, 0x41, 0x54, - 0x48, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, - 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x42, 0x55, 0x52, 0x4e, 0x10, - 0x03, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, - 0x54, 0x4f, 0x4d, 0x42, 0x53, 0x54, 0x4f, 0x4e, 0x45, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x53, - 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, - 0x4c, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, - 0x59, 0x5f, 0x55, 0x4e, 0x49, 0x51, 0x55, 0x45, 0x5f, 0x50, 0x45, 0x44, 0x45, 0x52, 0x53, 0x45, - 0x4e, 0x10, 0x06, 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, 0x9b, 0x02, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x45, 0x5f, 0x56, 0x49, 0x52, 0x54, 0x55, 0x41, 0x4c, 0x5f, 0x49, 0x4e, 0x50, 0x55, 0x54, - 0x5f, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x4e, - 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x56, 0x49, 0x52, 0x54, 0x55, 0x41, 0x4c, 0x5f, - 0x53, 0x49, 0x47, 0x4e, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x47, 0x4e, - 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, - 0x5f, 0x4c, 0x4f, 0x47, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x10, - 0x03, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, - 0x42, 0x52, 0x4f, 0x41, 0x44, 0x43, 0x41, 0x53, 0x54, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x53, - 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x57, 0x41, 0x49, 0x54, 0x5f, 0x43, - 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1b, 0x0a, - 0x17, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x52, - 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x53, 0x10, 0x06, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x45, - 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, - 0x52, 0x5f, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x53, 0x10, 0x07, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, - 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, - 0x45, 0x44, 0x10, 0x08, 0x2a, 0x78, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x41, 0x52, 0x43, 0x45, 0x4c, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x50, - 0x41, 0x52, 0x43, 0x45, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x5f, 0x53, - 0x49, 0x47, 0x4e, 0x45, 0x44, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x41, 0x52, 0x43, 0x45, - 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, - 0x12, 0x1c, 0x0a, 0x18, 0x50, 0x41, 0x52, 0x43, 0x45, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x50, 0x52, 0x45, 0x5f, 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x45, 0x44, 0x10, 0x03, 0x32, 0xd2, - 0x0c, 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, + 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, 0x52, 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, 0x22, 0x04, 0x08, 0x02, 0x10, + 0x02, 0x22, 0x04, 0x08, 0x03, 0x10, 0x03, 0x22, 0x04, 0x08, 0x04, 0x10, 0x04, 0x2a, 0x86, 0x01, + 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x28, 0x0a, 0x24, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x44, + 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4e, + 0x4f, 0x54, 0x5f, 0x41, 0x50, 0x50, 0x4c, 0x49, 0x43, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, + 0x22, 0x0a, 0x1e, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x44, 0x45, 0x4c, 0x49, 0x56, 0x45, 0x52, + 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, + 0x45, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x52, 0x4f, 0x4f, 0x46, 0x5f, 0x44, 0x45, 0x4c, + 0x49, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, + 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x2a, 0x6a, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x18, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x56, 0x45, + 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x56, 0x45, 0x52, 0x53, + 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x30, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x44, 0x52, + 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x31, 0x10, 0x02, 0x12, 0x13, 0x0a, + 0x0f, 0x41, 0x44, 0x44, 0x52, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x56, 0x32, + 0x10, 0x03, 0x2a, 0xc9, 0x01, 0x0a, 0x0d, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x4b, 0x65, 0x79, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, + 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x42, 0x49, 0x50, 0x38, 0x36, + 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, + 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x50, 0x41, 0x54, 0x48, 0x5f, 0x45, 0x58, 0x54, + 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x43, 0x52, 0x49, 0x50, + 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x42, 0x55, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x54, 0x4f, 0x4d, 0x42, 0x53, + 0x54, 0x4f, 0x4e, 0x45, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, + 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x05, 0x12, 0x1e, + 0x0a, 0x1a, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x49, + 0x51, 0x55, 0x45, 0x5f, 0x50, 0x45, 0x44, 0x45, 0x52, 0x53, 0x45, 0x4e, 0x10, 0x06, 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, 0x9b, 0x02, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x23, 0x0a, 0x1f, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x56, 0x49, + 0x52, 0x54, 0x55, 0x41, 0x4c, 0x5f, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x5f, 0x53, 0x45, 0x4c, 0x45, + 0x43, 0x54, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x5f, 0x56, 0x49, 0x52, 0x54, 0x55, 0x41, 0x4c, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x10, + 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, + 0x41, 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x10, 0x02, 0x12, 0x1d, 0x0a, + 0x19, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4c, 0x4f, 0x47, 0x5f, + 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, + 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x42, 0x52, 0x4f, 0x41, 0x44, + 0x43, 0x41, 0x53, 0x54, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x57, 0x41, 0x49, 0x54, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, + 0x4d, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x45, 0x4e, 0x44, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x52, 0x45, 0x5f, 0x50, 0x52, 0x4f, + 0x4f, 0x46, 0x53, 0x10, 0x06, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x50, 0x52, 0x4f, + 0x4f, 0x46, 0x53, 0x10, 0x07, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x4e, 0x44, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x08, 0x2a, + 0x78, 0x0a, 0x0a, 0x50, 0x61, 0x72, 0x63, 0x65, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, + 0x13, 0x50, 0x41, 0x52, 0x43, 0x45, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x44, 0x44, + 0x52, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x50, 0x41, 0x52, 0x43, 0x45, 0x4c, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x45, 0x44, + 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x41, 0x52, 0x43, 0x45, 0x4c, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x50, + 0x41, 0x52, 0x43, 0x45, 0x4c, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x5f, 0x41, + 0x4e, 0x43, 0x48, 0x4f, 0x52, 0x45, 0x44, 0x10, 0x03, 0x32, 0xd2, 0x0c, 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, 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, 0x52, 0x0a, 0x0f, - 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x12, - 0x1e, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x50, - 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 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, 0x40, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x72, 0x6e, - 0x73, 0x12, 0x18, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, - 0x75, 0x72, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, - 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x73, 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, 0x4f, 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, 0x1e, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x74, - 0x63, 0x68, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x25, 0x2e, - 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, - 0x63, 0x65, 0x69, 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x13, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x22, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x55, 0x0a, 0x10, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, - 0x12, 0x1f, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 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, + 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, 0x52, 0x0a, 0x0f, 0x55, 0x6e, 0x70, 0x61, 0x63, + 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1e, 0x2e, 0x74, 0x61, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x74, 0x61, 0x70, + 0x72, 0x70, 0x63, 0x2e, 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 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, + 0x40, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x74, + 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x72, 0x6e, 0x73, 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, 0x4f, 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, 0x1e, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x74, 0x63, 0x68, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, + 0x0a, 0x16, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x25, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x14, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x62, 0x65, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x22, + 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x53, 0x65, 0x6e, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x55, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x74, 0x61, + 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, + 0x61, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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 ( @@ -7920,7 +8042,7 @@ func file_taprootassets_proto_rawDescGZIP() []byte { } var file_taprootassets_proto_enumTypes = make([]protoimpl.EnumInfo, 10) -var file_taprootassets_proto_msgTypes = make([]protoimpl.MessageInfo, 86) +var file_taprootassets_proto_msgTypes = make([]protoimpl.MessageInfo, 87) var file_taprootassets_proto_goTypes = []any{ (AssetType)(0), // 0: taprpc.AssetType (AssetMetaType)(0), // 1: taprpc.AssetMetaType @@ -7995,35 +8117,36 @@ var file_taprootassets_proto_goTypes = []any{ (*AddrReceivesRequest)(nil), // 70: taprpc.AddrReceivesRequest (*AddrReceivesResponse)(nil), // 71: taprpc.AddrReceivesResponse (*SendAssetRequest)(nil), // 72: taprpc.SendAssetRequest - (*PrevInputAsset)(nil), // 73: taprpc.PrevInputAsset - (*SendAssetResponse)(nil), // 74: taprpc.SendAssetResponse - (*GetInfoRequest)(nil), // 75: taprpc.GetInfoRequest - (*GetInfoResponse)(nil), // 76: taprpc.GetInfoResponse - (*FetchAssetMetaRequest)(nil), // 77: taprpc.FetchAssetMetaRequest - (*FetchAssetMetaResponse)(nil), // 78: taprpc.FetchAssetMetaResponse - (*BurnAssetRequest)(nil), // 79: taprpc.BurnAssetRequest - (*BurnAssetResponse)(nil), // 80: taprpc.BurnAssetResponse - (*ListBurnsRequest)(nil), // 81: taprpc.ListBurnsRequest - (*AssetBurn)(nil), // 82: taprpc.AssetBurn - (*ListBurnsResponse)(nil), // 83: taprpc.ListBurnsResponse - (*SubscribeReceiveEventsRequest)(nil), // 84: taprpc.SubscribeReceiveEventsRequest - (*ReceiveEvent)(nil), // 85: taprpc.ReceiveEvent - (*SubscribeSendEventsRequest)(nil), // 86: taprpc.SubscribeSendEventsRequest - (*SendEvent)(nil), // 87: taprpc.SendEvent - (*AnchorTransaction)(nil), // 88: taprpc.AnchorTransaction - (*RegisterTransferRequest)(nil), // 89: taprpc.RegisterTransferRequest - (*RegisterTransferResponse)(nil), // 90: taprpc.RegisterTransferResponse - nil, // 91: taprpc.ListUtxosResponse.ManagedUtxosEntry - nil, // 92: taprpc.ListGroupsResponse.GroupsEntry - nil, // 93: taprpc.ListBalancesResponse.AssetBalancesEntry - nil, // 94: taprpc.ListBalancesResponse.AssetGroupBalancesEntry - nil, // 95: taprpc.FetchAssetMetaResponse.UnknownOddTypesEntry - (*OutPoint)(nil), // 96: taprpc.OutPoint + (*AddressWithAmount)(nil), // 73: taprpc.AddressWithAmount + (*PrevInputAsset)(nil), // 74: taprpc.PrevInputAsset + (*SendAssetResponse)(nil), // 75: taprpc.SendAssetResponse + (*GetInfoRequest)(nil), // 76: taprpc.GetInfoRequest + (*GetInfoResponse)(nil), // 77: taprpc.GetInfoResponse + (*FetchAssetMetaRequest)(nil), // 78: taprpc.FetchAssetMetaRequest + (*FetchAssetMetaResponse)(nil), // 79: taprpc.FetchAssetMetaResponse + (*BurnAssetRequest)(nil), // 80: taprpc.BurnAssetRequest + (*BurnAssetResponse)(nil), // 81: taprpc.BurnAssetResponse + (*ListBurnsRequest)(nil), // 82: taprpc.ListBurnsRequest + (*AssetBurn)(nil), // 83: taprpc.AssetBurn + (*ListBurnsResponse)(nil), // 84: taprpc.ListBurnsResponse + (*SubscribeReceiveEventsRequest)(nil), // 85: taprpc.SubscribeReceiveEventsRequest + (*ReceiveEvent)(nil), // 86: taprpc.ReceiveEvent + (*SubscribeSendEventsRequest)(nil), // 87: taprpc.SubscribeSendEventsRequest + (*SendEvent)(nil), // 88: taprpc.SendEvent + (*AnchorTransaction)(nil), // 89: taprpc.AnchorTransaction + (*RegisterTransferRequest)(nil), // 90: taprpc.RegisterTransferRequest + (*RegisterTransferResponse)(nil), // 91: taprpc.RegisterTransferResponse + nil, // 92: taprpc.ListUtxosResponse.ManagedUtxosEntry + nil, // 93: taprpc.ListGroupsResponse.GroupsEntry + nil, // 94: taprpc.ListBalancesResponse.AssetBalancesEntry + nil, // 95: taprpc.ListBalancesResponse.AssetGroupBalancesEntry + nil, // 96: taprpc.FetchAssetMetaResponse.UnknownOddTypesEntry + (*OutPoint)(nil), // 97: taprpc.OutPoint } var file_taprootassets_proto_depIdxs = []int32{ 1, // 0: taprpc.AssetMeta.type:type_name -> taprpc.AssetMetaType 54, // 1: taprpc.ListAssetRequest.script_key:type_name -> taprpc.ScriptKey - 96, // 2: taprpc.ListAssetRequest.anchor_outpoint:type_name -> taprpc.OutPoint + 97, // 2: taprpc.ListAssetRequest.anchor_outpoint:type_name -> taprpc.OutPoint 53, // 3: taprpc.ListAssetRequest.script_key_type:type_name -> taprpc.ScriptKeyTypeQuery 0, // 4: taprpc.GenesisInfo.asset_type:type_name -> taprpc.AssetType 56, // 5: taprpc.GroupKeyRequest.raw_key:type_name -> taprpc.KeyDescriptor @@ -8038,21 +8161,21 @@ var file_taprootassets_proto_depIdxs = []int32{ 24, // 14: taprpc.Asset.prev_witnesses:type_name -> taprpc.PrevWitness 22, // 15: taprpc.Asset.decimal_display:type_name -> taprpc.DecimalDisplay 6, // 16: taprpc.Asset.script_key_type:type_name -> taprpc.ScriptKeyType - 73, // 17: taprpc.PrevWitness.prev_id:type_name -> taprpc.PrevInputAsset + 74, // 17: taprpc.PrevWitness.prev_id:type_name -> taprpc.PrevInputAsset 25, // 18: taprpc.PrevWitness.split_commitment:type_name -> taprpc.SplitCommitment 23, // 19: taprpc.SplitCommitment.root_asset:type_name -> taprpc.Asset 23, // 20: taprpc.ListAssetResponse.assets:type_name -> taprpc.Asset 53, // 21: taprpc.ListUtxosRequest.script_key_type:type_name -> taprpc.ScriptKeyTypeQuery 23, // 22: taprpc.ManagedUtxo.assets:type_name -> taprpc.Asset - 91, // 23: taprpc.ListUtxosResponse.managed_utxos:type_name -> taprpc.ListUtxosResponse.ManagedUtxosEntry + 92, // 23: taprpc.ListUtxosResponse.managed_utxos:type_name -> taprpc.ListUtxosResponse.ManagedUtxosEntry 0, // 24: taprpc.AssetHumanReadable.type:type_name -> taprpc.AssetType 2, // 25: taprpc.AssetHumanReadable.version:type_name -> taprpc.AssetVersion 31, // 26: taprpc.GroupedAssets.assets:type_name -> taprpc.AssetHumanReadable - 92, // 27: taprpc.ListGroupsResponse.groups:type_name -> taprpc.ListGroupsResponse.GroupsEntry + 93, // 27: taprpc.ListGroupsResponse.groups:type_name -> taprpc.ListGroupsResponse.GroupsEntry 53, // 28: taprpc.ListBalancesRequest.script_key_type:type_name -> taprpc.ScriptKeyTypeQuery 13, // 29: taprpc.AssetBalance.asset_genesis:type_name -> taprpc.GenesisInfo - 93, // 30: taprpc.ListBalancesResponse.asset_balances:type_name -> taprpc.ListBalancesResponse.AssetBalancesEntry - 94, // 31: taprpc.ListBalancesResponse.asset_group_balances:type_name -> taprpc.ListBalancesResponse.AssetGroupBalancesEntry + 94, // 30: taprpc.ListBalancesResponse.asset_balances:type_name -> taprpc.ListBalancesResponse.AssetBalancesEntry + 95, // 31: taprpc.ListBalancesResponse.asset_group_balances:type_name -> taprpc.ListBalancesResponse.AssetGroupBalancesEntry 41, // 32: taprpc.ListTransfersResponse.transfers:type_name -> taprpc.AssetTransfer 42, // 33: taprpc.AssetTransfer.inputs:type_name -> taprpc.TransferInput 44, // 34: taprpc.AssetTransfer.outputs:type_name -> taprpc.TransferOutput @@ -8080,81 +8203,82 @@ var file_taprootassets_proto_depIdxs = []int32{ 20, // 56: taprpc.DecodedProof.group_key_reveal:type_name -> taprpc.GroupKeyReveal 62, // 57: taprpc.VerifyProofResponse.decoded_proof:type_name -> taprpc.DecodedProof 62, // 58: taprpc.DecodeProofResponse.decoded_proof:type_name -> taprpc.DecodedProof - 96, // 59: taprpc.ExportProofRequest.outpoint:type_name -> taprpc.OutPoint + 97, // 59: taprpc.ExportProofRequest.outpoint:type_name -> taprpc.OutPoint 49, // 60: taprpc.AddrEvent.addr:type_name -> taprpc.Addr 7, // 61: taprpc.AddrEvent.status:type_name -> taprpc.AddrEventStatus 7, // 62: taprpc.AddrReceivesRequest.filter_status:type_name -> taprpc.AddrEventStatus 69, // 63: taprpc.AddrReceivesResponse.events:type_name -> taprpc.AddrEvent - 41, // 64: taprpc.SendAssetResponse.transfer:type_name -> taprpc.AssetTransfer - 1, // 65: taprpc.FetchAssetMetaResponse.type:type_name -> taprpc.AssetMetaType - 95, // 66: taprpc.FetchAssetMetaResponse.unknown_odd_types:type_name -> taprpc.FetchAssetMetaResponse.UnknownOddTypesEntry - 41, // 67: taprpc.BurnAssetResponse.burn_transfer:type_name -> taprpc.AssetTransfer - 62, // 68: taprpc.BurnAssetResponse.burn_proof:type_name -> taprpc.DecodedProof - 82, // 69: taprpc.ListBurnsResponse.burns:type_name -> taprpc.AssetBurn - 49, // 70: taprpc.ReceiveEvent.address:type_name -> taprpc.Addr - 7, // 71: taprpc.ReceiveEvent.status:type_name -> taprpc.AddrEventStatus - 9, // 72: taprpc.SendEvent.parcel_type:type_name -> taprpc.ParcelType - 49, // 73: taprpc.SendEvent.addresses:type_name -> taprpc.Addr - 88, // 74: taprpc.SendEvent.anchor_transaction:type_name -> taprpc.AnchorTransaction - 41, // 75: taprpc.SendEvent.transfer:type_name -> taprpc.AssetTransfer - 96, // 76: taprpc.AnchorTransaction.lnd_locked_utxos:type_name -> taprpc.OutPoint - 96, // 77: taprpc.RegisterTransferRequest.outpoint:type_name -> taprpc.OutPoint - 23, // 78: taprpc.RegisterTransferResponse.registered_asset:type_name -> taprpc.Asset - 28, // 79: taprpc.ListUtxosResponse.ManagedUtxosEntry.value:type_name -> taprpc.ManagedUtxo - 32, // 80: taprpc.ListGroupsResponse.GroupsEntry.value:type_name -> taprpc.GroupedAssets - 35, // 81: taprpc.ListBalancesResponse.AssetBalancesEntry.value:type_name -> taprpc.AssetBalance - 36, // 82: taprpc.ListBalancesResponse.AssetGroupBalancesEntry.value:type_name -> taprpc.AssetGroupBalance - 11, // 83: taprpc.TaprootAssets.ListAssets:input_type -> taprpc.ListAssetRequest - 27, // 84: taprpc.TaprootAssets.ListUtxos:input_type -> taprpc.ListUtxosRequest - 30, // 85: taprpc.TaprootAssets.ListGroups:input_type -> taprpc.ListGroupsRequest - 34, // 86: taprpc.TaprootAssets.ListBalances:input_type -> taprpc.ListBalancesRequest - 38, // 87: taprpc.TaprootAssets.ListTransfers:input_type -> taprpc.ListTransfersRequest - 45, // 88: taprpc.TaprootAssets.StopDaemon:input_type -> taprpc.StopRequest - 47, // 89: taprpc.TaprootAssets.DebugLevel:input_type -> taprpc.DebugLevelRequest - 50, // 90: taprpc.TaprootAssets.QueryAddrs:input_type -> taprpc.QueryAddrRequest - 52, // 91: taprpc.TaprootAssets.NewAddr:input_type -> taprpc.NewAddrRequest - 60, // 92: taprpc.TaprootAssets.DecodeAddr:input_type -> taprpc.DecodeAddrRequest - 70, // 93: taprpc.TaprootAssets.AddrReceives:input_type -> taprpc.AddrReceivesRequest - 61, // 94: taprpc.TaprootAssets.VerifyProof:input_type -> taprpc.ProofFile - 64, // 95: taprpc.TaprootAssets.DecodeProof:input_type -> taprpc.DecodeProofRequest - 66, // 96: taprpc.TaprootAssets.ExportProof:input_type -> taprpc.ExportProofRequest - 67, // 97: taprpc.TaprootAssets.UnpackProofFile:input_type -> taprpc.UnpackProofFileRequest - 72, // 98: taprpc.TaprootAssets.SendAsset:input_type -> taprpc.SendAssetRequest - 79, // 99: taprpc.TaprootAssets.BurnAsset:input_type -> taprpc.BurnAssetRequest - 81, // 100: taprpc.TaprootAssets.ListBurns:input_type -> taprpc.ListBurnsRequest - 75, // 101: taprpc.TaprootAssets.GetInfo:input_type -> taprpc.GetInfoRequest - 77, // 102: taprpc.TaprootAssets.FetchAssetMeta:input_type -> taprpc.FetchAssetMetaRequest - 84, // 103: taprpc.TaprootAssets.SubscribeReceiveEvents:input_type -> taprpc.SubscribeReceiveEventsRequest - 86, // 104: taprpc.TaprootAssets.SubscribeSendEvents:input_type -> taprpc.SubscribeSendEventsRequest - 89, // 105: taprpc.TaprootAssets.RegisterTransfer:input_type -> taprpc.RegisterTransferRequest - 26, // 106: taprpc.TaprootAssets.ListAssets:output_type -> taprpc.ListAssetResponse - 29, // 107: taprpc.TaprootAssets.ListUtxos:output_type -> taprpc.ListUtxosResponse - 33, // 108: taprpc.TaprootAssets.ListGroups:output_type -> taprpc.ListGroupsResponse - 37, // 109: taprpc.TaprootAssets.ListBalances:output_type -> taprpc.ListBalancesResponse - 39, // 110: taprpc.TaprootAssets.ListTransfers:output_type -> taprpc.ListTransfersResponse - 46, // 111: taprpc.TaprootAssets.StopDaemon:output_type -> taprpc.StopResponse - 48, // 112: taprpc.TaprootAssets.DebugLevel:output_type -> taprpc.DebugLevelResponse - 51, // 113: taprpc.TaprootAssets.QueryAddrs:output_type -> taprpc.QueryAddrResponse - 49, // 114: taprpc.TaprootAssets.NewAddr:output_type -> taprpc.Addr - 49, // 115: taprpc.TaprootAssets.DecodeAddr:output_type -> taprpc.Addr - 71, // 116: taprpc.TaprootAssets.AddrReceives:output_type -> taprpc.AddrReceivesResponse - 63, // 117: taprpc.TaprootAssets.VerifyProof:output_type -> taprpc.VerifyProofResponse - 65, // 118: taprpc.TaprootAssets.DecodeProof:output_type -> taprpc.DecodeProofResponse - 61, // 119: taprpc.TaprootAssets.ExportProof:output_type -> taprpc.ProofFile - 68, // 120: taprpc.TaprootAssets.UnpackProofFile:output_type -> taprpc.UnpackProofFileResponse - 74, // 121: taprpc.TaprootAssets.SendAsset:output_type -> taprpc.SendAssetResponse - 80, // 122: taprpc.TaprootAssets.BurnAsset:output_type -> taprpc.BurnAssetResponse - 83, // 123: taprpc.TaprootAssets.ListBurns:output_type -> taprpc.ListBurnsResponse - 76, // 124: taprpc.TaprootAssets.GetInfo:output_type -> taprpc.GetInfoResponse - 78, // 125: taprpc.TaprootAssets.FetchAssetMeta:output_type -> taprpc.FetchAssetMetaResponse - 85, // 126: taprpc.TaprootAssets.SubscribeReceiveEvents:output_type -> taprpc.ReceiveEvent - 87, // 127: taprpc.TaprootAssets.SubscribeSendEvents:output_type -> taprpc.SendEvent - 90, // 128: taprpc.TaprootAssets.RegisterTransfer:output_type -> taprpc.RegisterTransferResponse - 106, // [106:129] is the sub-list for method output_type - 83, // [83:106] is the sub-list for method input_type - 83, // [83:83] is the sub-list for extension type_name - 83, // [83:83] is the sub-list for extension extendee - 0, // [0:83] is the sub-list for field type_name + 73, // 64: taprpc.SendAssetRequest.addresses_with_amounts:type_name -> taprpc.AddressWithAmount + 41, // 65: taprpc.SendAssetResponse.transfer:type_name -> taprpc.AssetTransfer + 1, // 66: taprpc.FetchAssetMetaResponse.type:type_name -> taprpc.AssetMetaType + 96, // 67: taprpc.FetchAssetMetaResponse.unknown_odd_types:type_name -> taprpc.FetchAssetMetaResponse.UnknownOddTypesEntry + 41, // 68: taprpc.BurnAssetResponse.burn_transfer:type_name -> taprpc.AssetTransfer + 62, // 69: taprpc.BurnAssetResponse.burn_proof:type_name -> taprpc.DecodedProof + 83, // 70: taprpc.ListBurnsResponse.burns:type_name -> taprpc.AssetBurn + 49, // 71: taprpc.ReceiveEvent.address:type_name -> taprpc.Addr + 7, // 72: taprpc.ReceiveEvent.status:type_name -> taprpc.AddrEventStatus + 9, // 73: taprpc.SendEvent.parcel_type:type_name -> taprpc.ParcelType + 49, // 74: taprpc.SendEvent.addresses:type_name -> taprpc.Addr + 89, // 75: taprpc.SendEvent.anchor_transaction:type_name -> taprpc.AnchorTransaction + 41, // 76: taprpc.SendEvent.transfer:type_name -> taprpc.AssetTransfer + 97, // 77: taprpc.AnchorTransaction.lnd_locked_utxos:type_name -> taprpc.OutPoint + 97, // 78: taprpc.RegisterTransferRequest.outpoint:type_name -> taprpc.OutPoint + 23, // 79: taprpc.RegisterTransferResponse.registered_asset:type_name -> taprpc.Asset + 28, // 80: taprpc.ListUtxosResponse.ManagedUtxosEntry.value:type_name -> taprpc.ManagedUtxo + 32, // 81: taprpc.ListGroupsResponse.GroupsEntry.value:type_name -> taprpc.GroupedAssets + 35, // 82: taprpc.ListBalancesResponse.AssetBalancesEntry.value:type_name -> taprpc.AssetBalance + 36, // 83: taprpc.ListBalancesResponse.AssetGroupBalancesEntry.value:type_name -> taprpc.AssetGroupBalance + 11, // 84: taprpc.TaprootAssets.ListAssets:input_type -> taprpc.ListAssetRequest + 27, // 85: taprpc.TaprootAssets.ListUtxos:input_type -> taprpc.ListUtxosRequest + 30, // 86: taprpc.TaprootAssets.ListGroups:input_type -> taprpc.ListGroupsRequest + 34, // 87: taprpc.TaprootAssets.ListBalances:input_type -> taprpc.ListBalancesRequest + 38, // 88: taprpc.TaprootAssets.ListTransfers:input_type -> taprpc.ListTransfersRequest + 45, // 89: taprpc.TaprootAssets.StopDaemon:input_type -> taprpc.StopRequest + 47, // 90: taprpc.TaprootAssets.DebugLevel:input_type -> taprpc.DebugLevelRequest + 50, // 91: taprpc.TaprootAssets.QueryAddrs:input_type -> taprpc.QueryAddrRequest + 52, // 92: taprpc.TaprootAssets.NewAddr:input_type -> taprpc.NewAddrRequest + 60, // 93: taprpc.TaprootAssets.DecodeAddr:input_type -> taprpc.DecodeAddrRequest + 70, // 94: taprpc.TaprootAssets.AddrReceives:input_type -> taprpc.AddrReceivesRequest + 61, // 95: taprpc.TaprootAssets.VerifyProof:input_type -> taprpc.ProofFile + 64, // 96: taprpc.TaprootAssets.DecodeProof:input_type -> taprpc.DecodeProofRequest + 66, // 97: taprpc.TaprootAssets.ExportProof:input_type -> taprpc.ExportProofRequest + 67, // 98: taprpc.TaprootAssets.UnpackProofFile:input_type -> taprpc.UnpackProofFileRequest + 72, // 99: taprpc.TaprootAssets.SendAsset:input_type -> taprpc.SendAssetRequest + 80, // 100: taprpc.TaprootAssets.BurnAsset:input_type -> taprpc.BurnAssetRequest + 82, // 101: taprpc.TaprootAssets.ListBurns:input_type -> taprpc.ListBurnsRequest + 76, // 102: taprpc.TaprootAssets.GetInfo:input_type -> taprpc.GetInfoRequest + 78, // 103: taprpc.TaprootAssets.FetchAssetMeta:input_type -> taprpc.FetchAssetMetaRequest + 85, // 104: taprpc.TaprootAssets.SubscribeReceiveEvents:input_type -> taprpc.SubscribeReceiveEventsRequest + 87, // 105: taprpc.TaprootAssets.SubscribeSendEvents:input_type -> taprpc.SubscribeSendEventsRequest + 90, // 106: taprpc.TaprootAssets.RegisterTransfer:input_type -> taprpc.RegisterTransferRequest + 26, // 107: taprpc.TaprootAssets.ListAssets:output_type -> taprpc.ListAssetResponse + 29, // 108: taprpc.TaprootAssets.ListUtxos:output_type -> taprpc.ListUtxosResponse + 33, // 109: taprpc.TaprootAssets.ListGroups:output_type -> taprpc.ListGroupsResponse + 37, // 110: taprpc.TaprootAssets.ListBalances:output_type -> taprpc.ListBalancesResponse + 39, // 111: taprpc.TaprootAssets.ListTransfers:output_type -> taprpc.ListTransfersResponse + 46, // 112: taprpc.TaprootAssets.StopDaemon:output_type -> taprpc.StopResponse + 48, // 113: taprpc.TaprootAssets.DebugLevel:output_type -> taprpc.DebugLevelResponse + 51, // 114: taprpc.TaprootAssets.QueryAddrs:output_type -> taprpc.QueryAddrResponse + 49, // 115: taprpc.TaprootAssets.NewAddr:output_type -> taprpc.Addr + 49, // 116: taprpc.TaprootAssets.DecodeAddr:output_type -> taprpc.Addr + 71, // 117: taprpc.TaprootAssets.AddrReceives:output_type -> taprpc.AddrReceivesResponse + 63, // 118: taprpc.TaprootAssets.VerifyProof:output_type -> taprpc.VerifyProofResponse + 65, // 119: taprpc.TaprootAssets.DecodeProof:output_type -> taprpc.DecodeProofResponse + 61, // 120: taprpc.TaprootAssets.ExportProof:output_type -> taprpc.ProofFile + 68, // 121: taprpc.TaprootAssets.UnpackProofFile:output_type -> taprpc.UnpackProofFileResponse + 75, // 122: taprpc.TaprootAssets.SendAsset:output_type -> taprpc.SendAssetResponse + 81, // 123: taprpc.TaprootAssets.BurnAsset:output_type -> taprpc.BurnAssetResponse + 84, // 124: taprpc.TaprootAssets.ListBurns:output_type -> taprpc.ListBurnsResponse + 77, // 125: taprpc.TaprootAssets.GetInfo:output_type -> taprpc.GetInfoResponse + 79, // 126: taprpc.TaprootAssets.FetchAssetMeta:output_type -> taprpc.FetchAssetMetaResponse + 86, // 127: taprpc.TaprootAssets.SubscribeReceiveEvents:output_type -> taprpc.ReceiveEvent + 88, // 128: taprpc.TaprootAssets.SubscribeSendEvents:output_type -> taprpc.SendEvent + 91, // 129: taprpc.TaprootAssets.RegisterTransfer:output_type -> taprpc.RegisterTransferResponse + 107, // [107:130] is the sub-list for method output_type + 84, // [84:107] is the sub-list for method input_type + 84, // [84:84] is the sub-list for extension type_name + 84, // [84:84] is the sub-list for extension extendee + 0, // [0:84] is the sub-list for field type_name } func init() { file_taprootassets_proto_init() } @@ -8921,7 +9045,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[63].Exporter = func(v any, i int) any { - switch v := v.(*PrevInputAsset); i { + switch v := v.(*AddressWithAmount); i { case 0: return &v.state case 1: @@ -8933,7 +9057,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[64].Exporter = func(v any, i int) any { - switch v := v.(*SendAssetResponse); i { + switch v := v.(*PrevInputAsset); i { case 0: return &v.state case 1: @@ -8945,7 +9069,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[65].Exporter = func(v any, i int) any { - switch v := v.(*GetInfoRequest); i { + switch v := v.(*SendAssetResponse); i { case 0: return &v.state case 1: @@ -8957,7 +9081,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[66].Exporter = func(v any, i int) any { - switch v := v.(*GetInfoResponse); i { + switch v := v.(*GetInfoRequest); i { case 0: return &v.state case 1: @@ -8969,7 +9093,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[67].Exporter = func(v any, i int) any { - switch v := v.(*FetchAssetMetaRequest); i { + switch v := v.(*GetInfoResponse); i { case 0: return &v.state case 1: @@ -8981,7 +9105,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[68].Exporter = func(v any, i int) any { - switch v := v.(*FetchAssetMetaResponse); i { + switch v := v.(*FetchAssetMetaRequest); i { case 0: return &v.state case 1: @@ -8993,7 +9117,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[69].Exporter = func(v any, i int) any { - switch v := v.(*BurnAssetRequest); i { + switch v := v.(*FetchAssetMetaResponse); i { case 0: return &v.state case 1: @@ -9005,7 +9129,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[70].Exporter = func(v any, i int) any { - switch v := v.(*BurnAssetResponse); i { + switch v := v.(*BurnAssetRequest); i { case 0: return &v.state case 1: @@ -9017,7 +9141,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[71].Exporter = func(v any, i int) any { - switch v := v.(*ListBurnsRequest); i { + switch v := v.(*BurnAssetResponse); i { case 0: return &v.state case 1: @@ -9029,7 +9153,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[72].Exporter = func(v any, i int) any { - switch v := v.(*AssetBurn); i { + switch v := v.(*ListBurnsRequest); i { case 0: return &v.state case 1: @@ -9041,7 +9165,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[73].Exporter = func(v any, i int) any { - switch v := v.(*ListBurnsResponse); i { + switch v := v.(*AssetBurn); i { case 0: return &v.state case 1: @@ -9053,7 +9177,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[74].Exporter = func(v any, i int) any { - switch v := v.(*SubscribeReceiveEventsRequest); i { + switch v := v.(*ListBurnsResponse); i { case 0: return &v.state case 1: @@ -9065,7 +9189,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[75].Exporter = func(v any, i int) any { - switch v := v.(*ReceiveEvent); i { + switch v := v.(*SubscribeReceiveEventsRequest); i { case 0: return &v.state case 1: @@ -9077,7 +9201,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[76].Exporter = func(v any, i int) any { - switch v := v.(*SubscribeSendEventsRequest); i { + switch v := v.(*ReceiveEvent); i { case 0: return &v.state case 1: @@ -9089,7 +9213,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[77].Exporter = func(v any, i int) any { - switch v := v.(*SendEvent); i { + switch v := v.(*SubscribeSendEventsRequest); i { case 0: return &v.state case 1: @@ -9101,7 +9225,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[78].Exporter = func(v any, i int) any { - switch v := v.(*AnchorTransaction); i { + switch v := v.(*SendEvent); i { case 0: return &v.state case 1: @@ -9113,7 +9237,7 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[79].Exporter = func(v any, i int) any { - switch v := v.(*RegisterTransferRequest); i { + switch v := v.(*AnchorTransaction); i { case 0: return &v.state case 1: @@ -9125,6 +9249,18 @@ func file_taprootassets_proto_init() { } } file_taprootassets_proto_msgTypes[80].Exporter = func(v any, i int) any { + switch v := v.(*RegisterTransferRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_taprootassets_proto_msgTypes[81].Exporter = func(v any, i int) any { switch v := v.(*RegisterTransferResponse); i { case 0: return &v.state @@ -9145,13 +9281,13 @@ func file_taprootassets_proto_init() { (*ScriptKeyTypeQuery_ExplicitType)(nil), (*ScriptKeyTypeQuery_AllTypes)(nil), } - file_taprootassets_proto_msgTypes[67].OneofWrappers = []any{ + file_taprootassets_proto_msgTypes[68].OneofWrappers = []any{ (*FetchAssetMetaRequest_AssetId)(nil), (*FetchAssetMetaRequest_MetaHash)(nil), (*FetchAssetMetaRequest_AssetIdStr)(nil), (*FetchAssetMetaRequest_MetaHashStr)(nil), } - file_taprootassets_proto_msgTypes[69].OneofWrappers = []any{ + file_taprootassets_proto_msgTypes[70].OneofWrappers = []any{ (*BurnAssetRequest_AssetId)(nil), (*BurnAssetRequest_AssetIdStr)(nil), } @@ -9161,7 +9297,7 @@ func file_taprootassets_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_taprootassets_proto_rawDesc, NumEnums: 10, - NumMessages: 86, + NumMessages: 87, NumExtensions: 0, NumServices: 1, }, diff --git a/taprpc/taprootassets.proto b/taprpc/taprootassets.proto index 05ab39241..5db7a5eff 100644 --- a/taprpc/taprootassets.proto +++ b/taprpc/taprootassets.proto @@ -916,19 +916,27 @@ enum AddrVersion { // ADDR_VERSION_V1 is the address version that uses V2 Taproot Asset // commitments. ADDR_VERSION_V1 = 2; + + // ADDR_VERSION_V2 is the address version that supports sending grouped + // assets and require the new auth mailbox proof courier address format. + ADDR_VERSION_V2 = 3; } message Addr { // The bech32 encoded Taproot Asset address. string encoded = 1; - // The asset ID that uniquely identifies the asset. + // The asset ID that uniquely identifies the asset. This can be all zeroes + // for V2 addresses that have a group key set. bytes asset_id = 2; // The type of the asset. AssetType asset_type = 3; - // The total amount of the asset stored in this Taproot Asset UTXO. + // The total amount of the asset stored in this Taproot Asset UTXO. The + // amount is allowed to be unset for V2 addresses, where the sender will + // post a fragment containing the asset IDs and amounts to the proof + // courier's auth mailbox. uint64 amount = 4; // The group key of the asset (if it exists) @@ -958,7 +966,9 @@ message Addr { */ bytes taproot_output_key = 9; - // The address of the proof courier service used in proof transfer. + // The address of the proof courier service used in proof transfer. For V2 + // addresses the proof courier address is mandatory and must be a valid auth + // mailbox address (authmailbox+universerpc://host:port). string proof_courier_addr = 10; // The asset version of the address. @@ -993,8 +1003,18 @@ message QueryAddrResponse { } message NewAddrRequest { + /* + The asset ID to create the address for. This is required for V0 and V1 + addresses. For V2 addresses, this field is optional and must be empty if the + group key is set. + */ bytes asset_id = 1; + /* + The number of asset units to be sent to the address. This is required for V0 + and V1 addresses. For V2 addresses, this field is optional and can be left + at 0 to indicate that the sender can choose the amount of assets to send. + */ uint64 amt = 2; /* @@ -1040,6 +1060,12 @@ message NewAddrRequest { The version of this address. */ AddrVersion address_version = 8; + + /* + The group key to receive assets for. This can only be specified for V2 + addresses. If this field is set, the asset_id field must be empty. + */ + bytes group_key = 9; } enum ScriptKeyType { @@ -1374,12 +1400,17 @@ message AddrReceivesResponse { } message SendAssetRequest { + // The list of TAP addresses to send assets to. The amount to send to each + // address is determined by the amount specified in the address itself. For + // V2 addresses that are allowed to not specify an amount, use the + // addresses_with_amounts list to specify the amount to send to each + // address. The tap_addrs and addresses_with_amounts lists are mutually + // exclusive, meaning that if addresses_with_amounts is set, then tap_addrs + // must be empty, and vice versa. repeated string tap_addrs = 1; // The optional fee rate to use for the minting transaction, in sat/kw. uint32 fee_rate = 2; - // TODO(roasbeef): maybe in future add details re type of ProofCourier or - // w/e // An optional short label for the send transfer. This label can be used to // track the progress of the transfer via the logs or an event subscription. @@ -1390,6 +1421,26 @@ message SendAssetRequest { // testing purposes and for forced transfers when the proof courier // is not immediately available. bool skip_proof_courier_ping_check = 4; + + // A list of addresses and the amounts of asset units to send to them. This + // must be used for V2 TAP addresses that don't specify an amount in the + // address itself and allow the sender to choose the amount to send. The + // tap_addrs and addresses_with_amounts lists are mutually exclusive, + // meaning that if addresses_with_amounts is set, then tap_addrs must be + // empty, and vice versa. + repeated AddressWithAmount addresses_with_amounts = 5; +} + +message AddressWithAmount { + // The TAP address to send assets to. + string tap_addr = 1; + + // The amount of asset units to send to the address. This is only used for + // re-usable V2 addresses that don't specify an amount in the address itself + // and allow the sender to specify the amount on each send attempt. For V0 + // or V1 addresses, this can be left empty (zero) as the amount is taken + // from the address itself. + uint64 amount = 2; } message PrevInputAsset { diff --git a/taprpc/taprootassets.swagger.json b/taprpc/taprootassets.swagger.json index 40374345e..8b9fe2b41 100644 --- a/taprpc/taprootassets.swagger.json +++ b/taprpc/taprootassets.swagger.json @@ -1172,7 +1172,7 @@ "asset_id": { "type": "string", "format": "byte", - "description": "The asset ID that uniquely identifies the asset." + "description": "The asset ID that uniquely identifies the asset. This can be all zeroes\nfor V2 addresses that have a group key set." }, "asset_type": { "$ref": "#/definitions/taprpcAssetType", @@ -1181,7 +1181,7 @@ "amount": { "type": "string", "format": "uint64", - "description": "The total amount of the asset stored in this Taproot Asset UTXO." + "description": "The total amount of the asset stored in this Taproot Asset UTXO. The\namount is allowed to be unset for V2 addresses, where the sender will\npost a fragment containing the asset IDs and amounts to the proof\ncourier's auth mailbox." }, "group_key": { "type": "string", @@ -1210,7 +1210,7 @@ }, "proof_courier_addr": { "type": "string", - "description": "The address of the proof courier service used in proof transfer." + "description": "The address of the proof courier service used in proof transfer. For V2\naddresses the proof courier address is mandatory and must be a valid auth\nmailbox address (authmailbox+universerpc://host:port)." }, "asset_version": { "$ref": "#/definitions/taprpcAssetVersion", @@ -1305,10 +1305,25 @@ "enum": [ "ADDR_VERSION_UNSPECIFIED", "ADDR_VERSION_V0", - "ADDR_VERSION_V1" + "ADDR_VERSION_V1", + "ADDR_VERSION_V2" ], "default": "ADDR_VERSION_UNSPECIFIED", - "description": " - ADDR_VERSION_UNSPECIFIED: ADDR_VERSION_UNSPECIFIED is the default value for an address version in\nan RPC message. It is unmarshalled to the latest address version.\n - ADDR_VERSION_V0: ADDR_VERSION_V0 is the initial address version.\n - ADDR_VERSION_V1: ADDR_VERSION_V1 is the address version that uses V2 Taproot Asset\ncommitments." + "description": " - ADDR_VERSION_UNSPECIFIED: ADDR_VERSION_UNSPECIFIED is the default value for an address version in\nan RPC message. It is unmarshalled to the latest address version.\n - ADDR_VERSION_V0: ADDR_VERSION_V0 is the initial address version.\n - ADDR_VERSION_V1: ADDR_VERSION_V1 is the address version that uses V2 Taproot Asset\ncommitments.\n - ADDR_VERSION_V2: ADDR_VERSION_V2 is the address version that supports sending grouped\nassets and require the new auth mailbox proof courier address format." + }, + "taprpcAddressWithAmount": { + "type": "object", + "properties": { + "tap_addr": { + "type": "string", + "description": "The TAP address to send assets to." + }, + "amount": { + "type": "string", + "format": "uint64", + "description": "The amount of asset units to send to the address. This is only used for\nre-usable V2 addresses that don't specify an amount in the address itself\nand allow the sender to specify the amount on each send attempt. For V0\nor V1 addresses, this can be left empty (zero) as the amount is taken\nfrom the address itself." + } + } }, "taprpcAnchorInfo": { "type": "object", @@ -2239,11 +2254,13 @@ "properties": { "asset_id": { "type": "string", - "format": "byte" + "format": "byte", + "description": "The asset ID to create the address for. This is required for V0 and V1\naddresses. For V2 addresses, this field is optional and must be empty if the\ngroup key is set." }, "amt": { "type": "string", - "format": "uint64" + "format": "uint64", + "description": "The number of asset units to be sent to the address. This is required for V0\nand V1 addresses. For V2 addresses, this field is optional and can be left\nat 0 to indicate that the sender can choose the amount of assets to send." }, "script_key": { "$ref": "#/definitions/taprpcScriptKey", @@ -2269,6 +2286,11 @@ "address_version": { "$ref": "#/definitions/taprpcAddrVersion", "description": "The version of this address." + }, + "group_key": { + "type": "string", + "format": "byte", + "description": "The group key to receive assets for. This can only be specified for V2\naddresses. If this field is set, the asset_id field must be empty." } } }, @@ -2501,12 +2523,13 @@ "type": "array", "items": { "type": "string" - } + }, + "description": "The list of TAP addresses to send assets to. The amount to send to each\naddress is determined by the amount specified in the address itself. For\nV2 addresses that are allowed to not specify an amount, use the\naddresses_with_amounts list to specify the amount to send to each\naddress. The tap_addrs and addresses_with_amounts lists are mutually\nexclusive, meaning that if addresses_with_amounts is set, then tap_addrs\nmust be empty, and vice versa." }, "fee_rate": { "type": "integer", "format": "int64", - "description": "The optional fee rate to use for the minting transaction, in sat/kw.\n\nTODO(roasbeef): maybe in future add details re type of ProofCourier or\n w/e" + "description": "The optional fee rate to use for the minting transaction, in sat/kw." }, "label": { "type": "string", @@ -2515,6 +2538,14 @@ "skip_proof_courier_ping_check": { "type": "boolean", "description": "A flag to skip the proof courier ping check. This is useful for\ntesting purposes and for forced transfers when the proof courier\nis not immediately available." + }, + "addresses_with_amounts": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/taprpcAddressWithAmount" + }, + "description": "A list of addresses and the amounts of asset units to send to them. This\nmust be used for V2 TAP addresses that don't specify an amount in the\naddress itself and allow the sender to choose the amount to send. The\ntap_addrs and addresses_with_amounts lists are mutually exclusive,\nmeaning that if addresses_with_amounts is set, then tap_addrs must be\nempty, and vice versa." } } }, diff --git a/tapsend/allocation.go b/tapsend/allocation.go index 76d53778c..1c0be0c98 100644 --- a/tapsend/allocation.go +++ b/tapsend/allocation.go @@ -211,6 +211,10 @@ type Allocation struct { // upload the proof for this allocation. ProofDeliveryAddress *url.URL + // Address is the Taproot Address that the asset allocation is + // intended for. + Address *address.Tap + // AltLeaves represent data used to construct an Asset commitment, that // will be inserted in the output anchor Tap commitment. These // data-carrying leaves are used for a purpose distinct from @@ -622,6 +626,7 @@ func allocatePiece(p piece, a Allocation, toFill uint64, LockTime: a.LockTime, RelativeLockTime: uint64(a.Sequence), AltLeaves: a.AltLeaves, + Address: a.Address, } // If we've allocated all pieces, or we don't need to allocate anything @@ -846,6 +851,7 @@ func setAllocationFieldsFromOutput(alloc *Allocation, vOut *tappsbt.VOutput) { alloc.ProofDeliveryAddress = vOut.ProofDeliveryAddress alloc.AltLeaves = vOut.AltLeaves alloc.SiblingPreimage = vOut.AnchorOutputTapscriptSibling + alloc.Address = vOut.Address } // GroupProofsByAssetID groups the given proofs by their asset ID. diff --git a/tapsend/send.go b/tapsend/send.go index d5b1f1af4..8d9d3bba5 100644 --- a/tapsend/send.go +++ b/tapsend/send.go @@ -252,6 +252,12 @@ func DescribeAddrs(addrs []*address.Tap) (*FundingDescriptor, error) { firstAddr.AssetID, firstAddr.GroupKey, ) + if firstAddr.Version == address.V2 && firstAddr.GroupKey != nil { + assetSpecifier = asset.NewSpecifierFromGroupKey( + *firstAddr.GroupKey, + ) + } + desc := &FundingDescriptor{ AssetSpecifier: assetSpecifier, }