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

Added actions filters #4

Closed
wants to merge 4 commits into from
Closed
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
292 changes: 106 additions & 186 deletions docs/docs.go
Original file line number Diff line number Diff line change
@@ -96,6 +96,32 @@ const docTemplate = `{
"summary": "Get Actions",
"operationId": "api_v3_get_actions",
"parameters": [
{
"type": "string",
"description": "List of account addresses to get actions. Can be sent in hex, base64 or base64url form.",
"name": "account",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "Find actions by transaction hash.",
"name": "tx_hash",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "Find actions by message hash.",
"name": "msg_hash",
"in": "query"
},
{
"type": "array",
"items": {
@@ -115,6 +141,68 @@ const docTemplate = `{
"description": "Find actions by the trace_id.",
"name": "trace_id",
"in": "query"
},
{
"type": "integer",
"description": "Query actions of events which was completed in masterchain block with given seqno",
"name": "mc_seqno",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events, which was finished **after** given timestamp.",
"name": "start_utime",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events, which was finished **before** given timestamp.",
"name": "end_utime",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events with ` + "`" + `end_lt \u003e= start_lt` + "`" + `.",
"name": "start_lt",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events with ` + "`" + `end_lt \u003c= end_lt` + "`" + `.",
"name": "end_lt",
"in": "query"
},
{
"maximum": 1000,
"minimum": 1,
"type": "integer",
"default": 10,
"description": "Limit number of queried rows. Use with *offset* to batch read.",
"name": "limit",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"default": 0,
"description": "Skip first N rows. Use with *limit* to batch read.",
"name": "offset",
"in": "query"
},
{
"enum": [
"asc",
"desc"
],
"type": "string",
"default": "desc",
"description": "Sort actions by lt.",
"name": "sort",
"in": "query"
}
],
"responses": {
@@ -514,7 +602,7 @@ const docTemplate = `{
},
{
"type": "integer",
"description": "Masterchain block seqno",
"description": "Query events that was completed in masterchain block with given seqno",
"name": "mc_seqno",
"in": "query"
},
@@ -1097,6 +1185,23 @@ const docTemplate = `{
"name": "seqno",
"in": "query",
"required": true
},
{
"maximum": 1000,
"minimum": 1,
"type": "integer",
"default": 10,
"description": "Limit number of queried rows. Use with *offset* to batch read.",
"name": "limit",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"default": 0,
"description": "Skip first N rows. Use with *limit* to batch read.",
"name": "offset",
"in": "query"
}
],
"responses": {
@@ -2279,9 +2384,6 @@ const docTemplate = `{
"end_utime": {
"type": "integer"
},
"raw_action": {
"$ref": "#/definitions/RawAction"
},
"start_lt": {
"type": "string",
"example": "0"
@@ -3180,188 +3282,6 @@ const docTemplate = `{
}
}
},
"RawAction": {
"type": "object",
"properties": {
"actionId": {
"type": "string"
},
"amount": {
"type": "string"
},
"asset": {
"type": "string"
},
"asset2": {
"type": "string"
},
"asset2Secondary": {
"type": "string"
},
"assetSecondary": {
"type": "string"
},
"changeDNSRecordFlags": {
"type": "integer"
},
"changeDNSRecordKey": {
"type": "string"
},
"changeDNSRecordValue": {
"type": "string"
},
"changeDNSRecordValueSchema": {
"type": "string"
},
"destination": {
"type": "string"
},
"destinationSecondary": {
"type": "string"
},
"endLt": {
"type": "integer"
},
"endUtime": {
"type": "integer"
},
"jettonSwapDex": {
"type": "string"
},
"jettonSwapDexIncomingTransferAmount": {
"type": "string"
},
"jettonSwapDexIncomingTransferAsset": {
"type": "string"
},
"jettonSwapDexIncomingTransferDestination": {
"type": "string"
},
"jettonSwapDexIncomingTransferDestinationJettonWallet": {
"type": "string"
},
"jettonSwapDexIncomingTransferSource": {
"type": "string"
},
"jettonSwapDexIncomingTransferSourceJettonWallet": {
"type": "string"
},
"jettonSwapDexOutgoingTransferAmount": {
"type": "string"
},
"jettonSwapDexOutgoingTransferAsset": {
"type": "string"
},
"jettonSwapDexOutgoingTransferDestination": {
"type": "string"
},
"jettonSwapDexOutgoingTransferDestinationJettonWallet": {
"type": "string"
},
"jettonSwapDexOutgoingTransferSource": {
"type": "string"
},
"jettonSwapDexOutgoingTransferSourceJettonWallet": {
"type": "string"
},
"jettonSwapPeerSwaps": {
"type": "array",
"items": {
"type": "string"
}
},
"jettonSwapSender": {
"type": "string"
},
"jettonTransferComment": {
"type": "string"
},
"jettonTransferCustomPayload": {
"type": "string"
},
"jettonTransferForwardAmount": {
"type": "string"
},
"jettonTransferForwardPayload": {
"type": "string"
},
"jettonTransferIsEncryptedComment": {
"type": "boolean"
},
"jettonTransferQueryId": {
"type": "string"
},
"jettonTransferResponseDestination": {
"type": "string"
},
"nftmintNFTItemIndex": {
"type": "string"
},
"nfttransferCustomPayload": {
"type": "string"
},
"nfttransferForwardAmount": {
"type": "string"
},
"nfttransferForwardPayload": {
"type": "string"
},
"nfttransferIsPurchase": {
"type": "boolean"
},
"nfttransferNFTItemIndex": {
"type": "string"
},
"nfttransferPrice": {
"type": "string"
},
"nfttransferQueryId": {
"type": "string"
},
"nfttransferResponseDestination": {
"type": "string"
},
"opcode": {
"type": "integer"
},
"source": {
"type": "string"
},
"sourceSecondary": {
"type": "string"
},
"startLt": {
"type": "integer"
},
"startUtime": {
"type": "integer"
},
"success": {
"type": "boolean"
},
"tonTransferContent": {
"type": "string"
},
"tonTransferEncrypted": {
"type": "boolean"
},
"traceId": {
"type": "string"
},
"txHashes": {
"type": "array",
"items": {
"type": "string"
}
},
"type": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"RequestError": {
"type": "object",
"properties": {
292 changes: 106 additions & 186 deletions docs/swagger.json
Original file line number Diff line number Diff line change
@@ -88,6 +88,32 @@
"summary": "Get Actions",
"operationId": "api_v3_get_actions",
"parameters": [
{
"type": "string",
"description": "List of account addresses to get actions. Can be sent in hex, base64 or base64url form.",
"name": "account",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "Find actions by transaction hash.",
"name": "tx_hash",
"in": "query"
},
{
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi",
"description": "Find actions by message hash.",
"name": "msg_hash",
"in": "query"
},
{
"type": "array",
"items": {
@@ -107,6 +133,68 @@
"description": "Find actions by the trace_id.",
"name": "trace_id",
"in": "query"
},
{
"type": "integer",
"description": "Query actions of events which was completed in masterchain block with given seqno",
"name": "mc_seqno",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events, which was finished **after** given timestamp.",
"name": "start_utime",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events, which was finished **before** given timestamp.",
"name": "end_utime",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events with `end_lt \u003e= start_lt`.",
"name": "start_lt",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"description": "Query actions for events with `end_lt \u003c= end_lt`.",
"name": "end_lt",
"in": "query"
},
{
"maximum": 1000,
"minimum": 1,
"type": "integer",
"default": 10,
"description": "Limit number of queried rows. Use with *offset* to batch read.",
"name": "limit",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"default": 0,
"description": "Skip first N rows. Use with *limit* to batch read.",
"name": "offset",
"in": "query"
},
{
"enum": [
"asc",
"desc"
],
"type": "string",
"default": "desc",
"description": "Sort actions by lt.",
"name": "sort",
"in": "query"
}
],
"responses": {
@@ -506,7 +594,7 @@
},
{
"type": "integer",
"description": "Masterchain block seqno",
"description": "Query events that was completed in masterchain block with given seqno",
"name": "mc_seqno",
"in": "query"
},
@@ -1089,6 +1177,23 @@
"name": "seqno",
"in": "query",
"required": true
},
{
"maximum": 1000,
"minimum": 1,
"type": "integer",
"default": 10,
"description": "Limit number of queried rows. Use with *offset* to batch read.",
"name": "limit",
"in": "query"
},
{
"minimum": 0,
"type": "integer",
"default": 0,
"description": "Skip first N rows. Use with *limit* to batch read.",
"name": "offset",
"in": "query"
}
],
"responses": {
@@ -2271,9 +2376,6 @@
"end_utime": {
"type": "integer"
},
"raw_action": {
"$ref": "#/definitions/RawAction"
},
"start_lt": {
"type": "string",
"example": "0"
@@ -3172,188 +3274,6 @@
}
}
},
"RawAction": {
"type": "object",
"properties": {
"actionId": {
"type": "string"
},
"amount": {
"type": "string"
},
"asset": {
"type": "string"
},
"asset2": {
"type": "string"
},
"asset2Secondary": {
"type": "string"
},
"assetSecondary": {
"type": "string"
},
"changeDNSRecordFlags": {
"type": "integer"
},
"changeDNSRecordKey": {
"type": "string"
},
"changeDNSRecordValue": {
"type": "string"
},
"changeDNSRecordValueSchema": {
"type": "string"
},
"destination": {
"type": "string"
},
"destinationSecondary": {
"type": "string"
},
"endLt": {
"type": "integer"
},
"endUtime": {
"type": "integer"
},
"jettonSwapDex": {
"type": "string"
},
"jettonSwapDexIncomingTransferAmount": {
"type": "string"
},
"jettonSwapDexIncomingTransferAsset": {
"type": "string"
},
"jettonSwapDexIncomingTransferDestination": {
"type": "string"
},
"jettonSwapDexIncomingTransferDestinationJettonWallet": {
"type": "string"
},
"jettonSwapDexIncomingTransferSource": {
"type": "string"
},
"jettonSwapDexIncomingTransferSourceJettonWallet": {
"type": "string"
},
"jettonSwapDexOutgoingTransferAmount": {
"type": "string"
},
"jettonSwapDexOutgoingTransferAsset": {
"type": "string"
},
"jettonSwapDexOutgoingTransferDestination": {
"type": "string"
},
"jettonSwapDexOutgoingTransferDestinationJettonWallet": {
"type": "string"
},
"jettonSwapDexOutgoingTransferSource": {
"type": "string"
},
"jettonSwapDexOutgoingTransferSourceJettonWallet": {
"type": "string"
},
"jettonSwapPeerSwaps": {
"type": "array",
"items": {
"type": "string"
}
},
"jettonSwapSender": {
"type": "string"
},
"jettonTransferComment": {
"type": "string"
},
"jettonTransferCustomPayload": {
"type": "string"
},
"jettonTransferForwardAmount": {
"type": "string"
},
"jettonTransferForwardPayload": {
"type": "string"
},
"jettonTransferIsEncryptedComment": {
"type": "boolean"
},
"jettonTransferQueryId": {
"type": "string"
},
"jettonTransferResponseDestination": {
"type": "string"
},
"nftmintNFTItemIndex": {
"type": "string"
},
"nfttransferCustomPayload": {
"type": "string"
},
"nfttransferForwardAmount": {
"type": "string"
},
"nfttransferForwardPayload": {
"type": "string"
},
"nfttransferIsPurchase": {
"type": "boolean"
},
"nfttransferNFTItemIndex": {
"type": "string"
},
"nfttransferPrice": {
"type": "string"
},
"nfttransferQueryId": {
"type": "string"
},
"nfttransferResponseDestination": {
"type": "string"
},
"opcode": {
"type": "integer"
},
"source": {
"type": "string"
},
"sourceSecondary": {
"type": "string"
},
"startLt": {
"type": "integer"
},
"startUtime": {
"type": "integer"
},
"success": {
"type": "boolean"
},
"tonTransferContent": {
"type": "string"
},
"tonTransferEncrypted": {
"type": "boolean"
},
"traceId": {
"type": "string"
},
"txHashes": {
"type": "array",
"items": {
"type": "string"
}
},
"type": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"RequestError": {
"type": "object",
"properties": {
206 changes: 82 additions & 124 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
@@ -70,8 +70,6 @@ definitions:
type: string
end_utime:
type: integer
raw_action:
$ref: '#/definitions/RawAction'
start_lt:
example: "0"
type: string
@@ -672,127 +670,6 @@ definitions:
$ref: '#/definitions/NFTTransfer'
type: array
type: object
RawAction:
properties:
actionId:
type: string
amount:
type: string
asset:
type: string
asset2:
type: string
asset2Secondary:
type: string
assetSecondary:
type: string
changeDNSRecordFlags:
type: integer
changeDNSRecordKey:
type: string
changeDNSRecordValue:
type: string
changeDNSRecordValueSchema:
type: string
destination:
type: string
destinationSecondary:
type: string
endLt:
type: integer
endUtime:
type: integer
jettonSwapDex:
type: string
jettonSwapDexIncomingTransferAmount:
type: string
jettonSwapDexIncomingTransferAsset:
type: string
jettonSwapDexIncomingTransferDestination:
type: string
jettonSwapDexIncomingTransferDestinationJettonWallet:
type: string
jettonSwapDexIncomingTransferSource:
type: string
jettonSwapDexIncomingTransferSourceJettonWallet:
type: string
jettonSwapDexOutgoingTransferAmount:
type: string
jettonSwapDexOutgoingTransferAsset:
type: string
jettonSwapDexOutgoingTransferDestination:
type: string
jettonSwapDexOutgoingTransferDestinationJettonWallet:
type: string
jettonSwapDexOutgoingTransferSource:
type: string
jettonSwapDexOutgoingTransferSourceJettonWallet:
type: string
jettonSwapPeerSwaps:
items:
type: string
type: array
jettonSwapSender:
type: string
jettonTransferComment:
type: string
jettonTransferCustomPayload:
type: string
jettonTransferForwardAmount:
type: string
jettonTransferForwardPayload:
type: string
jettonTransferIsEncryptedComment:
type: boolean
jettonTransferQueryId:
type: string
jettonTransferResponseDestination:
type: string
nftmintNFTItemIndex:
type: string
nfttransferCustomPayload:
type: string
nfttransferForwardAmount:
type: string
nfttransferForwardPayload:
type: string
nfttransferIsPurchase:
type: boolean
nfttransferNFTItemIndex:
type: string
nfttransferPrice:
type: string
nfttransferQueryId:
type: string
nfttransferResponseDestination:
type: string
opcode:
type: integer
source:
type: string
sourceSecondary:
type: string
startLt:
type: integer
startUtime:
type: integer
success:
type: boolean
tonTransferContent:
type: string
tonTransferEncrypted:
type: boolean
traceId:
type: string
txHashes:
items:
type: string
type: array
type:
type: string
value:
type: string
type: object
RequestError:
properties:
code:
@@ -1108,6 +985,25 @@ paths:
description: Get actions by specified filter.
operationId: api_v3_get_actions
parameters:
- description: List of account addresses to get actions. Can be sent in hex,
base64 or base64url form.
in: query
name: account
type: string
- collectionFormat: multi
description: Find actions by transaction hash.
in: query
items:
type: string
name: tx_hash
type: array
- collectionFormat: multi
description: Find actions by message hash.
in: query
items:
type: string
name: msg_hash
type: array
- collectionFormat: multi
description: Find actions by the action_id.
in: query
@@ -1122,6 +1018,54 @@ paths:
type: string
name: trace_id
type: array
- description: Query actions of events which was completed in masterchain block
with given seqno
in: query
name: mc_seqno
type: integer
- description: Query actions for events, which was finished **after** given
timestamp.
in: query
minimum: 0
name: start_utime
type: integer
- description: Query actions for events, which was finished **before** given
timestamp.
in: query
minimum: 0
name: end_utime
type: integer
- description: Query actions for events with `end_lt >= start_lt`.
in: query
minimum: 0
name: start_lt
type: integer
- description: Query actions for events with `end_lt <= end_lt`.
in: query
minimum: 0
name: end_lt
type: integer
- default: 10
description: Limit number of queried rows. Use with *offset* to batch read.
in: query
maximum: 1000
minimum: 1
name: limit
type: integer
- default: 0
description: Skip first N rows. Use with *limit* to batch read.
in: query
minimum: 0
name: offset
type: integer
- default: desc
description: Sort actions by lt.
enum:
- asc
- desc
in: query
name: sort
type: string
produces:
- application/json
responses:
@@ -1378,7 +1322,8 @@ paths:
type: string
name: msg_hash
type: array
- description: Masterchain block seqno
- description: Query events that was completed in masterchain block with given
seqno
in: query
name: mc_seqno
type: integer
@@ -1777,6 +1722,19 @@ paths:
name: seqno
required: true
type: integer
- default: 10
description: Limit number of queried rows. Use with *offset* to batch read.
in: query
maximum: 1000
minimum: 1
name: limit
type: integer
- default: 0
description: Skip first N rows. Use with *limit* to batch read.
in: query
minimum: 0
name: offset
type: integer
produces:
- application/json
responses:
214 changes: 181 additions & 33 deletions index/crud.go
Original file line number Diff line number Diff line change
@@ -748,8 +748,8 @@ func buildJettonTransfersQuery(transfer_req JettonTransferRequest, utime_req Uti
return query, nil
}

func buildActionsQuery(act_req ActionRequest, lim_req LimitRequest, settings RequestSettings) (string, error) {
clmn_query := `A.trace_id, A.action_id, A.start_lt, A.end_lt, A.start_utime, A.end_utime, A.source, A.source_secondary,
func buildActionsQuery(act_req ActionRequest, utime_req UtimeRequest, lt_req LtRequest, lim_req LimitRequest, settings RequestSettings) (string, error) {
clmn_query_default := `A.trace_id, A.action_id, A.start_lt, A.end_lt, A.start_utime, A.end_utime, A.source, A.source_secondary,
A.destination, A.destination_secondary, A.asset, A.asset_secondary, A.asset2, A.asset2_secondary, A.opcode, A.tx_hashes,
A.type, (A.ton_transfer_data).content, (A.ton_transfer_data).encrypted, A.value, A.amount,
(A.jetton_transfer_data).response_destination, (A.jetton_transfer_data).forward_amount, (A.jetton_transfer_data).query_id,
@@ -766,7 +766,8 @@ func buildActionsQuery(act_req ActionRequest, lim_req LimitRequest, settings Req
((A.jetton_swap_data).dex_outgoing_transfer).destination_jetton_wallet, (A.jetton_swap_data).peer_swaps,
(A.change_dns_record_data).key, (A.change_dns_record_data).value_schema, (A.change_dns_record_data).value,
(A.change_dns_record_data).flags, (A.nft_mint_data).nft_item_index, A.success`
from_query := `actions as A`
clmn_query := clmn_query_default
from_query := `actions as A join traces as E on A.trace_id = E.trace_id`
filter_list := []string{}
filter_query := ``
orderby_query := ``
@@ -775,19 +776,92 @@ func buildActionsQuery(act_req ActionRequest, lim_req LimitRequest, settings Req
return "", err
}

sort_order := "desc"
if v := lim_req.Sort; v != nil {
sort_order, err = getSortOrder(*v)
if err != nil {
return "", err
}
}
// time
order_by_now := false
if v := utime_req.StartUtime; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_utime >= %d", *v))
order_by_now = true
}
if v := utime_req.EndUtime; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_utime <= %d", *v))
order_by_now = true
}
if v := lt_req.StartLt; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_lt >= %d", *v))
}
if v := lt_req.EndLt; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_lt <= %d", *v))
}
if v := act_req.AccountAddress; v != nil && len(*v) > 0 {
filter_str := fmt.Sprintf("T.account = '%s'", *v)
filter_list = append(filter_list, filter_str)

from_query = `actions as A join traces as E on E.trace_id = A.trace_id join transactions as T on E.trace_id = T.trace_id and A.tx_hashes @> array[T.hash::tonhash]`
if order_by_now {
clmn_query = `distinct on (E.end_utime, E.trace_id, A.end_utime, A.action_id) ` + clmn_query_default
} else {
clmn_query = `distinct on (E.end_lt, E.trace_id, A.end_lt, A.action_id) ` + clmn_query_default
}
}
if v := act_req.TransactionHash; v != nil {
filter_str := filterByArray("T.hash", v)
if len(filter_str) > 0 {
filter_list = append(filter_list, filter_str)
}
from_query = `actions as A join traces as E on E.trace_id = A.trace_id join transactions as T on E.trace_id = T.trace_id and A.tx_hashes @> array[T.hash::tonhash]`
if order_by_now {
clmn_query = `distinct on (E.end_utime, E.trace_id, A.end_utime, A.action_id) ` + clmn_query_default
} else {
clmn_query = `distinct on (E.end_lt, E.trace_id, A.end_lt, A.action_id) ` + clmn_query_default
}
}
if v := act_req.MessageHash; v != nil {
filter_str := filterByArray("M.msg_hash", v)
if len(filter_str) > 0 {
filter_list = append(filter_list, filter_str)
}
from_query = `actions as A join messages as M on A.trace_id = M.trace_id and array[M.tx_hash::tonhash] @> A.tx_hashes`
from_query = `actions as A join traces as E on E.trace_id = A.trace_id join messages as M on E.trace_id = T.trace_id and A.tx_hashes @> array[T.hash::tonhash]`
if order_by_now {
clmn_query = `distinct on (E.end_utime, E.trace_id, A.end_utime, A.action_id) ` + clmn_query_default
} else {
clmn_query = `distinct on (E.end_lt, E.trace_id, A.end_lt, A.action_id) ` + clmn_query_default
}
}
if v := act_req.McSeqno; v != nil {
filter_list = append(filter_list, `E.state = 'complete'`)
filter_list = append(filter_list, fmt.Sprintf("E.mc_seqno_end = %d", *v))
from_query = `actions as A join traces as E on A.trace_id = E.trace_id`
clmn_query = clmn_query_default
}
if v := act_req.ActionId; v != nil {
filter_str := filterByArray("A.action_id", v)
if len(filter_str) > 0 {
filter_list = append(filter_list, filter_str)
filter_list = []string{filter_str}
}
from_query = `actions as A`
clmn_query = clmn_query_default
}
if v := act_req.TraceId; v != nil {
filter_str := filterByArray("A.trace_id", v)
if len(filter_str) > 0 {
filter_list = append(filter_list, filter_str)
filter_list = []string{filter_str}
}
}

if order_by_now {
orderby_query = fmt.Sprintf(" order by E.end_utime %s, E.trace_id %s, A.end_utime %s, A.action_id %s", sort_order, sort_order, sort_order, sort_order)
} else {
orderby_query = fmt.Sprintf(" order by E.end_lt %s, E.trace_id %s, A.end_lt %s, A.action_id %s", sort_order, sort_order, sort_order, sort_order)
}

// build query
if len(filter_list) > 0 {
filter_query = ` where ` + strings.Join(filter_list, " and ")
@@ -823,28 +897,65 @@ func buildEventsQuery(event_req EventRequest, utime_req UtimeRequest, lt_req LtR
}
}

// time
order_by_now := false
if v := utime_req.StartUtime; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_utime >= %d", *v))
order_by_now = true
}
if v := utime_req.EndUtime; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_utime <= %d", *v))
order_by_now = true
}
if v := lt_req.StartLt; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_lt >= %d", *v))
}
if v := lt_req.EndLt; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_lt <= %d", *v))
}

if order_by_now {
orderby_query = fmt.Sprintf(" order by E.end_utime %s, E.trace_id %s", sort_order, sort_order)
} else {
orderby_query = fmt.Sprintf(" order by E.end_lt %s, E.trace_id %s", sort_order, sort_order)
}

if v := event_req.AccountAddress; v != nil && len(*v) > 0 {
filter_str := fmt.Sprintf("T.account = '%s'", *v)
filter_list = append(filter_list, filter_str)

from_query = `traces as E join transactions as T on E.trace_id = T.trace_id`
clmn_query = `distinct on (E.end_lt, E.trace_id) ` + clmn_query_default
if order_by_now {
clmn_query = `distinct on (E.end_utime, E.trace_id) ` + clmn_query_default
} else {
clmn_query = `distinct on (E.end_lt, E.trace_id) ` + clmn_query_default
}
}
if v := event_req.TransactionHash; v != nil {
filter_str := filterByArray("T.hash", v)
if len(filter_str) > 0 {
filter_list = append(filter_list, filter_str)
}
from_query = `traces as E join transactions as T on E.trace_id = T.trace_id`
clmn_query = `distinct on (E.end_lt, E.trace_id) ` + clmn_query_default

if order_by_now {
clmn_query = `distinct on (E.end_utime, E.trace_id) ` + clmn_query_default
} else {
clmn_query = `distinct on (E.end_lt, E.trace_id) ` + clmn_query_default
}
}
if v := event_req.MessageHash; v != nil {
filter_str := filterByArray("M.msg_hash", v)
if len(filter_str) > 0 {
filter_list = append(filter_list, filter_str)
}
from_query = `traces as E join messages as M on E.trace_id = M.trace_id`
clmn_query = `distinct on (E.end_lt, E.trace_id) ` + clmn_query_default

if order_by_now {
clmn_query = `distinct on (E.end_utime, E.trace_id) ` + clmn_query_default
} else {
clmn_query = `distinct on (E.end_lt, E.trace_id) ` + clmn_query_default
}
}

if v := event_req.TraceId; v != nil {
@@ -858,29 +969,6 @@ func buildEventsQuery(event_req EventRequest, utime_req UtimeRequest, lt_req LtR
filter_list = append(filter_list, fmt.Sprintf("E.mc_seqno_end = %d", *v))
}

// time
order_by_now := false
if v := utime_req.StartUtime; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_utime >= %d", *v))
order_by_now = true
}
if v := utime_req.EndUtime; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_utime <= %d", *v))
order_by_now = true
}
if v := lt_req.StartLt; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_lt >= %d", *v))
}
if v := lt_req.EndLt; v != nil {
filter_list = append(filter_list, fmt.Sprintf("E.end_lt <= %d", *v))
}

if order_by_now {
orderby_query = fmt.Sprintf(" order by E.end_utime %s, E.trace_id asc", sort_order)
} else {
orderby_query = fmt.Sprintf(" order by E.end_lt %s, E.trace_id asc", sort_order)
}

// build query
if len(filter_list) > 0 {
filter_query = ` where ` + strings.Join(filter_list, " and ")
@@ -1973,6 +2061,9 @@ func (db *DbClient) QueryTransactions(
}

book := AddressBook{}
if settings.NoAddressBook {
return txs, book, nil
}
addr_list := []string{}
for _, t := range txs {
addr_list = append(addr_list, string(t.Account))
@@ -2026,6 +2117,9 @@ func (db *DbClient) QueryAdjacentTransactions(
}

book := AddressBook{}
if settings.NoAddressBook {
return txs, book, nil
}
addr_list := []string{}
for _, t := range txs {
addr_list = append(addr_list, string(t.Account))
@@ -2077,6 +2171,9 @@ func (db *DbClient) QueryMessages(
}

book := AddressBook{}
if settings.NoAddressBook {
return msgs, book, nil
}
addr_list := []string{}
for _, m := range msgs {
if m.Source != nil {
@@ -2121,6 +2218,9 @@ func (db *DbClient) QueryNFTCollections(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
addr_list = append(addr_list, string(t.Address))
@@ -2163,6 +2263,9 @@ func (db *DbClient) QueryNFTItems(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
addr_list = append(addr_list, string(t.Address))
@@ -2207,6 +2310,9 @@ func (db *DbClient) QueryNFTTransfers(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
addr_list = append(addr_list, string(t.NftItemAddress))
@@ -2252,6 +2358,9 @@ func (db *DbClient) QueryJettonMasters(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
addr_list = append(addr_list, string(t.Address))
@@ -2295,6 +2404,9 @@ func (db *DbClient) QueryJettonWallets(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
addr_list = append(addr_list, string(t.Address))
@@ -2338,6 +2450,9 @@ func (db *DbClient) QueryJettonTransfers(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
addr_list = append(addr_list, string(t.Source))
@@ -2385,6 +2500,9 @@ func (db *DbClient) QueryJettonBurns(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
addr_list = append(addr_list, string(t.Owner))
@@ -2429,6 +2547,9 @@ func (db *DbClient) QueryAccountStates(
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
addr_list := []string{}
for _, t := range res {
if t.AccountAddress != nil {
@@ -2488,10 +2609,12 @@ func (db *DbClient) QueryTopAccountBalances(lim_req LimitRequest, settings Reque
// events
func (db *DbClient) QueryActions(
act_req ActionRequest,
utime_req UtimeRequest,
lt_req LtRequest,
lim_req LimitRequest,
settings RequestSettings,
) ([]Action, AddressBook, error) {
query, err := buildActionsQuery(act_req, lim_req, settings)
query, err := buildActionsQuery(act_req, utime_req, lt_req, lim_req, settings)
if settings.DebugRequest {
log.Println("Debug query:", query)
}
@@ -2506,6 +2629,17 @@ func (db *DbClient) QueryActions(
}
defer conn.Release()

// check block
if seqno := act_req.McSeqno; seqno != nil {
exists, err := queryBlockExists(*seqno, conn, settings)
if err != nil {
return nil, nil, err
}
if !exists {
return nil, nil, IndexError{Code: 404, Message: fmt.Sprintf("masterchain block %d not found", *seqno)}
}
}

raw_actions, err := queryRawActionsImpl(query, conn, settings)
if err != nil {
return nil, nil, IndexError{Code: 500, Message: err.Error()}
@@ -2521,7 +2655,7 @@ func (db *DbClient) QueryActions(
}
actions = append(actions, *action)
}
if len(addr_map) > 0 {
if len(addr_map) > 0 && !settings.NoAddressBook {
addr_list := []string{}
for k := range addr_map {
addr_list = append(addr_list, string(k))
@@ -2557,13 +2691,27 @@ func (db *DbClient) QueryEvents(
}
defer conn.Release()

// check block
if seqno := event_req.McSeqno; seqno != nil {
exists, err := queryBlockExists(*seqno, conn, settings)
if err != nil {
return nil, nil, err
}
if !exists {
return nil, nil, IndexError{Code: 404, Message: fmt.Sprintf("masterchain block %d not found", *seqno)}
}
}

res, addr_list, err := queryEventsImpl(query, conn, settings)
if err != nil {
log.Println(query)
return nil, nil, IndexError{Code: 500, Message: err.Error()}
}

book := AddressBook{}
if settings.NoAddressBook {
return res, book, nil
}
if len(addr_list) > 0 {
book, err = queryAddressBookImpl(addr_list, conn, settings)
if err != nil {
2 changes: 1 addition & 1 deletion index/models.go
Original file line number Diff line number Diff line change
@@ -586,7 +586,7 @@ type Action struct {
Success *bool `json:"success"`
Type string `json:"type"`
Details interface{} `json:"details"`
RawAction *RawAction `json:"raw_action,omitempty"`
RawAction *RawAction `json:"raw_action,omitempty" swaggerignore:"true"`
} // @name Action

type EventMeta struct {
9 changes: 7 additions & 2 deletions index/request.go
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ type RequestSettings struct {
MaxLimit int
MaxEventTransactions int
DebugRequest bool
NoAddressBook bool
}

// requests
@@ -112,8 +113,12 @@ type AccountRequest struct {
}

type ActionRequest struct {
ActionId []HashType `query:"action_id"`
TraceId []HashType `query:"trace_id"`
AccountAddress *AccountAddress `query:"account"`
TransactionHash []HashType `query:"tx_hash"`
MessageHash []HashType `query:"msg_hash"`
TraceId []HashType `query:"trace_id"`
ActionId []HashType `query:"action_id"`
McSeqno *int32 `query:"mc_seqno"`
}

type EventRequest struct {
45 changes: 39 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
@@ -169,16 +169,23 @@ func GetShards(c *fiber.Ctx) error {
// @success 200 {object} index.TransactionsResponse
// @failure 400 {object} index.RequestError
// @param seqno query int32 true "Masterchain block seqno."
// @param limit query int32 false "Limit number of queried rows. Use with *offset* to batch read." minimum(1) maximum(1000) default(10)
// @param offset query int32 false "Skip first N rows. Use with *limit* to batch read." minimum(0) default(0)
// @router /api/v3/masterchainBlockShards [get]
// @security APIKeyHeader
// @security APIKeyQuery
func GetShardsDiff(c *fiber.Ctx) error {
request_settings := GetRequestSettings(c, &settings)
seqno := c.QueryInt("seqno")
blk_req := index.BlockRequest{}
lim_req := index.LimitRequest{}
blk_req.McSeqno = new(int32)
*blk_req.McSeqno = int32(seqno)
blks, err := pool.QueryBlocks(blk_req, index.UtimeRequest{}, index.LtRequest{}, index.LimitRequest{}, request_settings)
if err := c.QueryParser(&lim_req); err != nil {
return index.IndexError{Code: 422, Message: err.Error()}
}

blks, err := pool.QueryBlocks(blk_req, index.UtimeRequest{}, index.LtRequest{}, lim_req, request_settings)
if err != nil {
return err
}
@@ -960,7 +967,7 @@ func GetJettonBurns(c *fiber.Ctx) error {
// @param account query string false "List of account addresses to get transactions. Can be sent in hex, base64 or base64url form."
// @param tx_hash query []string false "Find event by transaction hash."
// @param msg_hash query []string false "Find event by message hash."
// @param mc_seqno query int32 false "Masterchain block seqno"
// @param mc_seqno query int32 false "Query events that was completed in masterchain block with given seqno"
// @param start_utime query int32 false "Query events, which was finished **after** given timestamp." minimum(0)
// @param end_utime query int32 false "Query events, which was finished **before** given timestamp." minimum(0)
// @param start_lt query int64 false "Query events with `end_lt >= start_lt`." minimum(0)
@@ -1015,25 +1022,46 @@ func GetEvents(c *fiber.Ctx) error {
// @Produce json
// @success 200 {object} index.ActionsResponse
// @failure 400 {object} index.RequestError
// @param account query string false "List of account addresses to get actions. Can be sent in hex, base64 or base64url form."
// @param tx_hash query []string false "Find actions by transaction hash."
// @param msg_hash query []string false "Find actions by message hash."
// @param action_id query []string false "Find actions by the action_id." collectionFormat(multi)
// @param trace_id query []string false "Find actions by the trace_id." collectionFormat(multi)
// @param mc_seqno query int32 false "Query actions of events which was completed in masterchain block with given seqno"
// @param start_utime query int32 false "Query actions for events, which was finished **after** given timestamp." minimum(0)
// @param end_utime query int32 false "Query actions for events, which was finished **before** given timestamp." minimum(0)
// @param start_lt query int64 false "Query actions for events with `end_lt >= start_lt`." minimum(0)
// @param end_lt query int64 false "Query actions for events with `end_lt <= end_lt`." minimum(0)
// @param limit query int32 false "Limit number of queried rows. Use with *offset* to batch read." minimum(1) maximum(1000) default(10)
// @param offset query int32 false "Skip first N rows. Use with *limit* to batch read." minimum(0) default(0)
// @param sort query string false "Sort actions by lt." Enums(asc, desc) default(desc)
// @router /api/v3/actions [get]
// @security APIKeyHeader
// @security APIKeyQuery
func GetActions(c *fiber.Ctx) error {
request_settings := GetRequestSettings(c, &settings)
var act_req index.ActionRequest
var lim_req index.LimitRequest
act_req := index.ActionRequest{}
lim_req := index.LimitRequest{}
utime_req := index.UtimeRequest{}
lt_req := index.LtRequest{}

if err := c.QueryParser(&act_req); err != nil {
return index.IndexError{Code: 422, Message: err.Error()}
}

if err := c.QueryParser(&lim_req); err != nil {
return index.IndexError{Code: 422, Message: err.Error()}
}
if err := c.QueryParser(&utime_req); err != nil {
return index.IndexError{Code: 422, Message: err.Error()}
}
if err := c.QueryParser(&lt_req); err != nil {
return index.IndexError{Code: 422, Message: err.Error()}
}
if err := c.QueryParser(&lim_req); err != nil {
return index.IndexError{Code: 422, Message: err.Error()}
}

res, book, err := pool.QueryActions(act_req, lim_req, request_settings)
res, book, err := pool.QueryActions(act_req, utime_req, lt_req, lim_req, request_settings)
if err != nil {
return err
}
@@ -1342,6 +1370,11 @@ func GetRequestSettings(c *fiber.Ctx, settings *Settings) index.RequestSettings
request_settings.Timeout = time.Duration(value) * time.Millisecond
}
}
if value_str, ok := ExtractParam(c, "X-No-Address-Book", "x_no_address_book"); ok {
if value, err := strconv.ParseBool(value_str); err == nil {
request_settings.NoAddressBook = value
}
}
return request_settings
}