From 755521edf0dc155f3fd5441359b64d000f53471b Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 13:54:38 -0800 Subject: [PATCH 01/11] Add first indexer endpoints --- api.yaml | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/api.yaml b/api.yaml index 4bfc2b8..de798bc 100644 --- a/api.yaml +++ b/api.yaml @@ -653,6 +653,58 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' + /events/blocks: + post: + summary: blah blah + description: | + operationId: eventsBlocks + tags: + - Events + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/EventsBlocksRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/EventsBlocksResponse' + '500': + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /search/transactions: + post: + summary: blah blah + description: | + operationId: searchTransactions + tags: + - Search + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SearchTransactionsRequest' + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: '#/components/schemas/SearchTransactionsResponse' + '500': + description: unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: schemas: # Identifiers From 62562cba11aa5bc3fbd5a452fbe4c63e0a54249b Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 14:26:09 -0800 Subject: [PATCH 02/11] Add scaffolding for events --- api.yaml | 42 ++++++++++++++++++++++++++++++++++++++ models/BlockEvent.yaml | 25 +++++++++++++++++++++++ models/BlockEventType.yaml | 19 +++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 models/BlockEvent.yaml create mode 100644 models/BlockEventType.yaml diff --git a/api.yaml b/api.yaml index de798bc..a43b1a1 100644 --- a/api.yaml +++ b/api.yaml @@ -770,6 +770,10 @@ components: $ref: 'models/BalanceExemption.yaml' ExemptionType: $ref: 'models/ExemptionType.yaml' + BlockEventType: + $ref: 'models/BlockEventType.yaml' + BlockEvent: + $ref: 'models/BlockEvent.yaml' # Request/Responses AccountBalanceRequest: @@ -1455,6 +1459,44 @@ components: to avoid making unnecessary calls to the Rosetta implementation. For this reason, implementers should be very conservative about returning true here or they could cause issues for the caller. + EventsBlocksRequest: + description: | + type: object + required: + - network_identifier + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + offset: + description: | + type: integer + format: int64 + minimum: 0 + example: 5 + limit: + description: | + type: integer + format: int64 + minimum: 0 + example: 5 + EventsBlocksResponse: + description: | + type: object + required: + - max_sequence + - events + properties: + max_sequence: + description: | + type: integer + format: int64 + minimum: 0 + example: 5 + events: + type: array + description: | + items: + $ref: '#/components/schemas/BlockEvent' # Miscellaneous Error: diff --git a/models/BlockEvent.yaml b/models/BlockEvent.yaml new file mode 100644 index 0000000..9322868 --- /dev/null +++ b/models/BlockEvent.yaml @@ -0,0 +1,25 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | +type: object +required: + - sequence + - block_identifier + - type +properties: + block_identifier: + $ref: 'BlockIdentifier.yaml' + type: + $ref: 'BlockEventType.yaml' diff --git a/models/BlockEventType.yaml b/models/BlockEventType.yaml new file mode 100644 index 0000000..d963801 --- /dev/null +++ b/models/BlockEventType.yaml @@ -0,0 +1,19 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | +type: string +enum: + - block_added + - block_removed From bd65ab9639dd238f0dca909ae4100646993ffa0c Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 14:34:48 -0800 Subject: [PATCH 03/11] Start populating event items --- api.yaml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/api.yaml b/api.yaml index a43b1a1..3697f31 100644 --- a/api.yaml +++ b/api.yaml @@ -770,10 +770,10 @@ components: $ref: 'models/BalanceExemption.yaml' ExemptionType: $ref: 'models/ExemptionType.yaml' - BlockEventType: - $ref: 'models/BlockEventType.yaml' BlockEvent: $ref: 'models/BlockEvent.yaml' + BlockEventType: + $ref: 'models/BlockEventType.yaml' # Request/Responses AccountBalanceRequest: @@ -1461,6 +1461,7 @@ components: true here or they could cause issues for the caller. EventsBlocksRequest: description: | + EventsBlocksRequest type: object required: - network_identifier @@ -1469,18 +1470,26 @@ components: $ref: '#/components/schemas/NetworkIdentifier' offset: description: | + offset is the offset into the event stream to sync events from. If this + is left empty, we stream the limit from tip. If this is set to 0, + we start from the beginning. type: integer format: int64 minimum: 0 example: 5 limit: description: | + limit is the maximum number of events to fetch in one call. The implementation + may return up to this limit but there is no guarantee it will return all limit + events. type: integer format: int64 minimum: 0 example: 5 EventsBlocksResponse: description: | + EventsBlocksResponse contains an ordered collection of BlockEvents + and the largest available retrievable sequence. type: object required: - max_sequence @@ -1488,6 +1497,7 @@ components: properties: max_sequence: description: | + max_sequence is the maximum available sequence number to fetch. type: integer format: int64 minimum: 0 @@ -1495,6 +1505,10 @@ components: events: type: array description: | + events is an array of BlockEvents indicating the order to add + and remove blocks to maintain a consistent view of blockchain + state. Following this event stream prevents some lightweight + clients from running their own syncer. items: $ref: '#/components/schemas/BlockEvent' From f1bed8338b0d803d099c663a39d1b24c24d02800 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 16:26:44 -0800 Subject: [PATCH 04/11] Add descriptions --- api.yaml | 39 +++++++++++++++++++++++++++++--------- models/BlockEvent.yaml | 12 ++++++++++++ models/BlockEventType.yaml | 2 ++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/api.yaml b/api.yaml index 3697f31..ecd18db 100644 --- a/api.yaml +++ b/api.yaml @@ -655,8 +655,19 @@ paths: $ref: '#/components/schemas/Error' /events/blocks: post: - summary: blah blah + summary: [INDEXER] Get a range of BlockEvents description: | + `/events/blocks` allows the caller to query a stream + of BlockEvents indicating which blocks were added and + removed from storage to reach the indexer's current state. + Streaming BlockEvents allows lightweight clients to update + their state without needing to implement their own syncing + logic (like finding the common parent in a reorg). + + `/events/blocks` is considered an "indexer" endpoint + and Rosetta implementations are not required to complete it + to adhere to the Rosetta spec. However, any Rosetta "indexer" + MUST support this endpoint. operationId: eventsBlocks tags: - Events @@ -681,8 +692,18 @@ paths: $ref: '#/components/schemas/Error' /search/transactions: post: - summary: blah blah + summary: [INDEXER] Search for Transactions description: | + `/search/transactions` allows the caller to search for + transactions that meet certain conditions. Some conditions + include matching a transaction hash, containing an + operation with a certain status, or containing an operation + that affects a certain account. + + `/search/transactions` is considered an "indexer" endpoint + and Rosetta implementations are not required to complete it + to adhere to the Rosetta spec. However, any Rosetta "indexer" + MUST support this endpoint. operationId: searchTransactions tags: - Search @@ -1461,7 +1482,8 @@ components: true here or they could cause issues for the caller. EventsBlocksRequest: description: | - EventsBlocksRequest + EventsBlocksRequest is utilized to fetch a sequence of BlockEvents + indicating which blocks were added and removed during syncing. type: object required: - network_identifier @@ -1480,8 +1502,7 @@ components: limit: description: | limit is the maximum number of events to fetch in one call. The implementation - may return up to this limit but there is no guarantee it will return all limit - events. + may return <= limit events. type: integer format: int64 minimum: 0 @@ -1489,7 +1510,7 @@ components: EventsBlocksResponse: description: | EventsBlocksResponse contains an ordered collection of BlockEvents - and the largest available retrievable sequence. + and the max retrievable sequence. type: object required: - max_sequence @@ -1506,9 +1527,9 @@ components: type: array description: | events is an array of BlockEvents indicating the order to add - and remove blocks to maintain a consistent view of blockchain - state. Following this event stream prevents some lightweight - clients from running their own syncer. + and remove blocks to maintain a canonical view of blockchain + state. Lightweight clients can use this event stream to update + state without implementing their own block syncing logic. items: $ref: '#/components/schemas/BlockEvent' diff --git a/models/BlockEvent.yaml b/models/BlockEvent.yaml index 9322868..09a8397 100644 --- a/models/BlockEvent.yaml +++ b/models/BlockEvent.yaml @@ -13,12 +13,24 @@ # limitations under the License. description: | + BlockEvent represents the addition or removal of a BlockIdentifier + from the stored state of an indexer. Streaming BlockEvents allows + lightweight clients to update their own state without needing to + implement their own syncing logic. type: object required: - sequence - block_identifier - type properties: + sequence: + description: | + sequence is the unique identifier of a BlockEvent + within the context of a NetworkIdentifier. + type: integer + format: int64 + minimum: 0 + example: 5 block_identifier: $ref: 'BlockIdentifier.yaml' type: diff --git a/models/BlockEventType.yaml b/models/BlockEventType.yaml index d963801..4ddc7d1 100644 --- a/models/BlockEventType.yaml +++ b/models/BlockEventType.yaml @@ -13,6 +13,8 @@ # limitations under the License. description: | + BlockEventType determines if a BlockEvent represents the + addition or removal of a block. type: string enum: - block_added From c610fdafaee93e51c4b431f13708b9d1a15cada1 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 16:52:45 -0800 Subject: [PATCH 05/11] Add description for search transactions --- api.yaml | 95 ++++++++++++++++++++++++++++++++++++ models/BlockTransaction.yaml | 26 ++++++++++ models/Operator.yaml | 21 ++++++++ 3 files changed, 142 insertions(+) create mode 100644 models/BlockTransaction.yaml create mode 100644 models/Operator.yaml diff --git a/api.yaml b/api.yaml index ecd18db..96d1b52 100644 --- a/api.yaml +++ b/api.yaml @@ -795,6 +795,10 @@ components: $ref: 'models/BlockEvent.yaml' BlockEventType: $ref: 'models/BlockEventType.yaml' + Operator: + $ref: 'models/Operator.yaml' + BlockTransaction: + $ref: 'models/BlockTransaction.yaml' # Request/Responses AccountBalanceRequest: @@ -1532,6 +1536,97 @@ components: state without implementing their own block syncing logic. items: $ref: '#/components/schemas/BlockEvent' + SearchTransactionsRequest: + description: | + SearchTransactionsRequest is used to search for transactions + matching a set of provided conditions. + type: object + required: + - network_identifier + - operator + properties: + network_identifier: + $ref: '#/components/schemas/NetworkIdentifier' + operator: + $ref: '#/components/schemas/Operator' + max_block: + description: | + max_block is the largest block index to consider when searching + for transactions. If this field is not populated, the current + block is considered the max_block. + type: integer + format: int64 + minimum: 0 + example: 5 + limit: + description: | + limit is the maximum number of transactions to return in one call. The implementation + may return <= limit transactions. + + If returning all transactions in a block would surpass the specified + limit (so that only some transactions in a block would be returned), + no transactions from that block are returned. + type: integer + format: int64 + minimum: 0 + example: 5 + transaction_identifier: + $ref: '#/components/schemas/TransactionIdentifier' + account_identifier: + $ref: '#/components/schemas/AccountIdentifier' + currency: + $ref: '#/components/schemas/Currency' + status: + type: string + description: | + status is the network-specific operation type. + example: "reverted" + type: + type: string + description: | + type is the network-specific operation type. + example: "transfer" + address: + type: string + description: | + address is AccountIdentifier.Address. This is used to get all + transactions related to an AccountIdentifier.Address, regardless + of SubAccountIdentifier. + example: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + success: + type: boolean + description: | + success is a synthetic condition populated by parsing network-specific + operation statuses (using the mapping provided in `/network/options`). + SearchTransactionsResponse: + description: | + SearchTransactionsResponse contains an ordered collection of BlockTransactions + that match the query in SearchTransactionsRequest. These BlockTransactions + are sorted from most recent block to oldest block. + type: object + required: + - transactions + properties: + next_max_block: + description: | + next_max_block is the next max_block to use when querying transactions. + If there are no more transactions to fetch, this field is not returned. + type: integer + format: int64 + minimum: 0 + example: 5 + transactions: + type: array + description: | + transactions is an array of BlockTransactions sorted by most recent + BlockIdentifier (meaning that transactions in recent blocks appear + first). + + If there are many transactions for a particular search, transactions + may not contain all matching transactions. It is up to the caller to + paginate these transactions using the max_block field. + items: + $ref: 'BlockTransaction.yaml' # Miscellaneous Error: diff --git a/models/BlockTransaction.yaml b/models/BlockTransaction.yaml new file mode 100644 index 0000000..bbf1d04 --- /dev/null +++ b/models/BlockTransaction.yaml @@ -0,0 +1,26 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | + BlockTransaction contains a populated Transaction + and the BlockIdentifier that contains it. +type: object +required: + - block_identifier + - transaction +properties: + block_identifier: + $ref: 'BlockIdentifier.yaml' + transaction: + $ref: 'Transaction.yaml' diff --git a/models/Operator.yaml b/models/Operator.yaml new file mode 100644 index 0000000..ebf286f --- /dev/null +++ b/models/Operator.yaml @@ -0,0 +1,21 @@ +# Copyright 2020 Coinbase, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +description: | + Operator is used by query-related endpoints + to determine how to apply conditions. +type: string +enum: + - or + - and From bc941e8f8c96e2a49cbee45f709fda238675c21d Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 17:31:48 -0800 Subject: [PATCH 06/11] Add offset to query --- api.yaml | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/api.yaml b/api.yaml index 96d1b52..239ffbd 100644 --- a/api.yaml +++ b/api.yaml @@ -1539,7 +1539,7 @@ components: SearchTransactionsRequest: description: | SearchTransactionsRequest is used to search for transactions - matching a set of provided conditions. + matching a set of provided conditions in canonical blocks. type: object required: - network_identifier @@ -1554,6 +1554,20 @@ components: max_block is the largest block index to consider when searching for transactions. If this field is not populated, the current block is considered the max_block. + + If you do not specify a max_block, it is possible a newly synced + block will interfere with paginated transaction queries (as the offset + could become invalid with newly added rows). + type: integer + format: int64 + minimum: 0 + example: 5 + offset: + description: | + offset is the offset into the query result to start returning transactions. + + If any search conditions are changed, the query offset will change and you + must restart your search iteration. type: integer format: int64 minimum: 0 @@ -1562,10 +1576,6 @@ components: description: | limit is the maximum number of transactions to return in one call. The implementation may return <= limit transactions. - - If returning all transactions in a block would surpass the specified - limit (so that only some transactions in a block would be returned), - no transactions from that block are returned. type: integer format: int64 minimum: 0 @@ -1607,10 +1617,11 @@ components: required: - transactions properties: - next_max_block: + next_offset: description: | - next_max_block is the next max_block to use when querying transactions. - If there are no more transactions to fetch, this field is not returned. + next_offset is the next offset to use when paginating through + transaction results. If this field is not populated, there are + no more transactions to query. type: integer format: int64 minimum: 0 From 23ec41e1c8f302ba9399086c76d939189f3ecad5 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 17:34:50 -0800 Subject: [PATCH 07/11] make gen --- api.json | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ api.yaml | 8 +- 2 files changed, 283 insertions(+), 3 deletions(-) diff --git a/api.json b/api.json index f46e84a..0c14693 100644 --- a/api.json +++ b/api.json @@ -765,6 +765,90 @@ } } } + }, + "/events/blocks": { + "post": { + "summary":"[INDEXER] Get a range of BlockEvents", + "description":"`/events/blocks` allows the caller to query a stream of BlockEvents indicating which blocks were added and removed from storage to reach the indexer's current state. Streaming BlockEvents allows lightweight clients to update their state without needing to implement their own syncing logic (like finding the common parent in a reorg). `/events/blocks` is considered an \"indexer\" endpoint and Rosetta implementations are not required to complete it to adhere to the Rosetta spec. However, any Rosetta \"indexer\" MUST support this endpoint.", + "operationId":"eventsBlocks", + "tags": [ + "Events" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/EventsBlocksRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/EventsBlocksResponse" + } + } + } + }, + "500": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } + }, + "/search/transactions": { + "post": { + "summary":"[INDEXER] Search for Transactions", + "description":"`/search/transactions` allows the caller to search for transactions that meet certain conditions. Some conditions include matching a transaction hash, containing an operation with a certain status, or containing an operation that affects a certain account. `/search/transactions` is considered an \"indexer\" endpoint and Rosetta implementations are not required to complete it to adhere to the Rosetta spec. However, any Rosetta \"indexer\" MUST support this endpoint.", + "operationId":"searchTransactions", + "tags": [ + "Search" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/SearchTransactionsRequest" + } + } + } + }, + "responses": { + "200": { + "description":"Expected response to a valid request", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/SearchTransactionsResponse" + } + } + } + }, + "500": { + "description":"unexpected error", + "content": { + "application/json": { + "schema": { + "$ref":"#/components/schemas/Error" + } + } + } + } + } + } } }, "components": { @@ -1416,6 +1500,62 @@ "dynamic" ] }, + "BlockEvent": { + "description":"BlockEvent represents the addition or removal of a BlockIdentifier from the stored state of an indexer. Streaming BlockEvents allows lightweight clients to update their own state without needing to implement their own syncing logic.", + "type":"object", + "required": [ + "sequence", + "block_identifier", + "type" + ], + "properties": { + "sequence": { + "description":"sequence is the unique identifier of a BlockEvent within the context of a NetworkIdentifier.", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + }, + "block_identifier": { + "$ref":"#/components/schemas/BlockIdentifier" + }, + "type": { + "$ref":"#/components/schemas/BlockEventType" + } + } + }, + "BlockEventType": { + "description":"BlockEventType determines if a BlockEvent represents the addition or removal of a block.", + "type":"string", + "enum": [ + "block_added", + "block_removed" + ] + }, + "Operator": { + "description":"Operator is used by query-related endpoints to determine how to apply conditions.", + "type":"string", + "enum": [ + "or", + "and" + ] + }, + "BlockTransaction": { + "description":"BlockTransaction contains a populated Transaction and the BlockIdentifier that contains it.", + "type":"object", + "required": [ + "block_identifier", + "transaction" + ], + "properties": { + "block_identifier": { + "$ref":"#/components/schemas/BlockIdentifier" + }, + "transaction": { + "$ref":"#/components/schemas/Transaction" + } + } + }, "AccountBalanceRequest": { "description":"An AccountBalanceRequest is utilized to make a balance request on the /account/balance endpoint. If the block_identifier is populated, a historical balance query should be performed.", "type":"object", @@ -2084,6 +2224,144 @@ } } }, + "EventsBlocksRequest": { + "description":"EventsBlocksRequest is utilized to fetch a sequence of BlockEvents indicating which blocks were added and removed during syncing.", + "type":"object", + "required": [ + "network_identifier" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "offset": { + "description":"offset is the offset into the event stream to sync events from. If this is left empty, we stream the limit from tip. If this is set to 0, we start from the beginning.", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + }, + "limit": { + "description":"limit is the maximum number of events to fetch in one call. The implementation may return <= limit events.", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + } + } + }, + "EventsBlocksResponse": { + "description":"EventsBlocksResponse contains an ordered collection of BlockEvents and the max retrievable sequence.", + "type":"object", + "required": [ + "max_sequence", + "events" + ], + "properties": { + "max_sequence": { + "description":"max_sequence is the maximum available sequence number to fetch.", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + }, + "events": { + "type":"array", + "description":"events is an array of BlockEvents indicating the order to add and remove blocks to maintain a canonical view of blockchain state. Lightweight clients can use this event stream to update state without implementing their own block syncing logic.", + "items": { + "$ref":"#/components/schemas/BlockEvent" + } + } + } + }, + "SearchTransactionsRequest": { + "description":"SearchTransactionsRequest is used to search for transactions matching a set of provided conditions in canonical blocks.", + "type":"object", + "required": [ + "network_identifier", + "operator" + ], + "properties": { + "network_identifier": { + "$ref":"#/components/schemas/NetworkIdentifier" + }, + "operator": { + "$ref":"#/components/schemas/Operator" + }, + "max_block": { + "description":"max_block is the largest block index to consider when searching for transactions. If this field is not populated, the current block is considered the max_block. If you do not specify a max_block, it is possible a newly synced block will interfere with paginated transaction queries (as the offset could become invalid with newly added rows).", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + }, + "offset": { + "description":"offset is the offset into the query result to start returning transactions. If any search conditions are changed, the query offset will change and you must restart your search iteration.", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + }, + "limit": { + "description":"limit is the maximum number of transactions to return in one call. The implementation may return <= limit transactions.", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + }, + "transaction_identifier": { + "$ref":"#/components/schemas/TransactionIdentifier" + }, + "account_identifier": { + "$ref":"#/components/schemas/AccountIdentifier" + }, + "currency": { + "$ref":"#/components/schemas/Currency" + }, + "status": { + "type":"string", + "description":"status is the network-specific operation type.", + "example":"reverted" + }, + "type": { + "type":"string", + "description":"type is the network-specific operation type.", + "example":"transfer" + }, + "address": { + "type":"string", + "description":"address is AccountIdentifier.Address. This is used to get all transactions related to an AccountIdentifier.Address, regardless of SubAccountIdentifier.", + "example":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "success": { + "type":"boolean", + "description":"success is a synthetic condition populated by parsing network-specific operation statuses (using the mapping provided in `/network/options`)." + } + } + }, + "SearchTransactionsResponse": { + "description":"SearchTransactionsResponse contains an ordered collection of BlockTransactions that match the query in SearchTransactionsRequest. These BlockTransactions are sorted from most recent block to oldest block.", + "type":"object", + "required": [ + "transactions" + ], + "properties": { + "next_offset": { + "description":"next_offset is the next offset to use when paginating through transaction results. If this field is not populated, there are no more transactions to query.", + "type":"integer", + "format":"int64", + "minimum": 0, + "example": 5 + }, + "transactions": { + "type":"array", + "description":"transactions is an array of BlockTransactions sorted by most recent BlockIdentifier (meaning that transactions in recent blocks appear first). If there are many transactions for a particular search, transactions may not contain all matching transactions. It is up to the caller to paginate these transactions using the max_block field.", + "items": { + "$ref":"#/components/schemas/BlockTransaction" + } + } + } + }, "Error": { "description":"Instead of utilizing HTTP status codes to describe node errors (which often do not have a good analog), rich errors are returned using this object. Both the code and message fields can be individually used to correctly identify an error. Implementations MUST use unique values for both fields.", "type":"object", diff --git a/api.yaml b/api.yaml index 239ffbd..35ebc44 100644 --- a/api.yaml +++ b/api.yaml @@ -655,7 +655,8 @@ paths: $ref: '#/components/schemas/Error' /events/blocks: post: - summary: [INDEXER] Get a range of BlockEvents + summary: | + [INDEXER] Get a range of BlockEvents description: | `/events/blocks` allows the caller to query a stream of BlockEvents indicating which blocks were added and @@ -692,7 +693,8 @@ paths: $ref: '#/components/schemas/Error' /search/transactions: post: - summary: [INDEXER] Search for Transactions + summary: | + [INDEXER] Search for Transactions description: | `/search/transactions` allows the caller to search for transactions that meet certain conditions. Some conditions @@ -1637,7 +1639,7 @@ components: may not contain all matching transactions. It is up to the caller to paginate these transactions using the max_block field. items: - $ref: 'BlockTransaction.yaml' + $ref: '#/components/schemas/BlockTransaction' # Miscellaneous Error: From 267cc9f751088121ad876c352a1cc240c44e0294 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 17:59:42 -0800 Subject: [PATCH 08/11] Update README to comment on indexers --- README.md | 36 ++++++++++++++++++++++++++++++++++++ api.json | 3 +++ api.yaml | 2 ++ 3 files changed, 41 insertions(+) diff --git a/README.md b/README.md index a419f43..46477d1 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,40 @@ this illustration: ![Rosetta Modules](images/rosetta-modules.png) +## Indexers +For some developers, the existing Data API and Construction API endpoints are not +sufficent to fully support an asset integration. It is not possible, for example, +to search for a transaction by hash or access all transactions that affected +a particular account. Traditionally database-intensive functionality was purposely +excluded from the collection of endpoints any Rosetta implementation must complete +as to avoid imposing cumbersome requirements on Rosetta implementers (that could require +maintaining architecture alongside their core node). + +Because of the standardization introduced by Rosetta, it is possible +to write a generic indexer for any Rosetta implementation. +To avoid a proliferation of interfaces that service Rosetta in this layer, +we've defined a set of standard "indexer" endpoints that enable developers +to automatically integrate (with the SDK they already use to access the +Rosetta API). + +### Required Endpoints +* Data API (proxied) +* Construction API (proxied) +* `/events/*` +* `/search/*` + +_If you think an endpoint is missing from this list, please reach out +on our [community](https://community.rosetta-api.org/)._ + +Indexer implementations must proxy non-indexer Data API and +Construction API calls to the implementation of interest (potentially +caching some data) so that developers do not need to connect to multiple +endpoints to access Rosetta. All calls contain a `NetworkIdentifier` so it +should be possible to route requests without too much difficulty. + +**Rosetta implementations do not need to implement "indexer" endpoints +but are welcome to do so!** + ## Documentation Now that you have some familiarity with the flow of operations, we recommend taking a look at the Rosetta API Docs: @@ -325,6 +359,8 @@ endpoints (other than `/construction/metadata` and `/construction/submit`). * `/construction/submit` #### Offline Mode Endpoints +* `/network/list` +* `/network/options` * `/construction/derive` * `/construction/preprocess` * `/construction/payloads` diff --git a/api.json b/api.json index 0c14693..ac4d5bf 100644 --- a/api.json +++ b/api.json @@ -2315,6 +2315,9 @@ "account_identifier": { "$ref":"#/components/schemas/AccountIdentifier" }, + "coin_identifier": { + "$ref":"#/components/schemas/CoinIdentifier" + }, "currency": { "$ref":"#/components/schemas/Currency" }, diff --git a/api.yaml b/api.yaml index 35ebc44..5957208 100644 --- a/api.yaml +++ b/api.yaml @@ -1586,6 +1586,8 @@ components: $ref: '#/components/schemas/TransactionIdentifier' account_identifier: $ref: '#/components/schemas/AccountIdentifier' + coin_identifier: + $ref: '#/components/schemas/CoinIdentifier' currency: $ref: '#/components/schemas/Currency' status: From 3605677fb833d092925837ff1131c71c9b0c2b58 Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 18:01:17 -0800 Subject: [PATCH 09/11] cleanup readme --- README.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 46477d1..65439bc 100644 --- a/README.md +++ b/README.md @@ -227,7 +227,14 @@ to write a generic indexer for any Rosetta implementation. To avoid a proliferation of interfaces that service Rosetta in this layer, we've defined a set of standard "indexer" endpoints that enable developers to automatically integrate (with the SDK they already use to access the -Rosetta API). +Rosetta API). **Rosetta implementations are not required to implement "indexer" endpoints +but are welcome to do so!** + +Indexer implementations must proxy non-indexer Data API and +Construction API calls to the implementation of interest (potentially +caching some data) so that developers do not need to connect to multiple +endpoints to access Rosetta. All calls contain a `NetworkIdentifier` so it +should be possible to route requests without too much difficulty. ### Required Endpoints * Data API (proxied) @@ -238,15 +245,6 @@ Rosetta API). _If you think an endpoint is missing from this list, please reach out on our [community](https://community.rosetta-api.org/)._ -Indexer implementations must proxy non-indexer Data API and -Construction API calls to the implementation of interest (potentially -caching some data) so that developers do not need to connect to multiple -endpoints to access Rosetta. All calls contain a `NetworkIdentifier` so it -should be possible to route requests without too much difficulty. - -**Rosetta implementations do not need to implement "indexer" endpoints -but are welcome to do so!** - ## Documentation Now that you have some familiarity with the flow of operations, we recommend taking a look at the Rosetta API Docs: From 3c70fe04778b6684feffd4c38901920873e65e0d Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 18:02:15 -0800 Subject: [PATCH 10/11] fix spelling --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 65439bc..110bc7e 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,7 @@ this illustration: ## Indexers For some developers, the existing Data API and Construction API endpoints are not -sufficent to fully support an asset integration. It is not possible, for example, +sufficient to fully support an asset integration. It is not possible, for example, to search for a transaction by hash or access all transactions that affected a particular account. Traditionally database-intensive functionality was purposely excluded from the collection of endpoints any Rosetta implementation must complete From 6715162164f2929a8e5e3f373626345a00b5a8ca Mon Sep 17 00:00:00 2001 From: Patrick O'Grady Date: Thu, 5 Nov 2020 18:17:42 -0800 Subject: [PATCH 11/11] nits --- api.json | 8 ++++---- api.yaml | 13 +++++++------ models/BlockEvent.yaml | 5 ++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/api.json b/api.json index ac4d5bf..90fcb2f 100644 --- a/api.json +++ b/api.json @@ -769,7 +769,7 @@ "/events/blocks": { "post": { "summary":"[INDEXER] Get a range of BlockEvents", - "description":"`/events/blocks` allows the caller to query a stream of BlockEvents indicating which blocks were added and removed from storage to reach the indexer's current state. Streaming BlockEvents allows lightweight clients to update their state without needing to implement their own syncing logic (like finding the common parent in a reorg). `/events/blocks` is considered an \"indexer\" endpoint and Rosetta implementations are not required to complete it to adhere to the Rosetta spec. However, any Rosetta \"indexer\" MUST support this endpoint.", + "description":"`/events/blocks` allows the caller to query a sequence of BlockEvents indicating which blocks were added and removed from storage to reach the current state. Following BlockEvents allows lightweight clients to update their state without needing to implement their own syncing logic (like finding the common parent in a reorg). `/events/blocks` is considered an \"indexer\" endpoint and Rosetta implementations are not required to complete it to adhere to the Rosetta spec. However, any Rosetta \"indexer\" MUST support this endpoint.", "operationId":"eventsBlocks", "tags": [ "Events" @@ -1501,7 +1501,7 @@ ] }, "BlockEvent": { - "description":"BlockEvent represents the addition or removal of a BlockIdentifier from the stored state of an indexer. Streaming BlockEvents allows lightweight clients to update their own state without needing to implement their own syncing logic.", + "description":"BlockEvent represents the addition or removal of a BlockIdentifier from storage. Streaming BlockEvents allows lightweight clients to update their own state without needing to implement their own syncing logic.", "type":"object", "required": [ "sequence", @@ -2225,7 +2225,7 @@ } }, "EventsBlocksRequest": { - "description":"EventsBlocksRequest is utilized to fetch a sequence of BlockEvents indicating which blocks were added and removed during syncing.", + "description":"EventsBlocksRequest is utilized to fetch a sequence of BlockEvents indicating which blocks were added and removed from storage to reach the current state.", "type":"object", "required": [ "network_identifier" @@ -2235,7 +2235,7 @@ "$ref":"#/components/schemas/NetworkIdentifier" }, "offset": { - "description":"offset is the offset into the event stream to sync events from. If this is left empty, we stream the limit from tip. If this is set to 0, we start from the beginning.", + "description":"offset is the offset into the event stream to sync events from. If this field is not populated, we return the limit events backwards from tip. If this is set to 0, we start from the beginning.", "type":"integer", "format":"int64", "minimum": 0, diff --git a/api.yaml b/api.yaml index 5957208..1fa844d 100644 --- a/api.yaml +++ b/api.yaml @@ -658,10 +658,10 @@ paths: summary: | [INDEXER] Get a range of BlockEvents description: | - `/events/blocks` allows the caller to query a stream + `/events/blocks` allows the caller to query a sequence of BlockEvents indicating which blocks were added and - removed from storage to reach the indexer's current state. - Streaming BlockEvents allows lightweight clients to update + removed from storage to reach the current state. + Following BlockEvents allows lightweight clients to update their state without needing to implement their own syncing logic (like finding the common parent in a reorg). @@ -1489,7 +1489,8 @@ components: EventsBlocksRequest: description: | EventsBlocksRequest is utilized to fetch a sequence of BlockEvents - indicating which blocks were added and removed during syncing. + indicating which blocks were added and removed from storage to + reach the current state. type: object required: - network_identifier @@ -1499,8 +1500,8 @@ components: offset: description: | offset is the offset into the event stream to sync events from. If this - is left empty, we stream the limit from tip. If this is set to 0, - we start from the beginning. + field is not populated, we return the limit events backwards from tip. + If this is set to 0, we start from the beginning. type: integer format: int64 minimum: 0 diff --git a/models/BlockEvent.yaml b/models/BlockEvent.yaml index 09a8397..c0ae50e 100644 --- a/models/BlockEvent.yaml +++ b/models/BlockEvent.yaml @@ -14,9 +14,8 @@ description: | BlockEvent represents the addition or removal of a BlockIdentifier - from the stored state of an indexer. Streaming BlockEvents allows - lightweight clients to update their own state without needing to - implement their own syncing logic. + from storage. Streaming BlockEvents allows lightweight clients to + update their own state without needing to implement their own syncing logic. type: object required: - sequence