diff --git a/go.mod b/go.mod index 508042df8..1bc367eb0 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/libsv/go-bc v0.1.29 github.com/libsv/go-bk v0.1.6 github.com/libsv/go-bt/v2 v2.2.5 - github.com/libsv/go-p2p v0.2.6 + github.com/libsv/go-p2p v0.3.0 github.com/lmittmann/tint v1.0.3 github.com/mitchellh/mapstructure v1.5.0 github.com/nats-io/nats.go v1.31.0 diff --git a/go.sum b/go.sum index f6145b9bc..e4b49ba7e 100644 --- a/go.sum +++ b/go.sum @@ -355,6 +355,10 @@ github.com/libsv/go-p2p v0.2.5 h1:Kg7WQphZDZycNtihMOUr49qNX1oieXxLDeirSqklsnM= github.com/libsv/go-p2p v0.2.5/go.mod h1:TENFxbTT/bfSfuiirjU6l+PfAWxwZgF8GYUxs5tzc/M= github.com/libsv/go-p2p v0.2.6 h1:lquJf+Wrpk54ttD9mrX7gdHEqAfJq1u+HOv96+dmYU8= github.com/libsv/go-p2p v0.2.6/go.mod h1:TENFxbTT/bfSfuiirjU6l+PfAWxwZgF8GYUxs5tzc/M= +github.com/libsv/go-p2p v0.2.7 h1:RSYPJzhJL3zURY0qwOhfXKqcR0Lb8rRna8GbTFuJaJg= +github.com/libsv/go-p2p v0.2.7/go.mod h1:TENFxbTT/bfSfuiirjU6l+PfAWxwZgF8GYUxs5tzc/M= +github.com/libsv/go-p2p v0.3.0 h1:/jtNveHFNbCaC7+FQzvGQb988MaTLupw0bC0yHGANVY= +github.com/libsv/go-p2p v0.3.0/go.mod h1:TENFxbTT/bfSfuiirjU6l+PfAWxwZgF8GYUxs5tzc/M= github.com/lmittmann/tint v1.0.3 h1:W5PHeA2D8bBJVvabNfQD/XW9HPLZK1XoPZH0cq8NouQ= github.com/lmittmann/tint v1.0.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= diff --git a/internal/blocktx/peer_handler.go b/internal/blocktx/peer_handler.go index ec5eacf17..8278d4c22 100644 --- a/internal/blocktx/peer_handler.go +++ b/internal/blocktx/peer_handler.go @@ -181,7 +181,6 @@ func WithTracer() func(handler *PeerHandler) { } func NewPeerHandler(logger *slog.Logger, storeI store.BlocktxStore, opts ...func(*PeerHandler)) (*PeerHandler, error) { - hostname, err := os.Hostname() if err != nil { return nil, err @@ -421,33 +420,27 @@ func (ph *PeerHandler) registerTransactions(txHashes []*blocktx_api.TransactionA } } -func (ph *PeerHandler) HandleTransactionGet(_ *wire.InvVect, peer p2p.PeerI) ([]byte, error) { - +func (ph *PeerHandler) HandleTransactionsGet(_ []*wire.InvVect, peer p2p.PeerI) ([][]byte, error) { return nil, nil } func (ph *PeerHandler) HandleTransactionSent(_ *wire.MsgTx, peer p2p.PeerI) error { - return nil } func (ph *PeerHandler) HandleTransactionAnnouncement(_ *wire.InvVect, peer p2p.PeerI) error { - return nil } func (ph *PeerHandler) HandleTransactionRejection(_ *wire.MsgReject, _ p2p.PeerI) error { - return nil } func (ph *PeerHandler) HandleTransaction(_ *wire.MsgTx, _ p2p.PeerI) error { - return nil } func (ph *PeerHandler) HandleBlockAnnouncement(msg *wire.InvVect, peer p2p.PeerI) error { - pair := hashPeer{ Hash: &msg.Hash, Peer: peer, @@ -546,7 +539,6 @@ const ( ) func (ph *PeerHandler) fillGaps(peer p2p.PeerI) error { - heightRange := ph.dataRetentionDays * hoursPerDay * blocksPerHour blockHeightGaps, err := ph.store.GetBlockGaps(ph.ctx, heightRange) @@ -576,7 +568,6 @@ func (ph *PeerHandler) fillGaps(peer p2p.PeerI) error { } func (ph *PeerHandler) insertBlock(ctx context.Context, blockHash *chainhash.Hash, merkleRoot *chainhash.Hash, previousBlockHash *chainhash.Hash, height uint64) (uint64, error) { - ph.logger.Info("Inserting block", slog.String("hash", blockHash.String()), slog.Int64("height", int64(height))) block := &blocktx_api.Block{ @@ -736,12 +727,10 @@ func ExtractHeightFromCoinbaseTx(tx *bt.Tx) uint64 { } func (ph *PeerHandler) Shutdown() { - if ph.cancelAll != nil { ph.cancelAll() } ph.waitGroup.Wait() - } // for testing purposes diff --git a/internal/metamorph/peer_handler.go b/internal/metamorph/peer_handler.go index 887018db6..553152eab 100644 --- a/internal/metamorph/peer_handler.go +++ b/internal/metamorph/peer_handler.go @@ -33,7 +33,6 @@ func NewPeerHandler(s store.MetamorphStore, messageCh chan *PeerTxMessage) *Peer // HandleTransactionSent is called when a transaction is sent to a peer. func (m *PeerHandler) HandleTransactionSent(msg *wire.MsgTx, peer p2p.PeerI) error { - hash := msg.TxHash() m.messageCh <- &PeerTxMessage{ Hash: &hash, @@ -46,7 +45,6 @@ func (m *PeerHandler) HandleTransactionSent(msg *wire.MsgTx, peer p2p.PeerI) err // HandleTransactionAnnouncement is a message sent to the PeerHandler when a transaction INV message is received from a peer. func (m *PeerHandler) HandleTransactionAnnouncement(msg *wire.InvVect, peer p2p.PeerI) error { - m.messageCh <- &PeerTxMessage{ Hash: &msg.Hash, Status: metamorph_api.Status_SEEN_ON_NETWORK, @@ -58,7 +56,6 @@ func (m *PeerHandler) HandleTransactionAnnouncement(msg *wire.InvVect, peer p2p. // HandleTransactionRejection is called when a transaction is rejected by a peer. func (m *PeerHandler) HandleTransactionRejection(rejMsg *wire.MsgReject, peer p2p.PeerI) error { - m.messageCh <- &PeerTxMessage{ Hash: &rejMsg.Hash, Status: metamorph_api.Status_REJECTED, @@ -69,21 +66,21 @@ func (m *PeerHandler) HandleTransactionRejection(rejMsg *wire.MsgReject, peer p2 return nil } -// HandleTransactionGet is called when a peer requests a transaction. -func (m *PeerHandler) HandleTransactionGet(msg *wire.InvVect, peer p2p.PeerI) ([]byte, error) { +// HandleTransactionsGet is called when a peer requests a transaction. +func (m *PeerHandler) HandleTransactionsGet(msgs []*wire.InvVect, peer p2p.PeerI) ([][]byte, error) { + hashes := make([][]byte, len(msgs)) - m.messageCh <- &PeerTxMessage{ - Hash: &msg.Hash, - Status: metamorph_api.Status_REQUESTED_BY_NETWORK, - Peer: peer.String(), - } + for i, msg := range msgs { + m.messageCh <- &PeerTxMessage{ + Hash: &msg.Hash, + Status: metamorph_api.Status_REQUESTED_BY_NETWORK, + Peer: peer.String(), + } - sd, err := m.store.Get(m.ctx, msg.Hash.CloneBytes()) - if err != nil { - return nil, err + hashes[i] = msg.Hash[:] } - return sd.RawTx, nil + return m.store.GetRawTxs(m.ctx, hashes) } // HandleTransaction is called when a transaction is received from a peer. @@ -101,18 +98,15 @@ func (m *PeerHandler) HandleTransaction(msg *wire.MsgTx, peer p2p.PeerI) error { // HandleBlockAnnouncement is called when a block INV message is received from a peer. func (m *PeerHandler) HandleBlockAnnouncement(_ *wire.InvVect, _ p2p.PeerI) error { - return nil } // HandleBlock is called when a block is received from a peer. func (m *PeerHandler) HandleBlock(_ wire.Message, _ p2p.PeerI) error { - return nil } func (m *PeerHandler) Shutdown() { - if m.cancelAll != nil { m.cancelAll() } diff --git a/internal/metamorph/peer_handler_test.go b/internal/metamorph/peer_handler_test.go index 0f893d053..1ff29e807 100644 --- a/internal/metamorph/peer_handler_test.go +++ b/internal/metamorph/peer_handler_test.go @@ -7,7 +7,6 @@ import ( "time" "github.com/bitcoin-sv/arc/internal/metamorph" - "github.com/bitcoin-sv/arc/internal/metamorph/store" storeMocks "github.com/bitcoin-sv/arc/internal/metamorph/store/mocks" "github.com/bitcoin-sv/arc/pkg/metamorph/metamorph_api" "github.com/libsv/go-p2p" @@ -20,10 +19,9 @@ import ( func TestPeerHandler(t *testing.T) { messageCh := make(chan *metamorph.PeerTxMessage) mtmStore := &storeMocks.MetamorphStoreMock{ - GetFunc: func(ctx context.Context, key []byte) (*store.StoreData, error) { - return &store.StoreData{ - RawTx: []byte("1234"), - }, nil + GetRawTxsFunc: func(ctx context.Context, hashes [][]byte) ([][]byte, error) { + rawTx := []byte("1234") + return [][]byte{rawTx, rawTx}, nil }, } @@ -102,28 +100,40 @@ func TestPeerHandler(t *testing.T) { } }) - t.Run("HandleTransactionGet", func(t *testing.T) { - hash, err := chainhash.NewHashFromStr("1234") - require.NoError(t, err) + t.Run("HandleTransactionsGet", func(t *testing.T) { + txsCount := 2 + invMsgs := make([]*wire.InvVect, txsCount) + expectedMsgs := make([]*metamorph.PeerTxMessage, txsCount) - msgInv := wire.NewInvVect(wire.InvTypeBlock, hash) - require.NoError(t, err) + for i := 0; i < txsCount; i++ { + hash, err := chainhash.NewHashFromStr("1234") + require.NoError(t, err) - expectedMsg := &metamorph.PeerTxMessage{ - Hash: &msgInv.Hash, - Status: metamorph_api.Status_REQUESTED_BY_NETWORK, - Peer: "mock_peer", + msgInv := wire.NewInvVect(wire.InvTypeTx, hash) + require.NoError(t, err) + + invMsgs[i] = msgInv + + expectedMsgs[i] = &metamorph.PeerTxMessage{ + Hash: hash, + Status: metamorph_api.Status_REQUESTED_BY_NETWORK, + Peer: "mock_peer", + } } go func() { - _, _ = peerHandler.HandleTransactionGet(msgInv, peer) + _, _ = peerHandler.HandleTransactionsGet(invMsgs, peer) }() - select { - case msg := <-messageCh: - assert.Equal(t, expectedMsg, msg) - case <-time.After(time.Second): - t.Fatal("test timed out or error while executing goroutine") + counter := 0 + for i := 0; i < txsCount; i++ { + select { + case msg := <-messageCh: + assert.Equal(t, expectedMsgs[counter], msg) + counter++ + case <-time.After(5 * time.Second): + t.Fatal("test timed out or error while executing goroutine") + } } }) diff --git a/internal/metamorph/store/mocks/store_mock.go b/internal/metamorph/store/mocks/store_mock.go index bfa61b82b..61a01f259 100644 --- a/internal/metamorph/store/mocks/store_mock.go +++ b/internal/metamorph/store/mocks/store_mock.go @@ -34,6 +34,9 @@ var _ store.MetamorphStore = &MetamorphStoreMock{} // GetFunc: func(ctx context.Context, key []byte) (*store.StoreData, error) { // panic("mock out the Get method") // }, +// GetRawTxsFunc: func(ctx context.Context, hashes [][]byte) ([][]byte, error) { +// panic("mock out the GetRawTxs method") +// }, // GetSeenOnNetworkFunc: func(ctx context.Context, since time.Time, until time.Time, limit int64, offset int64) ([]*store.StoreData, error) { // panic("mock out the GetSeenOnNetwork method") // }, @@ -86,6 +89,9 @@ type MetamorphStoreMock struct { // GetFunc mocks the Get method. GetFunc func(ctx context.Context, key []byte) (*store.StoreData, error) + // GetRawTxsFunc mocks the GetRawTxs method. + GetRawTxsFunc func(ctx context.Context, hashes [][]byte) ([][]byte, error) + // GetSeenOnNetworkFunc mocks the GetSeenOnNetwork method. GetSeenOnNetworkFunc func(ctx context.Context, since time.Time, until time.Time, limit int64, offset int64) ([]*store.StoreData, error) @@ -147,6 +153,13 @@ type MetamorphStoreMock struct { // Key is the key argument value. Key []byte } + // GetRawTxs holds details about calls to the GetRawTxs method. + GetRawTxs []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Hashes is the hashes argument value. + Hashes [][]byte + } // GetSeenOnNetwork holds details about calls to the GetSeenOnNetwork method. GetSeenOnNetwork []struct { // Ctx is the ctx argument value. @@ -243,6 +256,7 @@ type MetamorphStoreMock struct { lockClose sync.RWMutex lockDel sync.RWMutex lockGet sync.RWMutex + lockGetRawTxs sync.RWMutex lockGetSeenOnNetwork sync.RWMutex lockGetStats sync.RWMutex lockGetUnmined sync.RWMutex @@ -396,6 +410,42 @@ func (mock *MetamorphStoreMock) GetCalls() []struct { return calls } +// GetRawTxs calls GetRawTxsFunc. +func (mock *MetamorphStoreMock) GetRawTxs(ctx context.Context, hashes [][]byte) ([][]byte, error) { + if mock.GetRawTxsFunc == nil { + panic("MetamorphStoreMock.GetRawTxsFunc: method is nil but MetamorphStore.GetRawTxs was just called") + } + callInfo := struct { + Ctx context.Context + Hashes [][]byte + }{ + Ctx: ctx, + Hashes: hashes, + } + mock.lockGetRawTxs.Lock() + mock.calls.GetRawTxs = append(mock.calls.GetRawTxs, callInfo) + mock.lockGetRawTxs.Unlock() + return mock.GetRawTxsFunc(ctx, hashes) +} + +// GetRawTxsCalls gets all the calls that were made to GetRawTxs. +// Check the length with: +// +// len(mockedMetamorphStore.GetRawTxsCalls()) +func (mock *MetamorphStoreMock) GetRawTxsCalls() []struct { + Ctx context.Context + Hashes [][]byte +} { + var calls []struct { + Ctx context.Context + Hashes [][]byte + } + mock.lockGetRawTxs.RLock() + calls = mock.calls.GetRawTxs + mock.lockGetRawTxs.RUnlock() + return calls +} + // GetSeenOnNetwork calls GetSeenOnNetworkFunc. func (mock *MetamorphStoreMock) GetSeenOnNetwork(ctx context.Context, since time.Time, until time.Time, limit int64, offset int64) ([]*store.StoreData, error) { if mock.GetSeenOnNetworkFunc == nil { diff --git a/internal/metamorph/store/postgresql/fixtures/get_rawtxs/metamorph.transactions.yaml b/internal/metamorph/store/postgresql/fixtures/get_rawtxs/metamorph.transactions.yaml new file mode 100644 index 000000000..01d97f5d8 --- /dev/null +++ b/internal/metamorph/store/postgresql/fixtures/get_rawtxs/metamorph.transactions.yaml @@ -0,0 +1,18 @@ +- hash: 0xcd3d2f97dfc0cdb6a07ec4b72df5e1794c9553ff2f62d90ed4add047e8088853 + raw_tx: 0x010000000000000000ef016f8828b2d3f8085561d0b4ff6f5d17c269206fa3d32bcd3b22e26ce659ed12e7000000006b483045022100d3649d120249a09af44b4673eecec873109a3e120b9610b78858087fb225c9b9022037f16999b7a4fecdd9f47ebdc44abd74567a18940c37e1481ab0fe84d62152e4412102f87ce69f6ba5444aed49c34470041189c1e1060acd99341959c0594002c61bf0ffffffffe7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac01e7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac00000000 + locked_by: metamorph-3 + status: 4 + stored_at: 2023-10-01 14:00:00 + last_submitted_at: 2023-10-01 14:00:00 +- hash: 0x21132d32cb5411c058bb4391f24f6a36ed9b810df851d0e36cac514fd03d6b4e + raw_tx: 0x020000000000000000ef016f8828b2d3f8085561d0b4ff6f5d17c269206fa3d32bcd3b22e26ce659ed12e7000000006b483045022100d3649d120249a09af44b4673eecec873109a3e120b9610b78858087fb225c9b9022037f16999b7a4fecdd9f47ebdc44abd74567a18940c37e1481ab0fe84d62152e4412102f87ce69f6ba5444aed49c34470041189c1e1060acd99341959c0594002c61bf0ffffffffe7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac01e7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac00000000 + locked_by: metamorph-3 + status: 4 + stored_at: 2023-10-01 14:00:00 + last_submitted_at: 2023-10-01 14:00:00 +- hash: 0x3e0b5b218c344110f09bf485bc58de4ea5378e55744185edf9c1dafa40068ecd + raw_tx: 0x030000000000000000ef016f8828b2d3f8085561d0b4ff6f5d17c269206fa3d32bcd3b22e26ce659ed12e7000000006b483045022100d3649d120249a09af44b4673eecec873109a3e120b9610b78858087fb225c9b9022037f16999b7a4fecdd9f47ebdc44abd74567a18940c37e1481ab0fe84d62152e4412102f87ce69f6ba5444aed49c34470041189c1e1060acd99341959c0594002c61bf0ffffffffe7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac01e7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac00000000 + locked_by: metamorph-1 + status: 4 + stored_at: 2023-10-01 14:00:00 + last_submitted_at: 2023-10-01 14:00:00 diff --git a/internal/metamorph/store/postgresql/postgres.go b/internal/metamorph/store/postgresql/postgres.go index e377f0e9b..954a2db1b 100644 --- a/internal/metamorph/store/postgresql/postgres.go +++ b/internal/metamorph/store/postgresql/postgres.go @@ -191,6 +191,39 @@ func (p *PostgreSQL) Get(ctx context.Context, hash []byte) (*store.StoreData, er return data, nil } +// GetRawTxs implements the MetamorphStore interface. It attempts to get rawTxs for given hashes. +// If the hashes do not exist an empty array is returned, otherwise the retrieved values. +// If an error happens during the process of getting the results, the error is returned +// along with already found rawTxs up to the error point. +func (p *PostgreSQL) GetRawTxs(ctx context.Context, hashes [][]byte) ([][]byte, error) { + retRawTxs := make([][]byte, 0) + + q := `SELECT raw_tx + FROM metamorph.transactions + WHERE hash in (SELECT UNNEST($1::BYTEA[]))` + + rows, err := p.db.QueryContext(ctx, q, pq.Array(hashes)) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var rawTx []byte + err = rows.Scan(&rawTx) + if err != nil { + return retRawTxs, err + } + retRawTxs = append(retRawTxs, rawTx) + } + + if err = rows.Err(); err != nil { + return retRawTxs, err + } + + return retRawTxs, nil +} + func (p *PostgreSQL) IncrementRetries(ctx context.Context, hash *chainhash.Hash) error { q := `UPDATE metamorph.transactions SET retries = retries+1 WHERE hash = $1;` @@ -355,7 +388,6 @@ func (p *PostgreSQL) SetLocked(ctx context.Context, since time.Time, limit int64 } func (p *PostgreSQL) GetUnmined(ctx context.Context, since time.Time, limit int64, offset int64) ([]*store.StoreData, error) { - q := `SELECT stored_at ,announced_at @@ -530,6 +562,7 @@ func (p *PostgreSQL) UpdateStatusBulk(ctx context.Context, updates []store.Updat } return nil, err } + defer rows.Close() res, err := p.getStoreDataFromRows(rows) if err != nil { @@ -615,6 +648,7 @@ func (p *PostgreSQL) UpdateMined(ctx context.Context, txsBlocks *blocktx_api.Tra } return nil, err } + defer rows.Close() res, err := p.getStoreDataFromRows(rows) if err != nil { @@ -745,12 +779,12 @@ func (p *PostgreSQL) Close(ctx context.Context) error { } func (p *PostgreSQL) Ping(ctx context.Context) error { - _, err := p.db.QueryContext(ctx, "SELECT 1;") + rows, err := p.db.QueryContext(ctx, "SELECT 1;") if err != nil { return err } - return nil + return rows.Close() } func (p *PostgreSQL) ClearData(ctx context.Context, retentionDays int32) (int64, error) { diff --git a/internal/metamorph/store/postgresql/postgres_test.go b/internal/metamorph/store/postgresql/postgres_test.go index 6b23c9fcc..b0a39c34a 100644 --- a/internal/metamorph/store/postgresql/postgres_test.go +++ b/internal/metamorph/store/postgresql/postgres_test.go @@ -23,6 +23,7 @@ import ( "github.com/libsv/go-p2p/chaincfg/chainhash" "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -34,9 +35,7 @@ const ( dbPassword = "arcpass" ) -var ( - dbInfo string -) +var dbInfo string func revChainhash(t *testing.T, hashString string) *chainhash.Hash { hash, err := hex.DecodeString(hashString) @@ -237,6 +236,40 @@ func TestPostgresDB(t *testing.T) { require.True(t, errors.Is(err, store.ErrNotFound)) }) + t.Run("get raw txs", func(t *testing.T) { + defer require.NoError(t, pruneTables(postgresDB.db)) + + require.NoError(t, loadFixtures(postgresDB.db, "fixtures/get_rawtxs")) + + hash1 := "cd3d2f97dfc0cdb6a07ec4b72df5e1794c9553ff2f62d90ed4add047e8088853" + hash2 := "21132d32cb5411c058bb4391f24f6a36ed9b810df851d0e36cac514fd03d6b4e" + hash3 := "3e0b5b218c344110f09bf485bc58de4ea5378e55744185edf9c1dafa40068ecd" + + hashes := make([][]byte, 0) + hashes = append(hashes, revChainhash(t, hash1).CloneBytes()) + hashes = append(hashes, revChainhash(t, hash2).CloneBytes()) + hashes = append(hashes, revChainhash(t, hash3).CloneBytes()) + + expectedRawTxs := make([][]byte, 0) + + rawTx, err := hex.DecodeString("010000000000000000ef016f8828b2d3f8085561d0b4ff6f5d17c269206fa3d32bcd3b22e26ce659ed12e7000000006b483045022100d3649d120249a09af44b4673eecec873109a3e120b9610b78858087fb225c9b9022037f16999b7a4fecdd9f47ebdc44abd74567a18940c37e1481ab0fe84d62152e4412102f87ce69f6ba5444aed49c34470041189c1e1060acd99341959c0594002c61bf0ffffffffe7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac01e7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac00000000") + require.NoError(t, err) + expectedRawTxs = append(expectedRawTxs, rawTx) + + rawTx, err = hex.DecodeString("020000000000000000ef016f8828b2d3f8085561d0b4ff6f5d17c269206fa3d32bcd3b22e26ce659ed12e7000000006b483045022100d3649d120249a09af44b4673eecec873109a3e120b9610b78858087fb225c9b9022037f16999b7a4fecdd9f47ebdc44abd74567a18940c37e1481ab0fe84d62152e4412102f87ce69f6ba5444aed49c34470041189c1e1060acd99341959c0594002c61bf0ffffffffe7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac01e7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac00000000") + require.NoError(t, err) + expectedRawTxs = append(expectedRawTxs, rawTx) + + rawTx, err = hex.DecodeString("030000000000000000ef016f8828b2d3f8085561d0b4ff6f5d17c269206fa3d32bcd3b22e26ce659ed12e7000000006b483045022100d3649d120249a09af44b4673eecec873109a3e120b9610b78858087fb225c9b9022037f16999b7a4fecdd9f47ebdc44abd74567a18940c37e1481ab0fe84d62152e4412102f87ce69f6ba5444aed49c34470041189c1e1060acd99341959c0594002c61bf0ffffffffe7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac01e7030000000000001976a914c2b6fd4319122b9b5156a2a0060d19864c24f49a88ac00000000") + require.NoError(t, err) + expectedRawTxs = append(expectedRawTxs, rawTx) + + rawTxs, err := postgresDB.GetRawTxs(context.Background(), hashes) + require.NoError(t, err) + + assert.Equal(t, expectedRawTxs, rawTxs) + }) + t.Run("set bulk", func(t *testing.T) { defer require.NoError(t, pruneTables(postgresDB.db)) @@ -380,7 +413,6 @@ func TestPostgresDB(t *testing.T) { hash4Data, err := postgresDB.Get(ctx, hash4[:]) require.NoError(t, err) require.Equal(t, "NONE", hash4Data.LockedBy) - }) t.Run("update status", func(t *testing.T) { diff --git a/internal/metamorph/store/store.go b/internal/metamorph/store/store.go index a1d852e57..ffc503c01 100644 --- a/internal/metamorph/store/store.go +++ b/internal/metamorph/store/store.go @@ -66,6 +66,7 @@ type MetamorphStore interface { Ping(ctx context.Context) error GetStats(ctx context.Context, since time.Time, notSeenLimit time.Duration, notMinedLimit time.Duration) (*Stats, error) + GetRawTxs(ctx context.Context, hashes [][]byte) ([][]byte, error) } type UpdateStatus struct {