diff --git a/indexer/indexer.go b/indexer/indexer.go index 0b6f68f..15bdc02 100644 --- a/indexer/indexer.go +++ b/indexer/indexer.go @@ -746,7 +746,6 @@ func (i *Indexer) GetScriptPubKeys( // GetBlockLazy returns a *types.BlockResponse from the indexer's block storage. // All transactions in a block must be fetched individually. -// TODO: replace with GetBlock func (i *Indexer) GetBlockLazy( ctx context.Context, blockIdentifier *types.PartialBlockIdentifier, @@ -756,7 +755,6 @@ func (i *Indexer) GetBlockLazy( // GetBlockTransaction returns a *types.Transaction if it is in the provided // *types.BlockIdentifier. -// TODO: remove method func (i *Indexer) GetBlockTransaction( ctx context.Context, blockIdentifier *types.BlockIdentifier, diff --git a/rosetta-cli-conf/mainnet/config.json b/rosetta-cli-conf/mainnet/config.json index 69c25a1..e700c91 100644 --- a/rosetta-cli-conf/mainnet/config.json +++ b/rosetta-cli-conf/mainnet/config.json @@ -11,6 +11,8 @@ "max_sync_concurrency": 0, "tip_delay": 1800, "log_configuration": false, + "compression_disabled": true, + "memory_limit_disabled": true, "data": { "active_reconciliation_concurrency": 0, "inactive_reconciliation_concurrency": 0, diff --git a/rosetta-cli-conf/testnet/config.json b/rosetta-cli-conf/testnet/config.json index ea1b75d..cdd9b45 100644 --- a/rosetta-cli-conf/testnet/config.json +++ b/rosetta-cli-conf/testnet/config.json @@ -11,6 +11,8 @@ "max_sync_concurrency": 0, "tip_delay": 1800, "log_configuration": false, + "compression_disabled": true, + "memory_limit_disabled": true, "construction": { "max_offline_connections": 0, "stale_depth": 0, diff --git a/services/block_service.go b/services/block_service.go index b837765..489da48 100644 --- a/services/block_service.go +++ b/services/block_service.go @@ -54,6 +54,12 @@ func (s *BlockAPIService) Block( return nil, wrapErr(ErrBlockNotFound, err) } + // Direct client to fetch transactions individually if + // more than inlineFetchLimit. + if len(blockResponse.OtherTransactions) > inlineFetchLimit { + return blockResponse, nil + } + txs := make([]*types.Transaction, len(blockResponse.OtherTransactions)) for i, otherTx := range blockResponse.OtherTransactions { transaction, err := s.i.GetBlockTransaction( @@ -78,5 +84,20 @@ func (s *BlockAPIService) BlockTransaction( ctx context.Context, request *types.BlockTransactionRequest, ) (*types.BlockTransactionResponse, *types.Error) { - return nil, ErrUnimplemented + if s.config.Mode != configuration.Online { + return nil, wrapErr(ErrUnavailableOffline, nil) + } + + transaction, err := s.i.GetBlockTransaction( + ctx, + request.BlockIdentifier, + request.TransactionIdentifier, + ) + if err != nil { + return nil, wrapErr(ErrTransactionNotFound, err) + } + + return &types.BlockTransactionResponse{ + Transaction: transaction, + }, nil } diff --git a/services/block_service_test.go b/services/block_service_test.go index 8f7787b..bdbf297 100644 --- a/services/block_service_test.go +++ b/services/block_service_test.go @@ -16,6 +16,7 @@ package services import ( "context" + "fmt" "testing" "github.com/coinbase/rosetta-bitcoin/configuration" @@ -40,13 +41,13 @@ func TestBlockService_Offline(t *testing.T) { blockTransaction, err := servicer.BlockTransaction(ctx, &types.BlockTransactionRequest{}) assert.Nil(t, blockTransaction) - assert.Equal(t, ErrUnimplemented.Code, err.Code) - assert.Equal(t, ErrUnimplemented.Message, err.Message) + assert.Equal(t, ErrUnavailableOffline.Code, err.Code) + assert.Equal(t, ErrUnavailableOffline.Message, err.Message) mockIndexer.AssertExpectations(t) } -func TestBlockService_Online(t *testing.T) { +func TestBlockService_Online_Inline(t *testing.T) { cfg := &configuration.Configuration{ Mode: configuration.Online, } @@ -146,3 +147,68 @@ func TestBlockService_Online(t *testing.T) { mockIndexer.AssertExpectations(t) } + +func TestBlockService_Online_External(t *testing.T) { + cfg := &configuration.Configuration{ + Mode: configuration.Online, + } + mockIndexer := &mocks.Indexer{} + servicer := NewBlockAPIService(cfg, mockIndexer) + ctx := context.Background() + + blockResponse := &types.BlockResponse{ + Block: &types.Block{ + BlockIdentifier: &types.BlockIdentifier{ + Index: 100, + Hash: "block 100", + }, + }, + } + + otherTxs := []*types.TransactionIdentifier{} + for i := 0; i < 200; i++ { + otherTxs = append(otherTxs, &types.TransactionIdentifier{ + Hash: fmt.Sprintf("tx%d", i), + }) + } + blockResponse.OtherTransactions = otherTxs + + mockIndexer.On( + "GetBlockLazy", + ctx, + (*types.PartialBlockIdentifier)(nil), + ).Return( + blockResponse, + nil, + ).Once() + b, err := servicer.Block(ctx, &types.BlockRequest{}) + assert.Nil(t, err) + assert.Equal(t, blockResponse, b) + + for _, otherTx := range b.OtherTransactions { + tx := &types.Transaction{ + TransactionIdentifier: otherTx, + } + mockIndexer.On( + "GetBlockTransaction", + ctx, + blockResponse.Block.BlockIdentifier, + otherTx, + ).Return( + tx, + nil, + ).Once() + + bTx, err := servicer.BlockTransaction(ctx, &types.BlockTransactionRequest{ + BlockIdentifier: blockResponse.Block.BlockIdentifier, + TransactionIdentifier: otherTx, + }) + assert.Nil(t, err) + assert.Equal(t, &types.BlockTransactionResponse{ + Transaction: tx, + }, bTx) + + } + + mockIndexer.AssertExpectations(t) +} diff --git a/services/types.go b/services/types.go index b753d39..e039dc9 100644 --- a/services/types.go +++ b/services/types.go @@ -30,6 +30,10 @@ const ( // HistoricalBalanceLookup indicates // that historical balance lookup is supported. HistoricalBalanceLookup = true + + // inlineFetchLimit is the maximum number + // of transactions to fetch inline. + inlineFetchLimit = 100 ) var (