Skip to content

Commit a41c113

Browse files
authored
Merge pull request #1658 from lightninglabs/more-group-key-refactors
[group key addrs 6/7]: bug fixes and refactors
2 parents 09bd0cc + 1111c6a commit a41c113

40 files changed

+1032
-488
lines changed

address/book.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ type Storage interface {
138138
SetAddrManaged(ctx context.Context, addr *AddrWithKeyInfo,
139139
managedFrom time.Time) error
140140

141+
// LastEventHeightByVersion returns the last event height for a given
142+
// address version.
143+
LastEventHeightByVersion(ctx context.Context,
144+
version Version) (uint32, error)
145+
141146
// InsertInternalKey inserts an internal key into the database to make
142147
// sure it is identified as a local key later on when importing proofs.
143148
// The key can be an internal key for an asset script key or the
@@ -701,6 +706,14 @@ func (b *Book) SetAddrManaged(ctx context.Context, addr *AddrWithKeyInfo,
701706
return b.cfg.Store.SetAddrManaged(ctx, addr, managedFrom)
702707
}
703708

709+
// LastEventHeightByVersion returns the last event height for a given address
710+
// version.
711+
func (b *Book) LastEventHeightByVersion(ctx context.Context,
712+
version Version) (uint32, error) {
713+
714+
return b.cfg.Store.LastEventHeightByVersion(ctx, version)
715+
}
716+
704717
// GetOrCreateEvent creates a new address event for the given status, address
705718
// and transaction. If an event for that address and transaction already exists,
706719
// then the status and transaction information is updated instead.

address/book_test.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ func TestBook_QueryAssetInfo(t *testing.T) {
146146
expectsError: false,
147147
}}
148148

149-
for _, test := range tests {
150-
t.Run(test.name, func(t *testing.T) {
149+
for _, tc := range tests {
150+
t.Run(tc.name, func(t *testing.T) {
151151
mockStorage := &MockStorage{}
152152
mockSyncer := &MockAssetSyncer{}
153153
book := NewBook(BookConfig{
@@ -157,9 +157,9 @@ func TestBook_QueryAssetInfo(t *testing.T) {
157157
Chain: ChainParams{},
158158
StoreTimeout: time.Second,
159159
})
160-
test.setupMocks(mockStorage, mockSyncer)
161-
_, err := book.QueryAssetInfo(ctx, test.specifier)
162-
if test.expectsError {
160+
tc.setupMocks(mockStorage, mockSyncer)
161+
_, err := book.QueryAssetInfo(ctx, tc.specifier)
162+
if tc.expectsError {
163163
require.Error(t, err)
164164
} else {
165165
require.NoError(t, err)
@@ -182,6 +182,13 @@ func (m *MockStorage) FetchAllAssetMeta(
182182
return args.Get(0).(map[asset.ID]*proof.MetaReveal), args.Error(1)
183183
}
184184

185+
func (m *MockStorage) LastEventHeightByVersion(ctx context.Context,
186+
version Version) (uint32, error) {
187+
188+
args := m.Called(ctx, version)
189+
return args.Get(0).(uint32), args.Error(1)
190+
}
191+
185192
func (m *MockStorage) AddrByScriptKeyAndVersion(ctx context.Context,
186193
key *btcec.PublicKey, version Version) (*AddrWithKeyInfo, error) {
187194

authmailbox/client_test.go

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ type serverHarness struct {
3333
clientCfg *ClientConfig
3434
mockSigner *test.MockSigner
3535
mockMsgStore *MockMsgStore
36-
mockTxStore proof.TxProofStore
3736
srv *Server
3837
grpcServer *grpc.Server
3938
cleanup func()
@@ -45,7 +44,6 @@ func newServerHarness(t *testing.T) *serverHarness {
4544
signer.Signature = test.RandBytes(64)
4645

4746
inMemMsgStore := NewMockStore()
48-
inMemTxStore := proof.NewMockTxProofStore()
4947

5048
nextPort := port.NextAvailablePort()
5149
listenAddr := fmt.Sprintf(test.ListenAddrTemplate, nextPort)
@@ -56,7 +54,6 @@ func newServerHarness(t *testing.T) *serverHarness {
5654
HeaderVerifier: proof.MockHeaderVerifier,
5755
MerkleVerifier: proof.DefaultMerkleVerifier,
5856
MsgStore: inMemMsgStore,
59-
TxProofStore: inMemTxStore,
6057
}
6158
h := &serverHarness{
6259
listenAddr: listenAddr,
@@ -70,7 +67,6 @@ func newServerHarness(t *testing.T) *serverHarness {
7067
},
7168
mockSigner: signer,
7269
mockMsgStore: inMemMsgStore,
73-
mockTxStore: inMemTxStore,
7470
}
7571
h.start(t)
7672

@@ -217,6 +213,15 @@ func (h *clientHarness) stop(t *testing.T) {
217213
require.NoError(t, err)
218214
}
219215

216+
func randProof(t *testing.T) proof.TxProof {
217+
t.Helper()
218+
219+
randOp := test.RandOp(t)
220+
return proof.TxProof{
221+
ClaimedOutPoint: randOp,
222+
}
223+
}
224+
220225
// TestServerClientAuthAndRestart tests the server and client authentication
221226
// process, and that the client can re-connect to the server after it has
222227
// restarted. It also tests that the client can receive messages from the
@@ -226,7 +231,6 @@ func TestServerClientAuthAndRestart(t *testing.T) {
226231
harness := newServerHarness(t)
227232
clientCfg := harness.clientCfg
228233

229-
randOp := test.RandOp(t)
230234
clientKey1, _ := test.RandKeyDesc(t)
231235
clientKey2, _ := test.RandKeyDesc(t)
232236
filter := MessageFilter{}
@@ -279,7 +283,7 @@ func TestServerClientAuthAndRestart(t *testing.T) {
279283
}
280284

281285
// We also store the message in the store, so we can retrieve it later.
282-
_, err = harness.mockMsgStore.StoreMessage(ctx, randOp, msg1)
286+
_, err = harness.mockMsgStore.StoreMessage(ctx, randProof(t), msg1)
283287
require.NoError(t, err)
284288

285289
harness.srv.publishMessage(msg1)
@@ -310,7 +314,7 @@ func TestServerClientAuthAndRestart(t *testing.T) {
310314
ReceiverKey: *clientKey1.PubKey,
311315
ArrivalTimestamp: time.Now(),
312316
}
313-
_, err = harness.mockMsgStore.StoreMessage(ctx, randOp, msg2)
317+
_, err = harness.mockMsgStore.StoreMessage(ctx, randProof(t), msg2)
314318
require.NoError(t, err)
315319

316320
harness.srv.publishMessage(msg2)
@@ -379,6 +383,7 @@ func TestSendMessage(t *testing.T) {
379383

380384
clientKey1, _ := test.RandKeyDesc(t)
381385
clientKey2, _ := test.RandKeyDesc(t)
386+
clientKey3, _ := test.RandKeyDesc(t)
382387

383388
proofWithHeight := func(p proof.TxProof, h uint32) proof.TxProof {
384389
p.BlockHeight = h
@@ -391,7 +396,7 @@ func TestSendMessage(t *testing.T) {
391396
testCases := []struct {
392397
name string
393398
txProofs []proof.TxProof
394-
recvKey keychain.KeyDescriptor
399+
recvKeys []keychain.KeyDescriptor
395400
sendKey keychain.KeyDescriptor
396401
msgs [][]byte
397402
expiryHeight uint32
@@ -400,15 +405,15 @@ func TestSendMessage(t *testing.T) {
400405
{
401406
name: "empty payload",
402407
txProofs: []proof.TxProof{*txProof1},
403-
recvKey: clientKey2,
408+
recvKeys: []keychain.KeyDescriptor{clientKey2},
404409
sendKey: clientKey1,
405410
msgs: [][]byte{nil},
406411
expectedErrs: []string{"empty payload"},
407412
},
408413
{
409414
name: "long payload",
410415
txProofs: []proof.TxProof{*txProof1},
411-
recvKey: clientKey2,
416+
recvKeys: []keychain.KeyDescriptor{clientKey2},
412417
sendKey: clientKey1,
413418
msgs: [][]byte{
414419
bytes.Repeat([]byte("foo"), MsgMaxSize),
@@ -418,7 +423,7 @@ func TestSendMessage(t *testing.T) {
418423
{
419424
name: "missing expiry height",
420425
txProofs: []proof.TxProof{*txProof1},
421-
recvKey: clientKey2,
426+
recvKeys: []keychain.KeyDescriptor{clientKey2},
422427
sendKey: clientKey1,
423428
msgs: [][]byte{[]byte("yoooo")},
424429
expectedErrs: []string{"missing expiry block height"},
@@ -428,7 +433,7 @@ func TestSendMessage(t *testing.T) {
428433
txProofs: []proof.TxProof{
429434
proofWithHeight(*txProof1, 100002),
430435
},
431-
recvKey: clientKey2,
436+
recvKeys: []keychain.KeyDescriptor{clientKey2},
432437
sendKey: clientKey1,
433438
msgs: [][]byte{[]byte("yoooo")},
434439
expiryHeight: 123,
@@ -442,7 +447,7 @@ func TestSendMessage(t *testing.T) {
442447
txProofs: []proof.TxProof{
443448
proofWithHeight(*txProof1, 100002),
444449
},
445-
recvKey: clientKey2,
450+
recvKeys: []keychain.KeyDescriptor{clientKey2},
446451
sendKey: clientKey1,
447452
msgs: [][]byte{[]byte("yoooo")},
448453
expiryHeight: 100002 + 123,
@@ -453,7 +458,10 @@ func TestSendMessage(t *testing.T) {
453458
proofWithHeight(*txProof1, 100002),
454459
proofWithHeight(*txProof1, 100002),
455460
},
456-
recvKey: clientKey2,
461+
recvKeys: []keychain.KeyDescriptor{
462+
clientKey2,
463+
clientKey3,
464+
},
457465
sendKey: clientKey1,
458466
msgs: [][]byte{
459467
[]byte("yoooo"),
@@ -472,7 +480,11 @@ func TestSendMessage(t *testing.T) {
472480
proofWithHeight(*txProof2, 100002),
473481
proofWithHeight(*txProof3, 100002),
474482
},
475-
recvKey: clientKey2,
483+
recvKeys: []keychain.KeyDescriptor{
484+
clientKey2,
485+
clientKey2,
486+
clientKey2,
487+
},
476488
sendKey: clientKey1,
477489
msgs: [][]byte{
478490
[]byte("yoooo"),
@@ -507,9 +519,10 @@ func TestSendMessage(t *testing.T) {
507519
for idx := range tc.msgs {
508520
msg := tc.msgs[idx]
509521
txProof := tc.txProofs[idx]
522+
recvKey := tc.recvKeys[idx]
510523

511524
msgID, err := client1.client.SendMessage(
512-
ctx, *tc.recvKey.PubKey, msg, txProof,
525+
ctx, *recvKey.PubKey, msg, txProof,
513526
tc.expiryHeight,
514527
)
515528

@@ -528,6 +541,18 @@ func TestSendMessage(t *testing.T) {
528541
// We should be able to read the message if
529542
// there was no error sending it.
530543
client2.readMessages(t, msgID)
544+
545+
// Sending the same message again should result
546+
// in the same message ID, but should not cause
547+
// another message to be sent to any recipients.
548+
msgIDReSend, err := client1.client.SendMessage(
549+
ctx, *recvKey.PubKey, msg, txProof,
550+
tc.expiryHeight,
551+
)
552+
require.NoError(t, err)
553+
554+
require.Equal(t, msgID, msgIDReSend)
555+
client2.expectNoMessage(t)
531556
}
532557
})
533558
}
@@ -569,7 +594,6 @@ func TestReceiveBacklog(t *testing.T) {
569594
harness := newServerHarness(t)
570595

571596
ctx := context.Background()
572-
randOp := test.RandOp(t)
573597
receiver1, _ := test.RandKeyDesc(t)
574598
receiver2, _ := test.RandKeyDesc(t)
575599
receiver3, _ := test.RandKeyDesc(t)
@@ -611,7 +635,9 @@ func TestReceiveBacklog(t *testing.T) {
611635
}
612636

613637
for _, msg := range messages {
614-
_, err := harness.mockMsgStore.StoreMessage(ctx, randOp, msg)
638+
_, err := harness.mockMsgStore.StoreMessage(
639+
ctx, randProof(t), msg,
640+
)
615641
require.NoError(t, err)
616642
}
617643

authmailbox/message.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/btcsuite/btcd/btcec/v2"
99
"github.com/btcsuite/btcd/wire"
10+
"github.com/lightninglabs/taproot-assets/proof"
1011
)
1112

1213
const (
@@ -19,6 +20,10 @@ var (
1920
// allowed length.
2021
ErrMessageTooLong = fmt.Errorf("message too long, max %d bytes",
2122
MsgMaxSize)
23+
24+
// ErrMessageNotFound is returned when a message with the given ID or
25+
// outpoint cannot be found in the mailbox.
26+
ErrMessageNotFound = fmt.Errorf("message not found")
2227
)
2328

2429
// Message represents a message in the mailbox.
@@ -90,12 +95,19 @@ type MsgStore interface {
9095
// outpoint of the transaction that was used to prove the message's
9196
// authenticity. If a message with the same outpoint already exists,
9297
// it returns proof.ErrTxMerkleProofExists.
93-
StoreMessage(ctx context.Context, claimedOp wire.OutPoint,
98+
StoreMessage(ctx context.Context, proof proof.TxProof,
9499
msg *Message) (uint64, error)
95100

96101
// FetchMessage retrieves a message from the mailbox by its ID.
97102
FetchMessage(ctx context.Context, id uint64) (*Message, error)
98103

104+
// FetchMessageByOutPoint retrieves a message from the mailbox by its
105+
// claimed outpoint of the TX proof that was used to send it. If no
106+
// message with the given outpoint exists, it returns
107+
// ErrMessageNotFound.
108+
FetchMessageByOutPoint(ctx context.Context,
109+
claimedOp wire.OutPoint) (*Message, error)
110+
99111
// QueryMessages retrieves messages based on a query.
100112
QueryMessages(ctx context.Context, filter MessageFilter) ([]*Message,
101113
error)

authmailbox/mock.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,42 @@ import (
77
"sync/atomic"
88

99
"github.com/btcsuite/btcd/wire"
10+
"github.com/lightninglabs/taproot-assets/proof"
1011
)
1112

1213
type MockMsgStore struct {
13-
messages map[uint64]*Message
14-
nextMessageID atomic.Uint64
15-
mu sync.RWMutex
14+
messages map[uint64]*Message
15+
outpointToMessage map[wire.OutPoint]uint64
16+
nextMessageID atomic.Uint64
17+
proofs map[wire.OutPoint]struct{}
18+
mu sync.RWMutex
1619
}
1720

1821
var _ MsgStore = (*MockMsgStore)(nil)
1922

2023
func NewMockStore() *MockMsgStore {
2124
return &MockMsgStore{
22-
messages: make(map[uint64]*Message),
25+
messages: make(map[uint64]*Message),
26+
outpointToMessage: make(map[wire.OutPoint]uint64),
27+
proofs: make(map[wire.OutPoint]struct{}),
2328
}
2429
}
2530

26-
func (s *MockMsgStore) StoreMessage(_ context.Context, _ wire.OutPoint,
31+
func (s *MockMsgStore) StoreMessage(_ context.Context, txProof proof.TxProof,
2732
msg *Message) (uint64, error) {
2833

2934
s.mu.Lock()
3035
defer s.mu.Unlock()
3136

37+
if _, exists := s.proofs[txProof.ClaimedOutPoint]; exists {
38+
return 0, proof.ErrTxMerkleProofExists
39+
}
40+
41+
s.proofs[txProof.ClaimedOutPoint] = struct{}{}
42+
3243
id := s.nextMessageID.Add(1)
3344
s.messages[id] = msg
45+
s.outpointToMessage[txProof.ClaimedOutPoint] = id
3446

3547
return id, nil
3648
}
@@ -49,6 +61,20 @@ func (s *MockMsgStore) FetchMessage(_ context.Context,
4961
return msg, nil
5062
}
5163

64+
func (s *MockMsgStore) FetchMessageByOutPoint(ctx context.Context,
65+
claimedOp wire.OutPoint) (*Message, error) {
66+
67+
s.mu.RLock()
68+
defer s.mu.RUnlock()
69+
70+
msgID, exists := s.outpointToMessage[claimedOp]
71+
if !exists {
72+
return nil, ErrMessageNotFound
73+
}
74+
75+
return s.FetchMessage(ctx, msgID)
76+
}
77+
5278
func (s *MockMsgStore) QueryMessages(_ context.Context,
5379
filter MessageFilter) ([]*Message, error) {
5480

0 commit comments

Comments
 (0)