Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional memo to TAP addresses #757

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions address/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ type Tap struct {
// ProofCourierAddr is the address of the proof courier that will be
// used to distribute related proofs for this address.
ProofCourierAddr url.URL

// Memo is an optional memo that can be attached to the address.
Memo string
}

// newAddrOptions are a set of options that can modified how a new address is
Expand Down Expand Up @@ -154,7 +157,7 @@ func New(version Version, genesis asset.Genesis, groupKey *btcec.PublicKey,
groupWitness wire.TxWitness, scriptKey btcec.PublicKey,
internalKey btcec.PublicKey, amt uint64,
tapscriptSibling *commitment.TapscriptPreimage,
net *ChainParams, proofCourierAddr url.URL,
net *ChainParams, proofCourierAddr url.URL, memo string,
opts ...NewAddrOpt) (*Tap, error) {

options := defaultNewAddrOptions()
Expand Down Expand Up @@ -214,6 +217,7 @@ func New(version Version, genesis asset.Genesis, groupKey *btcec.PublicKey,
Amount: amt,
assetGen: genesis,
ProofCourierAddr: proofCourierAddr,
Memo: memo,
}
return &payload, nil
}
Expand Down Expand Up @@ -323,7 +327,7 @@ func (a *Tap) TaprootOutputKey() (*btcec.PublicKey, error) {
// EncodeRecords determines the non-nil records to include when encoding an
// address at runtime.
func (a *Tap) EncodeRecords() []tlv.Record {
records := make([]tlv.Record, 0, 9)
records := make([]tlv.Record, 0, 10)
records = append(records, newAddressVersionRecord(&a.Version))
records = append(records, newAddressAssetVersionRecord(&a.AssetVersion))
records = append(records, newAddressAssetID(&a.AssetID))
Expand All @@ -345,6 +349,10 @@ func (a *Tap) EncodeRecords() []tlv.Record {
records, newProofCourierAddrRecord(&a.ProofCourierAddr),
)

if a.Memo != "" {
records = append(records, newMemoRecord(&a.Memo))
}

return records
}

Expand All @@ -361,6 +369,7 @@ func (a *Tap) DecodeRecords() []tlv.Record {
newAddressTapscriptSiblingRecord(&a.TapscriptSibling),
newAddressAmountRecord(&a.Amount),
newProofCourierAddrRecord(&a.ProofCourierAddr),
newMemoRecord(&a.Memo),
}
}

Expand Down
7 changes: 4 additions & 3 deletions address/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ var (
"a0afeb165f0ec36880b68e0baabd9ad9c62fd1a69aa998bc30e9a346202e" +
"078f",
)
pubKey, _ = schnorr.ParsePubKey(pubKeyBytes)

pubKey, _ = schnorr.ParsePubKey(pubKeyBytes)
addrMemo = "memo"
generatedTestVectorName = "address_tlv_encoding_generated.json"

allTestVectorFiles = []string{
Expand Down Expand Up @@ -79,7 +79,7 @@ func randAddress(t *testing.T, net *ChainParams, v Version, groupPubKey,

return New(
v, genesis, groupKey, groupWitness, scriptKey, internalKey,
amount, tapscriptSibling, net, proofCourierAddr,
amount, tapscriptSibling, net, proofCourierAddr, addrMemo,
addrOpts...,
)
}
Expand Down Expand Up @@ -112,6 +112,7 @@ func assertAddressEqual(t *testing.T, a, b *Tap) {
require.Equal(t, a.ScriptKey, b.ScriptKey)
require.Equal(t, a.InternalKey, b.InternalKey)
require.Equal(t, a.Amount, b.Amount)
require.Equal(t, a.Memo, b.Memo)
}

// TestNewAddress tests edge cases around creating a new address.
Expand Down
8 changes: 4 additions & 4 deletions address/book.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func (b *Book) queryAssetInfo(ctx context.Context,

// NewAddress creates a new Taproot Asset address based on the input parameters.
func (b *Book) NewAddress(ctx context.Context, assetID asset.ID, amount uint64,
tapscriptSibling *commitment.TapscriptPreimage,
tapscriptSibling *commitment.TapscriptPreimage, memo string,
proofCourierAddr url.URL, addrOpts ...NewAddrOpt,
) (*AddrWithKeyInfo, error) {

Expand Down Expand Up @@ -278,7 +278,7 @@ func (b *Book) NewAddress(ctx context.Context, assetID asset.ID, amount uint64,

return b.NewAddressWithKeys(
ctx, assetID, amount, scriptKey, internalKeyDesc,
tapscriptSibling, proofCourierAddr, addrOpts...,
tapscriptSibling, proofCourierAddr, memo, addrOpts...,
)
}

Expand All @@ -288,7 +288,7 @@ func (b *Book) NewAddressWithKeys(ctx context.Context, assetID asset.ID,
amount uint64, scriptKey asset.ScriptKey,
internalKeyDesc keychain.KeyDescriptor,
tapscriptSibling *commitment.TapscriptPreimage,
proofCourierAddr url.URL,
proofCourierAddr url.URL, memo string,
addrOpts ...NewAddrOpt) (*AddrWithKeyInfo, error) {

// Before we proceed, we'll make sure that the asset group is known to
Expand All @@ -312,7 +312,7 @@ func (b *Book) NewAddressWithKeys(ctx context.Context, assetID asset.ID,
baseAddr, err := New(
V0, *assetGroup.Genesis, groupKey, groupWitness,
*scriptKey.PubKey, *internalKeyDesc.PubKey, amount,
tapscriptSibling, &b.cfg.Chain, proofCourierAddr,
tapscriptSibling, &b.cfg.Chain, proofCourierAddr, memo,
addrOpts...,
)
if err != nil {
Expand Down
21 changes: 21 additions & 0 deletions address/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,24 @@ func VersionDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error {
}
return tlv.NewTypeForDecodingErr(val, "Version", l, 1)
}

func memoEncoder(w io.Writer, val any, buf *[8]byte) error {
if t, ok := val.(*string); ok {
memoBytes := []byte(*t)
return tlv.EVarBytes(w, &memoBytes, buf)
}
return tlv.NewTypeForEncodingErr(val, "*string")
}

func memoDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error {
if t, ok := val.(*string); ok {
var memoBytes []byte
err := tlv.DVarBytes(r, &memoBytes, buf, l)
if err != nil {
return err
}
*t = string(memoBytes)
return nil
}
return tlv.NewTypeForDecodingErr(val, "*string", l, l)
}
4 changes: 3 additions & 1 deletion address/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ func RandAddr(t testing.TB, params *ChainParams,
assetVersion = asset.V1
}

randMemo := test.RandHash().String()

tapAddr, err := New(
V0, genesis, groupPubKey, groupWitness, *scriptKey.PubKey,
*internalKey.PubKey(), amount, tapscriptSibling, params,
proofCourierAddr, WithAssetVersion(assetVersion),
proofCourierAddr, randMemo, WithAssetVersion(assetVersion),
)
require.NoError(t, err)

Expand Down
16 changes: 16 additions & 0 deletions address/records.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ const (

// addrProofCourierType is the TLV type of the proof courier address.
addrProofCourierAddrType addressTLVType = 12

// addrMemoType is the TLV type of the memo.
addrMemoType addressTLVType = 13
)

func newAddressVersionRecord(version *Version) tlv.Record {
Expand Down Expand Up @@ -118,3 +121,16 @@ func newProofCourierAddrRecord(addr *url.URL) tlv.Record {
urlEncoder, urlDecoder,
)
}

func newMemoRecord(memo *string) tlv.Record {
var memoBytes []byte
if memo != nil {
memoBytes = []byte(*memo)
}
recordSize := tlv.SizeVarBytes(&memoBytes)

return tlv.MakeDynamicRecord(
addrMemoType, memo, recordSize,
memoEncoder, memoDecoder,
)
}
6 changes: 6 additions & 0 deletions cmd/tapcli/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const (
amtName = "amt"
assetVersionName = "asset_version"
proofCourierAddrName = "proof_courier_addr"
memoName = "memo"
)

var newAddrCommand = cli.Command{
Expand Down Expand Up @@ -59,6 +60,10 @@ var newAddrCommand = cli.Command{
"default proof courier should be " +
"overwritten; format: protocol://host:port",
},
cli.StringFlag{
Name: memoName,
Usage: "(optional) a memo to attach to the address",
},
},
Action: newAddr,
}
Expand Down Expand Up @@ -90,6 +95,7 @@ func newAddr(ctx *cli.Context) error {
Amt: ctx.Uint64(amtName),
AssetVersion: assetVersion,
ProofCourierAddr: ctx.String(proofCourierAddrName),
Memo: ctx.String(memoName),
})
if err != nil {
return fmt.Errorf("unable to make addr: %w", err)
Expand Down
2 changes: 2 additions & 0 deletions itest/addrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,10 @@ func testAddressAssetSyncer(t *harnessTest) {
AssetId: firstAsset.AssetGenesis.AssetId,
Amt: firstAsset.Amount,
AssetVersion: firstAsset.Version,
Memo: "first_address",
})
require.NoError(t.t, err)
require.Equal(t.t, "first_address", firstAddr.Memo)
AssertAddr(t.t, firstAsset, firstAddr)

secondAsset := secondRpcAssets[1]
Expand Down
7 changes: 4 additions & 3 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1106,8 +1106,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, assetID, req.Amt, tapscriptSibling, *courierAddr,
address.WithAssetVersion(assetVersion),
ctx, assetID, req.Amt, tapscriptSibling, req.Memo,
*courierAddr, address.WithAssetVersion(assetVersion),
)
if err != nil {
return nil, fmt.Errorf("unable to make new addr: %w",
Expand Down Expand Up @@ -1147,7 +1147,7 @@ func (r *rpcServer) NewAddr(ctx context.Context,
// address to the addr book.
addr, err = r.cfg.AddrBook.NewAddressWithKeys(
ctx, assetID, req.Amt, *scriptKey, internalKey,
tapscriptSibling, *courierAddr,
tapscriptSibling, *courierAddr, req.Memo,
address.WithAssetVersion(assetVersion),
)
if err != nil {
Expand Down Expand Up @@ -1896,6 +1896,7 @@ func marshalAddr(addr *address.Tap,
TaprootOutputKey: taprootOutputKey,
AssetType: taprpc.AssetType(addr.AssetType()),
ProofCourierAddr: addr.ProofCourierAddr.String(),
Memo: addr.Memo,
}

if addr.GroupKey != nil {
Expand Down
4 changes: 3 additions & 1 deletion tapdb/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ func (t *TapAddressBook) InsertAddrs(ctx context.Context,
AssetType: int16(assetGen.AssetType),
CreationTime: addr.CreationTime.UTC(),
ProofCourierAddr: proofCourierAddrBytes,
Memo: addr.Memo,
})
if err != nil {
return fmt.Errorf("unable to insert addr: %w",
Expand Down Expand Up @@ -438,6 +439,7 @@ func (t *TapAddressBook) QueryAddrs(ctx context.Context,
groupKey, groupWitness,
*scriptKey, *internalKey, uint64(addr.Amount),
tapscriptSibling, t.params, *proofCourierAddr,
addr.Memo,
address.WithAssetVersion(
asset.Version(addr.AssetVersion),
),
Expand Down Expand Up @@ -587,7 +589,7 @@ func fetchAddr(ctx context.Context, db AddrBook, params *address.ChainParams,
tapAddr, err := address.New(
address.Version(dbAddr.Version), genesis, groupKey,
groupWitness, *scriptKey, *internalKey, uint64(dbAddr.Amount),
tapscriptSibling, params, *proofCourierAddr,
tapscriptSibling, params, *proofCourierAddr, dbAddr.Memo,
address.WithAssetVersion(asset.Version(dbAddr.AssetVersion)),
)
if err != nil {
Expand Down
14 changes: 10 additions & 4 deletions tapdb/sqlc/addrs.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tapdb/sqlc/migrations/000015_addr_memo.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Alter the addrs table to add a memo field.
ALTER TABLE addrs DROP COLUMN memo;
2 changes: 2 additions & 0 deletions tapdb/sqlc/migrations/000015_addr_memo.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- Alter the addrs table to add a memo field.
ALTER TABLE addrs ADD COLUMN memo TEXT NOT NULL DEFAULT '';
1 change: 1 addition & 0 deletions tapdb/sqlc/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions tapdb/sqlc/queries/addrs.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
INSERT INTO addrs (
version, asset_version, genesis_asset_id, group_key, script_key_id,
taproot_key_id, tapscript_sibling, taproot_output_key, amount, asset_type,
creation_time, proof_courier_addr
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING id;
creation_time, proof_courier_addr, memo
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id;

-- name: FetchAddrs :many
SELECT
version, asset_version, genesis_asset_id, group_key, tapscript_sibling,
taproot_output_key, amount, asset_type, creation_time, managed_from,
proof_courier_addr,
proof_courier_addr, memo,
script_keys.tweaked_script_key,
script_keys.tweak AS script_key_tweak,
raw_script_keys.raw_key AS raw_script_key,
Expand All @@ -36,7 +36,7 @@ LIMIT @num_limit OFFSET @num_offset;
SELECT
version, asset_version, genesis_asset_id, group_key, tapscript_sibling,
taproot_output_key, amount, asset_type, creation_time, managed_from,
proof_courier_addr,
proof_courier_addr, memo,
script_keys.tweaked_script_key,
script_keys.tweak AS script_key_tweak,
raw_script_keys.raw_key as raw_script_key,
Expand Down
Loading
Loading