From eb76db31ec22182e897c5745d5f7d3d0fb9d0714 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 18 Jun 2025 12:04:19 +0000 Subject: [PATCH 01/24] Enable configurable directory for HAF app location in setup_postgres.sh script --- scripts/setup_postgres.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/setup_postgres.sh b/scripts/setup_postgres.sh index 1a626ded8..c570be316 100755 --- a/scripts/setup_postgres.sh +++ b/scripts/setup_postgres.sh @@ -21,6 +21,7 @@ print_help () { echo " --host=VALUE Allows to specify a PostgreSQL host location (defaults to /var/run/postgresql)" echo " --port=NUMBER Allows to specify a PostgreSQL operating port (defaults to 5432)" echo " --postgres-url=URL Allows to specify a PostgreSQL URL (in opposite to separate --host and --port options)" + echo " --path-to-haf=PATH Allows to specify a path to HAF installation (defaults to the parent directory of this script)" echo " --help Display this help screen and exit" echo } @@ -35,6 +36,7 @@ supplement_builtin_roles() { POSTGRES_HOST="/var/run/postgresql" POSTGRES_PORT=5432 POSTGRES_URL="" +HAF_PATH="$SCRIPTPATH/../haf" while [ $# -gt 0 ]; do case "$1" in @@ -47,6 +49,9 @@ while [ $# -gt 0 ]; do --postgres-url=*) POSTGRES_URL="${1#*=}" ;; + --path-to-haf=*) + HAF_PATH="${1#*=}" + ;; --help) print_help exit 0 @@ -73,7 +78,7 @@ else POSTGRES_ACCESS=$POSTGRES_URL fi -"$SCRIPTPATH/../haf/scripts/create_haf_app_role.sh" --postgres-url="$POSTGRES_ACCESS" --haf-app-account="hafah_owner" -"$SCRIPTPATH/../haf/scripts/create_haf_app_role.sh" --postgres-url="$POSTGRES_ACCESS" --haf-app-account="hafah_user" +"$HAF_PATH/scripts/create_haf_app_role.sh" --postgres-url="$POSTGRES_ACCESS" --haf-app-account="hafah_owner" +"$HAF_PATH/scripts/create_haf_app_role.sh" --postgres-url="$POSTGRES_ACCESS" --haf-app-account="hafah_user" supplement_builtin_roles "$POSTGRES_ACCESS" -- GitLab From d44790597e3c6d36ec3d1beda44458ee4a3f29d0 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 16 Jul 2025 21:43:36 +0000 Subject: [PATCH 02/24] Remove obsolite backend function --- .../account_history/account_history.sql | 193 ------------------ 1 file changed, 193 deletions(-) diff --git a/queries/hafah_rest_backend/account_history/account_history.sql b/queries/hafah_rest_backend/account_history/account_history.sql index 327d26b90..cfdac08c9 100644 --- a/queries/hafah_rest_backend/account_history/account_history.sql +++ b/queries/hafah_rest_backend/account_history/account_history.sql @@ -1,198 +1,5 @@ SET ROLE hafah_owner; -CREATE OR REPLACE FUNCTION hafah_python.get_account_history_json( - IN _filter_low NUMERIC, - IN _filter_high NUMERIC, - IN _account VARCHAR, - IN _start BIGINT, - IN _limit BIGINT, - IN _include_reversible BOOLEAN, - IN _is_legacy_style BOOLEAN ) -RETURNS JSONB -AS -$function$ -BEGIN - RETURN jsonb_agg( - json_build_array( - ops.operation_seq_num, - ( - CASE - WHEN _is_legacy_style THEN to_jsonb(ops) - 'operation_id' - 'operation_seq_num' - ELSE to_jsonb(ops) - 'operation_seq_num' - END - ) - ) - ) - FROM ( - SELECT - _block AS "block", - _value::JSON AS "op", - _op_in_trx AS "op_in_trx", - _timestamp AS "timestamp", - _trx_id AS "trx_id", - _trx_in_block AS "trx_in_block", - _virtual_op AS "virtual_op", - _operation_id::TEXT AS "operation_id", - _operation_seq_number AS "operation_seq_num" - FROM - hafah_python.get_account_history( - hafah_python.numeric_to_bigint(_filter_low), - hafah_python.numeric_to_bigint(_filter_high), - _account, - _start, - _limit, - _include_reversible, - _is_legacy_style - ) - ) ops; -END -$function$ -language plpgsql STABLE; - -CREATE OR REPLACE FUNCTION hafah_python.get_account_history( - IN _filter_low BIGINT, - IN _filter_high BIGINT, - IN _account VARCHAR, - IN _start BIGINT, - IN _limit BIGINT, - IN _include_reversible BOOLEAN, - IN _is_legacy_style BOOLEAN -) -RETURNS TABLE( - _trx_id TEXT, - _block INT, - _trx_in_block BIGINT, - _op_in_trx BIGINT, - _virtual_op BOOLEAN, - _timestamp TEXT, - _value TEXT, - _operation_id BIGINT, - _operation_seq_number INT -) -AS -$function$ -DECLARE - __resolved_filter SMALLINT[]; - __account_id INT; - __upper_block_limit INT; - __use_filter INT; -BEGIN - - PERFORM hafah_python.validate_limit( _limit, 1000 ); - PERFORM hafah_python.validate_start_limit( _start, _limit ); - - IF (NOT (_filter_low IS NULL AND _filter_high IS NULL)) AND COALESCE(_filter_low, 0) + COALESCE(_filter_high, 0) = 0 THEN - RETURN QUERY SELECT - NULL :: TEXT, - NULL :: INT, - NULL :: BIGINT, - NULL :: BIGINT, - NULL :: BOOLEAN, - NULL :: TEXT, - NULL :: TEXT, - NULL :: BIGINT, - NULL :: INT - LIMIT 0; - RETURN; - END IF; - - SELECT hafah_python.translate_get_account_history_filter(_filter_low, _filter_high) INTO __resolved_filter; - - IF _include_reversible THEN - SELECT num from hive.blocks_view order by num desc limit 1 INTO __upper_block_limit; - ELSE - SELECT hive.app_get_irreversible_block() INTO __upper_block_limit; - END IF; - - - IF _include_reversible THEN - SELECT INTO __account_id ( select id from hive.accounts_view where name = _account ); - ELSE - SELECT INTO __account_id ( select id from hafd.accounts where name = _account ); - END IF; - - __use_filter := array_length( __resolved_filter, 1 ); - - RETURN QUERY - WITH pre_result AS - ( - SELECT -- hafah_python.ah_get_account_history - ( - CASE - WHEN ho.trx_in_block < 0 THEN '0000000000000000000000000000000000000000' - ELSE encode( (SELECT htv.trx_hash FROM hive.transactions_view htv WHERE ho.trx_in_block >= 0 AND ds.block_num = htv.block_num AND ho.trx_in_block = htv.trx_in_block), 'hex') - END - ) AS _trx_id, - ds.block_num AS _block, - ( - CASE - WHEN ho.trx_in_block < 0 THEN 4294967295 - ELSE ho.trx_in_block - END - ) AS _trx_in_block, - ho.op_pos::BIGINT AS _op_in_trx, - hot.is_virtual AS virtual_op, - ( - CASE - WHEN _is_legacy_style THEN hive.get_legacy_style_operation(ho.body_binary)::TEXT - ELSE ho.body :: text - END - ) AS _value, - ds.operation_id AS _operation_id, - ds.account_op_seq_no AS _operation_seq_number - FROM - ( - WITH accepted_types AS MATERIALIZED - ( - SELECT ot.id FROM hafd.operation_types ot WHERE __use_filter IS NOT NULL AND ot.id=ANY(__resolved_filter) - ) - (SELECT hao.operation_id, hao.op_type_id,hao.block_num, hao.account_op_seq_no - FROM hive.account_operations_view hao - JOIN accepted_types t ON hao.op_type_id = t.id - WHERE __use_filter IS NOT NULL AND hao.account_id = __account_id AND hao.account_op_seq_no <= _start AND hao.block_num <= __upper_block_limit - ORDER BY hao.account_op_seq_no DESC - LIMIT _limit - ) - UNION ALL - (SELECT hao.operation_id, hao.op_type_id,hao.block_num, hao.account_op_seq_no - FROM hive.account_operations_view hao - WHERE __use_filter IS NULL AND hao.account_id = __account_id AND hao.account_op_seq_no <= _start AND hao.block_num <= __upper_block_limit - ORDER BY hao.account_op_seq_no DESC - LIMIT _limit - ) - - ) ds - JOIN LATERAL (SELECT hov.body, hov.body_binary, hov.op_pos, hov.trx_in_block FROM hive.operations_view hov WHERE ds.operation_id = hov.id) ho ON TRUE - JOIN LATERAL (select ot.is_virtual FROM hafd.operation_types ot WHERE ds.op_type_id = ot.id) hot on true - ORDER BY ds.account_op_seq_no ASC - - ) - SELECT -- hafah_python.ah_get_account_history - pre_result._trx_id, - pre_result._block, - pre_result._trx_in_block, - pre_result._op_in_trx, - pre_result.virtual_op, - btrim(to_json(hb.created_at)::TEXT, '"'::TEXT) AS formated_timestamp, - pre_result._value, - pre_result._operation_id, - pre_result._operation_seq_number - FROM - pre_result - JOIN hive.blocks_view hb ON hb.num = pre_result._block - ORDER BY pre_result._operation_seq_number ASC; - -END -$function$ -LANGUAGE plpgsql STABLE -SET JIT=OFF -SET join_collapse_limit=16 -SET from_collapse_limit=16 -SET plan_cache_mode=force_generic_plan -; - - - CREATE OR REPLACE FUNCTION hafah_backend.get_ops_by_account( _account_id INT, _operations INT [], -- GitLab From 868e08ed6f8918fb24f39e68d33bdb8e799e5de0 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 16 Jul 2025 22:07:15 +0000 Subject: [PATCH 03/24] Add block_range object to account_history API --- .../accounts/get_ops_by_account.sql | 8 +++- postgrest/hafah_REST/types/operation.sql | 45 +++++++++++++++++++ .../positive/blocktrades_first_page.pat.json | 4 ++ .../positive/blocktrades_last_page.pat.json | 4 ++ .../positive/filter_by_op.pat.json | 4 ++ .../positive/filter_by_range.pat.json | 4 ++ 6 files changed, 67 insertions(+), 2 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index 5c6ebb595..b31369814 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -98,14 +98,18 @@ SET ROLE hafah_owner; Result contains total number of operations, total pages, and the list of operations. - * Returns `hafah_backend.operation_history` + * Returns `hafah_backend.account_operation_history` content: application/json: schema: - $ref: '#/components/schemas/hafah_backend.operation_history' + $ref: '#/components/schemas/hafah_backend.account_operation_history' example: { "total_operations": 219867, "total_pages": 73289, + "block_range": { + "from": 1, + "to": 5000000 + }, "operations_result": [ { "op": { diff --git a/postgrest/hafah_REST/types/operation.sql b/postgrest/hafah_REST/types/operation.sql index 26eb85309..8a876d67a 100644 --- a/postgrest/hafah_REST/types/operation.sql +++ b/postgrest/hafah_REST/types/operation.sql @@ -1,5 +1,22 @@ SET ROLE hafah_owner; +/** openapi:components:schemas +hafah_backend.block_range_type: + type: object + properties: + from: + type: integer + to: + type: integer + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.block_range_type CASCADE; +CREATE TYPE hafah_backend.block_range_type AS ( + "from" INT, + "to" INT +); +-- openapi-generated-code-end + /** openapi:components:schemas hafah_backend.operation_body: type: object @@ -97,6 +114,34 @@ CREATE TYPE hafah_backend.operation_history AS ( ); -- openapi-generated-code-end +/** openapi:components:schemas +hafah_backend.account_operation_history: + type: object + properties: + total_operations: + type: integer + description: Total number of operations + total_pages: + type: integer + description: Total number of pages + block_range: + $ref: '#/components/schemas/hafah_backend.block_range_type' + description: Range of blocks that contains the returned pages + operations_result: + type: array + items: + $ref: '#/components/schemas/hafah_backend.operation' + description: List of operation results + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.account_operation_history CASCADE; +CREATE TYPE hafah_backend.account_operation_history AS ( + "total_operations" INT, + "total_pages" INT, + "block_range" hafah_backend.block_range_type, + "operations_result" hafah_backend.operation[] +); +-- openapi-generated-code-end /** openapi:components:schemas hafah_backend.operations_in_block_range: type: object diff --git a/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.pat.json b/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.pat.json index 7d011f370..63896fecc 100644 --- a/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.pat.json +++ b/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.pat.json @@ -1,6 +1,10 @@ { "total_operations": 219867, "total_pages": 10994, + "block_range": { + "from": 1, + "to": 5000000 + }, "operations_result": [ { "op": { diff --git a/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.pat.json b/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.pat.json index f90f0404c..0daef3cf7 100644 --- a/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.pat.json +++ b/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.pat.json @@ -1,6 +1,10 @@ { "total_operations": 219867, "total_pages": 10994, + "block_range": { + "from": 1, + "to": 5000000 + }, "operations_result": [ { "op": { diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_op.pat.json b/tests/tavern/get_ops_by_account/positive/filter_by_op.pat.json index ce745ec50..3bc8043b0 100644 --- a/tests/tavern/get_ops_by_account/positive/filter_by_op.pat.json +++ b/tests/tavern/get_ops_by_account/positive/filter_by_op.pat.json @@ -1,6 +1,10 @@ { "total_operations": 7947, "total_pages": 398, + "block_range": { + "from": 1, + "to": 5000000 + }, "operations_result": [ { "op": { diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_range.pat.json b/tests/tavern/get_ops_by_account/positive/filter_by_range.pat.json index e1864a764..330199297 100644 --- a/tests/tavern/get_ops_by_account/positive/filter_by_range.pat.json +++ b/tests/tavern/get_ops_by_account/positive/filter_by_range.pat.json @@ -1,6 +1,10 @@ { "total_operations": 158805, "total_pages": 7941, + "block_range": { + "from": 1, + "to": 4000000 + }, "operations_result": [ { "op": { -- GitLab From 85c268181d1cf1bda8c0ac33716f5cccff825955 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 16 Jul 2025 22:08:35 +0000 Subject: [PATCH 04/24] Add filtering parameter transacting-account-name to account_history API --- .../accounts/get_ops_by_account.sql | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index b31369814..af3b8e179 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -23,6 +23,14 @@ SET ROLE hafah_owner; schema: type: string description: Account to get operations for. + - in: query + name: transacting-account-name + required: false + schema: + type: string + default: NULL + description: | + Account to filter operations by, if provided only operations where the account is an author will be returned. - in: query name: operation-types required: false @@ -185,6 +193,7 @@ SET ROLE hafah_owner; DROP FUNCTION IF EXISTS hafah_endpoints.get_ops_by_account; CREATE OR REPLACE FUNCTION hafah_endpoints.get_ops_by_account( "account-name" TEXT, + "transacting-account-name" TEXT = NULL, "operation-types" TEXT = NULL, "page" INT = NULL, "page-size" INT = 100, @@ -192,7 +201,7 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_ops_by_account( "from-block" TEXT = NULL, "to-block" TEXT = NULL ) -RETURNS hafah_backend.operation_history +RETURNS hafah_backend.account_operation_history -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE SET JIT = OFF @@ -204,20 +213,18 @@ $$ DECLARE _block_range hive.blocks_range := hive.convert_to_blocks_range("from-block","to-block"); _account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); - _ops_count INT; - _from INT; - _to INT; + _transacting_account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "transacting-account-name"); _operation_types INT[] := (SELECT string_to_array("operation-types", ',')::INT[]); - _result hafah_backend.operation[]; - - __total_pages INT; - __offset INT; - __limit INT; BEGIN + -- Validate inputs IF _account_id IS NULL THEN PERFORM hafah_backend.rest_raise_missing_account("account-name"); END IF; + IF "transacting-account-name" IS NOT NULL AND _transacting_account_id IS NULL THEN + PERFORM hafah_backend.rest_raise_missing_account("transacting-account-name"); + END IF; + PERFORM hafah_python.validate_limit("page-size", 1000, 'page-size'); PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); PERFORM hafah_python.validate_negative_page("page"); -- GitLab From baca2ddb9620c1660743f556b8e4cdaed41c7f97 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 16 Jul 2025 22:09:47 +0000 Subject: [PATCH 05/24] Refactor and rewrite account_history API for new transacting_account_ids filtering method --- .../accounts/get_ops_by_account.sql | 49 ++----- .../account_history/account_history.sql | 85 +++++++---- .../account_history/by_operations.sql | 132 +++++++++++------- .../account_history/count.sql | 13 +- .../account_history/default.sql | 129 +++++++++++------ .../account_history/paging.sql | 30 +++- scripts/install_app.sh | 2 +- 7 files changed, 275 insertions(+), 165 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index af3b8e179..3fc1ef2f4 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -229,48 +229,23 @@ BEGIN PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); PERFORM hafah_python.validate_negative_page("page"); - -----------PAGING LOGIC---------------- - SELECT count, from_seq, to_seq - INTO _ops_count, _from, _to - FROM hafah_backend.account_range(_operation_types, _account_id, _block_range.first_block, _block_range.last_block); - - SELECT total_pages, offset_filter, limit_filter - INTO __total_pages, __offset, __limit - FROM hafah_backend.calculate_pages(_ops_count, "page", 'desc', "page-size"); - - IF (_block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL) OR ("page" IS NOT NULL AND __total_pages != "page") THEN + IF (_block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL) THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); ELSE PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); END IF; - _result := array_agg(row ORDER BY row.operation_id::BIGINT DESC) FROM ( - SELECT - ba.op, - ba.block, - ba.trx_id, - ba.op_pos, - ba.op_type_id, - ba.timestamp, - ba.virtual_op, - ba.operation_id, - ba.trx_in_block - FROM hafah_backend.get_ops_by_account( - _account_id, - _operation_types, - _from, - _to, - "data-size-limit", - __offset, - __limit - ) ba - ) row; - - RETURN ( - COALESCE(_ops_count,0), - COALESCE(__total_pages,0), - COALESCE(_result, '{}'::hafah_backend.operation[]) - )::hafah_backend.operation_history; + RETURN hafah_backend.get_ops_by_account( + _account_id, + ARRAY[_transacting_account_id], + _operation_types, + _block_range.first_block, + _block_range.last_block, + "page", + "data-size-limit", + "page-size", + TRUE -- incluede account - flag determines if the transacting account's operations are included or excluded +); -- ops_count returns number of operations found with current filter -- to count total_pages we need to check if there was a rest from division by "page-size", if there was the page count is +1 diff --git a/queries/hafah_rest_backend/account_history/account_history.sql b/queries/hafah_rest_backend/account_history/account_history.sql index cfdac08c9..0a7a19bad 100644 --- a/queries/hafah_rest_backend/account_history/account_history.sql +++ b/queries/hafah_rest_backend/account_history/account_history.sql @@ -2,41 +2,78 @@ SET ROLE hafah_owner; CREATE OR REPLACE FUNCTION hafah_backend.get_ops_by_account( _account_id INT, + _filter_account_ids INT [], _operations INT [], - _from INT, - _to INT, + _from_block INT, + _to_block INT, + _page INT, _body_limit INT, - _offset INT, - _limit INT + _limit INT, + _include_accounts BOOLEAN DEFAULT TRUE ) -RETURNS SETOF hafah_backend.operation -- noqa: LT01, CP05 +RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 LANGUAGE 'plpgsql' STABLE AS $$ +DECLARE + _result hafah_backend.account_operation_history; + + -- flags + _filter_by_op BOOLEAN:= (_operations IS NOT NULL); + _filter_by_account BOOLEAN := (_filter_account_ids != ARRAY[NULL]::INT[]); BEGIN - IF _operations IS NULL THEN - RETURN QUERY - SELECT * FROM hafah_backend.account_history_default( + CASE + -- If no filters are applied, use the default account history function + WHEN (NOT _filter_by_account) AND (NOT _filter_by_op) THEN + _result := hafah_backend.account_history_default( + _account_id, + _from_block, + _to_block, + _page, + _body_limit, + _limit + ); + + -- If only operations are filtered, use the account history by operations function + WHEN (NOT _filter_by_account) AND (_filter_by_op) THEN + _result := hafah_backend.account_history_by_operations( _account_id, - _from, - _to, + _operations, + _from_block, + _to_block, + _page, _body_limit, - _offset, _limit - ); - END IF; - - RETURN QUERY - SELECT * FROM hafah_backend.account_history_by_operations( - _account_id, - _operations, - _from, - _to, - _body_limit, - _offset, - _limit - ); + ); + -- If accounts are filtered, use the account history by accounts function (including accounts) + WHEN (_filter_by_account) AND (_include_accounts) THEN + _result := hafah_backend.account_history_including_accounts( + _account_id, + _operations, + _filter_account_ids[1], + _from_block, + _to_block, + _page, + _body_limit, + _limit + ); + -- If accounts are filtered, use the account history by accounts function (excluding accounts) + WHEN (_filter_by_account) AND (NOT _include_accounts) THEN + _result := hafah_backend.account_history_excluding_accounts( + _account_id, + _operations, + _filter_account_ids, + _from_block, + _to_block, + _page, + _body_limit, + _limit + ); + ELSE + RAISE EXCEPTION 'Invalid parameters'; + END CASE; + RETURN _result; END $$; diff --git a/queries/hafah_rest_backend/account_history/by_operations.sql b/queries/hafah_rest_backend/account_history/by_operations.sql index 7453f9835..f6f496854 100644 --- a/queries/hafah_rest_backend/account_history/by_operations.sql +++ b/queries/hafah_rest_backend/account_history/by_operations.sql @@ -3,13 +3,13 @@ SET ROLE hafah_owner; CREATE OR REPLACE FUNCTION hafah_backend.account_history_by_operations( _account_id INT, _operations INT [], - _from INT, - _to INT, + _from_block INT, + _to_block INT, + _page INT, _body_limit INT, - _offset INT, _limit INT ) -RETURNS SETOF hafah_backend.operation -- noqa: LT01, CP05 +RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 LANGUAGE 'plpgsql' STABLE COST 10000 SET JIT = OFF @@ -17,50 +17,88 @@ SET join_collapse_limit = 16 SET from_collapse_limit = 16 AS $$ +DECLARE + _result hafah_backend.operation[]; + _account_range hafah_backend.account_filter_return; + _calculate_pages hafah_backend.calculate_pages_return; + _ops_count INT; BEGIN - RETURN QUERY - WITH operation_range AS MATERIALIZED ( - SELECT - ls.operation_id AS id, - ls.block_num, - ov.trx_in_block, - encode(htv.trx_hash, 'hex') AS trx_hash, - ov.op_pos, - ls.op_type_id, - ov.body, - hot.is_virtual - FROM ( - SELECT aov.operation_id, aov.op_type_id, aov.block_num - FROM hive.account_operations_view aov - WHERE aov.account_id = _account_id - AND aov.op_type_id = ANY(_operations) - AND aov.account_op_seq_no >= _from - AND aov.account_op_seq_no <= _to - ORDER BY aov.account_op_seq_no DESC - LIMIT _limit - OFFSET _offset - ) ls - JOIN hive.operations_view ov ON ov.id = ls.operation_id - JOIN hafd.operation_types hot ON hot.id = ls.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block - ) - -- filter too long operation bodies - SELECT - (filtered_operations.composite).body, - filtered_operations.block_num, - filtered_operations.trx_hash, - filtered_operations.op_pos, - filtered_operations.op_type_id, - filtered_operations.created_at, - filtered_operations.is_virtual, - filtered_operations.id::TEXT, - filtered_operations.trx_in_block::SMALLINT - FROM ( - SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at - FROM operation_range ov - JOIN hive.blocks_view hb ON hb.num = ov.block_num - ) filtered_operations - ORDER BY filtered_operations.id DESC; + + -----------PAGING LOGIC---------------- + _account_range := hafah_backend.account_range(NULL, _account_id, _from_block, _to_block); + + _ops_count := hafah_backend.get_account_operations_count(NULL, _account_id, _account_range.from_seq, _account_range.to_seq); + + _calculate_pages := hafah_backend.calculate_pages(_ops_count, _page, 'desc', _limit); + + -- Fetching operations + WITH operation_range AS MATERIALIZED ( + SELECT + ls.operation_id AS id, + ls.block_num, + ov.trx_in_block, + encode(htv.trx_hash, 'hex') AS trx_hash, + ov.op_pos, + ls.op_type_id, + ov.body, + hot.is_virtual + FROM ( + SELECT aov.operation_id, aov.op_type_id, aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.op_type_id = ANY(_operations) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + ORDER BY aov.account_op_seq_no DESC + LIMIT _calculate_pages.limit_filter + OFFSET _calculate_pages.offset_filter + ) ls + JOIN hive.operations_view ov ON ov.id = ls.operation_id + JOIN hafd.operation_types hot ON hot.id = ls.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + ), + -- filter too long operation bodies + result_query AS ( + SELECT + (filtered_operations.composite).body, + filtered_operations.block_num, + filtered_operations.trx_hash, + filtered_operations.op_pos, + filtered_operations.op_type_id, + filtered_operations.created_at, + filtered_operations.is_virtual, + filtered_operations.id, + filtered_operations.trx_in_block + FROM ( + SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at + FROM operation_range ov + JOIN hive.blocks_view hb ON hb.num = ov.block_num + ) filtered_operations + ORDER BY filtered_operations.id DESC + ) + SELECT array_agg(rows ORDER BY rows.id::BIGINT DESC) + INTO _result + FROM ( + SELECT + s.body, + s.block_num, + s.trx_hash, + s.op_pos, + s.op_type_id, + s.created_at, + s.is_virtual, + s.id::TEXT, + s.trx_in_block::SMALLINT + FROM result_query s + ) rows; + + ---------------------------------------- + RETURN ( + COALESCE(_ops_count,0), + COALESCE(_calculate_pages.total_pages,0), + (_from_block, _to_block)::hafah_backend.block_range_type, + COALESCE(_result, '{}'::hafah_backend.operation[]) + )::hafah_backend.account_operation_history; END $$; diff --git a/queries/hafah_rest_backend/account_history/count.sql b/queries/hafah_rest_backend/account_history/count.sql index 42f56e07b..7ad5f6219 100644 --- a/queries/hafah_rest_backend/account_history/count.sql +++ b/queries/hafah_rest_backend/account_history/count.sql @@ -1,11 +1,11 @@ SET ROLE hafah_owner; --- used in account page endpoint +-- used in account page endpoint (not used when filtered by accounts) CREATE OR REPLACE FUNCTION hafah_backend.get_account_operations_count( _operations INT [], _account_id INT, - _from INT, - _to INT + _from_seq INT, + _to_seq INT ) RETURNS BIGINT -- noqa: LT01, CP05 LANGUAGE 'plpgsql' STABLE @@ -17,17 +17,16 @@ AS $$ BEGIN IF _operations IS NULL THEN - RETURN _to - _from + 1; + RETURN _to_seq - _from_seq + 1; END IF; RETURN ( - -- using hive_account_operations_uq2, we are forcing planner to use this index on (account_id,operation_id), it achives better performance results SELECT COUNT(*) FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND aov.op_type_id = ANY(_operations) - AND aov.account_op_seq_no >= _from - AND aov.account_op_seq_no <= _to + AND aov.account_op_seq_no >= _from_seq + AND aov.account_op_seq_no <= _to_seq ); END diff --git a/queries/hafah_rest_backend/account_history/default.sql b/queries/hafah_rest_backend/account_history/default.sql index dfe730f3c..01f5973a2 100644 --- a/queries/hafah_rest_backend/account_history/default.sql +++ b/queries/hafah_rest_backend/account_history/default.sql @@ -2,13 +2,13 @@ SET ROLE hafah_owner; CREATE OR REPLACE FUNCTION hafah_backend.account_history_default( _account_id INT, - _from INT, - _to INT, + _from_block INT, + _to_block INT, + _page INT, _body_limit INT, - _offset INT, _limit INT ) -RETURNS SETOF hafah_backend.operation -- noqa: LT01, CP05 +RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 LANGUAGE 'plpgsql' STABLE COST 10000 SET JIT = OFF @@ -16,48 +16,87 @@ SET join_collapse_limit = 16 SET from_collapse_limit = 16 AS $$ +DECLARE + _result hafah_backend.operation[]; + _account_range hafah_backend.account_filter_return; + _calculate_pages hafah_backend.calculate_pages_return; + _ops_count INT; BEGIN - RETURN QUERY - WITH operation_range AS MATERIALIZED ( - SELECT - ls.operation_id AS id, - ls.block_num, - ov.trx_in_block, - encode(htv.trx_hash, 'hex') AS trx_hash, - ov.op_pos, - ls.op_type_id, - ov.body, - hot.is_virtual - FROM ( - SELECT aov.operation_id, aov.op_type_id, aov.block_num - FROM hive.account_operations_view aov - WHERE aov.account_id = _account_id - AND aov.account_op_seq_no >= _from - AND aov.account_op_seq_no <= _to - _offset - ORDER BY aov.account_op_seq_no DESC - LIMIT _limit - ) ls - JOIN hive.operations_view ov ON ov.id = ls.operation_id - JOIN hafd.operation_types hot ON hot.id = ls.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block - ) - -- filter too long operation bodies - SELECT - (filtered_operations.composite).body, - filtered_operations.block_num, - filtered_operations.trx_hash, - filtered_operations.op_pos, - filtered_operations.op_type_id, - filtered_operations.created_at, - filtered_operations.is_virtual, - filtered_operations.id::TEXT, - filtered_operations.trx_in_block::SMALLINT - FROM ( - SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at - FROM operation_range ov - JOIN hive.blocks_view hb ON hb.num = ov.block_num - ) filtered_operations - ORDER BY filtered_operations.id DESC; + + -----------PAGING LOGIC---------------- + _account_range := hafah_backend.account_range(NULL, _account_id, _from_block, _to_block); + + _ops_count := hafah_backend.get_account_operations_count(NULL, _account_id, _account_range.from_seq, _account_range.to_seq); + + _calculate_pages := hafah_backend.calculate_pages(_ops_count, _page, 'desc', _limit); + + -- Fetching operations + WITH operation_range AS MATERIALIZED ( + SELECT + ls.operation_id AS id, + ls.block_num, + ov.trx_in_block, + encode(htv.trx_hash, 'hex') AS trx_hash, + ov.op_pos, + ls.op_type_id, + ov.body, + hot.is_virtual + FROM ( + SELECT aov.operation_id, aov.op_type_id, aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq - _calculate_pages.offset_filter + ORDER BY aov.account_op_seq_no DESC + LIMIT _calculate_pages.limit_filter + ) ls + JOIN hive.operations_view ov ON ov.id = ls.operation_id + JOIN hafd.operation_types hot ON hot.id = ls.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + ), + -- filter too long operation bodies + result_query AS ( + SELECT + (filtered_operations.composite).body, + filtered_operations.block_num, + filtered_operations.trx_hash, + filtered_operations.op_pos, + filtered_operations.op_type_id, + filtered_operations.created_at, + filtered_operations.is_virtual, + filtered_operations.id::TEXT, + filtered_operations.trx_in_block::SMALLINT + FROM ( + SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at + FROM operation_range ov + JOIN hive.blocks_view hb ON hb.num = ov.block_num + ) filtered_operations + ORDER BY filtered_operations.id DESC + ) + SELECT array_agg(rows ORDER BY rows.id::BIGINT DESC) + INTO _result + FROM ( + SELECT + s.body, + s.block_num, + s.trx_hash, + s.op_pos, + s.op_type_id, + s.created_at, + s.is_virtual, + s.id::TEXT, + s.trx_in_block::SMALLINT + FROM result_query s + ) rows; + + ---------------------------------------- + RETURN ( + COALESCE(_ops_count,0), + COALESCE(_calculate_pages.total_pages,0), + (_from_block, _to_block)::hafah_backend.block_range_type, + COALESCE(_result, '{}'::hafah_backend.operation[]) + )::hafah_backend.account_operation_history; + END $$; diff --git a/queries/hafah_rest_backend/account_history/paging.sql b/queries/hafah_rest_backend/account_history/paging.sql index 8729109ff..6b4e1e9ff 100644 --- a/queries/hafah_rest_backend/account_history/paging.sql +++ b/queries/hafah_rest_backend/account_history/paging.sql @@ -81,7 +81,8 @@ $$; DROP TYPE IF EXISTS hafah_backend.account_filter_return CASCADE; CREATE TYPE hafah_backend.account_filter_return AS ( - count INT, + from_block INT, + to_block INT, from_seq INT, to_seq INT ); @@ -98,9 +99,12 @@ SET JIT = OFF AS $$ DECLARE + __to INT; + __from INT; __to_seq INT; __from_seq INT; - __count INT; + + _current_block INT := (SELECT bv.num FROM hive.blocks_view bv ORDER BY bv.num DESC LIMIT 1); BEGIN /* we are using 3 diffrent methods of fetching data, @@ -135,9 +139,27 @@ BEGIN ORDER BY aov.account_op_seq_no ASC LIMIT 1 ); - __count := hafah_backend.get_account_operations_count(_operations, _account_id, __from_seq, __to_seq); + __to := ( + CASE + WHEN (_to IS NULL) THEN + _current_block + WHEN (_to IS NOT NULL) AND (_current_block < _to) THEN + _current_block + ELSE + _to + END + ); + + __from := ( + CASE + WHEN (_from IS NULL) THEN + 1 + ELSE + _from + END + ); - RETURN (__count, __from_seq, __to_seq)::hafah_backend.account_filter_return; + RETURN (__from, __to, __from_seq, __to_seq)::hafah_backend.account_filter_return; END $$; diff --git a/scripts/install_app.sh b/scripts/install_app.sh index f721c4b95..379ad2ffc 100755 --- a/scripts/install_app.sh +++ b/scripts/install_app.sh @@ -79,11 +79,11 @@ psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_R psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/block.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/transaction.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/fill_order.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/paging.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/account_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/by_operations.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/count.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/default.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/paging.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/recent_trades.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/trade_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/acc_op_types.sql" -- GitLab From 65a28b76e1409cbeecb9b8f19bd1292ac043a876 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 16 Jul 2025 22:16:43 +0000 Subject: [PATCH 06/24] Move filtering functions to seperate directory --- .../account_history/count.sql | 35 ------------------- .../by_operations.sql | 0 .../{ => filtering_functions}/default.sql | 0 .../account_history/paging.sql | 32 +++++++++++++++++ scripts/install_app.sh | 5 ++- 5 files changed, 34 insertions(+), 38 deletions(-) delete mode 100644 queries/hafah_rest_backend/account_history/count.sql rename queries/hafah_rest_backend/account_history/{ => filtering_functions}/by_operations.sql (100%) rename queries/hafah_rest_backend/account_history/{ => filtering_functions}/default.sql (100%) diff --git a/queries/hafah_rest_backend/account_history/count.sql b/queries/hafah_rest_backend/account_history/count.sql deleted file mode 100644 index 7ad5f6219..000000000 --- a/queries/hafah_rest_backend/account_history/count.sql +++ /dev/null @@ -1,35 +0,0 @@ -SET ROLE hafah_owner; - --- used in account page endpoint (not used when filtered by accounts) -CREATE OR REPLACE FUNCTION hafah_backend.get_account_operations_count( - _operations INT [], - _account_id INT, - _from_seq INT, - _to_seq INT -) -RETURNS BIGINT -- noqa: LT01, CP05 -LANGUAGE 'plpgsql' STABLE -SET from_collapse_limit = 16 -SET join_collapse_limit = 16 -SET enable_hashjoin = OFF -SET JIT = OFF -AS -$$ -BEGIN - IF _operations IS NULL THEN - RETURN _to_seq - _from_seq + 1; - END IF; - - RETURN ( - SELECT COUNT(*) - FROM hive.account_operations_view aov - WHERE aov.account_id = _account_id - AND aov.op_type_id = ANY(_operations) - AND aov.account_op_seq_no >= _from_seq - AND aov.account_op_seq_no <= _to_seq - ); - -END -$$; - -RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/by_operations.sql b/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql similarity index 100% rename from queries/hafah_rest_backend/account_history/by_operations.sql rename to queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql diff --git a/queries/hafah_rest_backend/account_history/default.sql b/queries/hafah_rest_backend/account_history/filtering_functions/default.sql similarity index 100% rename from queries/hafah_rest_backend/account_history/default.sql rename to queries/hafah_rest_backend/account_history/filtering_functions/default.sql diff --git a/queries/hafah_rest_backend/account_history/paging.sql b/queries/hafah_rest_backend/account_history/paging.sql index 6b4e1e9ff..e7e790317 100644 --- a/queries/hafah_rest_backend/account_history/paging.sql +++ b/queries/hafah_rest_backend/account_history/paging.sql @@ -163,4 +163,36 @@ BEGIN END $$; +-- used in account page endpoint (not used when filtered by accounts) +CREATE OR REPLACE FUNCTION hafah_backend.get_account_operations_count( + _operations INT [], + _account_id INT, + _from_seq INT, + _to_seq INT +) +RETURNS BIGINT -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +SET from_collapse_limit = 16 +SET join_collapse_limit = 16 +SET enable_hashjoin = OFF +SET JIT = OFF +AS +$$ +BEGIN + IF _operations IS NULL THEN + RETURN _to_seq - _from_seq + 1; + END IF; + + RETURN ( + SELECT COUNT(*) + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.op_type_id = ANY(_operations) + AND aov.account_op_seq_no >= _from_seq + AND aov.account_op_seq_no <= _to_seq + ); + +END +$$; + RESET ROLE; diff --git a/scripts/install_app.sh b/scripts/install_app.sh index 379ad2ffc..5e6a1af2f 100755 --- a/scripts/install_app.sh +++ b/scripts/install_app.sh @@ -81,9 +81,8 @@ psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_R psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/fill_order.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/paging.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/account_history.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/by_operations.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/count.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/default.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/default.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/recent_trades.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/trade_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/acc_op_types.sql" -- GitLab From e0841b4acb0cb1b64181cc17eb9b98f94e3820d2 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Thu, 17 Jul 2025 08:39:57 +0000 Subject: [PATCH 07/24] OpenAPI rewrite --- postgrest/hafah_REST/hafah_openapi.sql | 53 ++++++++++++++++++- .../filtering_functions/by_operations.sql | 6 +-- .../filtering_functions/default.sql | 2 +- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/postgrest/hafah_REST/hafah_openapi.sql b/postgrest/hafah_REST/hafah_openapi.sql index acf2cab33..16887ee4f 100644 --- a/postgrest/hafah_REST/hafah_openapi.sql +++ b/postgrest/hafah_REST/hafah_openapi.sql @@ -72,6 +72,17 @@ declare "all" ] }, + "hafah_backend.block_range_type": { + "type": "object", + "properties": { + "from": { + "type": "integer" + }, + "to": { + "type": "integer" + } + } + }, "hafah_backend.operation_body": { "type": "object", "x-sql-datatype": "JSON", @@ -154,6 +165,30 @@ declare } } }, + "hafah_backend.account_operation_history": { + "type": "object", + "properties": { + "total_operations": { + "type": "integer", + "description": "Total number of operations" + }, + "total_pages": { + "type": "integer", + "description": "Total number of pages" + }, + "block_range": { + "$ref": "#/components/schemas/hafah_backend.block_range_type", + "description": "Range of blocks that contains the returned pages" + }, + "operations_result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/hafah_backend.operation" + }, + "description": "List of operation results" + } + } + }, "hafah_backend.operations_in_block_range": { "type": "object", "properties": { @@ -1619,6 +1654,16 @@ declare }, "description": "Account to get operations for." }, + { + "in": "query", + "name": "transacting-account-name", + "required": false, + "schema": { + "type": "string", + "default": null + }, + "description": "Account to filter operations by, if provided only operations where the account is an author will be returned.\n" + }, { "in": "query", "name": "operation-types", @@ -1682,15 +1727,19 @@ declare ], "responses": { "200": { - "description": "Result contains total number of operations,\ntotal pages, and the list of operations.\n\n* Returns `hafah_backend.operation_history`\n", + "description": "Result contains total number of operations,\ntotal pages, and the list of operations.\n\n* Returns `hafah_backend.account_operation_history`\n", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/hafah_backend.operation_history" + "$ref": "#/components/schemas/hafah_backend.account_operation_history" }, "example": { "total_operations": 219867, "total_pages": 73289, + "block_range": { + "from": 1, + "to": 5000000 + }, "operations_result": [ { "op": { diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql b/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql index f6f496854..19b09b385 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql @@ -25,9 +25,9 @@ DECLARE BEGIN -----------PAGING LOGIC---------------- - _account_range := hafah_backend.account_range(NULL, _account_id, _from_block, _to_block); + _account_range := hafah_backend.account_range(_operations, _account_id, _from_block, _to_block); - _ops_count := hafah_backend.get_account_operations_count(NULL, _account_id, _account_range.from_seq, _account_range.to_seq); + _ops_count := hafah_backend.get_account_operations_count(_operations, _account_id, _account_range.from_seq, _account_range.to_seq); _calculate_pages := hafah_backend.calculate_pages(_ops_count, _page, 'desc', _limit); @@ -96,7 +96,7 @@ BEGIN RETURN ( COALESCE(_ops_count,0), COALESCE(_calculate_pages.total_pages,0), - (_from_block, _to_block)::hafah_backend.block_range_type, + (_account_range.from_block, _account_range.to_block)::hafah_backend.block_range_type, COALESCE(_result, '{}'::hafah_backend.operation[]) )::hafah_backend.account_operation_history; diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/default.sql b/queries/hafah_rest_backend/account_history/filtering_functions/default.sql index 01f5973a2..42c26ad50 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/default.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/default.sql @@ -93,7 +93,7 @@ BEGIN RETURN ( COALESCE(_ops_count,0), COALESCE(_calculate_pages.total_pages,0), - (_from_block, _to_block)::hafah_backend.block_range_type, + (_account_range.from_block, _account_range.to_block)::hafah_backend.block_range_type, COALESCE(_result, '{}'::hafah_backend.operation[]) )::hafah_backend.account_operation_history; -- GitLab From 39ce5a0ce9e47bc121c9ac8767af46a5f7bdaa54 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Thu, 17 Jul 2025 08:40:05 +0000 Subject: [PATCH 08/24] Bump haf --- haf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haf b/haf index f77f30821..85e611688 160000 --- a/haf +++ b/haf @@ -1 +1 @@ -Subproject commit f77f308210a2b051517dc08a986bab9fc1afe98d +Subproject commit 85e6116889fbbdb9a50909a3350210f21bd4b796 -- GitLab From 58f738610d0d6d39a47201b3304e5ae429a8611d Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Thu, 17 Jul 2025 10:23:43 +0000 Subject: [PATCH 09/24] Add backend and tests for transacting account filtering --- .../including_accounts.sql | 157 ++++++ scripts/install_app.sh | 1 + .../filter_by_transacting_account.pat.json | 478 ++++++++++++++++++ .../filter_by_transacting_account.tavern.yaml | 24 + 4 files changed, 660 insertions(+) create mode 100644 queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql create mode 100644 tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json create mode 100644 tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql new file mode 100644 index 000000000..80ca001f7 --- /dev/null +++ b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql @@ -0,0 +1,157 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.account_history_including_accounts( + _account_id INT, + _operations INT [], + _transacting_account_id INT, + _from_block INT, + _to_block INT, + _page INT, + _body_limit INT, + _limit INT +) +RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +COST 10000 +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 +AS +$$ +DECLARE + _result hafah_backend.operation[]; + _account_range hafah_backend.account_filter_return; + __max_page_count INT := 10; + + __total_pages INT; + __min_block_num INT; + __count INT; +BEGIN + -----------PAGING LOGIC---------------- + _account_range := hafah_backend.account_range(_operations, _account_id, _from_block, _to_block); + + -- Fetching operations + WITH operation_range AS MATERIALIZED ( + SELECT + ls.operation_id AS id, + ls.block_num, + ov.trx_in_block, + encode(htv.trx_hash, 'hex') AS trx_hash, + ov.op_pos, + ls.op_type_id, + ov.body, + hot.is_virtual + FROM ( + SELECT aov.operation_id, aov.op_type_id, aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.transacting_account_id = _transacting_account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + ORDER BY aov.account_op_seq_no DESC + LIMIT (__max_page_count * _limit) -- by default operation filter is limited to 10 pages + ) ls + JOIN hive.operations_view ov ON ov.id = ls.operation_id + JOIN hafd.operation_types hot ON hot.id = ls.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + ), + -----------PAGING LOGIC---------------- + -- Pages are counted differently compared to default.sql + -- The results are based on a set of blocks for each operation, + -- so the count and total number of pages depend on the specific query inside this cte chain + min_block_num AS ( + SELECT + MIN(block_num) AS block_num + FROM operation_range + ), + count_blocks AS MATERIALIZED ( + SELECT + COUNT(*) AS count + FROM operation_range + ), + calculate_pages AS MATERIALIZED ( + SELECT + total_pages, + offset_filter, + limit_filter + FROM hafah_backend.calculate_pages( + (SELECT count FROM count_blocks)::INT, + _page, + 'desc', + _limit + ) + ), + filter_page AS MATERIALIZED ( + SELECT * + FROM operation_range + ORDER BY id DESC + OFFSET (SELECT offset_filter FROM calculate_pages) + LIMIT (SELECT limit_filter FROM calculate_pages) + ), + -- filter too long operation bodies + result_query AS ( + SELECT + (filtered_operations.composite).body, + filtered_operations.block_num, + filtered_operations.trx_hash, + filtered_operations.op_pos, + filtered_operations.op_type_id, + filtered_operations.created_at, + filtered_operations.is_virtual, + filtered_operations.id, + filtered_operations.trx_in_block + FROM ( + SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at + FROM filter_page ov + JOIN hive.blocks_view hb ON hb.num = ov.block_num + ) filtered_operations + ORDER BY filtered_operations.id DESC + ) + SELECT + (SELECT count FROM count_blocks), + (SELECT total_pages FROM calculate_pages), + (SELECT block_num FROM min_block_num), + ( + SELECT array_agg(rows ORDER BY rows.id::BIGINT DESC) + FROM ( + SELECT + s.body, + s.block_num, + s.trx_hash, + s.op_pos, + s.op_type_id, + s.created_at, + s.is_virtual, + s.id::TEXT, + s.trx_in_block::SMALLINT + FROM result_query s + ) rows + ) + INTO __count, __total_pages, __min_block_num, _result; + + -- 1. If the min block number is NULL - the result is empty - there are no results for whole provided range + -- 2. If the min block number is NOT NULL and pages are not fully saturated it means there is no more blocks to fetch + -- 3. (ELSE) If the min block number is NOT NULL - the result is not empty - there are results for the provided range + -- and the min block number can be used as filter in the next API call (as a to-block parameter) + _account_range.from_block := ( + CASE + WHEN __min_block_num IS NULL THEN _account_range.from_block + WHEN __min_block_num IS NOT NULL AND __min_block_num = 1 THEN 1 + WHEN __min_block_num IS NOT NULL AND __min_block_num != 1 AND __count != __max_page_count * _limit THEN _account_range.from_block + ELSE __min_block_num - 1 + END + ); + + ---------------------------------------- + RETURN ( + COALESCE(__count,0), + COALESCE(__total_pages,0), + (_account_range.from_block, _account_range.to_block)::hafah_backend.block_range_type, + COALESCE(_result, '{}'::hafah_backend.operation[]) + )::hafah_backend.account_operation_history; + +END +$$; + +RESET ROLE; diff --git a/scripts/install_app.sh b/scripts/install_app.sh index 5e6a1af2f..62aa3d4ca 100755 --- a/scripts/install_app.sh +++ b/scripts/install_app.sh @@ -83,6 +83,7 @@ psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_res psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/account_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/default.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/recent_trades.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/trade_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/acc_op_types.sql" diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json new file mode 100644 index 000000000..cd7ccc925 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json @@ -0,0 +1,478 @@ +{ + "total_operations": 21, + "total_pages": 1, + "block_range": { + "from": 1, + "to": 5000000 + }, + "operations_result": [ + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "gtg", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 3784059, + "trx_id": "d448cf3bbe37ea308d8905ea580b79ff25b3dc43", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-08-04T08:58:27", + "virtual_op": false, + "operation_id": "16252409651136780", + "trx_in_block": 5 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 1883324796189, + "rshares": 108176539, + "permlink": "bitcoin-payments-accepted-in-20s-soon-to-be-6s", + "pending_payout": { + "nai": "@@000000013", + "amount": "319805", + "precision": 3 + }, + "total_vote_weight": "17313337917951663196" + } + }, + "block": 2887502, + "trx_id": "9729bd39ffede1ad4d461474012f2868b7d4d8a2", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-03T22:43:48", + "virtual_op": true, + "operation_id": "12401726657134920", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "bitcoin-payments-accepted-in-20s-soon-to-be-6s" + } + }, + "block": 2887502, + "trx_id": "9729bd39ffede1ad4d461474012f2868b7d4d8a2", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-03T22:43:48", + "virtual_op": false, + "operation_id": "12401726657134592", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 26467069, + "permlink": "-blocktrades-adds-support-for-directly-buyingselling-steem", + "pending_payout": { + "nai": "@@000000013", + "amount": "3395497", + "precision": 3 + }, + "total_vote_weight": 37079019999706 + } + }, + "block": 2840599, + "trx_id": "2bf9b0850282ed3867d9a2470dc8d6af55aa4ea4", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T07:34:18", + "virtual_op": true, + "operation_id": "12200279806050632", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "-blocktrades-adds-support-for-directly-buyingselling-steem" + } + }, + "block": 2840599, + "trx_id": "2bf9b0850282ed3867d9a2470dc8d6af55aa4ea4", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T07:34:18", + "virtual_op": false, + "operation_id": "12200279806050304", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 26467069, + "permlink": "openledger-pre-sale-of-dao-tokens-is-now-live", + "pending_payout": { + "nai": "@@000000013", + "amount": "1805443", + "precision": 3 + }, + "total_vote_weight": 39555131983403 + } + }, + "block": 2840592, + "trx_id": "5179c7745a8a8e729cf8faab0461e97bc1219ba3", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T07:33:57", + "virtual_op": true, + "operation_id": "12200249741280584", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "openledger-pre-sale-of-dao-tokens-is-now-live" + } + }, + "block": 2840592, + "trx_id": "5179c7745a8a8e729cf8faab0461e97bc1219ba3", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T07:33:57", + "virtual_op": false, + "operation_id": "12200249741280256", + "trx_in_block": 2 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 26467069, + "permlink": "is-vote-changing-an-important-feature-for-steem", + "pending_payout": { + "nai": "@@000000013", + "amount": "1004732", + "precision": 3 + }, + "total_vote_weight": 39522051255407 + } + }, + "block": 2840592, + "trx_id": "4fdfc9bcbc84c0b7d798cf3f0c606269043f14ff", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T07:33:57", + "virtual_op": true, + "operation_id": "12200249741280072", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "is-vote-changing-an-important-feature-for-steem" + } + }, + "block": 2840592, + "trx_id": "4fdfc9bcbc84c0b7d798cf3f0c606269043f14ff", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T07:33:57", + "virtual_op": false, + "operation_id": "12200249741279744", + "trx_in_block": 1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 26467069, + "permlink": "tax-issues-facing-us-based-cryptocurrency-holders-and-miners-intro-and-irs-guidelines", + "pending_payout": { + "nai": "@@000000013", + "amount": "2031797", + "precision": 3 + }, + "total_vote_weight": 38794385435057 + } + }, + "block": 2840592, + "trx_id": "88d2f81c37e1288448b334042c3eee02df6395d9", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T07:33:57", + "virtual_op": true, + "operation_id": "12200249741279560", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "tax-issues-facing-us-based-cryptocurrency-holders-and-miners-intro-and-irs-guidelines" + } + }, + "block": 2840592, + "trx_id": "88d2f81c37e1288448b334042c3eee02df6395d9", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T07:33:57", + "virtual_op": false, + "operation_id": "12200249741279232", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 27007214, + "permlink": "tax-issues-facing-us-based-cryptocurrency-holders-and-miners-part-1-capital-gainslosses-for-crypto", + "pending_payout": { + "nai": "@@000000013", + "amount": "2428829", + "precision": 3 + }, + "total_vote_weight": 38851983572277 + } + }, + "block": 2840591, + "trx_id": "9174e0f692023ecf91d632f9949a94c808302119", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T07:33:54", + "virtual_op": true, + "operation_id": "12200245446312264", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "tax-issues-facing-us-based-cryptocurrency-holders-and-miners-part-1-capital-gainslosses-for-crypto" + } + }, + "block": 2840591, + "trx_id": "9174e0f692023ecf91d632f9949a94c808302119", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T07:33:54", + "virtual_op": false, + "operation_id": "12200245446311936", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 27007214, + "permlink": "i-find-steemit-posts-with-summariesanalysis-of-3rd-party-content-more-compelling", + "pending_payout": { + "nai": "@@000000013", + "amount": "1386736", + "precision": 3 + }, + "total_vote_weight": 39919636650316 + } + }, + "block": 2840590, + "trx_id": "e909cd27baf117473ec99ec9b875a6916927c55e", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T07:33:51", + "virtual_op": true, + "operation_id": "12200241151344968", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "i-find-steemit-posts-with-summariesanalysis-of-3rd-party-content-more-compelling" + } + }, + "block": 2840590, + "trx_id": "e909cd27baf117473ec99ec9b875a6916927c55e", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T07:33:51", + "virtual_op": false, + "operation_id": "12200241151344640", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 27007214, + "permlink": "blocktrades-now-offering-steem-power-for-cryptocurrency", + "pending_payout": { + "nai": "@@000000013", + "amount": "1439043", + "precision": 3 + }, + "total_vote_weight": 40979209439222 + } + }, + "block": 2840585, + "trx_id": "8726774b3c8d53e9dcb870db6b3561a217871d27", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T07:33:36", + "virtual_op": true, + "operation_id": "12200219676508488", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "blocktrades-now-offering-steem-power-for-cryptocurrency" + } + }, + "block": 2840585, + "trx_id": "8726774b3c8d53e9dcb870db6b3561a217871d27", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T07:33:36", + "virtual_op": false, + "operation_id": "12200219676508160", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 27007214, + "permlink": "dao-gateway-on-openledger-is-fully-operational", + "pending_payout": { + "nai": "@@000000013", + "amount": "1102767", + "precision": 3 + }, + "total_vote_weight": 37317034722668 + } + }, + "block": 2839669, + "trx_id": "c02b46ca3eced3c6bd5cc43df2114143ce6c2105", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T06:47:45", + "virtual_op": true, + "operation_id": "12196285486465864", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "dao-gateway-on-openledger-is-fully-operational" + } + }, + "block": 2839669, + "trx_id": "c02b46ca3eced3c6bd5cc43df2114143ce6c2105", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T06:47:45", + "virtual_op": false, + "operation_id": "12196285486465536", + "trx_in_block": 1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 0, + "rshares": 27547358, + "permlink": "blocktrades-supports-buyingselling-dao-coins-without-exchange-risk", + "pending_payout": { + "nai": "@@000000013", + "amount": "2715326", + "precision": 3 + }, + "total_vote_weight": 41395120110223 + } + }, + "block": 2839669, + "trx_id": "2b79214e07cffd28c8ee026055d92767229d8b45", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-07-02T06:47:45", + "virtual_op": true, + "operation_id": "12196285486465352", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "blocktrades", + "weight": 10000, + "permlink": "blocktrades-supports-buyingselling-dao-coins-without-exchange-risk" + } + }, + "block": 2839669, + "trx_id": "2b79214e07cffd28c8ee026055d92767229d8b45", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-07-02T06:47:45", + "virtual_op": false, + "operation_id": "12196285486465024", + "trx_in_block": 0 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml new file mode 100644 index 000000000..7ef854bf8 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml @@ -0,0 +1,24 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_account" + method: POST + headers: + content-type: application/json + accept: application/json + json: + account-name: "blocktrades" + transacting-account-name: "gtg" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern -- GitLab From b6c106f54f5bec0aed7410dc3e2fac61674652e6 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Fri, 18 Jul 2025 11:04:24 +0000 Subject: [PATCH 10/24] Additional paging logic for corner case when filtering by transacting_account_id --- .../including_accounts.sql | 121 +- .../corner_case_transacting_account.pat.json | 2131 +++++++++++++++++ ...orner_case_transacting_account.tavern.yaml | 25 + 3 files changed, 2259 insertions(+), 18 deletions(-) create mode 100644 tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json create mode 100644 tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql index 80ca001f7..f60cab0ef 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql @@ -35,12 +35,8 @@ BEGIN SELECT ls.operation_id AS id, ls.block_num, - ov.trx_in_block, - encode(htv.trx_hash, 'hex') AS trx_hash, - ov.op_pos, ls.op_type_id, - ov.body, - hot.is_virtual + ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) FROM ( SELECT aov.operation_id, aov.op_type_id, aov.block_num FROM hive.account_operations_view aov @@ -50,25 +46,94 @@ BEGIN AND aov.account_op_seq_no >= _account_range.from_seq AND aov.account_op_seq_no <= _account_range.to_seq ORDER BY aov.account_op_seq_no DESC - LIMIT (__max_page_count * _limit) -- by default operation filter is limited to 10 pages + LIMIT (__max_page_count * _limit) + 1 -- by default operation filter is limited to 10 pages + -- The +1 is to check if there are more operations in block that are not included in the current page-range ) ls - JOIN hive.operations_view ov ON ov.id = ls.operation_id - JOIN hafd.operation_types hot ON hot.id = ls.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block ), -----------PAGING LOGIC---------------- - -- Pages are counted differently compared to default.sql - -- The results are based on a set of blocks for each operation, - -- so the count and total number of pages depend on the specific query inside this cte chain + -- Calculating pages based on result set (operation_range) + -- there is corner case when the last two operations are in the same block + -- when generating next batch of pages, we may miss operations made in the same block + -- to prevent this, we check if the last two operations are in the same block + -- if there at least 2 operations in the same block, we fetch all operations in that block + -- and add them to the result set + -- and calculate pages based on the new result set + check_if_saturated AS ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN MAX(row_num) = (__max_page_count * _limit) + 1 THEN + (__max_page_count * _limit) + 1 + ELSE + NULL + END + ) AS count + FROM operation_range + ), + if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty + SELECT + orr.block_num + FROM operation_range orr + WHERE orr.row_num IN ( + (SELECT count FROM check_if_saturated), + (SELECT count - 1 FROM check_if_saturated) + ) + ), + block_check AS MATERIALIZED ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(block_num) + ELSE + NULL + END + ) AS block_num + FROM if_saturated_find_last_two_ops + ), + -- returns empty if the last two operations are not in the same block + -- if the last two operations are in the same block, next CTE returns all operations in that block + find_all_records_for_page AS ( -- if not saturated, returns empty + SELECT + aov.operation_id AS id, + aov.op_type_id, + aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.transacting_account_id = _transacting_account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT block_num FROM block_check) IS NOT NULL + AND aov.block_num = (SELECT block_num FROM block_check) + ) + ), + union_operations AS MATERIALIZED ( + SELECT + id, + block_num, + op_type_id + FROM operation_range + WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row + AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) + -- if block_check is not NULL, exclude the operations from last block + -- operations from excluded block are fetched in find_all_records_for_page + UNION ALL + + SELECT + id, + block_num, + op_type_id + FROM find_all_records_for_page + ), min_block_num AS ( SELECT MIN(block_num) AS block_num - FROM operation_range + FROM union_operations ), count_blocks AS MATERIALIZED ( SELECT COUNT(*) AS count - FROM operation_range + FROM union_operations ), calculate_pages AS MATERIALIZED ( SELECT @@ -82,13 +147,33 @@ BEGIN _limit ) ), - filter_page AS MATERIALIZED ( + filter_page AS ( SELECT * - FROM operation_range + FROM union_operations ORDER BY id DESC OFFSET (SELECT offset_filter FROM calculate_pages) LIMIT (SELECT limit_filter FROM calculate_pages) ), + -----------END PAGING LOGIC---------------- + -- join the operations with other necessary tables + join_tables AS ( + SELECT + ls.id, + ls.block_num, + ov.trx_in_block, + encode(htv.trx_hash, 'hex') AS trx_hash, + ov.op_pos, + ls.op_type_id, + ov.body, + hot.is_virtual + FROM ( + SELECT aov.id, aov.op_type_id, aov.block_num + FROM filter_page aov + ) ls + JOIN hive.operations_view ov ON ov.id = ls.id + JOIN hafd.operation_types hot ON hot.id = ls.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + ), -- filter too long operation bodies result_query AS ( SELECT @@ -103,7 +188,7 @@ BEGIN filtered_operations.trx_in_block FROM ( SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at - FROM filter_page ov + FROM join_tables ov JOIN hive.blocks_view hb ON hb.num = ov.block_num ) filtered_operations ORDER BY filtered_operations.id DESC @@ -138,7 +223,7 @@ BEGIN CASE WHEN __min_block_num IS NULL THEN _account_range.from_block WHEN __min_block_num IS NOT NULL AND __min_block_num = 1 THEN 1 - WHEN __min_block_num IS NOT NULL AND __min_block_num != 1 AND __count != __max_page_count * _limit THEN _account_range.from_block + WHEN __min_block_num IS NOT NULL AND __min_block_num != 1 AND __count < __max_page_count * _limit THEN _account_range.from_block ELSE __min_block_num - 1 END ); diff --git a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json new file mode 100644 index 000000000..d0e9edd4c --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json @@ -0,0 +1,2131 @@ +{ + "total_operations": 1001, + "total_pages": 11, + "block_range": { + "from": 4981191, + "to": 5000000 + }, + "operations_result": [ + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013425676", + "precision": 6 + } + } + }, + "block": 4982887, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:22:51", + "virtual_op": true, + "operation_id": "21401336704664896", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013430053", + "precision": 6 + } + } + }, + "block": 4982879, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:22:27", + "virtual_op": true, + "operation_id": "21401302344925760", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013442940", + "precision": 6 + } + } + }, + "block": 4982856, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:21:18", + "virtual_op": true, + "operation_id": "21401203560677952", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013463791", + "precision": 6 + } + } + }, + "block": 4982819, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:19:27", + "virtual_op": true, + "operation_id": "21401044646887488", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013470113", + "precision": 6 + } + } + }, + "block": 4982808, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:18:54", + "virtual_op": true, + "operation_id": "21400997402247232", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013482454", + "precision": 6 + } + } + }, + "block": 4982786, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:17:48", + "virtual_op": true, + "operation_id": "21400902912967488", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013497288", + "precision": 6 + } + } + }, + "block": 4982760, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:16:30", + "virtual_op": true, + "operation_id": "21400791243817280", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013507987", + "precision": 6 + } + } + }, + "block": 4982741, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:15:33", + "virtual_op": true, + "operation_id": "21400709639439936", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013514310", + "precision": 6 + } + } + }, + "block": 4982730, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:15:00", + "virtual_op": true, + "operation_id": "21400662394798656", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013526408", + "precision": 6 + } + } + }, + "block": 4982709, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:13:57", + "virtual_op": true, + "operation_id": "21400572200484928", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013546652", + "precision": 6 + } + } + }, + "block": 4982672, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:12:06", + "virtual_op": true, + "operation_id": "21400413286695744", + "trx_in_block": -1 + }, + { + "op": { + "type": "curation_reward_operation", + "value": { + "author": "laonie", + "reward": { + "nai": "@@000000037", + "amount": "2995465372", + "precision": 6 + }, + "curator": "abit", + "permlink": "robinhoodwhale-14-09-2016", + "payout_must_be_claimed": false + } + }, + "block": 4982671, + "trx_id": null, + "op_pos": 3, + "op_type_id": 52, + "timestamp": "2016-09-15T05:12:03", + "virtual_op": true, + "operation_id": "21400408991729460", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013553765", + "precision": 6 + } + } + }, + "block": 4982659, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:11:27", + "virtual_op": true, + "operation_id": "21400357452120640", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013562824", + "precision": 6 + } + } + }, + "block": 4982643, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:10:39", + "virtual_op": true, + "operation_id": "21400288732643904", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013582278", + "precision": 6 + } + } + }, + "block": 4982608, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:08:54", + "virtual_op": true, + "operation_id": "21400138408789056", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013593221", + "precision": 6 + } + } + }, + "block": 4982588, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:07:54", + "virtual_op": true, + "operation_id": "21400052509443648", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013600638", + "precision": 6 + } + } + }, + "block": 4982575, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:07:15", + "virtual_op": true, + "operation_id": "21399996674872384", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013617662", + "precision": 6 + } + } + }, + "block": 4982545, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:05:45", + "virtual_op": true, + "operation_id": "21399867825850432", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013619303", + "precision": 6 + } + } + }, + "block": 4982542, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:05:36", + "virtual_op": true, + "operation_id": "21399854940946496", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013634381", + "precision": 6 + } + } + }, + "block": 4982515, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:04:15", + "virtual_op": true, + "operation_id": "21399738976830784", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5029755783", + "precision": 6 + }, + "worker": "abit" + } + }, + "block": 4982515, + "trx_id": "93a6c22ea048b25bdd24eff1452fa499ae85dc47", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T05:04:15", + "virtual_op": true, + "operation_id": "21399738976830542", + "trx_in_block": 2 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013644049", + "precision": 6 + } + } + }, + "block": 4982499, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:03:27", + "virtual_op": true, + "operation_id": "21399670257354048", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013654203", + "precision": 6 + } + } + }, + "block": 4982481, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:02:33", + "virtual_op": true, + "operation_id": "21399592947941440", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013667092", + "precision": 6 + } + } + }, + "block": 4982458, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:01:24", + "virtual_op": true, + "operation_id": "21399494163694400", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013678887", + "precision": 6 + } + } + }, + "block": 4982437, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T05:00:21", + "virtual_op": true, + "operation_id": "21399403969381440", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013689284", + "precision": 6 + } + } + }, + "block": 4982418, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:59:24", + "virtual_op": true, + "operation_id": "21399322365002816", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013710625", + "precision": 6 + } + } + }, + "block": 4982379, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:57:27", + "virtual_op": true, + "operation_id": "21399154861277504", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013720231", + "precision": 6 + } + } + }, + "block": 4982362, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:56:36", + "virtual_op": true, + "operation_id": "21399081846835264", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013729291", + "precision": 6 + } + } + }, + "block": 4982346, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:55:48", + "virtual_op": true, + "operation_id": "21399013127358528", + "trx_in_block": -1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "abit", + "author": "userlogin", + "weight": "5219181476551540775", + "rshares": 7016909099162, + "permlink": "steem-transfer-daily-2016-09-14-steem", + "pending_payout": { + "nai": "@@000000013", + "amount": "7164", + "precision": 3 + }, + "total_vote_weight": "13201860673658672410" + } + }, + "block": 4982346, + "trx_id": "f50be9b3d52340525260f7c9d87f6c884d70284f", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T04:55:48", + "virtual_op": true, + "operation_id": "21399013127357256", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "abit", + "author": "userlogin", + "weight": 10000, + "permlink": "steem-transfer-daily-2016-09-14-steem" + } + }, + "block": 4982346, + "trx_id": "f50be9b3d52340525260f7c9d87f6c884d70284f", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T04:55:48", + "virtual_op": false, + "operation_id": "21399013127356928", + "trx_in_block": 1 + }, + { + "op": { + "type": "curation_reward_operation", + "value": { + "author": "oflyhigh", + "reward": { + "nai": "@@000000037", + "amount": "5162538482", + "precision": 6 + }, + "curator": "abit", + "permlink": "6hoytq", + "payout_must_be_claimed": false + } + }, + "block": 4982324, + "trx_id": null, + "op_pos": 2, + "op_type_id": 52, + "timestamp": "2016-09-15T04:54:42", + "virtual_op": true, + "operation_id": "21398918638078260", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013743823", + "precision": 6 + } + } + }, + "block": 4982320, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:54:30", + "virtual_op": true, + "operation_id": "21398901458208064", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013757017", + "precision": 6 + } + } + }, + "block": 4982297, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:53:21", + "virtual_op": true, + "operation_id": "21398802673961536", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5029960462", + "precision": 6 + }, + "worker": "abit" + } + }, + "block": 4982297, + "trx_id": "d6acf652384c58c55a23127f09bf5f5652c2baf9", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T04:53:21", + "virtual_op": true, + "operation_id": "21398802673959246", + "trx_in_block": 0 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013761700", + "precision": 6 + } + } + }, + "block": 4982289, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:52:57", + "virtual_op": true, + "operation_id": "21398768314221632", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013778420", + "precision": 6 + } + } + }, + "block": 4982259, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:51:27", + "virtual_op": true, + "operation_id": "21398639465201728", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013792405", + "precision": 6 + } + } + }, + "block": 4982234, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:50:12", + "virtual_op": true, + "operation_id": "21398532091019840", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013800066", + "precision": 6 + } + } + }, + "block": 4982220, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:49:30", + "virtual_op": true, + "operation_id": "21398471961480512", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013813504", + "precision": 6 + } + } + }, + "block": 4982196, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:48:18", + "virtual_op": true, + "operation_id": "21398368882262080", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013826942", + "precision": 6 + } + } + }, + "block": 4982172, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:47:06", + "virtual_op": true, + "operation_id": "21398265803049792", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013835698", + "precision": 6 + } + } + }, + "block": 4982156, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:46:18", + "virtual_op": true, + "operation_id": "21398197083571264", + "trx_in_block": -1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "abit", + "author": "lemooljiang", + "weight": "11541103210750507335", + "rshares": 7016726247780, + "permlink": "471m1v", + "pending_payout": { + "nai": "@@000000013", + "amount": "3937", + "precision": 3 + }, + "total_vote_weight": "11780897525504116941" + } + }, + "block": 4982152, + "trx_id": "db504e419e8e1cb7160f5afb500d259e31c0f355", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T04:46:06", + "virtual_op": true, + "operation_id": "21398179903701832", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "abit", + "author": "lemooljiang", + "weight": 10000, + "permlink": "471m1v" + } + }, + "block": 4982152, + "trx_id": "db504e419e8e1cb7160f5afb500d259e31c0f355", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T04:46:06", + "virtual_op": false, + "operation_id": "21398179903701504", + "trx_in_block": 1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "abit", + "author": "yangyang", + "weight": "7647348356681883608", + "rshares": 7016726247780, + "permlink": "mid-autumn-day-s-pc-paint-drawing", + "pending_payout": { + "nai": "@@000000013", + "amount": "5297", + "precision": 3 + }, + "total_vote_weight": "12521623444169398596" + } + }, + "block": 4982150, + "trx_id": "6247131aa802ec51641b6ef81434f11b0e0f02b4", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T04:46:00", + "virtual_op": true, + "operation_id": "21398171313767496", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "abit", + "author": "yangyang", + "weight": 10000, + "permlink": "mid-autumn-day-s-pc-paint-drawing" + } + }, + "block": 4982150, + "trx_id": "6247131aa802ec51641b6ef81434f11b0e0f02b4", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T04:46:00", + "virtual_op": false, + "operation_id": "21398171313767168", + "trx_in_block": 2 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013851630", + "precision": 6 + } + } + }, + "block": 4982128, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:44:54", + "virtual_op": true, + "operation_id": "21398076824485952", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013853818", + "precision": 6 + } + } + }, + "block": 4982124, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:44:42", + "virtual_op": true, + "operation_id": "21398059644617280", + "trx_in_block": -1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "abit", + "author": "jademont", + "weight": "11681497147989204564", + "rshares": 7016696712023, + "permlink": "re-bloggersclub-breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be-20160915t040222007z", + "pending_payout": { + "nai": "@@000000013", + "amount": "3902", + "precision": 3 + }, + "total_vote_weight": "11759286132483617228" + } + }, + "block": 4982116, + "trx_id": "3f4082939c57dd19b9751d1bc911d46d24bb6d97", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T04:44:18", + "virtual_op": true, + "operation_id": "21398025284879688", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "abit", + "author": "jademont", + "weight": 10000, + "permlink": "re-bloggersclub-breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be-20160915t040222007z" + } + }, + "block": 4982116, + "trx_id": "3f4082939c57dd19b9751d1bc911d46d24bb6d97", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T04:44:18", + "virtual_op": false, + "operation_id": "21398025284879360", + "trx_in_block": 2 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "abit", + "author": "bloggersclub", + "weight": "8078580049650391897", + "rshares": 7159894604105, + "permlink": "breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be", + "pending_payout": { + "nai": "@@000000013", + "amount": "5262", + "precision": 3 + }, + "total_vote_weight": "12507535182167387389" + } + }, + "block": 4982114, + "trx_id": "1a4f109bafd56cfdaa64ce0426e07dbba6e68c75", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T04:44:12", + "virtual_op": true, + "operation_id": "21398016694944072", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "abit", + "author": "bloggersclub", + "weight": 10000, + "permlink": "breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be" + } + }, + "block": 4982114, + "trx_id": "1a4f109bafd56cfdaa64ce0426e07dbba6e68c75", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T04:44:12", + "virtual_op": false, + "operation_id": "21398016694943744", + "trx_in_block": 0 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013874980", + "precision": 6 + } + } + }, + "block": 4982087, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:42:51", + "virtual_op": true, + "operation_id": "21397900730827328", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013887567", + "precision": 6 + } + } + }, + "block": 4982064, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:41:42", + "virtual_op": true, + "operation_id": "21397801946579520", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013896323", + "precision": 6 + } + } + }, + "block": 4982048, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:40:54", + "virtual_op": true, + "operation_id": "21397733227103040", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013905079", + "precision": 6 + } + } + }, + "block": 4982032, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:40:06", + "virtual_op": true, + "operation_id": "21397664507626048", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013920707", + "precision": 6 + } + } + }, + "block": 4982004, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:38:39", + "virtual_op": true, + "operation_id": "21397544248542016", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013923991", + "precision": 6 + } + } + }, + "block": 4981998, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:38:21", + "virtual_op": true, + "operation_id": "21397518478738240", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013937977", + "precision": 6 + } + } + }, + "block": 4981973, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:37:06", + "virtual_op": true, + "operation_id": "21397411104555072", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013955794", + "precision": 6 + } + } + }, + "block": 4981941, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:35:30", + "virtual_op": true, + "operation_id": "21397273665601856", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013965098", + "precision": 6 + } + } + }, + "block": 4981924, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:34:39", + "virtual_op": true, + "operation_id": "21397200651157568", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013971118", + "precision": 6 + } + } + }, + "block": 4981913, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:34:06", + "virtual_op": true, + "operation_id": "21397153406518848", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013987964", + "precision": 6 + } + } + }, + "block": 4981885, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:32:42", + "virtual_op": true, + "operation_id": "21397033147433280", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3013995079", + "precision": 6 + } + } + }, + "block": 4981872, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:32:03", + "virtual_op": true, + "operation_id": "21396977312858688", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014016486", + "precision": 6 + } + } + }, + "block": 4981834, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:30:09", + "virtual_op": true, + "operation_id": "21396814104101440", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014021411", + "precision": 6 + } + } + }, + "block": 4981825, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:29:42", + "virtual_op": true, + "operation_id": "21396775449395776", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014039230", + "precision": 6 + } + } + }, + "block": 4981793, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:28:06", + "virtual_op": true, + "operation_id": "21396638010442816", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014047197", + "precision": 6 + } + } + }, + "block": 4981779, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:27:24", + "virtual_op": true, + "operation_id": "21396577880900928", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5030444771", + "precision": 6 + }, + "worker": "abit" + } + }, + "block": 4981779, + "trx_id": "fd069f532c0fedc78350bff449929379594ddd8d", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T04:27:24", + "virtual_op": true, + "operation_id": "21396577880900174", + "trx_in_block": 1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014054616", + "precision": 6 + } + } + }, + "block": 4981766, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:26:45", + "virtual_op": true, + "operation_id": "21396522046325056", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014076875", + "precision": 6 + } + } + }, + "block": 4981727, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:24:48", + "virtual_op": true, + "operation_id": "21396354542600768", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014081801", + "precision": 6 + } + } + }, + "block": 4981718, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:24:21", + "virtual_op": true, + "operation_id": "21396315887896896", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5030502526", + "precision": 6 + }, + "worker": "abit" + } + }, + "block": 4981718, + "trx_id": "e31cc6c7b75dbf93efcdb2ba490e582a754a3cce", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T04:24:21", + "virtual_op": true, + "operation_id": "21396315887895374", + "trx_in_block": 1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014091776", + "precision": 6 + } + } + }, + "block": 4981702, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:23:33", + "virtual_op": true, + "operation_id": "21396247168418624", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014106069", + "precision": 6 + } + } + }, + "block": 4981677, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:22:18", + "virtual_op": true, + "operation_id": "21396139794235712", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014119510", + "precision": 6 + } + } + }, + "block": 4981653, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:21:06", + "virtual_op": true, + "operation_id": "21396036715020864", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014135444", + "precision": 6 + } + } + }, + "block": 4981625, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:19:42", + "virtual_op": true, + "operation_id": "21395916455937344", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014139823", + "precision": 6 + } + } + }, + "block": 4981617, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:19:18", + "virtual_op": true, + "operation_id": "21395882096197696", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014154906", + "precision": 6 + } + } + }, + "block": 4981590, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:17:57", + "virtual_op": true, + "operation_id": "21395766132081216", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014171875", + "precision": 6 + } + } + }, + "block": 4981559, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:16:24", + "virtual_op": true, + "operation_id": "21395632988095296", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014175159", + "precision": 6 + } + } + }, + "block": 4981553, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:16:06", + "virtual_op": true, + "operation_id": "21395607218291776", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014188843", + "precision": 6 + } + } + }, + "block": 4981528, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:14:51", + "virtual_op": true, + "operation_id": "21395499844109120", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014200095", + "precision": 6 + } + } + }, + "block": 4981508, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:13:51", + "virtual_op": true, + "operation_id": "21395413944763456", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014215969", + "precision": 6 + } + } + }, + "block": 4981479, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:12:24", + "virtual_op": true, + "operation_id": "21395289390711616", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014227221", + "precision": 6 + } + } + }, + "block": 4981459, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:11:24", + "virtual_op": true, + "operation_id": "21395203491365184", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014240116", + "precision": 6 + } + } + }, + "block": 4981436, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:10:15", + "virtual_op": true, + "operation_id": "21395104707117888", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014248084", + "precision": 6 + } + } + }, + "block": 4981422, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:09:33", + "virtual_op": true, + "operation_id": "21395044577575488", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014261221", + "precision": 6 + } + } + }, + "block": 4981398, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:08:21", + "virtual_op": true, + "operation_id": "21394941498360384", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014272716", + "precision": 6 + } + } + }, + "block": 4981377, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:07:18", + "virtual_op": true, + "operation_id": "21394851304046656", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014280380", + "precision": 6 + } + } + }, + "block": 4981363, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:06:36", + "virtual_op": true, + "operation_id": "21394791174505024", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014300515", + "precision": 6 + } + } + }, + "block": 4981329, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:04:54", + "virtual_op": true, + "operation_id": "21394645145616960", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014302704", + "precision": 6 + } + } + }, + "block": 4981325, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:04:42", + "virtual_op": true, + "operation_id": "21394627965747776", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5030871214", + "precision": 6 + }, + "worker": "abit" + } + }, + "block": 4981325, + "trx_id": "f977e90eb13123cd1e57fbd457b0661e350f0b8d", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T04:04:42", + "virtual_op": true, + "operation_id": "21394627965747534", + "trx_in_block": 0 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014322230", + "precision": 6 + } + } + }, + "block": 4981291, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:03:00", + "virtual_op": true, + "operation_id": "21394481936859968", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014327461", + "precision": 6 + } + } + }, + "block": 4981282, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:02:33", + "virtual_op": true, + "operation_id": "21394443282154048", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014341756", + "precision": 6 + } + } + }, + "block": 4981257, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:01:18", + "virtual_op": true, + "operation_id": "21394335907971136", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014354347", + "precision": 6 + } + } + }, + "block": 4981234, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T04:00:09", + "virtual_op": true, + "operation_id": "21394237123724352", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014365843", + "precision": 6 + } + } + }, + "block": 4981213, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T03:59:06", + "virtual_op": true, + "operation_id": "21394146929410112", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "abit", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3014377339", + "precision": 6 + } + } + }, + "block": 4981192, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T03:58:03", + "virtual_op": true, + "operation_id": "21394056735097408", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5027981402", + "precision": 6 + }, + "worker": "abit" + } + }, + "block": 4981192, + "trx_id": "3dac4cc7d1bc5c01a5eca7aebff2af4b9fa3e7f5", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T03:58:03", + "virtual_op": true, + "operation_id": "21394056735097166", + "trx_in_block": 0 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml new file mode 100644 index 000000000..24e235152 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml @@ -0,0 +1,25 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_account" + method: POST + headers: + content-type: application/json + accept: application/json + json: + account-name: "abit" + transacting-account-name: "abit" + page: 1 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern -- GitLab From 8eac5362e1ad107b5fad59f4b41bb1a9137e93d3 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Fri, 18 Jul 2025 11:28:33 +0000 Subject: [PATCH 11/24] Add exclude filter for hivemind --- .../excluding_accounts.sql | 251 ++++++++++++++++++ scripts/install_app.sh | 1 + 2 files changed, 252 insertions(+) create mode 100644 queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql new file mode 100644 index 000000000..0294b96bc --- /dev/null +++ b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql @@ -0,0 +1,251 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.account_history_excluding_accounts( + _account_id INT, + _operations INT [], + _transacting_account_ids INT [], + _from_block INT, + _to_block INT, + _page INT, + _body_limit INT, + _limit INT +) +RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +COST 10000 +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 +AS +$$ +DECLARE + _result hafah_backend.operation[]; + _account_range hafah_backend.account_filter_return; + __max_page_count INT := 10; + + __total_pages INT; + __min_block_num INT; + __count INT; +BEGIN + -----------PAGING LOGIC---------------- + _account_range := hafah_backend.account_range(_operations, _account_id, _from_block, _to_block); + + -- Fetching operations + WITH excluded_ids AS MATERIALIZED ( + SELECT unnest(_transacting_account_ids) AS id + ), + operation_range AS MATERIALIZED ( + SELECT + ls.operation_id AS id, + ls.block_num, + ls.op_type_id, + ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) + FROM ( + SELECT aov.operation_id, aov.op_type_id, aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + AND NOT EXISTS ( + SELECT 1 FROM excluded_ids e + WHERE e.id = aov.transacting_account_id + ) + ORDER BY aov.account_op_seq_no DESC + LIMIT (__max_page_count * _limit) + 1 -- by default operation filter is limited to 10 pages + -- The +1 is to check if there are more operations in block that are not included in the current page-range + ) ls + ), + -----------PAGING LOGIC---------------- + -- Calculating pages based on result set (operation_range) + -- there is corner case when the last two operations are in the same block + -- when generating next batch of pages, we may miss operations made in the same block + -- to prevent this, we check if the last two operations are in the same block + -- if there at least 2 operations in the same block, we fetch all operations in that block + -- and add them to the result set + -- and calculate pages based on the new result set + check_if_saturated AS ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN MAX(row_num) = (__max_page_count * _limit) + 1 THEN + (__max_page_count * _limit) + 1 + ELSE + NULL + END + ) AS count + FROM operation_range + ), + if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty + SELECT + orr.block_num + FROM operation_range orr + WHERE orr.row_num IN ( + (SELECT count FROM check_if_saturated), + (SELECT count - 1 FROM check_if_saturated) + ) + ), + block_check AS MATERIALIZED ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(block_num) + ELSE + NULL + END + ) AS block_num + FROM if_saturated_find_last_two_ops + ), + -- returns empty if the last two operations are not in the same block + -- if the last two operations are in the same block, next CTE returns all operations in that block + find_all_records_for_page AS ( -- if not saturated, returns empty + SELECT + aov.operation_id AS id, + aov.op_type_id, + aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT block_num FROM block_check) IS NOT NULL + AND aov.block_num = (SELECT block_num FROM block_check) + ) + AND NOT EXISTS ( + SELECT 1 FROM excluded_ids e + WHERE e.id = aov.transacting_account_id + ) + ), + union_operations AS MATERIALIZED ( + SELECT + id, + block_num, + op_type_id + FROM operation_range + WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row + AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) + -- if block_check is not NULL, exclude the operations from last block + -- operations from excluded block are fetched in find_all_records_for_page + UNION ALL + + SELECT + id, + block_num, + op_type_id + FROM find_all_records_for_page + ), + min_block_num AS ( + SELECT + MIN(block_num) AS block_num + FROM union_operations + ), + count_blocks AS MATERIALIZED ( + SELECT + COUNT(*) AS count + FROM union_operations + ), + calculate_pages AS MATERIALIZED ( + SELECT + total_pages, + offset_filter, + limit_filter + FROM hafah_backend.calculate_pages( + (SELECT count FROM count_blocks)::INT, + _page, + 'desc', + _limit + ) + ), + filter_page AS ( + SELECT * + FROM union_operations + ORDER BY id DESC + OFFSET (SELECT offset_filter FROM calculate_pages) + LIMIT (SELECT limit_filter FROM calculate_pages) + ), + -----------END PAGING LOGIC---------------- + -- join the operations with other necessary tables + join_tables AS ( + SELECT + ls.id, + ls.block_num, + ov.trx_in_block, + encode(htv.trx_hash, 'hex') AS trx_hash, + ov.op_pos, + ls.op_type_id, + ov.body, + hot.is_virtual + FROM ( + SELECT aov.id, aov.op_type_id, aov.block_num + FROM filter_page aov + ) ls + JOIN hive.operations_view ov ON ov.id = ls.id + JOIN hafd.operation_types hot ON hot.id = ls.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + ), + -- filter too long operation bodies + result_query AS ( + SELECT + (filtered_operations.composite).body, + filtered_operations.block_num, + filtered_operations.trx_hash, + filtered_operations.op_pos, + filtered_operations.op_type_id, + filtered_operations.created_at, + filtered_operations.is_virtual, + filtered_operations.id, + filtered_operations.trx_in_block + FROM ( + SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at + FROM join_tables ov + JOIN hive.blocks_view hb ON hb.num = ov.block_num + ) filtered_operations + ORDER BY filtered_operations.id DESC + ) + SELECT + (SELECT count FROM count_blocks), + (SELECT total_pages FROM calculate_pages), + (SELECT block_num FROM min_block_num), + ( + SELECT array_agg(rows ORDER BY rows.id::BIGINT DESC) + FROM ( + SELECT + s.body, + s.block_num, + s.trx_hash, + s.op_pos, + s.op_type_id, + s.created_at, + s.is_virtual, + s.id::TEXT, + s.trx_in_block::SMALLINT + FROM result_query s + ) rows + ) + INTO __count, __total_pages, __min_block_num, _result; + + -- 1. If the min block number is NULL - the result is empty - there are no results for whole provided range + -- 2. If the min block number is NOT NULL and pages are not fully saturated it means there is no more blocks to fetch + -- 3. (ELSE) If the min block number is NOT NULL - the result is not empty - there are results for the provided range + -- and the min block number can be used as filter in the next API call (as a to-block parameter) + _account_range.from_block := ( + CASE + WHEN __min_block_num IS NULL THEN _account_range.from_block + WHEN __min_block_num IS NOT NULL AND __min_block_num = 1 THEN 1 + WHEN __min_block_num IS NOT NULL AND __min_block_num != 1 AND __count < __max_page_count * _limit THEN _account_range.from_block + ELSE __min_block_num - 1 + END + ); + + ---------------------------------------- + RETURN ( + COALESCE(__count,0), + COALESCE(__total_pages,0), + (_account_range.from_block, _account_range.to_block)::hafah_backend.block_range_type, + COALESCE(_result, '{}'::hafah_backend.operation[]) + )::hafah_backend.account_operation_history; + +END +$$; + +RESET ROLE; diff --git a/scripts/install_app.sh b/scripts/install_app.sh index 62aa3d4ca..85f16dfc4 100755 --- a/scripts/install_app.sh +++ b/scripts/install_app.sh @@ -83,6 +83,7 @@ psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_res psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/account_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/default.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/recent_trades.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/trade_history.sql" -- GitLab From 313512030a0b77b020078ec21c58b4736c0f2a38 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Tue, 22 Jul 2025 11:02:37 +0000 Subject: [PATCH 12/24] Add including/excluding filter modes for transacting_account_id in get_ops_by_account API --- .../accounts/get_ops_by_account.sql | 32 ++- .../hafah_REST/types/participation_mode.sql | 21 ++ postgrest/hafah_rest_exceptions.sql | 14 + .../account_history/account_history.sql | 39 ++- .../filtering_functions/exclude_account.sql | 242 ++++++++++++++++++ .../filtering_functions/include_account.sql | 242 ++++++++++++++++++ .../including_accounts.sql | 4 +- scripts/install_app.sh | 3 + scripts/openapi_rewrite.sh | 1 + 9 files changed, 582 insertions(+), 16 deletions(-) create mode 100644 postgrest/hafah_REST/types/participation_mode.sql create mode 100644 queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql create mode 100644 queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index 3fc1ef2f4..5d5e23351 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -31,6 +31,20 @@ SET ROLE hafah_owner; default: NULL description: | Account to filter operations by, if provided only operations where the account is an author will be returned. + - in: query + name: participation-mode + required: false + schema: + $ref: '#/components/schemas/hafah_backend.participation_mode' + default: all + description: | + filter operations by: + + * `include` - List only operations where transacting_account_id was the author. + + * `exclude` - List only operations where transacting_account_id was not the author. + + * `all` - No filtering, transacting_account_id must be NULL. - in: query name: operation-types required: false @@ -194,6 +208,7 @@ DROP FUNCTION IF EXISTS hafah_endpoints.get_ops_by_account; CREATE OR REPLACE FUNCTION hafah_endpoints.get_ops_by_account( "account-name" TEXT, "transacting-account-name" TEXT = NULL, + "participation-mode" hafah_backend.participation_mode = 'all', "operation-types" TEXT = NULL, "page" INT = NULL, "page-size" INT = 100, @@ -207,7 +222,7 @@ LANGUAGE 'plpgsql' STABLE SET JIT = OFF SET join_collapse_limit = 16 SET from_collapse_limit = 16 -SET enable_hashjoin = OFF +SET plan_cache_mode = force_custom_plan AS $$ DECLARE @@ -217,6 +232,11 @@ DECLARE _operation_types INT[] := (SELECT string_to_array("operation-types", ',')::INT[]); BEGIN -- Validate inputs + PERFORM hafah_backend.validate_participation_mode("participation-mode","transacting-account-name"); + PERFORM hafah_python.validate_limit("page-size", 1000, 'page-size'); + PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); + PERFORM hafah_python.validate_negative_page("page"); + IF _account_id IS NULL THEN PERFORM hafah_backend.rest_raise_missing_account("account-name"); END IF; @@ -225,10 +245,6 @@ BEGIN PERFORM hafah_backend.rest_raise_missing_account("transacting-account-name"); END IF; - PERFORM hafah_python.validate_limit("page-size", 1000, 'page-size'); - PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); - PERFORM hafah_python.validate_negative_page("page"); - IF (_block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL) THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); ELSE @@ -237,14 +253,16 @@ BEGIN RETURN hafah_backend.get_ops_by_account( _account_id, - ARRAY[_transacting_account_id], + -- in the current implementation, we only support a single transacting account, + -- we may extend this in the future to support multiple accounts + ARRAY[_transacting_account_id], _operation_types, _block_range.first_block, _block_range.last_block, "page", "data-size-limit", "page-size", - TRUE -- incluede account - flag determines if the transacting account's operations are included or excluded + "participation-mode" ); -- ops_count returns number of operations found with current filter diff --git a/postgrest/hafah_REST/types/participation_mode.sql b/postgrest/hafah_REST/types/participation_mode.sql new file mode 100644 index 000000000..1927d42a2 --- /dev/null +++ b/postgrest/hafah_REST/types/participation_mode.sql @@ -0,0 +1,21 @@ +SET ROLE hafah_owner; + +/** openapi:components:schemas +hafah_backend.participation_mode: + type: string + enum: + - include + - exclude + - all + + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.participation_mode CASCADE; +CREATE TYPE hafah_backend.participation_mode AS ENUM ( + 'include', + 'exclude', + 'all' +); +-- openapi-generated-code-end + +RESET ROLE; diff --git a/postgrest/hafah_rest_exceptions.sql b/postgrest/hafah_rest_exceptions.sql index b058eb1c9..833026f51 100644 --- a/postgrest/hafah_rest_exceptions.sql +++ b/postgrest/hafah_rest_exceptions.sql @@ -108,4 +108,18 @@ END $$ ; +CREATE OR REPLACE FUNCTION hafah_backend.validate_participation_mode(_mode hafah_backend.participation_mode, _account_name TEXT) +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + IF _mode = 'all' AND _account_name IS NOT NULL THEN + RAISE EXCEPTION 'For participation mode ''all'', account name should not be provided'; + END IF; +END +$$ +; + RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/account_history.sql b/queries/hafah_rest_backend/account_history/account_history.sql index 0a7a19bad..49c95fda9 100644 --- a/queries/hafah_rest_backend/account_history/account_history.sql +++ b/queries/hafah_rest_backend/account_history/account_history.sql @@ -9,7 +9,7 @@ CREATE OR REPLACE FUNCTION hafah_backend.get_ops_by_account( _page INT, _body_limit INT, _limit INT, - _include_accounts BOOLEAN DEFAULT TRUE + _participation_mode hafah_backend.participation_mode ) RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 LANGUAGE 'plpgsql' STABLE @@ -19,12 +19,13 @@ DECLARE _result hafah_backend.account_operation_history; -- flags + _filter_by_account_ids BOOLEAN := (_filter_account_ids != ARRAY[NULL]::INT[]); + _filter_by_single_acc BOOLEAN := (CASE WHEN (_filter_account_ids != ARRAY[NULL]::INT[]) AND (array_length(_filter_account_ids, 1) = 1) THEN TRUE ELSE FALSE END); _filter_by_op BOOLEAN:= (_operations IS NOT NULL); - _filter_by_account BOOLEAN := (_filter_account_ids != ARRAY[NULL]::INT[]); BEGIN CASE -- If no filters are applied, use the default account history function - WHEN (NOT _filter_by_account) AND (NOT _filter_by_op) THEN + WHEN (NOT _filter_by_account_ids) AND (NOT _filter_by_op) THEN _result := hafah_backend.account_history_default( _account_id, _from_block, @@ -35,7 +36,7 @@ BEGIN ); -- If only operations are filtered, use the account history by operations function - WHEN (NOT _filter_by_account) AND (_filter_by_op) THEN + WHEN (NOT _filter_by_account_ids) AND (_filter_by_op) THEN _result := hafah_backend.account_history_by_operations( _account_id, _operations, @@ -45,9 +46,33 @@ BEGIN _body_limit, _limit ); - -- If accounts are filtered, use the account history by accounts function (including accounts) - WHEN (_filter_by_account) AND (_include_accounts) THEN + -- If accounts are filtered, use the account history by accounts function (include account) + WHEN (_participation_mode = 'include') AND (_filter_by_account_ids) AND (_filter_by_single_acc) THEN + _result := hafah_backend.account_history_include_account( + _account_id, + _operations, + _filter_account_ids[1], + _from_block, + _to_block, + _page, + _body_limit, + _limit + ); + -- If accounts are filtered, use the account history by accounts function (include accounts) + WHEN (_participation_mode = 'include') AND (_filter_by_account_ids) AND (NOT _filter_by_single_acc) THEN _result := hafah_backend.account_history_including_accounts( + _account_id, + _operations, + _filter_account_ids, + _from_block, + _to_block, + _page, + _body_limit, + _limit + ); + -- If accounts are filtered, use the account history by accounts function (exclude account) + WHEN (_participation_mode = 'exclude') AND (_filter_by_account_ids) AND (_filter_by_single_acc) THEN + _result := hafah_backend.account_history_exclude_account( _account_id, _operations, _filter_account_ids[1], @@ -58,7 +83,7 @@ BEGIN _limit ); -- If accounts are filtered, use the account history by accounts function (excluding accounts) - WHEN (_filter_by_account) AND (NOT _include_accounts) THEN + WHEN (_participation_mode = 'exclude') AND (_filter_by_account_ids) AND (NOT _filter_by_single_acc) THEN _result := hafah_backend.account_history_excluding_accounts( _account_id, _operations, diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql new file mode 100644 index 000000000..b21e37210 --- /dev/null +++ b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql @@ -0,0 +1,242 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.account_history_exclude_account( + _account_id INT, + _operations INT [], + _transacting_account_id INT, + _from_block INT, + _to_block INT, + _page INT, + _body_limit INT, + _limit INT +) +RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +COST 10000 +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 +AS +$$ +DECLARE + _result hafah_backend.operation[]; + _account_range hafah_backend.account_filter_return; + __max_page_count INT := 10; + + __total_pages INT; + __min_block_num INT; + __count INT; +BEGIN + -----------PAGING LOGIC---------------- + _account_range := hafah_backend.account_range(_operations, _account_id, _from_block, _to_block); + + -- Fetching operations + WITH operation_range AS MATERIALIZED ( + SELECT + ls.operation_id AS id, + ls.block_num, + ls.op_type_id, + ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) + FROM ( + SELECT aov.operation_id, aov.op_type_id, aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.transacting_account_id != _transacting_account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + ORDER BY aov.account_op_seq_no DESC + LIMIT (__max_page_count * _limit) + 1 -- by default operation filter is limited to 10 pages + -- The +1 is to check if there are more operations in block that are not included in the current page-range + ) ls + ), + -----------PAGING LOGIC---------------- + -- Calculating pages based on result set (operation_range) + -- there is corner case when the last two operations are in the same block + -- when generating next batch of pages, we may miss operations made in the same block + -- to prevent this, we check if the last two operations are in the same block + -- if there at least 2 operations in the same block, we fetch all operations in that block + -- and add them to the result set + -- and calculate pages based on the new result set + check_if_saturated AS ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN MAX(row_num) = (__max_page_count * _limit) + 1 THEN + (__max_page_count * _limit) + 1 + ELSE + NULL + END + ) AS count + FROM operation_range + ), + if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty + SELECT + orr.block_num + FROM operation_range orr + WHERE orr.row_num IN ( + (SELECT count FROM check_if_saturated), + (SELECT count - 1 FROM check_if_saturated) + ) + ), + block_check AS MATERIALIZED ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(block_num) + ELSE + NULL + END + ) AS block_num + FROM if_saturated_find_last_two_ops + ), + -- returns empty if the last two operations are not in the same block + -- if the last two operations are in the same block, next CTE returns all operations in that block + find_all_records_for_page AS ( -- if not saturated, returns empty + SELECT + aov.operation_id AS id, + aov.op_type_id, + aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.transacting_account_id = _transacting_account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT block_num FROM block_check) IS NOT NULL + AND aov.block_num = (SELECT block_num FROM block_check) + ) + ), + union_operations AS MATERIALIZED ( + SELECT + id, + block_num, + op_type_id + FROM operation_range + WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row + AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) + -- if block_check is not NULL, exclude the operations from last block + -- operations from excluded block are fetched in find_all_records_for_page + UNION ALL + + SELECT + id, + block_num, + op_type_id + FROM find_all_records_for_page + ), + min_block_num AS ( + SELECT + MIN(block_num) AS block_num + FROM union_operations + ), + count_blocks AS MATERIALIZED ( + SELECT + COUNT(*) AS count + FROM union_operations + ), + calculate_pages AS MATERIALIZED ( + SELECT + total_pages, + offset_filter, + limit_filter + FROM hafah_backend.calculate_pages( + (SELECT count FROM count_blocks)::INT, + _page, + 'desc', + _limit + ) + ), + filter_page AS ( + SELECT * + FROM union_operations + ORDER BY id DESC + OFFSET (SELECT offset_filter FROM calculate_pages) + LIMIT (SELECT limit_filter FROM calculate_pages) + ), + -----------END PAGING LOGIC---------------- + -- join the operations with other necessary tables + join_tables AS ( + SELECT + ls.id, + ls.block_num, + ov.trx_in_block, + encode(htv.trx_hash, 'hex') AS trx_hash, + ov.op_pos, + ls.op_type_id, + ov.body, + hot.is_virtual + FROM ( + SELECT aov.id, aov.op_type_id, aov.block_num + FROM filter_page aov + ) ls + JOIN hive.operations_view ov ON ov.id = ls.id + JOIN hafd.operation_types hot ON hot.id = ls.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + ), + -- filter too long operation bodies + result_query AS ( + SELECT + (filtered_operations.composite).body, + filtered_operations.block_num, + filtered_operations.trx_hash, + filtered_operations.op_pos, + filtered_operations.op_type_id, + filtered_operations.created_at, + filtered_operations.is_virtual, + filtered_operations.id, + filtered_operations.trx_in_block + FROM ( + SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at + FROM join_tables ov + JOIN hive.blocks_view hb ON hb.num = ov.block_num + ) filtered_operations + ORDER BY filtered_operations.id DESC + ) + SELECT + (SELECT count FROM count_blocks), + (SELECT total_pages FROM calculate_pages), + (SELECT block_num FROM min_block_num), + ( + SELECT array_agg(rows ORDER BY rows.id::BIGINT DESC) + FROM ( + SELECT + s.body, + s.block_num, + s.trx_hash, + s.op_pos, + s.op_type_id, + s.created_at, + s.is_virtual, + s.id::TEXT, + s.trx_in_block::SMALLINT + FROM result_query s + ) rows + ) + INTO __count, __total_pages, __min_block_num, _result; + + -- 1. If the min block number is NULL - the result is empty - there are no results for whole provided range + -- 2. If the min block number is NOT NULL and pages are not fully saturated it means there is no more blocks to fetch + -- 3. (ELSE) If the min block number is NOT NULL - the result is not empty - there are results for the provided range + -- and the min block number can be used as filter in the next API call (as a to-block parameter) + _account_range.from_block := ( + CASE + WHEN __min_block_num IS NULL THEN _account_range.from_block + WHEN __min_block_num IS NOT NULL AND __min_block_num = 1 THEN 1 + WHEN __min_block_num IS NOT NULL AND __min_block_num != 1 AND __count < __max_page_count * _limit THEN _account_range.from_block + ELSE __min_block_num - 1 + END + ); + + ---------------------------------------- + RETURN ( + COALESCE(__count,0), + COALESCE(__total_pages,0), + (_account_range.from_block, _account_range.to_block)::hafah_backend.block_range_type, + COALESCE(_result, '{}'::hafah_backend.operation[]) + )::hafah_backend.account_operation_history; + +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql b/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql new file mode 100644 index 000000000..102b33eb9 --- /dev/null +++ b/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql @@ -0,0 +1,242 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.account_history_include_account( + _account_id INT, + _operations INT [], + _transacting_account_id INT, + _from_block INT, + _to_block INT, + _page INT, + _body_limit INT, + _limit INT +) +RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +COST 10000 +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 +AS +$$ +DECLARE + _result hafah_backend.operation[]; + _account_range hafah_backend.account_filter_return; + __max_page_count INT := 10; + + __total_pages INT; + __min_block_num INT; + __count INT; +BEGIN + -----------PAGING LOGIC---------------- + _account_range := hafah_backend.account_range(_operations, _account_id, _from_block, _to_block); + + -- Fetching operations + WITH operation_range AS MATERIALIZED ( + SELECT + ls.operation_id AS id, + ls.block_num, + ls.op_type_id, + ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) + FROM ( + SELECT aov.operation_id, aov.op_type_id, aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.transacting_account_id = _transacting_account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + ORDER BY aov.account_op_seq_no DESC + LIMIT (__max_page_count * _limit) + 1 -- by default operation filter is limited to 10 pages + -- The +1 is to check if there are more operations in block that are not included in the current page-range + ) ls + ), + -----------PAGING LOGIC---------------- + -- Calculating pages based on result set (operation_range) + -- there is corner case when the last two operations are in the same block + -- when generating next batch of pages, we may miss operations made in the same block + -- to prevent this, we check if the last two operations are in the same block + -- if there at least 2 operations in the same block, we fetch all operations in that block + -- and add them to the result set + -- and calculate pages based on the new result set + check_if_saturated AS ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN MAX(row_num) = (__max_page_count * _limit) + 1 THEN + (__max_page_count * _limit) + 1 + ELSE + NULL + END + ) AS count + FROM operation_range + ), + if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty + SELECT + orr.block_num + FROM operation_range orr + WHERE orr.row_num IN ( + (SELECT count FROM check_if_saturated), + (SELECT count - 1 FROM check_if_saturated) + ) + ), + block_check AS MATERIALIZED ( -- if not saturated, returns empty + SELECT ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(block_num) + ELSE + NULL + END + ) AS block_num + FROM if_saturated_find_last_two_ops + ), + -- returns empty if the last two operations are not in the same block + -- if the last two operations are in the same block, next CTE returns all operations in that block + find_all_records_for_page AS ( -- if not saturated, returns empty + SELECT + aov.operation_id AS id, + aov.op_type_id, + aov.block_num + FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id + AND aov.transacting_account_id = _transacting_account_id + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.account_op_seq_no >= _account_range.from_seq + AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT block_num FROM block_check) IS NOT NULL + AND aov.block_num = (SELECT block_num FROM block_check) + ) + ), + union_operations AS MATERIALIZED ( + SELECT + id, + block_num, + op_type_id + FROM operation_range + WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row + AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) + -- if block_check is not NULL, exclude the operations from last block + -- operations from excluded block are fetched in find_all_records_for_page + UNION ALL + + SELECT + id, + block_num, + op_type_id + FROM find_all_records_for_page + ), + min_block_num AS ( + SELECT + MIN(block_num) AS block_num + FROM union_operations + ), + count_blocks AS MATERIALIZED ( + SELECT + COUNT(*) AS count + FROM union_operations + ), + calculate_pages AS MATERIALIZED ( + SELECT + total_pages, + offset_filter, + limit_filter + FROM hafah_backend.calculate_pages( + (SELECT count FROM count_blocks)::INT, + _page, + 'desc', + _limit + ) + ), + filter_page AS ( + SELECT * + FROM union_operations + ORDER BY id DESC + OFFSET (SELECT offset_filter FROM calculate_pages) + LIMIT (SELECT limit_filter FROM calculate_pages) + ), + -----------END PAGING LOGIC---------------- + -- join the operations with other necessary tables + join_tables AS ( + SELECT + ls.id, + ls.block_num, + ov.trx_in_block, + encode(htv.trx_hash, 'hex') AS trx_hash, + ov.op_pos, + ls.op_type_id, + ov.body, + hot.is_virtual + FROM ( + SELECT aov.id, aov.op_type_id, aov.block_num + FROM filter_page aov + ) ls + JOIN hive.operations_view ov ON ov.id = ls.id + JOIN hafd.operation_types hot ON hot.id = ls.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + ), + -- filter too long operation bodies + result_query AS ( + SELECT + (filtered_operations.composite).body, + filtered_operations.block_num, + filtered_operations.trx_hash, + filtered_operations.op_pos, + filtered_operations.op_type_id, + filtered_operations.created_at, + filtered_operations.is_virtual, + filtered_operations.id, + filtered_operations.trx_in_block + FROM ( + SELECT hafah_backend.operation_body_filter(ov.body, ov.id, _body_limit) as composite, ov.id, ov.block_num, ov.trx_in_block, ov.trx_hash, ov.op_pos, ov.op_type_id, ov.is_virtual, hb.created_at + FROM join_tables ov + JOIN hive.blocks_view hb ON hb.num = ov.block_num + ) filtered_operations + ORDER BY filtered_operations.id DESC + ) + SELECT + (SELECT count FROM count_blocks), + (SELECT total_pages FROM calculate_pages), + (SELECT block_num FROM min_block_num), + ( + SELECT array_agg(rows ORDER BY rows.id::BIGINT DESC) + FROM ( + SELECT + s.body, + s.block_num, + s.trx_hash, + s.op_pos, + s.op_type_id, + s.created_at, + s.is_virtual, + s.id::TEXT, + s.trx_in_block::SMALLINT + FROM result_query s + ) rows + ) + INTO __count, __total_pages, __min_block_num, _result; + + -- 1. If the min block number is NULL - the result is empty - there are no results for whole provided range + -- 2. If the min block number is NOT NULL and pages are not fully saturated it means there is no more blocks to fetch + -- 3. (ELSE) If the min block number is NOT NULL - the result is not empty - there are results for the provided range + -- and the min block number can be used as filter in the next API call (as a to-block parameter) + _account_range.from_block := ( + CASE + WHEN __min_block_num IS NULL THEN _account_range.from_block + WHEN __min_block_num IS NOT NULL AND __min_block_num = 1 THEN 1 + WHEN __min_block_num IS NOT NULL AND __min_block_num != 1 AND __count < __max_page_count * _limit THEN _account_range.from_block + ELSE __min_block_num - 1 + END + ); + + ---------------------------------------- + RETURN ( + COALESCE(__count,0), + COALESCE(__total_pages,0), + (_account_range.from_block, _account_range.to_block)::hafah_backend.block_range_type, + COALESCE(_result, '{}'::hafah_backend.operation[]) + )::hafah_backend.account_operation_history; + +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql index f60cab0ef..2fe90bc28 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql @@ -3,7 +3,7 @@ SET ROLE hafah_owner; CREATE OR REPLACE FUNCTION hafah_backend.account_history_including_accounts( _account_id INT, _operations INT [], - _transacting_account_id INT, + _transacting_account_ids INT [], _from_block INT, _to_block INT, _page INT, @@ -41,7 +41,7 @@ BEGIN SELECT aov.operation_id, aov.op_type_id, aov.block_num FROM hive.account_operations_view aov WHERE aov.account_id = _account_id - AND aov.transacting_account_id = _transacting_account_id + AND aov.transacting_account_id = ANY(_transacting_account_ids) AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) AND aov.account_op_seq_no >= _account_range.from_seq AND aov.account_op_seq_no <= _account_range.to_seq diff --git a/scripts/install_app.sh b/scripts/install_app.sh index 85f16dfc4..4be54e5ca 100755 --- a/scripts/install_app.sh +++ b/scripts/install_app.sh @@ -79,12 +79,15 @@ psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_R psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/block.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/transaction.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/fill_order.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/participation_mode.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/paging.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/account_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/default.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/recent_trades.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/trade_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/acc_op_types.sql" diff --git a/scripts/openapi_rewrite.sh b/scripts/openapi_rewrite.sh index 22b4a0bae..47eed7ee8 100755 --- a/scripts/openapi_rewrite.sh +++ b/scripts/openapi_rewrite.sh @@ -20,6 +20,7 @@ ENDPOINTS_IN_ORDER=" ../$endpoints/types/block.sql ../$endpoints/types/transaction.sql ../$endpoints/types/fill_order.sql +../$endpoints/types/participation_mode.sql ../$endpoints/hafah_openapi.sql ../$endpoints/blocks/get_block_range.sql ../$endpoints/blocks/get_block.sql -- GitLab From eb6f5a420ddda789a3a1f8b3649f6d8e76e6d1af Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Tue, 22 Jul 2025 11:04:35 +0000 Subject: [PATCH 13/24] OpenAPI rewrite --- postgrest/hafah_REST/hafah_openapi.sql | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/postgrest/hafah_REST/hafah_openapi.sql b/postgrest/hafah_REST/hafah_openapi.sql index 16887ee4f..de9b9f02c 100644 --- a/postgrest/hafah_REST/hafah_openapi.sql +++ b/postgrest/hafah_REST/hafah_openapi.sql @@ -482,6 +482,14 @@ declare "$ref": "#/components/schemas/hafah_backend.fill_order" } }, + "hafah_backend.participation_mode": { + "type": "string", + "enum": [ + "include", + "exclude", + "all" + ] + }, "hafah_backend.array_of_block_range": { "type": "array", "items": { @@ -1664,6 +1672,16 @@ declare }, "description": "Account to filter operations by, if provided only operations where the account is an author will be returned.\n" }, + { + "in": "query", + "name": "participation-mode", + "required": false, + "schema": { + "$ref": "#/components/schemas/hafah_backend.participation_mode", + "default": "all" + }, + "description": "filter operations by:\n\n * `include` - List only operations where transacting_account_id was the author.\n\n * `exclude` - List only operations where transacting_account_id was not the author.\n\n * `all` - No filtering, transacting_account_id must be NULL.\n" + }, { "in": "query", "name": "operation-types", -- GitLab From 51626a7bcbc1f17f92127d899fc18e65c4119074 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Tue, 22 Jul 2025 11:11:24 +0000 Subject: [PATCH 14/24] Extend tests for include/exclude filters --- ...orner_case_transacting_account.tavern.yaml | 1 + .../filter_by_transacting_account.tavern.yaml | 1 + .../transacting_account_exclude.pat.json | 2180 +++++++++++++++++ .../transacting_account_exclude.tavern.yaml | 25 + 4 files changed, 2207 insertions(+) create mode 100644 tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json create mode 100644 tests/tavern/get_ops_by_account/positive/transacting_account_exclude.tavern.yaml diff --git a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml index 24e235152..b9f96ac9d 100644 --- a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml +++ b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml @@ -18,6 +18,7 @@ json: account-name: "abit" transacting-account-name: "abit" + participation-mode: "include" page: 1 response: status_code: 200 diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml index 7ef854bf8..1d0d9a4a6 100644 --- a/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml +++ b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.tavern.yaml @@ -18,6 +18,7 @@ json: account-name: "blocktrades" transacting-account-name: "gtg" + participation-mode: "include" response: status_code: 200 verify_response_with: diff --git a/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json new file mode 100644 index 000000000..b88fe923b --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json @@ -0,0 +1,2180 @@ +{ + "total_operations": 999, + "total_pages": 10, + "block_range": { + "from": 1, + "to": 5000000 + }, + "operations_result": [ + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "mrwang", + "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", + "amount": { + "nai": "@@000000013", + "amount": "1633", + "precision": 3 + } + } + }, + "block": 4999997, + "trx_id": "e75f833ceb62570c25504b55d0f23d86d9d76423", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T19:47:12", + "virtual_op": false, + "operation_id": "21474823595099394", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "condra", + "memo": "f2c3419c-9522-4bb3-aa41-472c8388f215", + "amount": { + "nai": "@@000000013", + "amount": "400000", + "precision": 3 + } + } + }, + "block": 4999607, + "trx_id": "2577322e21a18f9085cc5dba366b5292824f906b", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T19:26:42", + "virtual_op": false, + "operation_id": "21473148557854722", + "trx_in_block": 5 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "thisisbenbrick", + "memo": "0722aa82-10d0-4001-a286-130b633d58df", + "amount": { + "nai": "@@000000013", + "amount": "431587", + "precision": 3 + } + } + }, + "block": 4996294, + "trx_id": "01de85e061adde226a7ce59071973c9daaeca8ba", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T16:34:45", + "virtual_op": false, + "operation_id": "21458919331201538", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "roelandp", + "memo": "298eafac-95bb-4f27-b256-72df9d0ef222", + "amount": { + "nai": "@@000000021", + "amount": "148056", + "precision": 3 + } + } + }, + "block": 4996091, + "trx_id": "b1aa3d5f9308acd9cde664936c1b08eea77c3e49", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T16:24:36", + "virtual_op": false, + "operation_id": "21458047452841986", + "trx_in_block": 4 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "It just occurred to me that witness updates like this could make for interesting video material. Maybe a segment in our SteemSmart show?", + "title": "", + "author": "piedpiper", + "permlink": "re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160915t161707257z", + "json_metadata": "{\"tags\":[\"witness-category\"]}", + "parent_author": "blocktrades", + "parent_permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4995964, + "trx_id": "3ae419f4d37860c7d2dabec530ccf3ad79e79784", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T16:18:15", + "virtual_op": false, + "operation_id": "21457501991994369", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "macksby", + "memo": "92bff29e-2ee9-4ea4-ace1-6bb0c1331f67", + "amount": { + "nai": "@@000000013", + "amount": "50000", + "precision": 3 + } + } + }, + "block": 4994778, + "trx_id": "f2c59d933ba1fc08bd6f4c79ec52a0aeed6bb9e9", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T15:18:54", + "virtual_op": false, + "operation_id": "21452408160780290", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "good-karma", + "memo": "0c9ca5aa-53c2-445e-912f-d2cf6b111229", + "amount": { + "nai": "@@000000013", + "amount": "1500000", + "precision": 3 + } + } + }, + "block": 4994642, + "trx_id": "15a50977270c3b7e4e97715989f03099375b59bb", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T15:12:06", + "virtual_op": false, + "operation_id": "21451824045228034", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "blackjincrypto", + "memo": "7639138f-62f0-492a-b8e7-bad1add506dd", + "amount": { + "nai": "@@000000021", + "amount": "24838", + "precision": 3 + } + } + }, + "block": 4993122, + "trx_id": "a6e9f45a9b8fb6cd565936f64e13ae5b12ac94f2", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T13:56:03", + "virtual_op": false, + "operation_id": "21445295694938114", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "pakganern", + "author": "blocktrades", + "weight": 0, + "rshares": 2913900118, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august", + "pending_payout": { + "nai": "@@000000013", + "amount": "75", + "precision": 3 + }, + "total_vote_weight": 0 + } + }, + "block": 4987311, + "trx_id": "b89762657465f62895ff3c8acab554a69a5bab1e", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T09:04:45", + "virtual_op": true, + "operation_id": "21420337639983176", + "trx_in_block": 4 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "pakganern", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4987311, + "trx_id": "b89762657465f62895ff3c8acab554a69a5bab1e", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T09:04:45", + "virtual_op": false, + "operation_id": "21420337639982848", + "trx_in_block": 4 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "schro", + "memo": "d70dfb8e-277a-4070-9812-b38cf01579cf", + "amount": { + "nai": "@@000000021", + "amount": "126225", + "precision": 3 + } + } + }, + "block": 4986680, + "trx_id": "68656136a5cff365a0c5ab873a60a3cf7528e47c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T08:32:54", + "virtual_op": false, + "operation_id": "21417627515617282", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "aaronkoenig", + "memo": "b4c499fb-5deb-44dc-9646-e7feb3927e12", + "amount": { + "nai": "@@000000013", + "amount": "48000", + "precision": 3 + } + } + }, + "block": 4985503, + "trx_id": "2c918ba666c06946a792657b27ed18af196dfab5", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T07:34:00", + "virtual_op": false, + "operation_id": "21412572339109890", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "jeremyfromwi", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4984971, + "trx_id": "21b12d2246e1ceb0cedba3b04a504bb58d52b0d5", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T07:07:15", + "virtual_op": false, + "operation_id": "21410287416508684", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "cryptomental", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4984843, + "trx_id": "8c311c43f7dd1ddaa713aa6cb2f9d8dde96141bd", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T07:00:51", + "virtual_op": false, + "operation_id": "21409737660695052", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "I am not sure, but it is not funny anymore because I see the 12 points every time. Maybe my brain just recorded the pattern and remember it. I can not switch back again.\nAlso is truth that I work with crystal simetry pattern daily, so, maybe my brain is trained to see patterns and keep it. Also, in this occasion, I knew what was looking for...\nThis make me think how different we perceive the universe around us... Even when everybody is seeing the same thing...", + "title": "", + "author": "quigua", + "permlink": "re-blocktrades-re-quigua-re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t054809925z", + "json_metadata": "{\"tags\":[\"optical\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-quigua-re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t050900278z" + } + }, + "block": 4983394, + "trx_id": "5824e046a9235be9ba99440e3e8eb99860e8a63a", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T05:48:15", + "virtual_op": false, + "operation_id": "21403514253082625", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "therajmahal", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4982233, + "trx_id": "7df8d151a3c06fb31a6b902d80885d4a6ca5c1ab", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T04:50:09", + "virtual_op": false, + "operation_id": "21398527796051980", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "At first, I couldn't see more than 4 points at the same time. But, then I follow all points with the eyes making a circle pattern during 15 seconds, and surprising!. I can see the 12 points, and now I can not see the blinking points again. That is really crazy...", + "title": "", + "author": "quigua", + "permlink": "re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t044305573z", + "json_metadata": "{\"tags\":[\"optical\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t034947752z" + } + }, + "block": 4982094, + "trx_id": "40ae1f796b8d0409a799fe62b3b423972b83c9e5", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T04:43:12", + "virtual_op": false, + "operation_id": "21397930795598081", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "rishi556", + "memo": " 50c8c0c0-c9f6-41c3-ace1-791567e5c1ba", + "amount": { + "nai": "@@000000013", + "amount": "105", + "precision": 3 + } + } + }, + "block": 4980808, + "trx_id": "083fc2207f29a78e907e5865911cf7d62910fd21", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T03:38:48", + "virtual_op": false, + "operation_id": "21392407467656706", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "stackcats", + "memo": "b163536b-4058-4187-96c6-ac9f573088ae", + "amount": { + "nai": "@@000000021", + "amount": "57873", + "precision": 3 + } + } + }, + "block": 4980626, + "trx_id": "5ac596f0c2b61dcffc2aed0d70858b0d36d32b91", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T03:29:42", + "virtual_op": false, + "operation_id": "21391625783608834", + "trx_in_block": 3 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "acidyo", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4980106, + "trx_id": "cf47b1bdf8d3f9a84cbb88931900242a7725f7c1", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T03:03:39", + "virtual_op": false, + "operation_id": "21389392400613388", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "ranko-k", + "memo": "59824378-b1af-44ab-a181-a150ace86aa5", + "amount": { + "nai": "@@000000021", + "amount": "29421", + "precision": 3 + } + } + }, + "block": 4977199, + "trx_id": "015a69792b3d1ce6964a656f829d1d0b9ac1fd18", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T00:38:18", + "virtual_op": false, + "operation_id": "21376906930683906", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "theb0red1", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4974156, + "trx_id": "706d118879820969cd2056bf7c72cb16f952a952", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T22:06:00", + "virtual_op": false, + "operation_id": "21363837345203724", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "@@ -399,16 +399,17 @@\n nts will\n+,\n too, an\n", + "title": "", + "author": "slammr76", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t203223509z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4972329, + "trx_id": "f66ba76505558234d1532ad9030d349236b7ab85", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T20:34:30", + "virtual_op": false, + "operation_id": "21355990439952897", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Right now, Steem has value because you can exchange it for bitcoin. I don't have to exchange bitcoin for fiat for it to have value for me, even though the merchants accepting it are likely exchanging it for fiat. I can and do spend bitcoin all the time. I've never exchanged it for fiat but have always exchanged dollars for bitcoin. I prefer to have my weath stored in bitcoin. Someday, the merchants will too, and few will care what the exchange rate for bitcoin vs fiat is.", + "title": "", + "author": "slammr76", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t203223509z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4972289, + "trx_id": "34146d0288ea9070d2da2be5e191bb7c1885724e", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T20:32:30", + "virtual_op": false, + "operation_id": "21355818641261057", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "kranartz", + "memo": " 7702e0f5-8ab7-46d1-bbda-29d21c368160", + "amount": { + "nai": "@@000000013", + "amount": "1123", + "precision": 3 + } + } + }, + "block": 4971843, + "trx_id": "6412bb9abeec1f6e5027c11a165fa919fc233f03", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T20:10:12", + "virtual_op": false, + "operation_id": "21353903085846530", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "fatboy", + "memo": " 771b11ac-47f7-4b2f-b50a-71266e9b4026", + "amount": { + "nai": "@@000000013", + "amount": "28350", + "precision": 3 + } + } + }, + "block": 4971577, + "trx_id": "8b39da57e049a4f2d28eac4565183904a8765648", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:56:54", + "virtual_op": false, + "operation_id": "21352760624547330", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "fatboy", + "memo": " 9c0bf334-d8df-40bb-8002-409c03cf230f", + "amount": { + "nai": "@@000000021", + "amount": "22663", + "precision": 3 + } + } + }, + "block": 4971507, + "trx_id": "f817700f21c9c97b06eb61beb6eff948fb7ad07c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:53:24", + "virtual_op": false, + "operation_id": "21352459976835074", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "anasz", + "memo": " 9f6e1027-9d03-4785-90d4-04fe4dd29b5e", + "amount": { + "nai": "@@000000013", + "amount": "16000", + "precision": 3 + } + } + }, + "block": 4971215, + "trx_id": "a21a7bfb210848c0c7d73d4a799a3cd6757d66d3", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:38:48", + "virtual_op": false, + "operation_id": "21351205846385154", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "gomeravibz", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4971093, + "trx_id": "f0a69def7eba73ee3ccd9a92dd915ee3eacc2b6a", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T19:32:39", + "virtual_op": false, + "operation_id": "21350681860375564", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "shaneradliff", + "memo": "7f208b66-5a77-48a5-92fb-bd9fbc5fd50c", + "amount": { + "nai": "@@000000013", + "amount": "1300", + "precision": 3 + } + } + }, + "block": 4970678, + "trx_id": "0fa231ee90f74305cab404aaabac6654050b5df9", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:11:21", + "virtual_op": false, + "operation_id": "21348899448947458", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "anasz", + "memo": "314ae1d5-c9e9-4a21-8cb0-48cf6d2a3ccb", + "amount": { + "nai": "@@000000013", + "amount": "10000", + "precision": 3 + } + } + }, + "block": 4969806, + "trx_id": "3fee1c9286faaa4abec711e275f0e897ada9cb5f", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T18:25:36", + "virtual_op": false, + "operation_id": "21345154237465602", + "trx_in_block": 2 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Well, fiat money is worth something because you can use it to pay taxes.", + "title": "", + "author": "svamiva", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t175725339z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4969274, + "trx_id": "c6f8881aba4bc494f32cfffc15ad122b44c8d124", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:57:33", + "virtual_op": false, + "operation_id": "21342869314864129", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Thank you so much! I will remember this \").", + "title": "", + "author": "funny", + "permlink": "re-blocktrades-re-funny-re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t174018203z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t171338026z" + } + }, + "block": 4968948, + "trx_id": "26b80037ce89febd1c653fcbbbdf09faefc325b1", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:40:24", + "virtual_op": false, + "operation_id": "21341469155525121", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "You´re welcome :). Hehe, it´s always the last bit missing. Like the comments in this example :D", + "title": "", + "author": "lenatramper", + "permlink": "re-blocktrades-re-lenatramper-re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t173256475z", + "json_metadata": "{\"tags\":[\"adolf\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-lenatramper-re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t164216448z" + } + }, + "block": 4968805, + "trx_id": "2daac261fcc68c2461adc8524261bc11de614f3e", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:32:48", + "virtual_op": false, + "operation_id": "21340854975201281", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "good-karma", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4968789, + "trx_id": "07faf6e609944fa59dd2bdfe8fbc0c2270e83a4a", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T17:32:00", + "virtual_op": false, + "operation_id": "21340786255724556", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "mikemacintire", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4968546, + "trx_id": "ddfd6daa8550483afc8158b9926c7d1b1fa1f731", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T17:19:15", + "virtual_op": false, + "operation_id": "21339742578672396", + "trx_in_block": 2 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Hey @blocktrades, thanks for reading \"). \n\nAgreed, that was the point I was making, but with that statement, I meant it as you need a bridge to start. If everyone decided to adopt crypto tomorrow, and picked a few coins that we all used, then yes, you're right, it could work without fiat. \n\nAny chance you can upvote the post, I'm trying to build my account with steemit.", + "title": "", + "author": "funny", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t170230207z", + "json_metadata": "{\"tags\":[\"money\"],\"users\":[\"blocktrades\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4968231, + "trx_id": "f205fbcc8aee61419ad54982f3d594de07450a2a", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:02:36", + "virtual_op": false, + "operation_id": "21338389663973377", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "ziogio", + "memo": "92754b24-3405-434f-88ca-07ad5e74b089", + "amount": { + "nai": "@@000000013", + "amount": "10000", + "precision": 3 + } + } + }, + "block": 4967726, + "trx_id": "f620062399c31a45b339fb6ca2d8d3980a6bf747", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T16:37:03", + "virtual_op": false, + "operation_id": "21336220705488898", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Hi blocktrades,\n\nyou can check it here in the comments :)\nhttps://steemit.com/language/@lenatramper/top-10-hardest-languages-in-the-world-ranking", + "title": "", + "author": "lenatramper", + "permlink": "re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t160355256z", + "json_metadata": "{\"tags\":[\"adolf\"],\"links\":[\"https://steemit.com/language/@lenatramper/top-10-hardest-languages-in-the-world-ranking\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t155903950z" + } + }, + "block": 4967060, + "trx_id": "120b4917d02d628ae830fb480c1d049274489445", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T16:03:45", + "virtual_op": false, + "operation_id": "21333360257271553", + "trx_in_block": 4 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "juliac", + "memo": "0dba7938-f263-4da8-820e-8d883ddacff7", + "amount": { + "nai": "@@000000013", + "amount": "13334", + "precision": 3 + } + } + }, + "block": 4965170, + "trx_id": "515fca2bc83c7f460f18ec52457c0cd672826358", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T14:29:12", + "virtual_op": false, + "operation_id": "21325242769080322", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "blockchaingirl", + "memo": "6ebbb676-3fd8-4713-acbe-2f1d4da1a0b0", + "amount": { + "nai": "@@000000013", + "amount": "800000", + "precision": 3 + } + } + }, + "block": 4964407, + "trx_id": "cf4264043076e5af34318b9db392ccf469a66563", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T13:51:00", + "virtual_op": false, + "operation_id": "21321965709034498", + "trx_in_block": 2 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "solarguy", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4959174, + "trx_id": "6bd2741483e2659c957cb574b7fec5ba1fec25de", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T09:28:45", + "virtual_op": false, + "operation_id": "21299490145174284", + "trx_in_block": 2 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "royalmacro", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4957445, + "trx_id": "582159a7d6fa988594fe6f947bc73998fc655b14", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T08:02:00", + "virtual_op": false, + "operation_id": "21292064146721292", + "trx_in_block": 5 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "kaylinart", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4957104, + "trx_id": "8ce909995eaf91a2ed2676932000a4c7d4af80ad", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T07:44:54", + "virtual_op": false, + "operation_id": "21290599562870796", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "anasz", + "memo": "b16de592-76a1-485d-b8c8-4e8692f9803e", + "amount": { + "nai": "@@000000013", + "amount": "23", + "precision": 3 + } + } + }, + "block": 4954441, + "trx_id": "169310b87bfd1fde6ff207ea39ec09df7760391e", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T05:31:21", + "virtual_op": false, + "operation_id": "21279162064964098", + "trx_in_block": 5 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "bryner", + "memo": "4c93872a-7b82-42f3-b094-a54ab719c34c", + "amount": { + "nai": "@@000000021", + "amount": "8350", + "precision": 3 + } + } + }, + "block": 4952702, + "trx_id": "d7474d597f3cd27c895b477b1a7b1046888851d7", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T04:04:06", + "virtual_op": false, + "operation_id": "21271693116833794", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "theb0red1", + "author": "blocktrades", + "weight": "43666160499416273", + "rshares": 9491055943, + "permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z", + "pending_payout": { + "nai": "@@000000013", + "amount": "2", + "precision": 3 + }, + "total_vote_weight": "43666160499416273" + } + }, + "block": 4952567, + "trx_id": "182a7686346f290e1bf55d4a8e2474e5bd33697e", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-14T03:57:21", + "virtual_op": true, + "operation_id": "21271113296249672", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "theb0red1", + "author": "blocktrades", + "weight": 10000, + "permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z" + } + }, + "block": 4952567, + "trx_id": "182a7686346f290e1bf55d4a8e2474e5bd33697e", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-14T03:57:21", + "virtual_op": false, + "operation_id": "21271113296249344", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "themanualbot", + "memo": "a4f54c6d-bc77-404f-b4ce-8e3433fcc928", + "amount": { + "nai": "@@000000013", + "amount": "484185", + "precision": 3 + } + } + }, + "block": 4950730, + "trx_id": "aa54b0534c3e747051b5e88b620d9f8cd337c983", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T02:25:15", + "virtual_op": false, + "operation_id": "21263223441327618", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Ok, thanks!", + "title": "", + "author": "timcliff", + "permlink": "re-blocktrades-re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t015047838z", + "json_metadata": "{\"tags\":[\"poloniex\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z" + } + }, + "block": 4950046, + "trx_id": "a1467edcb59b7cf3cff77cd83c4af3ada0c4ffb6", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T01:50:51", + "virtual_op": false, + "operation_id": "21260285683696129", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "forrestwillie", + "memo": "34edb0f7-ad6f-4927-84ea-d5faf99f9e6e", + "amount": { + "nai": "@@000000021", + "amount": "66281", + "precision": 3 + } + } + }, + "block": 4949192, + "trx_id": "693841b51e3fe86929f71d5491fba422acbbae54", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T01:08:03", + "virtual_op": false, + "operation_id": "21256617781624834", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "shaneradliff", + "memo": "d1d42c18-b06f-4124-9c81-a4593dcea8cd", + "amount": { + "nai": "@@000000013", + "amount": "13000", + "precision": 3 + } + } + }, + "block": 4948215, + "trx_id": "1134409013de5dd70173d087edfe9763baec70ec", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T00:19:03", + "virtual_op": false, + "operation_id": "21252421598576642", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "wefdi", + "approve": false, + "witness": "blocktrades" + } + }, + "block": 4947057, + "trx_id": "b375567add15744604a2ab38d76ebeb82cb0e897", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T23:21:00", + "virtual_op": false, + "operation_id": "21247448026448908", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "lindee-hamner", + "memo": "3ecd1ed7-da35-4497-8106-92e26eff9103", + "amount": { + "nai": "@@000000021", + "amount": "22367", + "precision": 3 + } + } + }, + "block": 4946739, + "trx_id": "74bf8f7190a6a7e7c51692c27a0a8523e33e7821", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T23:05:03", + "virtual_op": false, + "operation_id": "21246082226847746", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "thisisbenbrick", + "memo": "2e62fd10-bd7b-43ee-a2a2-33324e576e93", + "amount": { + "nai": "@@000000021", + "amount": "766741", + "precision": 3 + } + } + }, + "block": 4946006, + "trx_id": "65c72bcffb05588cd274257969bee51f07d266d2", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T22:28:21", + "virtual_op": false, + "operation_id": "21242934015819778", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "mrwang", + "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", + "amount": { + "nai": "@@000000013", + "amount": "71475", + "precision": 3 + } + } + }, + "block": 4945986, + "trx_id": "555cc791ad80d0f025e6f7fa5965657c1e54b063", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T22:27:18", + "virtual_op": false, + "operation_id": "21242848116474882", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "yassinebentour", + "memo": "b9b4574a-220d-49ee-bf4e-6889df4e387c", + "amount": { + "nai": "@@000000021", + "amount": "1775", + "precision": 3 + } + } + }, + "block": 4944673, + "trx_id": "4e78a7c63beff4ffa7c715eae5c523231918d939", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T21:21:30", + "virtual_op": false, + "operation_id": "21237208824414978", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "furion", + "memo": "cffb8a8e-1f88-4654-945a-8888dcdac62a", + "amount": { + "nai": "@@000000021", + "amount": "50000", + "precision": 3 + } + } + }, + "block": 4943900, + "trx_id": "ee10f9357650aeaebfc4b34429b5465642edc41b", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T20:42:45", + "virtual_op": false, + "operation_id": "21233888814694402", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "dmilash", + "author": "blocktrades", + "weight": 0, + "rshares": 3144502568, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august", + "pending_payout": { + "nai": "@@000000013", + "amount": "82", + "precision": 3 + }, + "total_vote_weight": 0 + } + }, + "block": 4943618, + "trx_id": "c8bfb1ae741895c5d9ff90381faef14cb2bd9dc0", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-13T20:28:39", + "virtual_op": true, + "operation_id": "21232677633917768", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "dmilash", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4943618, + "trx_id": "c8bfb1ae741895c5d9ff90381faef14cb2bd9dc0", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T20:28:39", + "virtual_op": false, + "operation_id": "21232677633917440", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "vetvso", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4943513, + "trx_id": "18d12216537678f958f3e7e0c6550367d01a76fa", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T20:23:21", + "virtual_op": false, + "operation_id": "21232226662351116", + "trx_in_block": 1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "vetvso", + "author": "blocktrades", + "weight": 875968207384238, + "rshares": 190084642, + "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": 7199137524686013 + } + }, + "block": 4943368, + "trx_id": "fb9ee97aaafe8d8f0581a269d5f0ff2ca4c9ffa7", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-13T20:16:06", + "virtual_op": true, + "operation_id": "21231603892094536", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "vetvso", + "author": "blocktrades", + "weight": 10000, + "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" + } + }, + "block": 4943368, + "trx_id": "fb9ee97aaafe8d8f0581a269d5f0ff2ca4c9ffa7", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T20:16:06", + "virtual_op": false, + "operation_id": "21231603892094208", + "trx_in_block": 3 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "vetvso", + "author": "blocktrades", + "weight": 0, + "rshares": 198173350, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august", + "pending_payout": { + "nai": "@@000000013", + "amount": "81", + "precision": 3 + }, + "total_vote_weight": 0 + } + }, + "block": 4943233, + "trx_id": "596e450517c6f651b77492fc6a9ad3b1e46cf271", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-13T20:09:21", + "virtual_op": true, + "operation_id": "21231024071508296", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "vetvso", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4943233, + "trx_id": "596e450517c6f651b77492fc6a9ad3b1e46cf271", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T20:09:21", + "virtual_op": false, + "operation_id": "21231024071507968", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "novium", + "memo": " d48f47eb-5900-4a70-bfb3-a821ba90de30", + "amount": { + "nai": "@@000000013", + "amount": "40000", + "precision": 3 + } + } + }, + "block": 4942698, + "trx_id": "c38b4cf8d260ec43b48c55f3613428e5adb3dc93", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T19:42:33", + "virtual_op": false, + "operation_id": "21228726264005378", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "vasco-el-jim", + "memo": "edc7fa29-31d9-42a0-bf53-353d6c01f1c0", + "amount": { + "nai": "@@000000021", + "amount": "50000", + "precision": 3 + } + } + }, + "block": 4941972, + "trx_id": "c4aaf923be6e77740477d13d2e904cae164caa05", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T19:06:06", + "virtual_op": false, + "operation_id": "21225608117747714", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "trevorjenglish", + "memo": " be40e871-d9c4-494f-a85d-92deae85c97c", + "amount": { + "nai": "@@000000021", + "amount": "52407", + "precision": 3 + } + } + }, + "block": 4940759, + "trx_id": "d2bc1229e4138b9692170b2d23c5f71084dae5c0", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T18:05:21", + "virtual_op": false, + "operation_id": "21220398322417666", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "pathtomydream", + "author": "blocktrades", + "weight": 0, + "rshares": 136784207, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august", + "pending_payout": { + "nai": "@@000000013", + "amount": "82", + "precision": 3 + }, + "total_vote_weight": 0 + } + }, + "block": 4940594, + "trx_id": "e05d94343442b1ee91910b7c17eef0f2a71eb392", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-13T17:57:06", + "virtual_op": true, + "operation_id": "21219689652814664", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "pathtomydream", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4940594, + "trx_id": "e05d94343442b1ee91910b7c17eef0f2a71eb392", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T17:57:06", + "virtual_op": false, + "operation_id": "21219689652814336", + "trx_in_block": 1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "expedition", + "author": "blocktrades", + "weight": 6074412272894458, + "rshares": 1317647622, + "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": 6323169317301775 + } + }, + "block": 4939847, + "trx_id": "f4f666caa5199e09e0c8f29a3e8d8aa40b4b859f", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-13T17:19:36", + "virtual_op": true, + "operation_id": "21216481312244040", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "expedition", + "author": "blocktrades", + "weight": 10000, + "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" + } + }, + "block": 4939847, + "trx_id": "f4f666caa5199e09e0c8f29a3e8d8aa40b4b859f", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T17:19:36", + "virtual_op": false, + "operation_id": "21216481312243712", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "@@ -73,16 +73,23 @@\n ugh the \n+coffee \n ocean. J\n", + "title": "", + "author": "phenom", + "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t151302200z", + "json_metadata": "{\"tags\":[\"food\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" + } + }, + "block": 4937336, + "trx_id": "d41b3134e9d0ac8a797d4a534498aa158faa12f5", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T15:13:45", + "virtual_op": false, + "operation_id": "21205696649364225", + "trx_in_block": 2 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "haha, Initially I thought that this blue thing is a whale floating through the ocean. Just realized that it's a symbol of blocktrades platform", + "title": "", + "author": "phenom", + "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t151302200z", + "json_metadata": "{\"tags\":[\"food\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" + } + }, + "block": 4937323, + "trx_id": "7755512e9ec8350494408daa261d7627a04ac87a", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T15:13:06", + "virtual_op": false, + "operation_id": "21205640814789377", + "trx_in_block": 2 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "wefdi", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4937041, + "trx_id": "6cefffe540c5636c5fa9cef5bd29c57cc434121f", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T14:58:57", + "virtual_op": false, + "operation_id": "21204429634011148", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "karsmaxanes", + "memo": " 9823b75c-e743-47e4-bbe9-7d0e9edd914b", + "amount": { + "nai": "@@000000013", + "amount": "44000", + "precision": 3 + } + } + }, + "block": 4936718, + "trx_id": "2be56fa88ee477504d54ab8fb0ee410812daba21", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T14:42:42", + "virtual_op": false, + "operation_id": "21203042359575554", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "mrwang", + "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", + "amount": { + "nai": "@@000000013", + "amount": "2821", + "precision": 3 + } + } + }, + "block": 4936102, + "trx_id": "b254e42f7ee58f909bcb190d6c58d925543cc0a9", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T14:11:48", + "virtual_op": false, + "operation_id": "21200396659720706", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "blockchaingirl", + "memo": "039abf1c-19ed-4242-a267-78bcaf29b6df", + "amount": { + "nai": "@@000000013", + "amount": "800000", + "precision": 3 + } + } + }, + "block": 4935965, + "trx_id": "58943fa0fc2612ecbb0c4733fc85bca2a048a651", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T14:04:57", + "virtual_op": false, + "operation_id": "21199808249201154", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "I see, but I talk about two hidden from eye edges. \nhttps://s9.postimg.org/nny820clr/2016_09_13_1630.png\nIn 3D they will be visible :) or just duplicate symbols Bitcoin and BitShares?", + "title": "", + "author": "smailer", + "permlink": "re-blocktrades-re-smailer-re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t133200497z", + "json_metadata": "{\"tags\":[\"food\"],\"image\":[\"https://s9.postimg.org/nny820clr/2016_09_13_1630.png\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t132556933z" + } + }, + "block": 4935318, + "trx_id": "d600c1d7a2674b8044a9b419792bb5ee88fc8c60", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:32:12", + "virtual_op": false, + "operation_id": "21197029405360897", + "trx_in_block": 2 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "anasz", + "author": "blocktrades", + "weight": 0, + "rshares": 416094341, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august", + "pending_payout": { + "nai": "@@000000013", + "amount": "96", + "precision": 3 + }, + "total_vote_weight": 0 + } + }, + "block": 4935292, + "trx_id": "18c58076b75a07a6bfaebdf28ef0ac0d926fd6b8", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-13T13:30:54", + "virtual_op": true, + "operation_id": "21196917736211528", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "anasz", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4935292, + "trx_id": "18c58076b75a07a6bfaebdf28ef0ac0d926fd6b8", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T13:30:54", + "virtual_op": false, + "operation_id": "21196917736211200", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "@@ -25,16 +25,30 @@\n missing \n+classic movie \n lol than\n", + "title": "", + "author": "fairz", + "permlink": "re-blocktrades-re-fairz-it-the-clown-parody-20160913t132321388z", + "json_metadata": "{\"tags\":[\"animation\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-fairz-it-the-clown-parody-20160913t114531552z" + } + }, + "block": 4935240, + "trx_id": "e20a2875cef6b7b4b2f8d15af33e57b7f0fae003", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:28:18", + "virtual_op": false, + "operation_id": "21196694397912577", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "they dont no what there missing lol thanks for looking", + "title": "", + "author": "fairz", + "permlink": "re-blocktrades-re-fairz-it-the-clown-parody-20160913t132321388z", + "json_metadata": "{\"tags\":[\"animation\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-fairz-it-the-clown-parody-20160913t114531552z" + } + }, + "block": 4935141, + "trx_id": "35a2153fd3a78744bc149d1b1a77a65aee3d7ff7", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:23:21", + "virtual_op": false, + "operation_id": "21196269196150785", + "trx_in_block": 5 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Glad to hear you! thank you!\nWhen I find the way make more square block I will try add more details.\nCan you say me what the money symbols on another one edges ?", + "title": "", + "author": "smailer", + "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131414898z", + "json_metadata": "{\"tags\":[\"food\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" + } + }, + "block": 4934964, + "trx_id": "09845865ddf51d5b61350e7f8864b7bb01a5d514", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:14:27", + "virtual_op": false, + "operation_id": "21195508986938625", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "onetree", + "memo": "f5b4968c-2ecc-4bbd-a85c-af1c1541657d", + "amount": { + "nai": "@@000000013", + "amount": "94576", + "precision": 3 + } + } + }, + "block": 4934174, + "trx_id": "b1ef0b05d1913f8c51e52deb7ac2cb836ee222d0", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T12:34:39", + "virtual_op": false, + "operation_id": "21192115962774274", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Sent a followup email, specifically mentioning your comments (as an influential member here) and got this promising response :)\n
", + "title": "", + "author": "ausbitbank", + "permlink": "re-blocktrades-re-krystle-re-blocktrades-re-eight-rad-re-hugothepoet-brexit-rap-battles-of-history-the-irony-of-it-all-new-original-rap-20160913t095540421z", + "json_metadata": "{\"tags\":[\"hugothepoet\"],\"image\":[\"https://www.steemimg.com/images/2016/09/13/hugoemailb7efe.png\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-krystle-re-blocktrades-re-eight-rad-re-hugothepoet-brexit-rap-battles-of-history-the-irony-of-it-all-new-original-rap-20160910t185524205z" + } + }, + "block": 4931009, + "trx_id": "9e67c8a0528a527dce8c6cb450ff236b47822dde", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T09:55:45", + "virtual_op": false, + "operation_id": "21178522391282177", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "slowwalker", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4929491, + "trx_id": "38b0d2d1b33b3f6cd6392a5dd7daf938a4713873", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T08:39:33", + "virtual_op": false, + "operation_id": "21172002630926348", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "stranger27", + "approve": false, + "witness": "blocktrades" + } + }, + "block": 4929005, + "trx_id": "625f1260e080e0f9840bb58d793472dc60cb5dcf", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T08:15:15", + "virtual_op": false, + "operation_id": "21169915276821004", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "tinfoilfedora", + "memo": "d03e7b59-2dfb-4e08-8506-5f435cbb522e", + "amount": { + "nai": "@@000000013", + "amount": "25000", + "precision": 3 + } + } + }, + "block": 4927062, + "trx_id": "0b6a7666a14a312f9976e01375656f6a7da1bcd6", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T06:37:48", + "virtual_op": false, + "operation_id": "21161570155364354", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "tinfoilfedora", + "memo": "d03e7b59-2dfb-4e08-8506-5f435cbb522e", + "amount": { + "nai": "@@000000013", + "amount": "120000", + "precision": 3 + } + } + }, + "block": 4926872, + "trx_id": "f21ce3eb2aa1aa47a2f5ba389dd6bac96742016b", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T06:28:18", + "virtual_op": false, + "operation_id": "21160754111578370", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "levycore", + "memo": "5bf6f52a-01f2-4552-93a9-2318ab9c79ae", + "amount": { + "nai": "@@000000013", + "amount": "34000", + "precision": 3 + } + } + }, + "block": 4926832, + "trx_id": "a9449ff148d769878770031c14af8f608522384c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T06:26:15", + "virtual_op": false, + "operation_id": "21160582312886274", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "krypto", + "memo": "931ded82-cd09-4e3f-80ff-5fbba1b54cf7", + "amount": { + "nai": "@@000000021", + "amount": "40000", + "precision": 3 + } + } + }, + "block": 4925898, + "trx_id": "41a66f6d678d0e06100cd62e8a155d70d768a410", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T05:39:27", + "virtual_op": false, + "operation_id": "21156570813432066", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "kennyskitchen", + "memo": "6230441c-1436-4bd7-826b-e78cc86666d0", + "amount": { + "nai": "@@000000013", + "amount": "40151", + "precision": 3 + } + } + }, + "block": 4924611, + "trx_id": "2e75bc3b9f7405317797a37f6908a2042d13c7e1", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T04:34:54", + "virtual_op": false, + "operation_id": "21151043190522882", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "4435fc70-df36-43e3-b79c-dcb75118a90e", + "amount": { + "nai": "@@000000013", + "amount": "25000", + "precision": 3 + } + } + }, + "block": 4922698, + "trx_id": "2a67c362d3d6f1199611a000dbbd899d13d8f46e", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T02:58:33", + "virtual_op": false, + "operation_id": "21142826918084610", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Nice article !", + "title": "", + "author": "alex2016", + "permlink": "re-blocktrades-blocktrades-witness-report-for-3rd-week-of-august-20160913t025753852z", + "json_metadata": "{\"tags\":[\"witness-category\"]}", + "parent_author": "blocktrades", + "parent_permlink": "blocktrades-witness-report-for-3rd-week-of-august" + } + }, + "block": 4922686, + "trx_id": "e5538ed98b4286b3b220c9525582eb606eab8f6c", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T02:57:57", + "virtual_op": false, + "operation_id": "21142775378478337", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "12Ht7fzVCmUP8BWx1Nk3ThrsLvEoFhmfm2", + "amount": { + "nai": "@@000000013", + "amount": "23000", + "precision": 3 + } + } + }, + "block": 4922068, + "trx_id": "7b52cc62c5804b40262a74bcb8e8c711253b2462", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T02:27:00", + "virtual_op": false, + "operation_id": "21140121088688898", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "af2ed608-e7fa-4cdc-80b4-bb049c6125e2", + "amount": { + "nai": "@@000000013", + "amount": "24000", + "precision": 3 + } + } + }, + "block": 4921719, + "trx_id": "625f4822303c979e3f404010c59ae992b27458c3", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T02:09:21", + "virtual_op": false, + "operation_id": "21138622145102338", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "b1737718-81cc-46f4-a5de-7cfc25158ab9", + "amount": { + "nai": "@@000000013", + "amount": "30", + "precision": 3 + } + } + }, + "block": 4921269, + "trx_id": "3bd88459ff9b3d0b50dd0ee010ccc99e4da46e0c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T01:46:51", + "virtual_op": false, + "operation_id": "21136689409818626", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "51d939e0-9466-4204-b8ba-ea064ed5ad89", + "amount": { + "nai": "@@000000013", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 4921209, + "trx_id": "ab006f1ed38e768fe8336c08821b9ec832453c2c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T01:43:51", + "virtual_op": false, + "operation_id": "21136431711781890", + "trx_in_block": 2 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.tavern.yaml b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.tavern.yaml new file mode 100644 index 000000000..71a64b9fe --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.tavern.yaml @@ -0,0 +1,25 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_account" + method: POST + headers: + content-type: application/json + accept: application/json + json: + account-name: "blocktrades" + transacting-account-name: "blocktrades" + participation-mode: "exclude" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern -- GitLab From c9ffdbb443378f3a2b315711423ba3a6dfc27464 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 23 Jul 2025 08:14:17 +0000 Subject: [PATCH 15/24] Change filtering to ANY when exclude --- .../filtering_functions/excluding_accounts.sql | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql index 0294b96bc..ed92c3700 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql @@ -31,9 +31,9 @@ BEGIN _account_range := hafah_backend.account_range(_operations, _account_id, _from_block, _to_block); -- Fetching operations - WITH excluded_ids AS MATERIALIZED ( + WITH /* excluded_ids AS MATERIALIZED ( SELECT unnest(_transacting_account_ids) AS id - ), + ), */ operation_range AS MATERIALIZED ( SELECT ls.operation_id AS id, @@ -47,10 +47,14 @@ BEGIN AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) AND aov.account_op_seq_no >= _account_range.from_seq AND aov.account_op_seq_no <= _account_range.to_seq + AND aov.transacting_account_id != ANY(_transacting_account_ids) -- exclude all transacting accounts + AND aov.transacting_account_id IS NOT NULL -- for future compatibility + /* AND NOT EXISTS ( SELECT 1 FROM excluded_ids e WHERE e.id = aov.transacting_account_id ) + */ ORDER BY aov.account_op_seq_no DESC LIMIT (__max_page_count * _limit) + 1 -- by default operation filter is limited to 10 pages -- The +1 is to check if there are more operations in block that are not included in the current page-range @@ -105,16 +109,20 @@ BEGIN FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND aov.transacting_account_id != ANY(_transacting_account_ids) -- exclude all transacting accounts + AND aov.transacting_account_id IS NOT NULL -- for future compatibility AND aov.account_op_seq_no >= _account_range.from_seq AND aov.account_op_seq_no <= _account_range.to_seq AND ( (SELECT block_num FROM block_check) IS NOT NULL AND aov.block_num = (SELECT block_num FROM block_check) ) + /* AND NOT EXISTS ( SELECT 1 FROM excluded_ids e WHERE e.id = aov.transacting_account_id ) + */ ), union_operations AS MATERIALIZED ( SELECT -- GitLab From b5c5e7d70290f9e8694e144e37ca3260b9ab1e21 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 23 Jul 2025 08:14:56 +0000 Subject: [PATCH 16/24] Fix typo in single exclude account --- .../filtering_functions/exclude_account.sql | 3 +- .../transacting_account_exclude.pat.json | 2153 +---------------- 2 files changed, 5 insertions(+), 2151 deletions(-) diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql index b21e37210..653d6ea1e 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql @@ -98,7 +98,8 @@ BEGIN aov.block_num FROM hive.account_operations_view aov WHERE aov.account_id = _account_id - AND aov.transacting_account_id = _transacting_account_id + AND aov.transacting_account_id != _transacting_account_id + AND aov.transacting_account_id IS NOT NULL -- for future compatibility AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) AND aov.account_op_seq_no >= _account_range.from_seq AND aov.account_op_seq_no <= _account_range.to_seq diff --git a/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json index b88fe923b..f89fb0414 100644 --- a/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json +++ b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json @@ -1,8 +1,8 @@ { - "total_operations": 999, - "total_pages": 10, + "total_operations": 1001, + "total_pages": 11, "block_range": { - "from": 1, + "from": 4576727, "to": 5000000 }, "operations_result": [ @@ -28,2153 +28,6 @@ "virtual_op": false, "operation_id": "21474823595099394", "trx_in_block": 3 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "condra", - "memo": "f2c3419c-9522-4bb3-aa41-472c8388f215", - "amount": { - "nai": "@@000000013", - "amount": "400000", - "precision": 3 - } - } - }, - "block": 4999607, - "trx_id": "2577322e21a18f9085cc5dba366b5292824f906b", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T19:26:42", - "virtual_op": false, - "operation_id": "21473148557854722", - "trx_in_block": 5 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "thisisbenbrick", - "memo": "0722aa82-10d0-4001-a286-130b633d58df", - "amount": { - "nai": "@@000000013", - "amount": "431587", - "precision": 3 - } - } - }, - "block": 4996294, - "trx_id": "01de85e061adde226a7ce59071973c9daaeca8ba", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T16:34:45", - "virtual_op": false, - "operation_id": "21458919331201538", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "roelandp", - "memo": "298eafac-95bb-4f27-b256-72df9d0ef222", - "amount": { - "nai": "@@000000021", - "amount": "148056", - "precision": 3 - } - } - }, - "block": 4996091, - "trx_id": "b1aa3d5f9308acd9cde664936c1b08eea77c3e49", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T16:24:36", - "virtual_op": false, - "operation_id": "21458047452841986", - "trx_in_block": 4 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "It just occurred to me that witness updates like this could make for interesting video material. Maybe a segment in our SteemSmart show?", - "title": "", - "author": "piedpiper", - "permlink": "re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160915t161707257z", - "json_metadata": "{\"tags\":[\"witness-category\"]}", - "parent_author": "blocktrades", - "parent_permlink": "witness-report-for-blocktrades-for-last-week-of-august" - } - }, - "block": 4995964, - "trx_id": "3ae419f4d37860c7d2dabec530ccf3ad79e79784", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-15T16:18:15", - "virtual_op": false, - "operation_id": "21457501991994369", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "macksby", - "memo": "92bff29e-2ee9-4ea4-ace1-6bb0c1331f67", - "amount": { - "nai": "@@000000013", - "amount": "50000", - "precision": 3 - } - } - }, - "block": 4994778, - "trx_id": "f2c59d933ba1fc08bd6f4c79ec52a0aeed6bb9e9", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T15:18:54", - "virtual_op": false, - "operation_id": "21452408160780290", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "good-karma", - "memo": "0c9ca5aa-53c2-445e-912f-d2cf6b111229", - "amount": { - "nai": "@@000000013", - "amount": "1500000", - "precision": 3 - } - } - }, - "block": 4994642, - "trx_id": "15a50977270c3b7e4e97715989f03099375b59bb", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T15:12:06", - "virtual_op": false, - "operation_id": "21451824045228034", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "blackjincrypto", - "memo": "7639138f-62f0-492a-b8e7-bad1add506dd", - "amount": { - "nai": "@@000000021", - "amount": "24838", - "precision": 3 - } - } - }, - "block": 4993122, - "trx_id": "a6e9f45a9b8fb6cd565936f64e13ae5b12ac94f2", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T13:56:03", - "virtual_op": false, - "operation_id": "21445295694938114", - "trx_in_block": 0 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "pakganern", - "author": "blocktrades", - "weight": 0, - "rshares": 2913900118, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august", - "pending_payout": { - "nai": "@@000000013", - "amount": "75", - "precision": 3 - }, - "total_vote_weight": 0 - } - }, - "block": 4987311, - "trx_id": "b89762657465f62895ff3c8acab554a69a5bab1e", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-15T09:04:45", - "virtual_op": true, - "operation_id": "21420337639983176", - "trx_in_block": 4 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "pakganern", - "author": "blocktrades", - "weight": 10000, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august" - } - }, - "block": 4987311, - "trx_id": "b89762657465f62895ff3c8acab554a69a5bab1e", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-15T09:04:45", - "virtual_op": false, - "operation_id": "21420337639982848", - "trx_in_block": 4 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "schro", - "memo": "d70dfb8e-277a-4070-9812-b38cf01579cf", - "amount": { - "nai": "@@000000021", - "amount": "126225", - "precision": 3 - } - } - }, - "block": 4986680, - "trx_id": "68656136a5cff365a0c5ab873a60a3cf7528e47c", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T08:32:54", - "virtual_op": false, - "operation_id": "21417627515617282", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "aaronkoenig", - "memo": "b4c499fb-5deb-44dc-9646-e7feb3927e12", - "amount": { - "nai": "@@000000013", - "amount": "48000", - "precision": 3 - } - } - }, - "block": 4985503, - "trx_id": "2c918ba666c06946a792657b27ed18af196dfab5", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T07:34:00", - "virtual_op": false, - "operation_id": "21412572339109890", - "trx_in_block": 0 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "jeremyfromwi", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4984971, - "trx_id": "21b12d2246e1ceb0cedba3b04a504bb58d52b0d5", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-15T07:07:15", - "virtual_op": false, - "operation_id": "21410287416508684", - "trx_in_block": 1 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "cryptomental", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4984843, - "trx_id": "8c311c43f7dd1ddaa713aa6cb2f9d8dde96141bd", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-15T07:00:51", - "virtual_op": false, - "operation_id": "21409737660695052", - "trx_in_block": 1 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "I am not sure, but it is not funny anymore because I see the 12 points every time. Maybe my brain just recorded the pattern and remember it. I can not switch back again.\nAlso is truth that I work with crystal simetry pattern daily, so, maybe my brain is trained to see patterns and keep it. Also, in this occasion, I knew what was looking for...\nThis make me think how different we perceive the universe around us... Even when everybody is seeing the same thing...", - "title": "", - "author": "quigua", - "permlink": "re-blocktrades-re-quigua-re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t054809925z", - "json_metadata": "{\"tags\":[\"optical\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-quigua-re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t050900278z" - } - }, - "block": 4983394, - "trx_id": "5824e046a9235be9ba99440e3e8eb99860e8a63a", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-15T05:48:15", - "virtual_op": false, - "operation_id": "21403514253082625", - "trx_in_block": 0 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "therajmahal", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4982233, - "trx_id": "7df8d151a3c06fb31a6b902d80885d4a6ca5c1ab", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-15T04:50:09", - "virtual_op": false, - "operation_id": "21398527796051980", - "trx_in_block": 0 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "At first, I couldn't see more than 4 points at the same time. But, then I follow all points with the eyes making a circle pattern during 15 seconds, and surprising!. I can see the 12 points, and now I can not see the blinking points again. That is really crazy...", - "title": "", - "author": "quigua", - "permlink": "re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t044305573z", - "json_metadata": "{\"tags\":[\"optical\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t034947752z" - } - }, - "block": 4982094, - "trx_id": "40ae1f796b8d0409a799fe62b3b423972b83c9e5", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-15T04:43:12", - "virtual_op": false, - "operation_id": "21397930795598081", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "rishi556", - "memo": " 50c8c0c0-c9f6-41c3-ace1-791567e5c1ba", - "amount": { - "nai": "@@000000013", - "amount": "105", - "precision": 3 - } - } - }, - "block": 4980808, - "trx_id": "083fc2207f29a78e907e5865911cf7d62910fd21", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T03:38:48", - "virtual_op": false, - "operation_id": "21392407467656706", - "trx_in_block": 3 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "stackcats", - "memo": "b163536b-4058-4187-96c6-ac9f573088ae", - "amount": { - "nai": "@@000000021", - "amount": "57873", - "precision": 3 - } - } - }, - "block": 4980626, - "trx_id": "5ac596f0c2b61dcffc2aed0d70858b0d36d32b91", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T03:29:42", - "virtual_op": false, - "operation_id": "21391625783608834", - "trx_in_block": 3 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "acidyo", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4980106, - "trx_id": "cf47b1bdf8d3f9a84cbb88931900242a7725f7c1", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-15T03:03:39", - "virtual_op": false, - "operation_id": "21389392400613388", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "ranko-k", - "memo": "59824378-b1af-44ab-a181-a150ace86aa5", - "amount": { - "nai": "@@000000021", - "amount": "29421", - "precision": 3 - } - } - }, - "block": 4977199, - "trx_id": "015a69792b3d1ce6964a656f829d1d0b9ac1fd18", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-15T00:38:18", - "virtual_op": false, - "operation_id": "21376906930683906", - "trx_in_block": 0 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "theb0red1", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4974156, - "trx_id": "706d118879820969cd2056bf7c72cb16f952a952", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-14T22:06:00", - "virtual_op": false, - "operation_id": "21363837345203724", - "trx_in_block": 3 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "@@ -399,16 +399,17 @@\n nts will\n+,\n too, an\n", - "title": "", - "author": "slammr76", - "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t203223509z", - "json_metadata": "{\"tags\":[\"money\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" - } - }, - "block": 4972329, - "trx_id": "f66ba76505558234d1532ad9030d349236b7ab85", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T20:34:30", - "virtual_op": false, - "operation_id": "21355990439952897", - "trx_in_block": 1 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Right now, Steem has value because you can exchange it for bitcoin. I don't have to exchange bitcoin for fiat for it to have value for me, even though the merchants accepting it are likely exchanging it for fiat. I can and do spend bitcoin all the time. I've never exchanged it for fiat but have always exchanged dollars for bitcoin. I prefer to have my weath stored in bitcoin. Someday, the merchants will too, and few will care what the exchange rate for bitcoin vs fiat is.", - "title": "", - "author": "slammr76", - "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t203223509z", - "json_metadata": "{\"tags\":[\"money\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" - } - }, - "block": 4972289, - "trx_id": "34146d0288ea9070d2da2be5e191bb7c1885724e", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T20:32:30", - "virtual_op": false, - "operation_id": "21355818641261057", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "kranartz", - "memo": " 7702e0f5-8ab7-46d1-bbda-29d21c368160", - "amount": { - "nai": "@@000000013", - "amount": "1123", - "precision": 3 - } - } - }, - "block": 4971843, - "trx_id": "6412bb9abeec1f6e5027c11a165fa919fc233f03", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T20:10:12", - "virtual_op": false, - "operation_id": "21353903085846530", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "fatboy", - "memo": " 771b11ac-47f7-4b2f-b50a-71266e9b4026", - "amount": { - "nai": "@@000000013", - "amount": "28350", - "precision": 3 - } - } - }, - "block": 4971577, - "trx_id": "8b39da57e049a4f2d28eac4565183904a8765648", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T19:56:54", - "virtual_op": false, - "operation_id": "21352760624547330", - "trx_in_block": 3 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "fatboy", - "memo": " 9c0bf334-d8df-40bb-8002-409c03cf230f", - "amount": { - "nai": "@@000000021", - "amount": "22663", - "precision": 3 - } - } - }, - "block": 4971507, - "trx_id": "f817700f21c9c97b06eb61beb6eff948fb7ad07c", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T19:53:24", - "virtual_op": false, - "operation_id": "21352459976835074", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "anasz", - "memo": " 9f6e1027-9d03-4785-90d4-04fe4dd29b5e", - "amount": { - "nai": "@@000000013", - "amount": "16000", - "precision": 3 - } - } - }, - "block": 4971215, - "trx_id": "a21a7bfb210848c0c7d73d4a799a3cd6757d66d3", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T19:38:48", - "virtual_op": false, - "operation_id": "21351205846385154", - "trx_in_block": 1 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "gomeravibz", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4971093, - "trx_id": "f0a69def7eba73ee3ccd9a92dd915ee3eacc2b6a", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-14T19:32:39", - "virtual_op": false, - "operation_id": "21350681860375564", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "shaneradliff", - "memo": "7f208b66-5a77-48a5-92fb-bd9fbc5fd50c", - "amount": { - "nai": "@@000000013", - "amount": "1300", - "precision": 3 - } - } - }, - "block": 4970678, - "trx_id": "0fa231ee90f74305cab404aaabac6654050b5df9", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T19:11:21", - "virtual_op": false, - "operation_id": "21348899448947458", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "anasz", - "memo": "314ae1d5-c9e9-4a21-8cb0-48cf6d2a3ccb", - "amount": { - "nai": "@@000000013", - "amount": "10000", - "precision": 3 - } - } - }, - "block": 4969806, - "trx_id": "3fee1c9286faaa4abec711e275f0e897ada9cb5f", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T18:25:36", - "virtual_op": false, - "operation_id": "21345154237465602", - "trx_in_block": 2 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Well, fiat money is worth something because you can use it to pay taxes.", - "title": "", - "author": "svamiva", - "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t175725339z", - "json_metadata": "{\"tags\":[\"money\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" - } - }, - "block": 4969274, - "trx_id": "c6f8881aba4bc494f32cfffc15ad122b44c8d124", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T17:57:33", - "virtual_op": false, - "operation_id": "21342869314864129", - "trx_in_block": 3 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Thank you so much! I will remember this \").", - "title": "", - "author": "funny", - "permlink": "re-blocktrades-re-funny-re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t174018203z", - "json_metadata": "{\"tags\":[\"money\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-funny-re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t171338026z" - } - }, - "block": 4968948, - "trx_id": "26b80037ce89febd1c653fcbbbdf09faefc325b1", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T17:40:24", - "virtual_op": false, - "operation_id": "21341469155525121", - "trx_in_block": 1 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "You´re welcome :). Hehe, it´s always the last bit missing. Like the comments in this example :D", - "title": "", - "author": "lenatramper", - "permlink": "re-blocktrades-re-lenatramper-re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t173256475z", - "json_metadata": "{\"tags\":[\"adolf\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-lenatramper-re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t164216448z" - } - }, - "block": 4968805, - "trx_id": "2daac261fcc68c2461adc8524261bc11de614f3e", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T17:32:48", - "virtual_op": false, - "operation_id": "21340854975201281", - "trx_in_block": 0 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "good-karma", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4968789, - "trx_id": "07faf6e609944fa59dd2bdfe8fbc0c2270e83a4a", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-14T17:32:00", - "virtual_op": false, - "operation_id": "21340786255724556", - "trx_in_block": 0 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "mikemacintire", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4968546, - "trx_id": "ddfd6daa8550483afc8158b9926c7d1b1fa1f731", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-14T17:19:15", - "virtual_op": false, - "operation_id": "21339742578672396", - "trx_in_block": 2 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Hey @blocktrades, thanks for reading \"). \n\nAgreed, that was the point I was making, but with that statement, I meant it as you need a bridge to start. If everyone decided to adopt crypto tomorrow, and picked a few coins that we all used, then yes, you're right, it could work without fiat. \n\nAny chance you can upvote the post, I'm trying to build my account with steemit.", - "title": "", - "author": "funny", - "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t170230207z", - "json_metadata": "{\"tags\":[\"money\"],\"users\":[\"blocktrades\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" - } - }, - "block": 4968231, - "trx_id": "f205fbcc8aee61419ad54982f3d594de07450a2a", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T17:02:36", - "virtual_op": false, - "operation_id": "21338389663973377", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "ziogio", - "memo": "92754b24-3405-434f-88ca-07ad5e74b089", - "amount": { - "nai": "@@000000013", - "amount": "10000", - "precision": 3 - } - } - }, - "block": 4967726, - "trx_id": "f620062399c31a45b339fb6ca2d8d3980a6bf747", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T16:37:03", - "virtual_op": false, - "operation_id": "21336220705488898", - "trx_in_block": 0 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Hi blocktrades,\n\nyou can check it here in the comments :)\nhttps://steemit.com/language/@lenatramper/top-10-hardest-languages-in-the-world-ranking", - "title": "", - "author": "lenatramper", - "permlink": "re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t160355256z", - "json_metadata": "{\"tags\":[\"adolf\"],\"links\":[\"https://steemit.com/language/@lenatramper/top-10-hardest-languages-in-the-world-ranking\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t155903950z" - } - }, - "block": 4967060, - "trx_id": "120b4917d02d628ae830fb480c1d049274489445", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T16:03:45", - "virtual_op": false, - "operation_id": "21333360257271553", - "trx_in_block": 4 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "juliac", - "memo": "0dba7938-f263-4da8-820e-8d883ddacff7", - "amount": { - "nai": "@@000000013", - "amount": "13334", - "precision": 3 - } - } - }, - "block": 4965170, - "trx_id": "515fca2bc83c7f460f18ec52457c0cd672826358", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T14:29:12", - "virtual_op": false, - "operation_id": "21325242769080322", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "blockchaingirl", - "memo": "6ebbb676-3fd8-4713-acbe-2f1d4da1a0b0", - "amount": { - "nai": "@@000000013", - "amount": "800000", - "precision": 3 - } - } - }, - "block": 4964407, - "trx_id": "cf4264043076e5af34318b9db392ccf469a66563", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T13:51:00", - "virtual_op": false, - "operation_id": "21321965709034498", - "trx_in_block": 2 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "solarguy", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4959174, - "trx_id": "6bd2741483e2659c957cb574b7fec5ba1fec25de", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-14T09:28:45", - "virtual_op": false, - "operation_id": "21299490145174284", - "trx_in_block": 2 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "royalmacro", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4957445, - "trx_id": "582159a7d6fa988594fe6f947bc73998fc655b14", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-14T08:02:00", - "virtual_op": false, - "operation_id": "21292064146721292", - "trx_in_block": 5 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "kaylinart", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4957104, - "trx_id": "8ce909995eaf91a2ed2676932000a4c7d4af80ad", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-14T07:44:54", - "virtual_op": false, - "operation_id": "21290599562870796", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "anasz", - "memo": "b16de592-76a1-485d-b8c8-4e8692f9803e", - "amount": { - "nai": "@@000000013", - "amount": "23", - "precision": 3 - } - } - }, - "block": 4954441, - "trx_id": "169310b87bfd1fde6ff207ea39ec09df7760391e", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T05:31:21", - "virtual_op": false, - "operation_id": "21279162064964098", - "trx_in_block": 5 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "bryner", - "memo": "4c93872a-7b82-42f3-b094-a54ab719c34c", - "amount": { - "nai": "@@000000021", - "amount": "8350", - "precision": 3 - } - } - }, - "block": 4952702, - "trx_id": "d7474d597f3cd27c895b477b1a7b1046888851d7", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T04:04:06", - "virtual_op": false, - "operation_id": "21271693116833794", - "trx_in_block": 0 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "theb0red1", - "author": "blocktrades", - "weight": "43666160499416273", - "rshares": 9491055943, - "permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z", - "pending_payout": { - "nai": "@@000000013", - "amount": "2", - "precision": 3 - }, - "total_vote_weight": "43666160499416273" - } - }, - "block": 4952567, - "trx_id": "182a7686346f290e1bf55d4a8e2474e5bd33697e", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-14T03:57:21", - "virtual_op": true, - "operation_id": "21271113296249672", - "trx_in_block": 1 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "theb0red1", - "author": "blocktrades", - "weight": 10000, - "permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z" - } - }, - "block": 4952567, - "trx_id": "182a7686346f290e1bf55d4a8e2474e5bd33697e", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-14T03:57:21", - "virtual_op": false, - "operation_id": "21271113296249344", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "themanualbot", - "memo": "a4f54c6d-bc77-404f-b4ce-8e3433fcc928", - "amount": { - "nai": "@@000000013", - "amount": "484185", - "precision": 3 - } - } - }, - "block": 4950730, - "trx_id": "aa54b0534c3e747051b5e88b620d9f8cd337c983", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T02:25:15", - "virtual_op": false, - "operation_id": "21263223441327618", - "trx_in_block": 3 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Ok, thanks!", - "title": "", - "author": "timcliff", - "permlink": "re-blocktrades-re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t015047838z", - "json_metadata": "{\"tags\":[\"poloniex\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z" - } - }, - "block": 4950046, - "trx_id": "a1467edcb59b7cf3cff77cd83c4af3ada0c4ffb6", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-14T01:50:51", - "virtual_op": false, - "operation_id": "21260285683696129", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "forrestwillie", - "memo": "34edb0f7-ad6f-4927-84ea-d5faf99f9e6e", - "amount": { - "nai": "@@000000021", - "amount": "66281", - "precision": 3 - } - } - }, - "block": 4949192, - "trx_id": "693841b51e3fe86929f71d5491fba422acbbae54", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T01:08:03", - "virtual_op": false, - "operation_id": "21256617781624834", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "shaneradliff", - "memo": "d1d42c18-b06f-4124-9c81-a4593dcea8cd", - "amount": { - "nai": "@@000000013", - "amount": "13000", - "precision": 3 - } - } - }, - "block": 4948215, - "trx_id": "1134409013de5dd70173d087edfe9763baec70ec", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-14T00:19:03", - "virtual_op": false, - "operation_id": "21252421598576642", - "trx_in_block": 0 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "wefdi", - "approve": false, - "witness": "blocktrades" - } - }, - "block": 4947057, - "trx_id": "b375567add15744604a2ab38d76ebeb82cb0e897", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-13T23:21:00", - "virtual_op": false, - "operation_id": "21247448026448908", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "lindee-hamner", - "memo": "3ecd1ed7-da35-4497-8106-92e26eff9103", - "amount": { - "nai": "@@000000021", - "amount": "22367", - "precision": 3 - } - } - }, - "block": 4946739, - "trx_id": "74bf8f7190a6a7e7c51692c27a0a8523e33e7821", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T23:05:03", - "virtual_op": false, - "operation_id": "21246082226847746", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "thisisbenbrick", - "memo": "2e62fd10-bd7b-43ee-a2a2-33324e576e93", - "amount": { - "nai": "@@000000021", - "amount": "766741", - "precision": 3 - } - } - }, - "block": 4946006, - "trx_id": "65c72bcffb05588cd274257969bee51f07d266d2", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T22:28:21", - "virtual_op": false, - "operation_id": "21242934015819778", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "mrwang", - "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", - "amount": { - "nai": "@@000000013", - "amount": "71475", - "precision": 3 - } - } - }, - "block": 4945986, - "trx_id": "555cc791ad80d0f025e6f7fa5965657c1e54b063", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T22:27:18", - "virtual_op": false, - "operation_id": "21242848116474882", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "yassinebentour", - "memo": "b9b4574a-220d-49ee-bf4e-6889df4e387c", - "amount": { - "nai": "@@000000021", - "amount": "1775", - "precision": 3 - } - } - }, - "block": 4944673, - "trx_id": "4e78a7c63beff4ffa7c715eae5c523231918d939", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T21:21:30", - "virtual_op": false, - "operation_id": "21237208824414978", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "furion", - "memo": "cffb8a8e-1f88-4654-945a-8888dcdac62a", - "amount": { - "nai": "@@000000021", - "amount": "50000", - "precision": 3 - } - } - }, - "block": 4943900, - "trx_id": "ee10f9357650aeaebfc4b34429b5465642edc41b", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T20:42:45", - "virtual_op": false, - "operation_id": "21233888814694402", - "trx_in_block": 0 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "dmilash", - "author": "blocktrades", - "weight": 0, - "rshares": 3144502568, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august", - "pending_payout": { - "nai": "@@000000013", - "amount": "82", - "precision": 3 - }, - "total_vote_weight": 0 - } - }, - "block": 4943618, - "trx_id": "c8bfb1ae741895c5d9ff90381faef14cb2bd9dc0", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-13T20:28:39", - "virtual_op": true, - "operation_id": "21232677633917768", - "trx_in_block": 1 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "dmilash", - "author": "blocktrades", - "weight": 10000, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august" - } - }, - "block": 4943618, - "trx_id": "c8bfb1ae741895c5d9ff90381faef14cb2bd9dc0", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-13T20:28:39", - "virtual_op": false, - "operation_id": "21232677633917440", - "trx_in_block": 1 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "vetvso", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4943513, - "trx_id": "18d12216537678f958f3e7e0c6550367d01a76fa", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-13T20:23:21", - "virtual_op": false, - "operation_id": "21232226662351116", - "trx_in_block": 1 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "vetvso", - "author": "blocktrades", - "weight": 875968207384238, - "rshares": 190084642, - "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z", - "pending_payout": { - "nai": "@@000000013", - "amount": "0", - "precision": 3 - }, - "total_vote_weight": 7199137524686013 - } - }, - "block": 4943368, - "trx_id": "fb9ee97aaafe8d8f0581a269d5f0ff2ca4c9ffa7", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-13T20:16:06", - "virtual_op": true, - "operation_id": "21231603892094536", - "trx_in_block": 3 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "vetvso", - "author": "blocktrades", - "weight": 10000, - "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" - } - }, - "block": 4943368, - "trx_id": "fb9ee97aaafe8d8f0581a269d5f0ff2ca4c9ffa7", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-13T20:16:06", - "virtual_op": false, - "operation_id": "21231603892094208", - "trx_in_block": 3 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "vetvso", - "author": "blocktrades", - "weight": 0, - "rshares": 198173350, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august", - "pending_payout": { - "nai": "@@000000013", - "amount": "81", - "precision": 3 - }, - "total_vote_weight": 0 - } - }, - "block": 4943233, - "trx_id": "596e450517c6f651b77492fc6a9ad3b1e46cf271", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-13T20:09:21", - "virtual_op": true, - "operation_id": "21231024071508296", - "trx_in_block": 0 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "vetvso", - "author": "blocktrades", - "weight": 10000, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august" - } - }, - "block": 4943233, - "trx_id": "596e450517c6f651b77492fc6a9ad3b1e46cf271", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-13T20:09:21", - "virtual_op": false, - "operation_id": "21231024071507968", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "novium", - "memo": " d48f47eb-5900-4a70-bfb3-a821ba90de30", - "amount": { - "nai": "@@000000013", - "amount": "40000", - "precision": 3 - } - } - }, - "block": 4942698, - "trx_id": "c38b4cf8d260ec43b48c55f3613428e5adb3dc93", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T19:42:33", - "virtual_op": false, - "operation_id": "21228726264005378", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "vasco-el-jim", - "memo": "edc7fa29-31d9-42a0-bf53-353d6c01f1c0", - "amount": { - "nai": "@@000000021", - "amount": "50000", - "precision": 3 - } - } - }, - "block": 4941972, - "trx_id": "c4aaf923be6e77740477d13d2e904cae164caa05", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T19:06:06", - "virtual_op": false, - "operation_id": "21225608117747714", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "trevorjenglish", - "memo": " be40e871-d9c4-494f-a85d-92deae85c97c", - "amount": { - "nai": "@@000000021", - "amount": "52407", - "precision": 3 - } - } - }, - "block": 4940759, - "trx_id": "d2bc1229e4138b9692170b2d23c5f71084dae5c0", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T18:05:21", - "virtual_op": false, - "operation_id": "21220398322417666", - "trx_in_block": 0 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "pathtomydream", - "author": "blocktrades", - "weight": 0, - "rshares": 136784207, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august", - "pending_payout": { - "nai": "@@000000013", - "amount": "82", - "precision": 3 - }, - "total_vote_weight": 0 - } - }, - "block": 4940594, - "trx_id": "e05d94343442b1ee91910b7c17eef0f2a71eb392", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-13T17:57:06", - "virtual_op": true, - "operation_id": "21219689652814664", - "trx_in_block": 1 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "pathtomydream", - "author": "blocktrades", - "weight": 10000, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august" - } - }, - "block": 4940594, - "trx_id": "e05d94343442b1ee91910b7c17eef0f2a71eb392", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-13T17:57:06", - "virtual_op": false, - "operation_id": "21219689652814336", - "trx_in_block": 1 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "expedition", - "author": "blocktrades", - "weight": 6074412272894458, - "rshares": 1317647622, - "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z", - "pending_payout": { - "nai": "@@000000013", - "amount": "0", - "precision": 3 - }, - "total_vote_weight": 6323169317301775 - } - }, - "block": 4939847, - "trx_id": "f4f666caa5199e09e0c8f29a3e8d8aa40b4b859f", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-13T17:19:36", - "virtual_op": true, - "operation_id": "21216481312244040", - "trx_in_block": 0 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "expedition", - "author": "blocktrades", - "weight": 10000, - "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" - } - }, - "block": 4939847, - "trx_id": "f4f666caa5199e09e0c8f29a3e8d8aa40b4b859f", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-13T17:19:36", - "virtual_op": false, - "operation_id": "21216481312243712", - "trx_in_block": 0 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "@@ -73,16 +73,23 @@\n ugh the \n+coffee \n ocean. J\n", - "title": "", - "author": "phenom", - "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t151302200z", - "json_metadata": "{\"tags\":[\"food\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" - } - }, - "block": 4937336, - "trx_id": "d41b3134e9d0ac8a797d4a534498aa158faa12f5", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T15:13:45", - "virtual_op": false, - "operation_id": "21205696649364225", - "trx_in_block": 2 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "haha, Initially I thought that this blue thing is a whale floating through the ocean. Just realized that it's a symbol of blocktrades platform", - "title": "", - "author": "phenom", - "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t151302200z", - "json_metadata": "{\"tags\":[\"food\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" - } - }, - "block": 4937323, - "trx_id": "7755512e9ec8350494408daa261d7627a04ac87a", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T15:13:06", - "virtual_op": false, - "operation_id": "21205640814789377", - "trx_in_block": 2 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "wefdi", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4937041, - "trx_id": "6cefffe540c5636c5fa9cef5bd29c57cc434121f", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-13T14:58:57", - "virtual_op": false, - "operation_id": "21204429634011148", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "karsmaxanes", - "memo": " 9823b75c-e743-47e4-bbe9-7d0e9edd914b", - "amount": { - "nai": "@@000000013", - "amount": "44000", - "precision": 3 - } - } - }, - "block": 4936718, - "trx_id": "2be56fa88ee477504d54ab8fb0ee410812daba21", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T14:42:42", - "virtual_op": false, - "operation_id": "21203042359575554", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "mrwang", - "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", - "amount": { - "nai": "@@000000013", - "amount": "2821", - "precision": 3 - } - } - }, - "block": 4936102, - "trx_id": "b254e42f7ee58f909bcb190d6c58d925543cc0a9", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T14:11:48", - "virtual_op": false, - "operation_id": "21200396659720706", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "blockchaingirl", - "memo": "039abf1c-19ed-4242-a267-78bcaf29b6df", - "amount": { - "nai": "@@000000013", - "amount": "800000", - "precision": 3 - } - } - }, - "block": 4935965, - "trx_id": "58943fa0fc2612ecbb0c4733fc85bca2a048a651", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T14:04:57", - "virtual_op": false, - "operation_id": "21199808249201154", - "trx_in_block": 1 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "I see, but I talk about two hidden from eye edges. \nhttps://s9.postimg.org/nny820clr/2016_09_13_1630.png\nIn 3D they will be visible :) or just duplicate symbols Bitcoin and BitShares?", - "title": "", - "author": "smailer", - "permlink": "re-blocktrades-re-smailer-re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t133200497z", - "json_metadata": "{\"tags\":[\"food\"],\"image\":[\"https://s9.postimg.org/nny820clr/2016_09_13_1630.png\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-smailer-re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t132556933z" - } - }, - "block": 4935318, - "trx_id": "d600c1d7a2674b8044a9b419792bb5ee88fc8c60", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T13:32:12", - "virtual_op": false, - "operation_id": "21197029405360897", - "trx_in_block": 2 - }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "anasz", - "author": "blocktrades", - "weight": 0, - "rshares": 416094341, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august", - "pending_payout": { - "nai": "@@000000013", - "amount": "96", - "precision": 3 - }, - "total_vote_weight": 0 - } - }, - "block": 4935292, - "trx_id": "18c58076b75a07a6bfaebdf28ef0ac0d926fd6b8", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-13T13:30:54", - "virtual_op": true, - "operation_id": "21196917736211528", - "trx_in_block": 1 - }, - { - "op": { - "type": "vote_operation", - "value": { - "voter": "anasz", - "author": "blocktrades", - "weight": 10000, - "permlink": "witness-report-for-blocktrades-for-last-week-of-august" - } - }, - "block": 4935292, - "trx_id": "18c58076b75a07a6bfaebdf28ef0ac0d926fd6b8", - "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-13T13:30:54", - "virtual_op": false, - "operation_id": "21196917736211200", - "trx_in_block": 1 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "@@ -25,16 +25,30 @@\n missing \n+classic movie \n lol than\n", - "title": "", - "author": "fairz", - "permlink": "re-blocktrades-re-fairz-it-the-clown-parody-20160913t132321388z", - "json_metadata": "{\"tags\":[\"animation\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-fairz-it-the-clown-parody-20160913t114531552z" - } - }, - "block": 4935240, - "trx_id": "e20a2875cef6b7b4b2f8d15af33e57b7f0fae003", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T13:28:18", - "virtual_op": false, - "operation_id": "21196694397912577", - "trx_in_block": 3 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "they dont no what there missing lol thanks for looking", - "title": "", - "author": "fairz", - "permlink": "re-blocktrades-re-fairz-it-the-clown-parody-20160913t132321388z", - "json_metadata": "{\"tags\":[\"animation\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-fairz-it-the-clown-parody-20160913t114531552z" - } - }, - "block": 4935141, - "trx_id": "35a2153fd3a78744bc149d1b1a77a65aee3d7ff7", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T13:23:21", - "virtual_op": false, - "operation_id": "21196269196150785", - "trx_in_block": 5 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Glad to hear you! thank you!\nWhen I find the way make more square block I will try add more details.\nCan you say me what the money symbols on another one edges ?", - "title": "", - "author": "smailer", - "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131414898z", - "json_metadata": "{\"tags\":[\"food\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" - } - }, - "block": 4934964, - "trx_id": "09845865ddf51d5b61350e7f8864b7bb01a5d514", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T13:14:27", - "virtual_op": false, - "operation_id": "21195508986938625", - "trx_in_block": 3 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "onetree", - "memo": "f5b4968c-2ecc-4bbd-a85c-af1c1541657d", - "amount": { - "nai": "@@000000013", - "amount": "94576", - "precision": 3 - } - } - }, - "block": 4934174, - "trx_id": "b1ef0b05d1913f8c51e52deb7ac2cb836ee222d0", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T12:34:39", - "virtual_op": false, - "operation_id": "21192115962774274", - "trx_in_block": 1 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Sent a followup email, specifically mentioning your comments (as an influential member here) and got this promising response :)\n
", - "title": "", - "author": "ausbitbank", - "permlink": "re-blocktrades-re-krystle-re-blocktrades-re-eight-rad-re-hugothepoet-brexit-rap-battles-of-history-the-irony-of-it-all-new-original-rap-20160913t095540421z", - "json_metadata": "{\"tags\":[\"hugothepoet\"],\"image\":[\"https://www.steemimg.com/images/2016/09/13/hugoemailb7efe.png\"]}", - "parent_author": "blocktrades", - "parent_permlink": "re-krystle-re-blocktrades-re-eight-rad-re-hugothepoet-brexit-rap-battles-of-history-the-irony-of-it-all-new-original-rap-20160910t185524205z" - } - }, - "block": 4931009, - "trx_id": "9e67c8a0528a527dce8c6cb450ff236b47822dde", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T09:55:45", - "virtual_op": false, - "operation_id": "21178522391282177", - "trx_in_block": 1 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "slowwalker", - "approve": true, - "witness": "blocktrades" - } - }, - "block": 4929491, - "trx_id": "38b0d2d1b33b3f6cd6392a5dd7daf938a4713873", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-13T08:39:33", - "virtual_op": false, - "operation_id": "21172002630926348", - "trx_in_block": 0 - }, - { - "op": { - "type": "account_witness_vote_operation", - "value": { - "account": "stranger27", - "approve": false, - "witness": "blocktrades" - } - }, - "block": 4929005, - "trx_id": "625f1260e080e0f9840bb58d793472dc60cb5dcf", - "op_pos": 0, - "op_type_id": 12, - "timestamp": "2016-09-13T08:15:15", - "virtual_op": false, - "operation_id": "21169915276821004", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "tinfoilfedora", - "memo": "d03e7b59-2dfb-4e08-8506-5f435cbb522e", - "amount": { - "nai": "@@000000013", - "amount": "25000", - "precision": 3 - } - } - }, - "block": 4927062, - "trx_id": "0b6a7666a14a312f9976e01375656f6a7da1bcd6", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T06:37:48", - "virtual_op": false, - "operation_id": "21161570155364354", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "tinfoilfedora", - "memo": "d03e7b59-2dfb-4e08-8506-5f435cbb522e", - "amount": { - "nai": "@@000000013", - "amount": "120000", - "precision": 3 - } - } - }, - "block": 4926872, - "trx_id": "f21ce3eb2aa1aa47a2f5ba389dd6bac96742016b", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T06:28:18", - "virtual_op": false, - "operation_id": "21160754111578370", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "levycore", - "memo": "5bf6f52a-01f2-4552-93a9-2318ab9c79ae", - "amount": { - "nai": "@@000000013", - "amount": "34000", - "precision": 3 - } - } - }, - "block": 4926832, - "trx_id": "a9449ff148d769878770031c14af8f608522384c", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T06:26:15", - "virtual_op": false, - "operation_id": "21160582312886274", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "krypto", - "memo": "931ded82-cd09-4e3f-80ff-5fbba1b54cf7", - "amount": { - "nai": "@@000000021", - "amount": "40000", - "precision": 3 - } - } - }, - "block": 4925898, - "trx_id": "41a66f6d678d0e06100cd62e8a155d70d768a410", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T05:39:27", - "virtual_op": false, - "operation_id": "21156570813432066", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "kennyskitchen", - "memo": "6230441c-1436-4bd7-826b-e78cc86666d0", - "amount": { - "nai": "@@000000013", - "amount": "40151", - "precision": 3 - } - } - }, - "block": 4924611, - "trx_id": "2e75bc3b9f7405317797a37f6908a2042d13c7e1", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T04:34:54", - "virtual_op": false, - "operation_id": "21151043190522882", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "luzcypher", - "memo": "4435fc70-df36-43e3-b79c-dcb75118a90e", - "amount": { - "nai": "@@000000013", - "amount": "25000", - "precision": 3 - } - } - }, - "block": 4922698, - "trx_id": "2a67c362d3d6f1199611a000dbbd899d13d8f46e", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T02:58:33", - "virtual_op": false, - "operation_id": "21142826918084610", - "trx_in_block": 0 - }, - { - "op": { - "type": "comment_operation", - "value": { - "body": "Nice article !", - "title": "", - "author": "alex2016", - "permlink": "re-blocktrades-blocktrades-witness-report-for-3rd-week-of-august-20160913t025753852z", - "json_metadata": "{\"tags\":[\"witness-category\"]}", - "parent_author": "blocktrades", - "parent_permlink": "blocktrades-witness-report-for-3rd-week-of-august" - } - }, - "block": 4922686, - "trx_id": "e5538ed98b4286b3b220c9525582eb606eab8f6c", - "op_pos": 0, - "op_type_id": 1, - "timestamp": "2016-09-13T02:57:57", - "virtual_op": false, - "operation_id": "21142775378478337", - "trx_in_block": 3 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "luzcypher", - "memo": "12Ht7fzVCmUP8BWx1Nk3ThrsLvEoFhmfm2", - "amount": { - "nai": "@@000000013", - "amount": "23000", - "precision": 3 - } - } - }, - "block": 4922068, - "trx_id": "7b52cc62c5804b40262a74bcb8e8c711253b2462", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T02:27:00", - "virtual_op": false, - "operation_id": "21140121088688898", - "trx_in_block": 2 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "luzcypher", - "memo": "af2ed608-e7fa-4cdc-80b4-bb049c6125e2", - "amount": { - "nai": "@@000000013", - "amount": "24000", - "precision": 3 - } - } - }, - "block": 4921719, - "trx_id": "625f4822303c979e3f404010c59ae992b27458c3", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T02:09:21", - "virtual_op": false, - "operation_id": "21138622145102338", - "trx_in_block": 1 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "luzcypher", - "memo": "b1737718-81cc-46f4-a5de-7cfc25158ab9", - "amount": { - "nai": "@@000000013", - "amount": "30", - "precision": 3 - } - } - }, - "block": 4921269, - "trx_id": "3bd88459ff9b3d0b50dd0ee010ccc99e4da46e0c", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T01:46:51", - "virtual_op": false, - "operation_id": "21136689409818626", - "trx_in_block": 0 - }, - { - "op": { - "type": "transfer_operation", - "value": { - "to": "blocktrades", - "from": "luzcypher", - "memo": "51d939e0-9466-4204-b8ba-ea064ed5ad89", - "amount": { - "nai": "@@000000013", - "amount": "1000", - "precision": 3 - } - } - }, - "block": 4921209, - "trx_id": "ab006f1ed38e768fe8336c08821b9ec832453c2c", - "op_pos": 0, - "op_type_id": 2, - "timestamp": "2016-09-13T01:43:51", - "virtual_op": false, - "operation_id": "21136431711781890", - "trx_in_block": 2 } ] } \ No newline at end of file -- GitLab From 79e2eace06098ddfdb44353d0301820c9e512137 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 23 Jul 2025 08:15:24 +0000 Subject: [PATCH 17/24] Optimize filtering in find_all_records_for_page --- .../filtering_functions/exclude_account.sql | 26 ++++++++++++++----- .../excluding_accounts.sql | 24 +++++++++++++---- .../filtering_functions/include_account.sql | 25 +++++++++++++----- .../including_accounts.sql | 23 ++++++++++++---- 4 files changed, 76 insertions(+), 22 deletions(-) diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql index 653d6ea1e..62f11f510 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql @@ -36,12 +36,14 @@ BEGIN ls.operation_id AS id, ls.block_num, ls.op_type_id, + ls.account_op_seq_no, ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) FROM ( - SELECT aov.operation_id, aov.op_type_id, aov.block_num + SELECT aov.operation_id, aov.op_type_id, aov.block_num, aov.account_op_seq_no FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND aov.transacting_account_id != _transacting_account_id + AND aov.transacting_account_id IS NOT NULL -- for future compatibility AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) AND aov.account_op_seq_no >= _account_range.from_seq AND aov.account_op_seq_no <= _account_range.to_seq @@ -71,7 +73,8 @@ BEGIN ), if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty SELECT - orr.block_num + orr.block_num, + orr.account_op_seq_no FROM operation_range orr WHERE orr.row_num IN ( (SELECT count FROM check_if_saturated), @@ -86,7 +89,15 @@ BEGIN ELSE NULL END - ) AS block_num + ) AS block_num, + ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(account_op_seq_no) + ELSE + NULL + END + ) AS account_op_seq_no FROM if_saturated_find_last_two_ops ), -- returns empty if the last two operations are not in the same block @@ -102,11 +113,15 @@ BEGIN AND aov.transacting_account_id IS NOT NULL -- for future compatibility AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) AND aov.account_op_seq_no >= _account_range.from_seq - AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT account_op_seq_no FROM block_check) IS NOT NULL + AND aov.account_op_seq_no <= (SELECT account_op_seq_no FROM block_check) + ) AND ( (SELECT block_num FROM block_check) IS NOT NULL AND aov.block_num = (SELECT block_num FROM block_check) - ) + ) + ORDER BY aov.account_op_seq_no DESC ), union_operations AS MATERIALIZED ( SELECT @@ -115,7 +130,6 @@ BEGIN op_type_id FROM operation_range WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row - AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) -- if block_check is not NULL, exclude the operations from last block -- operations from excluded block are fetched in find_all_records_for_page UNION ALL diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql index ed92c3700..80131e17f 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql @@ -39,9 +39,10 @@ BEGIN ls.operation_id AS id, ls.block_num, ls.op_type_id, + ls.account_op_seq_no, ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) FROM ( - SELECT aov.operation_id, aov.op_type_id, aov.block_num + SELECT aov.operation_id, aov.op_type_id, aov.block_num, aov.account_op_seq_no FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) @@ -81,7 +82,8 @@ BEGIN ), if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty SELECT - orr.block_num + orr.block_num, + orr.account_op_seq_no FROM operation_range orr WHERE orr.row_num IN ( (SELECT count FROM check_if_saturated), @@ -96,7 +98,15 @@ BEGIN ELSE NULL END - ) AS block_num + ) AS block_num, + ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(account_op_seq_no) + ELSE + NULL + END + ) AS account_op_seq_no FROM if_saturated_find_last_two_ops ), -- returns empty if the last two operations are not in the same block @@ -112,7 +122,11 @@ BEGIN AND aov.transacting_account_id != ANY(_transacting_account_ids) -- exclude all transacting accounts AND aov.transacting_account_id IS NOT NULL -- for future compatibility AND aov.account_op_seq_no >= _account_range.from_seq - AND aov.account_op_seq_no <= _account_range.to_seq +-- AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT account_op_seq_no FROM block_check) IS NOT NULL + AND aov.account_op_seq_no <= (SELECT account_op_seq_no FROM block_check) + ) AND ( (SELECT block_num FROM block_check) IS NOT NULL AND aov.block_num = (SELECT block_num FROM block_check) @@ -123,6 +137,7 @@ BEGIN WHERE e.id = aov.transacting_account_id ) */ + ORDER BY aov.account_op_seq_no DESC ), union_operations AS MATERIALIZED ( SELECT @@ -131,7 +146,6 @@ BEGIN op_type_id FROM operation_range WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row - AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) -- if block_check is not NULL, exclude the operations from last block -- operations from excluded block are fetched in find_all_records_for_page UNION ALL diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql b/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql index 102b33eb9..f4c5c1c3b 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql @@ -36,9 +36,10 @@ BEGIN ls.operation_id AS id, ls.block_num, ls.op_type_id, + ls.account_op_seq_no, ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) FROM ( - SELECT aov.operation_id, aov.op_type_id, aov.block_num + SELECT aov.operation_id, aov.op_type_id, aov.block_num, aov.account_op_seq_no FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND aov.transacting_account_id = _transacting_account_id @@ -71,7 +72,8 @@ BEGIN ), if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty SELECT - orr.block_num + orr.block_num, + orr.account_op_seq_no FROM operation_range orr WHERE orr.row_num IN ( (SELECT count FROM check_if_saturated), @@ -86,7 +88,15 @@ BEGIN ELSE NULL END - ) AS block_num + ) AS block_num, + ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(account_op_seq_no) + ELSE + NULL + END + ) AS account_op_seq_no FROM if_saturated_find_last_two_ops ), -- returns empty if the last two operations are not in the same block @@ -101,11 +111,15 @@ BEGIN AND aov.transacting_account_id = _transacting_account_id AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) AND aov.account_op_seq_no >= _account_range.from_seq - AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT account_op_seq_no FROM block_check) IS NOT NULL + AND aov.account_op_seq_no <= (SELECT account_op_seq_no FROM block_check) + ) AND ( (SELECT block_num FROM block_check) IS NOT NULL AND aov.block_num = (SELECT block_num FROM block_check) - ) + ) + ORDER BY aov.account_op_seq_no DESC ), union_operations AS MATERIALIZED ( SELECT @@ -114,7 +128,6 @@ BEGIN op_type_id FROM operation_range WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row - AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) -- if block_check is not NULL, exclude the operations from last block -- operations from excluded block are fetched in find_all_records_for_page UNION ALL diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql index 2fe90bc28..90e07645d 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql @@ -36,9 +36,10 @@ BEGIN ls.operation_id AS id, ls.block_num, ls.op_type_id, + ls.account_op_seq_no, ROW_NUMBER() OVER (ORDER BY ls.operation_id DESC) AS row_num -- used to determine if last 2 records are in the same block (when page is saturated) FROM ( - SELECT aov.operation_id, aov.op_type_id, aov.block_num + SELECT aov.operation_id, aov.op_type_id, aov.block_num, aov.account_op_seq_no FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND aov.transacting_account_id = ANY(_transacting_account_ids) @@ -71,7 +72,8 @@ BEGIN ), if_saturated_find_last_two_ops AS ( -- if not saturated, returns empty SELECT - orr.block_num + orr.block_num, + orr.account_op_seq_no FROM operation_range orr WHERE orr.row_num IN ( (SELECT count FROM check_if_saturated), @@ -86,7 +88,15 @@ BEGIN ELSE NULL END - ) AS block_num + ) AS block_num, + ( + CASE + WHEN COUNT(DISTINCT block_num) = 1 THEN + MIN(account_op_seq_no) + ELSE + NULL + END + ) AS account_op_seq_no FROM if_saturated_find_last_two_ops ), -- returns empty if the last two operations are not in the same block @@ -101,11 +111,15 @@ BEGIN AND aov.transacting_account_id = _transacting_account_id AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) AND aov.account_op_seq_no >= _account_range.from_seq - AND aov.account_op_seq_no <= _account_range.to_seq + AND ( + (SELECT account_op_seq_no FROM block_check) IS NOT NULL + AND aov.account_op_seq_no <= (SELECT account_op_seq_no FROM block_check) + ) AND ( (SELECT block_num FROM block_check) IS NOT NULL AND aov.block_num = (SELECT block_num FROM block_check) ) + ORDER BY aov.account_op_seq_no DESC ), union_operations AS MATERIALIZED ( SELECT @@ -114,7 +128,6 @@ BEGIN op_type_id FROM operation_range WHERE row_num <= (__max_page_count * _limit) -- limit to the maximum number of rows for the page and remove the extra row - AND ((SELECT block_num FROM block_check) IS NULL OR block_num != (SELECT block_num FROM block_check) ) -- if block_check is not NULL, exclude the operations from last block -- operations from excluded block are fetched in find_all_records_for_page UNION ALL -- GitLab From b41dc264e167d33eeb58212413014402651f95f2 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Wed, 23 Jul 2025 13:13:48 +0000 Subject: [PATCH 18/24] Use only real operations when used transacting_account_id filtering in get_ops_by_account API --- .../account_history/account_history.sql | 5 +- .../account_history/paging.sql | 35 + .../corner_case_transacting_account.pat.json | 2806 ++++++++--------- ...orner_case_transacting_account.tavern.yaml | 2 +- .../filter_by_transacting_account.pat.json | 262 +- .../transacting_account_exclude.pat.json | 2140 ++++++++++++- 6 files changed, 3486 insertions(+), 1764 deletions(-) diff --git a/queries/hafah_rest_backend/account_history/account_history.sql b/queries/hafah_rest_backend/account_history/account_history.sql index 49c95fda9..d4e05b6a1 100644 --- a/queries/hafah_rest_backend/account_history/account_history.sql +++ b/queries/hafah_rest_backend/account_history/account_history.sql @@ -21,8 +21,11 @@ DECLARE -- flags _filter_by_account_ids BOOLEAN := (_filter_account_ids != ARRAY[NULL]::INT[]); _filter_by_single_acc BOOLEAN := (CASE WHEN (_filter_account_ids != ARRAY[NULL]::INT[]) AND (array_length(_filter_account_ids, 1) = 1) THEN TRUE ELSE FALSE END); - _filter_by_op BOOLEAN:= (_operations IS NOT NULL); + _filter_by_op BOOLEAN; BEGIN + _operations := hafah_backend.limit_to_only_real_operations(_operations, _participation_mode = 'all'); + _filter_by_op := (_operations IS NOT NULL); + CASE -- If no filters are applied, use the default account history function WHEN (NOT _filter_by_account_ids) AND (NOT _filter_by_op) THEN diff --git a/queries/hafah_rest_backend/account_history/paging.sql b/queries/hafah_rest_backend/account_history/paging.sql index e7e790317..e45684cf8 100644 --- a/queries/hafah_rest_backend/account_history/paging.sql +++ b/queries/hafah_rest_backend/account_history/paging.sql @@ -195,4 +195,39 @@ BEGIN END $$; + +CREATE OR REPLACE FUNCTION hafah_backend.limit_to_only_real_operations( + _operations INT [], + _include_virtual BOOLEAN +) +RETURNS INT []-- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +AS +$$ +DECLARE + _non_virtual_ops INT[]; +BEGIN + IF _include_virtual IS TRUE THEN + RETURN _operations; + END IF; + + _non_virtual_ops := ( + SELECT array_agg(id)::INT[] + FROM hafd.operation_types + WHERE is_virtual = FALSE + ); + + IF _operations IS NULL THEN + RETURN _non_virtual_ops; + END IF; + + IF NOT _operations <@ _non_virtual_ops THEN + RAISE EXCEPTION 'Invalid operation ID detected. Allowed IDs are: %', _non_virtual_ops; + END IF; + + RETURN _operations; +END +$$; + RESET ROLE; diff --git a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json index d0e9edd4c..00831ac4a 100644 --- a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json +++ b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.pat.json @@ -1,2131 +1,1941 @@ { - "total_operations": 1001, + "total_operations": 1007, "total_pages": 11, "block_range": { - "from": 4981191, + "from": 4168823, "to": 5000000 }, "operations_result": [ { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013425676", - "precision": 6 - } + "voter": "wilfred", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982887, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:22:51", - "virtual_op": true, - "operation_id": "21401336704664896", - "trx_in_block": -1 + "block": 4180549, + "trx_id": "d5513599594707e5e66301e46d84aa6b94235221", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T05:11:36", + "virtual_op": false, + "operation_id": "17955321234325760", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013430053", - "precision": 6 - } + "voter": "smooth.witness", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982879, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:22:27", - "virtual_op": true, - "operation_id": "21401302344925760", - "trx_in_block": -1 + "block": 4178023, + "trx_id": "6fe2120b5fe391fbdb8521d18511a2790ef63439", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T03:04:54", + "virtual_op": false, + "operation_id": "17944472146935808", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013442940", - "precision": 6 - } + "voter": "smooth", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982856, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:21:18", - "virtual_op": true, - "operation_id": "21401203560677952", - "trx_in_block": -1 + "block": 4178022, + "trx_id": "c9c2e39f80107a748ee61376ed24fb0c50e4bc6d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T03:04:51", + "virtual_op": false, + "operation_id": "17944467851969792", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013463791", - "precision": 6 - } + "body": "@@ -25,16 +25,18 @@\n Please \n+re\n move you\n", + "title": "", + "author": "future24", + "permlink": "re-abit-re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t025421970z", + "json_metadata": "{\"tags\":[\"steemit-help\"],\"users\":[\"abit\"]}", + "parent_author": "abit", + "parent_permlink": "re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t012856733z" } }, - "block": 4982819, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:19:27", - "virtual_op": true, - "operation_id": "21401044646887488", - "trx_in_block": -1 + "block": 4177999, + "trx_id": "897bea177ddb68a9e5206f38f43945ea16f9fb49", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T03:03:42", + "virtual_op": false, + "operation_id": "17944369067720705", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013470113", - "precision": 6 - } + "body": "@@ -22,10 +22,15 @@\n am? \n-Re\n+Please \n move\n@@ -80,8 +80,43 @@\n article!\n+ @abit and the two others flaggers.\n", + "title": "", + "author": "future24", + "permlink": "re-abit-re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t025421970z", + "json_metadata": "{\"tags\":[\"steemit-help\"],\"users\":[\"abit\"]}", + "parent_author": "abit", + "parent_permlink": "re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t012856733z" } }, - "block": 4982808, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:18:54", - "virtual_op": true, - "operation_id": "21400997402247232", - "trx_in_block": -1 + "block": 4177996, + "trx_id": "55b8fd7db82c14dfdb792c86758f273ddccee774", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T03:03:33", + "virtual_op": false, + "operation_id": "17944356182820609", + "trx_in_block": 4 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013482454", - "precision": 6 - } + "body": "What why? Where is spam? Remove your flag men, this is a really important article!", + "title": "", + "author": "future24", + "permlink": "re-abit-re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t025421970z", + "json_metadata": "{\"tags\":[\"steemit-help\"]}", + "parent_author": "abit", + "parent_permlink": "re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t012856733z" } }, - "block": 4982786, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:17:48", - "virtual_op": true, - "operation_id": "21400902912967488", - "trx_in_block": -1 + "block": 4177915, + "trx_id": "0bf3a247078a4084a72e5d4c7d9c69c8d5018bec", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T02:59:24", + "virtual_op": false, + "operation_id": "17944008290467841", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "account_witness_vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013497288", - "precision": 6 - } + "account": "cnfund", + "approve": true, + "witness": "abit" } }, - "block": 4982760, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:16:30", - "virtual_op": true, - "operation_id": "21400791243817280", - "trx_in_block": -1 + "block": 4177899, + "trx_id": "f9c4114303181912292fddfc2e8d67fb065a61db", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-08-18T02:58:33", + "virtual_op": false, + "operation_id": "17943939570991116", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013507987", - "precision": 6 - } + "body": "What why?", + "title": "", + "author": "future24", + "permlink": "re-abit-re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t025421970z", + "json_metadata": "{\"tags\":[\"steemit-help\"]}", + "parent_author": "abit", + "parent_permlink": "re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t012856733z" } }, - "block": 4982741, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:15:33", - "virtual_op": true, - "operation_id": "21400709639439936", - "trx_in_block": -1 + "block": 4177816, + "trx_id": "cf75dc7aa3df2cc8e510e2ca8b34249fed3f2029", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T02:54:24", + "virtual_op": false, + "operation_id": "17943583088706305", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013514310", - "precision": 6 - } + "body": ":(", + "title": "", + "author": "future24", + "permlink": "re-abit-re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t025355873z", + "json_metadata": "{\"tags\":[\"steemit-help\"]}", + "parent_author": "abit", + "parent_permlink": "re-future24-help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community-20160818t012856733z" } }, - "block": 4982730, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:15:00", - "virtual_op": true, - "operation_id": "21400662394798656", - "trx_in_block": -1 + "block": 4177808, + "trx_id": "3540e19c7f122b82c914fce3b721cca68c55316f", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T02:54:00", + "virtual_op": false, + "operation_id": "17943548728967169", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013526408", - "precision": 6 - } + "body": "Good post.", + "title": "", + "author": "cnfund", + "permlink": "re-abit-more-info-about-how-supercomputing-was-dominating-the-mining-queue-20160818t023833863z", + "json_metadata": "{\"tags\":[\"steem\"]}", + "parent_author": "abit", + "parent_permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982709, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:13:57", - "virtual_op": true, - "operation_id": "21400572200484928", - "trx_in_block": -1 + "block": 4177469, + "trx_id": "4ca220d0451d714738f6a77cde61f23f3688452d", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T02:37:00", + "virtual_op": false, + "operation_id": "17942092735055105", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013546652", - "precision": 6 - } + "body": "好深奥", + "title": "", + "author": "oflyhigh", + "permlink": "re-abit-more-info-about-how-supercomputing-was-dominating-the-mining-queue-20160818t023407147z", + "json_metadata": "{\"tags\":[\"steem\"]}", + "parent_author": "abit", + "parent_permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982672, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:12:06", - "virtual_op": true, - "operation_id": "21400413286695744", - "trx_in_block": -1 + "block": 4177413, + "trx_id": "5f8b65daf407cd9c241348fea07b9204431cbd3e", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T02:34:12", + "virtual_op": false, + "operation_id": "17941852216885505", + "trx_in_block": 1 }, { "op": { - "type": "curation_reward_operation", + "type": "vote_operation", "value": { - "author": "laonie", - "reward": { - "nai": "@@000000037", - "amount": "2995465372", - "precision": 6 - }, - "curator": "abit", - "permlink": "robinhoodwhale-14-09-2016", - "payout_must_be_claimed": false + "voter": "cnfund", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982671, - "trx_id": null, - "op_pos": 3, - "op_type_id": 52, - "timestamp": "2016-09-15T05:12:03", - "virtual_op": true, - "operation_id": "21400408991729460", - "trx_in_block": -1 + "block": 4177411, + "trx_id": "fd8dcdb936ea07b2c9879f7a064a09a244e9f2c7", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T02:34:06", + "virtual_op": false, + "operation_id": "17941843626950656", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013553765", - "precision": 6 - } + "voter": "oflyhigh", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982659, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:11:27", - "virtual_op": true, - "operation_id": "21400357452120640", - "trx_in_block": -1 + "block": 4177331, + "trx_id": "cd1ad5c664a2618d9f7eb65745420be244b92fd6", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T02:30:06", + "virtual_op": false, + "operation_id": "17941500029567488", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013562824", - "precision": 6 - } + "voter": "sweetsssj", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982643, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:10:39", - "virtual_op": true, - "operation_id": "21400288732643904", - "trx_in_block": -1 + "block": 4176288, + "trx_id": "0ae8cd08368b59aaed9194828a1f8958f85b2bf9", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:37:45", + "virtual_op": false, + "operation_id": "17937020378678016", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013582278", - "precision": 6 - } + "voter": "beowulfoflegend", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982608, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:08:54", - "virtual_op": true, - "operation_id": "21400138408789056", - "trx_in_block": -1 + "block": 4176086, + "trx_id": "bad6d9079a59b46ba3d99eb1005127ff93e1d38d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:27:36", + "virtual_op": false, + "operation_id": "17936152795283456", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013593221", - "precision": 6 - } + "voter": "johnbradshaw", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982588, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:07:54", - "virtual_op": true, - "operation_id": "21400052509443648", - "trx_in_block": -1 + "block": 4175958, + "trx_id": "b599d4c642abfb9b2e05dc8d2f0d29072a6c13d2", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:21:09", + "virtual_op": false, + "operation_id": "17935603039470592", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013600638", - "precision": 6 - } + "voter": "thebotkiller", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982575, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:07:15", - "virtual_op": true, - "operation_id": "21399996674872384", - "trx_in_block": -1 + "block": 4175954, + "trx_id": "c99499099a5e7302e73e8e8a1eb61414c84b1722", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:20:57", + "virtual_op": false, + "operation_id": "17935585859601152", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013617662", - "precision": 6 - } + "voter": "vote", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982545, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:05:45", - "virtual_op": true, - "operation_id": "21399867825850432", - "trx_in_block": -1 + "block": 4175951, + "trx_id": "a8293a43ed064e0420955b612d5f59e0c01b9686", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:20:48", + "virtual_op": false, + "operation_id": "17935572974699264", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013619303", - "precision": 6 - } + "voter": "unicornfarts", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982542, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:05:36", - "virtual_op": true, - "operation_id": "21399854940946496", - "trx_in_block": -1 + "block": 4175949, + "trx_id": "f75d2ab3c7efdd4637419f0862c2fcd0a8b0f2ba", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:20:42", + "virtual_op": false, + "operation_id": "17935564384764416", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013634381", - "precision": 6 - } + "voter": "the.whale", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982515, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:04:15", - "virtual_op": true, - "operation_id": "21399738976830784", - "trx_in_block": -1 + "block": 4175942, + "trx_id": "c211cf0909d0c2eaf60c6a8b683b79646fbfd428", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:20:21", + "virtual_op": false, + "operation_id": "17935534319993088", + "trx_in_block": 1 }, { "op": { - "type": "pow_reward_operation", + "type": "vote_operation", "value": { - "reward": { - "nai": "@@000000037", - "amount": "5029755783", - "precision": 6 - }, - "worker": "abit" + "voter": "kissmybutt", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982515, - "trx_id": "93a6c22ea048b25bdd24eff1452fa499ae85dc47", - "op_pos": 1, - "op_type_id": 78, - "timestamp": "2016-09-15T05:04:15", - "virtual_op": true, - "operation_id": "21399738976830542", - "trx_in_block": 2 + "block": 4175936, + "trx_id": "dadb9b8432490cb7df5c1d9701ca424f20929513", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:20:03", + "virtual_op": false, + "operation_id": "17935508550189568", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013644049", - "precision": 6 - } + "voter": "iloveporn", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982499, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:03:27", - "virtual_op": true, - "operation_id": "21399670257354048", - "trx_in_block": -1 + "block": 4175933, + "trx_id": "e9d28dad939a41cc3a542ab7d2a1ab2bacbdd031", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:19:54", + "virtual_op": false, + "operation_id": "17935495665287168", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "account_witness_vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013654203", - "precision": 6 - } + "account": "someguy123", + "approve": true, + "witness": "abit" } }, - "block": 4982481, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:02:33", - "virtual_op": true, - "operation_id": "21399592947941440", - "trx_in_block": -1 + "block": 4175931, + "trx_id": "af0cdbbacc531612c132376646f0e10369f4dd84", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-08-18T01:19:48", + "virtual_op": false, + "operation_id": "17935487075352588", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013667092", - "precision": 6 - } + "voter": "jimmytwoshoes", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982458, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:01:24", - "virtual_op": true, - "operation_id": "21399494163694400", - "trx_in_block": -1 + "block": 4175930, + "trx_id": "ef73c9df04c601a3066ce468ee98e3080c2b4505", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:19:45", + "virtual_op": false, + "operation_id": "17935482780386048", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013678887", - "precision": 6 - } + "voter": "fuck.off", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982437, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T05:00:21", - "virtual_op": true, - "operation_id": "21399403969381440", - "trx_in_block": -1 + "block": 4175923, + "trx_id": "a4d76fe4893a119c3c91900baf1ae558a26a5f58", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:19:24", + "virtual_op": false, + "operation_id": "17935452715614208", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013689284", - "precision": 6 - } + "voter": "the.bot", + "author": "abit", + "weight": 5000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982418, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:59:24", - "virtual_op": true, - "operation_id": "21399322365002816", - "trx_in_block": -1 + "block": 4175922, + "trx_id": "726f9aa74db51fd03774c97d52c45bd0575224b3", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:19:21", + "virtual_op": false, + "operation_id": "17935448420648192", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013710625", - "precision": 6 - } + "voter": "complexring", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982379, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:57:27", - "virtual_op": true, - "operation_id": "21399154861277504", - "trx_in_block": -1 + "block": 4175904, + "trx_id": "934fd359021968bfdd2cbcf9b076e43f72c4e091", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-18T01:18:27", + "virtual_op": false, + "operation_id": "17935371111237632", + "trx_in_block": 7 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013720231", - "precision": 6 - } + "body": "@@ -449,17 +449,19 @@\n he exist\n-s\n+ing\n APIs co\n", + "title": "", + "author": "arhag", + "permlink": "re-abit-more-info-about-how-supercomputing-was-dominating-the-mining-queue-20160817t205401396z", + "json_metadata": "{\"tags\":[\"steem\"],\"users\":[\"supercomputing\"]}", + "parent_author": "abit", + "parent_permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982362, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:56:36", - "virtual_op": true, - "operation_id": "21399081846835264", - "trx_in_block": -1 + "block": 4175841, + "trx_id": "e19ff8fd7af31528b0ed3cf909d261c31e014208", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-18T01:15:18", + "virtual_op": false, + "operation_id": "17935100528296193", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013729291", - "precision": 6 - } + "voter": "murh", + "author": "abit", + "weight": 3301, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982346, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:55:48", - "virtual_op": true, - "operation_id": "21399013127358528", - "trx_in_block": -1 + "block": 4173263, + "trx_id": "16448d8c45ac9913ee5bdd8f7e26ac4149c7cdcf", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T23:06:00", + "virtual_op": false, + "operation_id": "17924028102608384", + "trx_in_block": 3 }, { "op": { - "type": "effective_comment_vote_operation", + "type": "vote_operation", "value": { - "voter": "abit", - "author": "userlogin", - "weight": "5219181476551540775", - "rshares": 7016909099162, - "permlink": "steem-transfer-daily-2016-09-14-steem", - "pending_payout": { - "nai": "@@000000013", - "amount": "7164", - "precision": 3 - }, - "total_vote_weight": "13201860673658672410" + "voter": "ubg", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982346, - "trx_id": "f50be9b3d52340525260f7c9d87f6c884d70284f", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-15T04:55:48", - "virtual_op": true, - "operation_id": "21399013127357256", - "trx_in_block": 1 + "block": 4173117, + "trx_id": "8526ac2d81195029b97a9ab7350aef9e3476e5b0", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T22:58:42", + "virtual_op": false, + "operation_id": "17923401037381632", + "trx_in_block": 0 }, { "op": { - "type": "vote_operation", + "type": "comment_operation", "value": { - "voter": "abit", - "author": "userlogin", - "weight": 10000, - "permlink": "steem-transfer-daily-2016-09-14-steem" + "body": "Upvoted, thanks for this article! It would be really nice if you would upvote my new article here everyone, with which i will support a friend in gambia: https://steemit.com/steemit-help/@future24/help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community", + "title": "", + "author": "future24", + "permlink": "re-abit-more-info-about-how-supercomputing-was-dominating-the-mining-queue-20160817t223353721z", + "json_metadata": "{\"tags\":[\"steem\"],\"links\":[\"https://steemit.com/steemit-help/@future24/help-for-a-bro-in-africa-gambia-let-s-share-this-steemit-community\"]}", + "parent_author": "abit", + "parent_permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982346, - "trx_id": "f50be9b3d52340525260f7c9d87f6c884d70284f", + "block": 4172624, + "trx_id": "5e6deaad2db89a5638720105613f906a64bb21b6", "op_pos": 0, - "op_type_id": 0, - "timestamp": "2016-09-15T04:55:48", + "op_type_id": 1, + "timestamp": "2016-08-17T22:33:57", "virtual_op": false, - "operation_id": "21399013127356928", - "trx_in_block": 1 + "operation_id": "17921283618504705", + "trx_in_block": 0 }, { "op": { - "type": "curation_reward_operation", + "type": "vote_operation", "value": { - "author": "oflyhigh", - "reward": { - "nai": "@@000000037", - "amount": "5162538482", - "precision": 6 - }, - "curator": "abit", - "permlink": "6hoytq", - "payout_must_be_claimed": false + "voter": "future24", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982324, - "trx_id": null, - "op_pos": 2, - "op_type_id": 52, - "timestamp": "2016-09-15T04:54:42", - "virtual_op": true, - "operation_id": "21398918638078260", - "trx_in_block": -1 + "block": 4172554, + "trx_id": "b497671e6e3d6efd5a58d2180d918439df6a1bf8", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T22:30:27", + "virtual_op": false, + "operation_id": "17920982970793984", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013743823", - "precision": 6 - } + "voter": "picokernel", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982320, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:54:30", - "virtual_op": true, - "operation_id": "21398901458208064", - "trx_in_block": -1 + "block": 4171752, + "trx_id": "f217ba8648f509b092346b6f06c4bd0a3e750a88", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T21:50:12", + "virtual_op": false, + "operation_id": "17917538407024640", + "trx_in_block": 4 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013757017", - "precision": 6 - } + "voter": "kennyskitchen", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982297, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:53:21", - "virtual_op": true, - "operation_id": "21398802673961536", - "trx_in_block": -1 + "block": 4171719, + "trx_id": "c59b6600d68ea981e222e7de251ebf499a1c4f59", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T21:48:33", + "virtual_op": false, + "operation_id": "17917396673102848", + "trx_in_block": 3 }, { "op": { - "type": "pow_reward_operation", + "type": "vote_operation", "value": { - "reward": { - "nai": "@@000000037", - "amount": "5029960462", - "precision": 6 - }, - "worker": "abit" + "voter": "goose", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982297, - "trx_id": "d6acf652384c58c55a23127f09bf5f5652c2baf9", - "op_pos": 1, - "op_type_id": 78, - "timestamp": "2016-09-15T04:53:21", - "virtual_op": true, - "operation_id": "21398802673959246", - "trx_in_block": 0 + "block": 4171414, + "trx_id": "ded9cf3ec6836371294baebb5fd9139a966a0f76", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T21:33:15", + "virtual_op": false, + "operation_id": "17916086708078080", + "trx_in_block": 5 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013761700", - "precision": 6 - } + "voter": "doggnostic", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982289, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:52:57", - "virtual_op": true, - "operation_id": "21398768314221632", - "trx_in_block": -1 + "block": 4170809, + "trx_id": "2af2db3cfe109bffd30cb846a7315578fc1c621d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T21:02:51", + "virtual_op": false, + "operation_id": "17913488252862720", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013778420", - "precision": 6 - } + "body": "> she can simply recover the public key (which is needed to put into the PoW operation) with the same method used in step 6\n\n> because a transaction contains only a PoW operation requires no signature (which is another hole in the old algo which got fixed in new algo)\n\nGood point.\n\nThat means the implementation of the exploit was actually easier than I thought because it didn't require messing around the libsecp256k1 function implementations. The exists APIs could have been used to get the active public key, and that's most likely what was used by @supercomputing.", + "title": "", + "author": "arhag", + "permlink": "re-abit-more-info-about-how-supercomputing-was-dominating-the-mining-queue-20160817t205401396z", + "json_metadata": "{\"tags\":[\"steem\"],\"users\":[\"supercomputing\"]}", + "parent_author": "abit", + "parent_permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982259, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:51:27", - "virtual_op": true, - "operation_id": "21398639465201728", - "trx_in_block": -1 + "block": 4170633, + "trx_id": "dd415881c4c12104206e0b0b9e537732e517dbed", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-17T20:54:03", + "virtual_op": false, + "operation_id": "17912732338619905", + "trx_in_block": 4 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013792405", - "precision": 6 - } + "voter": "helen.tan", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982234, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:50:12", - "virtual_op": true, - "operation_id": "21398532091019840", - "trx_in_block": -1 + "block": 4170627, + "trx_id": "38039d31a66da9c06c42ddcddbc1088becf0d2ad", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:45", + "virtual_op": false, + "operation_id": "17912706568815104", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013800066", - "precision": 6 - } + "voter": "moon", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982220, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:49:30", - "virtual_op": true, - "operation_id": "21398471961480512", - "trx_in_block": -1 + "block": 4170626, + "trx_id": "06bd5756758c14cf92252941ce9cde0787448027", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:42", + "virtual_op": false, + "operation_id": "17912702273848064", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013813504", - "precision": 6 - } + "voter": "bunny", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982196, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:48:18", - "virtual_op": true, - "operation_id": "21398368882262080", - "trx_in_block": -1 + "block": 4170625, + "trx_id": "9a2729ac6f3a21e9c9b86333e8c6c59df754e64e", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:39", + "virtual_op": false, + "operation_id": "17912697978880000", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013826942", - "precision": 6 - } + "voter": "daniel.pan", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982172, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:47:06", - "virtual_op": true, - "operation_id": "21398265803049792", - "trx_in_block": -1 + "block": 4170624, + "trx_id": "55d598328b622c0c3e8f87aafb6ed95e3d8e1644", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:36", + "virtual_op": false, + "operation_id": "17912693683915520", + "trx_in_block": 7 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013835698", - "precision": 6 - } + "voter": "boy", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982156, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:46:18", - "virtual_op": true, - "operation_id": "21398197083571264", - "trx_in_block": -1 + "block": 4170624, + "trx_id": "26d2f4480f4919b2665d36ab8f5e1fdebdba7813", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:36", + "virtual_op": false, + "operation_id": "17912693683913472", + "trx_in_block": 2 }, { "op": { - "type": "effective_comment_vote_operation", + "type": "vote_operation", "value": { - "voter": "abit", - "author": "lemooljiang", - "weight": "11541103210750507335", - "rshares": 7016726247780, - "permlink": "471m1v", - "pending_payout": { - "nai": "@@000000013", - "amount": "3937", - "precision": 3 - }, - "total_vote_weight": "11780897525504116941" + "voter": "healthcare", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982152, - "trx_id": "db504e419e8e1cb7160f5afb500d259e31c0f355", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-15T04:46:06", - "virtual_op": true, - "operation_id": "21398179903701832", - "trx_in_block": 1 + "block": 4170623, + "trx_id": "e1cfadaff7dd3d191ce004e2b5cefee078effe93", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:33", + "virtual_op": false, + "operation_id": "17912689388946432", + "trx_in_block": 2 }, { "op": { "type": "vote_operation", "value": { - "voter": "abit", - "author": "lemooljiang", + "voter": "mini", + "author": "abit", "weight": 10000, - "permlink": "471m1v" + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982152, - "trx_id": "db504e419e8e1cb7160f5afb500d259e31c0f355", + "block": 4170622, + "trx_id": "9f1cbc3a0cbd787b839c4cadc0effcc0e2f550f1", "op_pos": 0, "op_type_id": 0, - "timestamp": "2016-09-15T04:46:06", + "timestamp": "2016-08-17T20:53:30", "virtual_op": false, - "operation_id": "21398179903701504", - "trx_in_block": 1 + "operation_id": "17912685093981440", + "trx_in_block": 7 }, { "op": { - "type": "effective_comment_vote_operation", + "type": "vote_operation", "value": { - "voter": "abit", - "author": "yangyang", - "weight": "7647348356681883608", - "rshares": 7016726247780, - "permlink": "mid-autumn-day-s-pc-paint-drawing", - "pending_payout": { - "nai": "@@000000013", - "amount": "5297", - "precision": 3 - }, - "total_vote_weight": "12521623444169398596" + "voter": "soupernerd", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982150, - "trx_id": "6247131aa802ec51641b6ef81434f11b0e0f02b4", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-15T04:46:00", - "virtual_op": true, - "operation_id": "21398171313767496", - "trx_in_block": 2 + "block": 4170622, + "trx_id": "ae5f38f37de3e7887feedae6bec141d1facb5bc6", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:30", + "virtual_op": false, + "operation_id": "17912685093980160", + "trx_in_block": 4 }, { "op": { "type": "vote_operation", "value": { - "voter": "abit", - "author": "yangyang", + "voter": "bue", + "author": "abit", "weight": 10000, - "permlink": "mid-autumn-day-s-pc-paint-drawing" + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982150, - "trx_id": "6247131aa802ec51641b6ef81434f11b0e0f02b4", + "block": 4170622, + "trx_id": "441e33562394078a9bb23d7c29e17e66e84c4211", "op_pos": 0, "op_type_id": 0, - "timestamp": "2016-09-15T04:46:00", + "timestamp": "2016-08-17T20:53:30", "virtual_op": false, - "operation_id": "21398171313767168", + "operation_id": "17912685093979136", "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013851630", - "precision": 6 - } + "voter": "weenis", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982128, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:44:54", - "virtual_op": true, - "operation_id": "21398076824485952", - "trx_in_block": -1 + "block": 4170622, + "trx_id": "9d2583236e6c09f981e716cd4ee43972c49902f1", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:30", + "virtual_op": false, + "operation_id": "17912685093978112", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013853818", - "precision": 6 - } + "voter": "bue-witness", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982124, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:44:42", - "virtual_op": true, - "operation_id": "21398059644617280", - "trx_in_block": -1 + "block": 4170621, + "trx_id": "65c112b5197cdc41ddf04d1105398fe1ca5ae97b", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:27", + "virtual_op": false, + "operation_id": "17912680799014400", + "trx_in_block": 8 }, { "op": { - "type": "effective_comment_vote_operation", + "type": "vote_operation", "value": { - "voter": "abit", - "author": "jademont", - "weight": "11681497147989204564", - "rshares": 7016696712023, - "permlink": "re-bloggersclub-breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be-20160915t040222007z", - "pending_payout": { - "nai": "@@000000013", - "amount": "3902", - "precision": 3 - }, - "total_vote_weight": "11759286132483617228" + "voter": "anonymous", + "author": "abit", + "weight": 100, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982116, - "trx_id": "3f4082939c57dd19b9751d1bc911d46d24bb6d97", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-15T04:44:18", - "virtual_op": true, - "operation_id": "21398025284879688", + "block": 4170612, + "trx_id": "c78ca80f68357fe63de38b9759bae157001b5cd0", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:53:00", + "virtual_op": false, + "operation_id": "17912642144305920", "trx_in_block": 2 }, { "op": { "type": "vote_operation", "value": { - "voter": "abit", - "author": "jademont", + "voter": "arhag", + "author": "abit", "weight": 10000, - "permlink": "re-bloggersclub-breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be-20160915t040222007z" + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982116, - "trx_id": "3f4082939c57dd19b9751d1bc911d46d24bb6d97", + "block": 4170610, + "trx_id": "fc52bfa8cafa36882448cd165fe6575caef44b39", "op_pos": 0, "op_type_id": 0, - "timestamp": "2016-09-15T04:44:18", + "timestamp": "2016-08-17T20:52:54", "virtual_op": false, - "operation_id": "21398025284879360", - "trx_in_block": 2 + "operation_id": "17912633554374144", + "trx_in_block": 8 }, { "op": { - "type": "effective_comment_vote_operation", + "type": "vote_operation", "value": { - "voter": "abit", - "author": "bloggersclub", - "weight": "8078580049650391897", - "rshares": 7159894604105, - "permlink": "breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be", - "pending_payout": { - "nai": "@@000000013", - "amount": "5262", - "precision": 3 - }, - "total_vote_weight": "12507535182167387389" + "voter": "lantto", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982114, - "trx_id": "1a4f109bafd56cfdaa64ce0426e07dbba6e68c75", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-09-15T04:44:12", - "virtual_op": true, - "operation_id": "21398016694944072", - "trx_in_block": 0 + "block": 4170584, + "trx_id": "fe485135ea19187752a31288fa4fbef482ab6008", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:51:33", + "virtual_op": false, + "operation_id": "17912521885221376", + "trx_in_block": 1 }, { "op": { "type": "vote_operation", "value": { - "voter": "abit", - "author": "bloggersclub", + "voter": "d-marim", + "author": "abit", "weight": 10000, - "permlink": "breaking-news-first-time-voting-option-as-shareholder-made-possible-on-the-decentralized-excahnge-openledger-let-your-voice-be" + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982114, - "trx_id": "1a4f109bafd56cfdaa64ce0426e07dbba6e68c75", + "block": 4170465, + "trx_id": "3c430f9ae353f382a33abb223de641517d394c91", "op_pos": 0, "op_type_id": 0, - "timestamp": "2016-09-15T04:44:12", + "timestamp": "2016-08-17T20:45:36", "virtual_op": false, - "operation_id": "21398016694943744", - "trx_in_block": 0 + "operation_id": "17912010784114176", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013874980", - "precision": 6 - } + "voter": "roadhog", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982087, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:42:51", - "virtual_op": true, - "operation_id": "21397900730827328", - "trx_in_block": -1 + "block": 4170412, + "trx_id": "e41e67e783eaa7071685dbdf639cd8040f0747cc", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:42:57", + "virtual_op": false, + "operation_id": "17911783150846720", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013887567", - "precision": 6 - } + "voter": "fatboy", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982064, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:41:42", - "virtual_op": true, - "operation_id": "21397801946579520", - "trx_in_block": -1 + "block": 4170164, + "trx_id": "57c8dde2f492f8d231babb9b9b06bb007d763ea5", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:30:24", + "virtual_op": false, + "operation_id": "17910717998959616", + "trx_in_block": 7 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013896323", - "precision": 6 - } + "voter": "analyzethis", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982048, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:40:54", - "virtual_op": true, - "operation_id": "21397733227103040", - "trx_in_block": -1 + "block": 4170010, + "trx_id": "2939bfa522efd72e3219f0fd05ca96bce51949c3", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:22:42", + "virtual_op": false, + "operation_id": "17910056573992960", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013905079", - "precision": 6 - } + "voter": "sunshinecrypto", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982032, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:40:06", - "virtual_op": true, - "operation_id": "21397664507626048", - "trx_in_block": -1 + "block": 4169776, + "trx_id": "382ccb0068157f6acac0244d77b3e0747141388a", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:10:57", + "virtual_op": false, + "operation_id": "17909051551648000", + "trx_in_block": 7 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013920707", - "precision": 6 - } + "voter": "jenny-talls", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4982004, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:38:39", - "virtual_op": true, - "operation_id": "21397544248542016", - "trx_in_block": -1 + "block": 4169622, + "trx_id": "9844a94ffdef916e7fca95150f8b4ddb82939802", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T20:03:15", + "virtual_op": false, + "operation_id": "17908390126682624", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013923991", - "precision": 6 - } + "voter": "xtester", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981998, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:38:21", - "virtual_op": true, - "operation_id": "21397518478738240", - "trx_in_block": -1 + "block": 4169555, + "trx_id": "0923e754731cebf0e2d5187602578a140875bc31", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:59:54", + "virtual_op": false, + "operation_id": "17908102363874304", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013937977", - "precision": 6 - } + "voter": "akareyon", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981973, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:37:06", - "virtual_op": true, - "operation_id": "21397411104555072", - "trx_in_block": -1 + "block": 4169417, + "trx_id": "a5c6aa66d2ff8fbe0dc2d49b4aa4d21acb0049f9", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:53:00", + "virtual_op": false, + "operation_id": "17907509658386944", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013955794", - "precision": 6 - } + "voter": "bingo-0", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981941, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:35:30", - "virtual_op": true, - "operation_id": "21397273665601856", - "trx_in_block": -1 + "block": 4169360, + "trx_id": "6b88d4f2b4e3f82fd1a71a408f8a050ff4ba2e2c", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:50:06", + "virtual_op": false, + "operation_id": "17907264845253376", + "trx_in_block": 7 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013965098", - "precision": 6 - } + "voter": "mineralwasser", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981924, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:34:39", - "virtual_op": true, - "operation_id": "21397200651157568", - "trx_in_block": -1 + "block": 4169331, + "trx_id": "fd16f81e0af11d8e9caf7e13f9d74deb93b5d252", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:48:39", + "virtual_op": false, + "operation_id": "17907140291200000", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013971118", - "precision": 6 - } + "voter": "boombastic", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981913, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:34:06", - "virtual_op": true, - "operation_id": "21397153406518848", - "trx_in_block": -1 + "block": 4169267, + "trx_id": "8e662a536807690328ae0bf81e6e846fd2bc213f", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:45:27", + "virtual_op": false, + "operation_id": "17906865413292288", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013987964", - "precision": 6 - } + "voter": "barrie", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981885, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:32:42", - "virtual_op": true, - "operation_id": "21397033147433280", - "trx_in_block": -1 + "block": 4169264, + "trx_id": "8bcf684d6a4b044912e5b5481d6b4701cafb63a8", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:45:18", + "virtual_op": false, + "operation_id": "17906852528390144", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3013995079", - "precision": 6 - } + "voter": "mrs.agsexplorer", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981872, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:32:03", - "virtual_op": true, - "operation_id": "21396977312858688", - "trx_in_block": -1 + "block": 4169256, + "trx_id": "9b24f8dc5c84ec440e47dca7b777134444858b47", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:44:54", + "virtual_op": false, + "operation_id": "17906818168651776", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014016486", - "precision": 6 - } + "voter": "rubybian", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981834, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:30:09", - "virtual_op": true, - "operation_id": "21396814104101440", - "trx_in_block": -1 + "block": 4169253, + "trx_id": "26feb906bdf2dbaeb150378a2fe438ec883ddca4", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:44:45", + "virtual_op": false, + "operation_id": "17906805283750400", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014021411", - "precision": 6 - } + "voter": "post-successful", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981825, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:29:42", - "virtual_op": true, - "operation_id": "21396775449395776", - "trx_in_block": -1 + "block": 4169209, + "trx_id": "6f67360bc47ea12751c4b484dc72fa11bf7926dd", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:42:33", + "virtual_op": false, + "operation_id": "17906616305188864", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014039230", - "precision": 6 - } + "voter": "litali", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981793, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:28:06", - "virtual_op": true, - "operation_id": "21396638010442816", - "trx_in_block": -1 + "block": 4169200, + "trx_id": "48f812a1d3432b19cead461b11f2fbcd8d26d27f", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:42:06", + "virtual_op": false, + "operation_id": "17906577650483712", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014047197", - "precision": 6 - } + "voter": "alenevaa", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981779, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:27:24", - "virtual_op": true, - "operation_id": "21396577880900928", - "trx_in_block": -1 + "block": 4169197, + "trx_id": "bf1e7f5633b2a9bbb2685501d9cb61463fd28a1e", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:41:57", + "virtual_op": false, + "operation_id": "17906564765581824", + "trx_in_block": 1 }, { "op": { - "type": "pow_reward_operation", + "type": "vote_operation", "value": { - "reward": { - "nai": "@@000000037", - "amount": "5030444771", - "precision": 6 - }, - "worker": "abit" + "voter": "michaeldodridge", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981779, - "trx_id": "fd069f532c0fedc78350bff449929379594ddd8d", - "op_pos": 1, - "op_type_id": 78, - "timestamp": "2016-09-15T04:27:24", - "virtual_op": true, - "operation_id": "21396577880900174", - "trx_in_block": 1 + "block": 4169143, + "trx_id": "c3343d0825bac9cb45c53f04494439860b6b21fb", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:39:15", + "virtual_op": false, + "operation_id": "17906332837347328", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014054616", - "precision": 6 - } + "voter": "cortegam", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981766, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:26:45", - "virtual_op": true, - "operation_id": "21396522046325056", - "trx_in_block": -1 + "block": 4169141, + "trx_id": "55511109529e1210724df33b6a11d1a11f9ff70c", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:39:09", + "virtual_op": false, + "operation_id": "17906324247412736", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "comment_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014076875", - "precision": 6 - } + "body": "> But there is a hole in the description, because the private key of a given signature shouldn't be so quickly to be resolved -- it's the nature of ECC algo.\n\nIs it bad?", + "title": "", + "author": "vi1son", + "permlink": "re-abit-more-info-about-how-supercomputing-was-dominating-the-mining-queue-20160817t193631631z", + "json_metadata": "{\"tags\":[\"steem\"]}", + "parent_author": "abit", + "parent_permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981727, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:24:48", - "virtual_op": true, - "operation_id": "21396354542600768", - "trx_in_block": -1 + "block": 4169089, + "trx_id": "bc2e2374fdca3bda39956135c015adffaab8dcc1", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-17T19:36:33", + "virtual_op": false, + "operation_id": "17906100909113345", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014081801", - "precision": 6 - } + "voter": "gsdalex", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981718, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:24:21", - "virtual_op": true, - "operation_id": "21396315887896896", - "trx_in_block": -1 + "block": 4169053, + "trx_id": "4d80b57eabf70c2ad2c791122b49f20908ab6623", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:34:45", + "virtual_op": false, + "operation_id": "17905946290292992", + "trx_in_block": 7 }, { "op": { - "type": "pow_reward_operation", + "type": "vote_operation", "value": { - "reward": { - "nai": "@@000000037", - "amount": "5030502526", - "precision": 6 - }, - "worker": "abit" + "voter": "runridefly", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981718, - "trx_id": "e31cc6c7b75dbf93efcdb2ba490e582a754a3cce", - "op_pos": 1, - "op_type_id": 78, - "timestamp": "2016-09-15T04:24:21", - "virtual_op": true, - "operation_id": "21396315887895374", + "block": 4169036, + "trx_id": "f915034739a322a79cdee3fcb75893a6531a6d03", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:33:54", + "virtual_op": false, + "operation_id": "17905873275846912", "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014091776", - "precision": 6 - } + "voter": "james-show", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981702, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:23:33", - "virtual_op": true, - "operation_id": "21396247168418624", - "trx_in_block": -1 + "block": 4169023, + "trx_id": "65802b72a716770e5ce79b4ff7b1b149844678d8", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:33:15", + "virtual_op": false, + "operation_id": "17905817441272320", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014106069", - "precision": 6 - } + "voter": "vi1son", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981677, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:22:18", - "virtual_op": true, - "operation_id": "21396139794235712", - "trx_in_block": -1 + "block": 4169015, + "trx_id": "910c1025d284a3ba733901a3cf025eae71f58fe2", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:32:51", + "virtual_op": false, + "operation_id": "17905783081533440", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014119510", - "precision": 6 - } + "voter": "mahekg", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981653, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:21:06", - "virtual_op": true, - "operation_id": "21396036715020864", - "trx_in_block": -1 + "block": 4168991, + "trx_id": "d72e7e898dd751996095b140a680e1e8fe971740", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:31:39", + "virtual_op": false, + "operation_id": "17905680002319872", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014135444", - "precision": 6 - } + "voter": "eileenbeach", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981625, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:19:42", - "virtual_op": true, - "operation_id": "21395916455937344", - "trx_in_block": -1 + "block": 4168934, + "trx_id": "ff0c6209649fc1780aeb3265569e7c67f3b1eb6c", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:28:48", + "virtual_op": false, + "operation_id": "17905435189182720", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014139823", - "precision": 6 - } + "voter": "mrainp", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981617, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:19:18", - "virtual_op": true, - "operation_id": "21395882096197696", - "trx_in_block": -1 + "block": 4168920, + "trx_id": "164cbb960dcd21ae4e7168da594a07af8a94ecfb", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:28:06", + "virtual_op": false, + "operation_id": "17905375059641600", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014154906", - "precision": 6 - } + "voter": "imp3", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981590, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:17:57", - "virtual_op": true, - "operation_id": "21395766132081216", - "trx_in_block": -1 + "block": 4168916, + "trx_id": "dfb7215af4bb9e9531acd9c4bfc956df7012e503", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:27:54", + "virtual_op": false, + "operation_id": "17905357879772928", + "trx_in_block": 4 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014171875", - "precision": 6 - } + "voter": "budda", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981559, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:16:24", - "virtual_op": true, - "operation_id": "21395632988095296", - "trx_in_block": -1 + "block": 4168899, + "trx_id": "839fee965784bef49507c7c4ea37e0e8669728e5", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:27:03", + "virtual_op": false, + "operation_id": "17905284865327616", + "trx_in_block": 2 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014175159", - "precision": 6 - } + "voter": "natalyt", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981553, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:16:06", - "virtual_op": true, - "operation_id": "21395607218291776", - "trx_in_block": -1 + "block": 4168897, + "trx_id": "76accba01ed499271558a77195a6fdf9caf8dca6", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:57", + "virtual_op": false, + "operation_id": "17905276275393792", + "trx_in_block": 3 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014188843", - "precision": 6 - } + "voter": "noodhoog", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981528, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:14:51", - "virtual_op": true, - "operation_id": "21395499844109120", - "trx_in_block": -1 + "block": 4168897, + "trx_id": "84cd3e893638a3dc27a7f6740a1a173af4a343c6", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:57", + "virtual_op": false, + "operation_id": "17905276275392512", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014200095", - "precision": 6 - } + "voter": "longtech", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981508, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:13:51", - "virtual_op": true, - "operation_id": "21395413944763456", - "trx_in_block": -1 + "block": 4168896, + "trx_id": "f80ce10451e7dc879020d461479080b6ca03e351", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:54", + "virtual_op": false, + "operation_id": "17905271980425728", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014215969", - "precision": 6 - } + "voter": "future-shock", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981479, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:12:24", - "virtual_op": true, - "operation_id": "21395289390711616", - "trx_in_block": -1 + "block": 4168895, + "trx_id": "24d35725edfac839e706e664e683f6424251c21c", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:51", + "virtual_op": false, + "operation_id": "17905267685458432", + "trx_in_block": 1 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014227221", - "precision": 6 - } + "voter": "immortality", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981459, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:11:24", - "virtual_op": true, - "operation_id": "21395203491365184", - "trx_in_block": -1 + "block": 4168891, + "trx_id": "fef6020765a93c5791d945cc1b1d588f2b65e469", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:39", + "virtual_op": false, + "operation_id": "17905250505588736", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014240116", - "precision": 6 - } + "voter": "longevity", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981436, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:10:15", - "virtual_op": true, - "operation_id": "21395104707117888", - "trx_in_block": -1 + "block": 4168890, + "trx_id": "89d2893d86392360c1e945667a740998d4c8f9cb", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:36", + "virtual_op": false, + "operation_id": "17905246210621440", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014248084", - "precision": 6 - } + "voter": "rashka", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981422, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:09:33", - "virtual_op": true, - "operation_id": "21395044577575488", - "trx_in_block": -1 + "block": 4168889, + "trx_id": "0d01eb4ad15f3537b4eac76cff25cc945ed74941", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:33", + "virtual_op": false, + "operation_id": "17905241915654144", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014261221", - "precision": 6 - } + "voter": "zite", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981398, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:08:21", - "virtual_op": true, - "operation_id": "21394941498360384", - "trx_in_block": -1 + "block": 4168888, + "trx_id": "9d9307ba12c74879e423bfa2eb58cc9817e2875b", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:30", + "virtual_op": false, + "operation_id": "17905237620686848", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014272716", - "precision": 6 - } + "voter": "gamerate", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981377, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:07:18", - "virtual_op": true, - "operation_id": "21394851304046656", - "trx_in_block": -1 + "block": 4168884, + "trx_id": "492f92cb048cc4299b79675d21f735617a85bb44", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:18", + "virtual_op": false, + "operation_id": "17905220440817664", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014280380", - "precision": 6 - } + "voter": "creatorgalaxy", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981363, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:06:36", - "virtual_op": true, - "operation_id": "21394791174505024", - "trx_in_block": -1 + "block": 4168883, + "trx_id": "8c8fe0c7af0da6d18639d77d69f3fc6c297e65a9", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:26:15", + "virtual_op": false, + "operation_id": "17905216145850368", + "trx_in_block": 0 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014300515", - "precision": 6 - } + "voter": "yarly11", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981329, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:04:54", - "virtual_op": true, - "operation_id": "21394645145616960", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "2db3ea74c66360a05357291caae34cbf21281f61", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742785536", + "trx_in_block": 12 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014302704", - "precision": 6 - } + "voter": "yarly4", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981325, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:04:42", - "virtual_op": true, - "operation_id": "21394627965747776", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "e80709bbc27f8d015b07ca28fef70e763bad07dc", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742785024", + "trx_in_block": 11 }, { "op": { - "type": "pow_reward_operation", + "type": "vote_operation", "value": { - "reward": { - "nai": "@@000000037", - "amount": "5030871214", - "precision": 6 - }, - "worker": "abit" + "voter": "yarly7", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981325, - "trx_id": "f977e90eb13123cd1e57fbd457b0661e350f0b8d", - "op_pos": 1, - "op_type_id": 78, - "timestamp": "2016-09-15T04:04:42", - "virtual_op": true, - "operation_id": "21394627965747534", - "trx_in_block": 0 + "block": 4168824, + "trx_id": "aa14551c25b73bf2b6348bb6c0731fc83f253e24", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742784512", + "trx_in_block": 10 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014322230", - "precision": 6 - } + "voter": "yarly10", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981291, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:03:00", - "virtual_op": true, - "operation_id": "21394481936859968", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "b4ecdb973b47497bf16cf2670e21634ae28990e0", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742784000", + "trx_in_block": 9 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014327461", - "precision": 6 - } + "voter": "yarly", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981282, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:02:33", - "virtual_op": true, - "operation_id": "21394443282154048", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "474028851579507d32efe9332fe215faa3e893bf", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742783488", + "trx_in_block": 8 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014341756", - "precision": 6 - } + "voter": "yarly12", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981257, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:01:18", - "virtual_op": true, - "operation_id": "21394335907971136", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "1b7fbca1616974eaec66e911719a47b30b2f5cf9", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742782976", + "trx_in_block": 7 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014354347", - "precision": 6 - } + "voter": "yarly5", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981234, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T04:00:09", - "virtual_op": true, - "operation_id": "21394237123724352", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "4c723177bfa892670b9e6c0a8bfd691cee6697db", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742782464", + "trx_in_block": 6 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014365843", - "precision": 6 - } + "voter": "yarly2", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981213, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T03:59:06", - "virtual_op": true, - "operation_id": "21394146929410112", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "54e5dc8744d77965716ef57afab36efc59a4c919", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742781952", + "trx_in_block": 5 }, { "op": { - "type": "producer_reward_operation", + "type": "vote_operation", "value": { - "producer": "abit", - "vesting_shares": { - "nai": "@@000000037", - "amount": "3014377339", - "precision": 6 - } + "voter": "yarly3", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981192, - "trx_id": null, - "op_pos": 1, - "op_type_id": 64, - "timestamp": "2016-09-15T03:58:03", - "virtual_op": true, - "operation_id": "21394056735097408", - "trx_in_block": -1 + "block": 4168824, + "trx_id": "05fc229b1687887f481b792a1319aea775c3d307", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742781440", + "trx_in_block": 4 }, { "op": { - "type": "pow_reward_operation", + "type": "vote_operation", "value": { - "reward": { - "nai": "@@000000037", - "amount": "5027981402", - "precision": 6 - }, - "worker": "abit" + "voter": "orly", + "author": "abit", + "weight": 10000, + "permlink": "more-info-about-how-supercomputing-was-dominating-the-mining-queue" } }, - "block": 4981192, - "trx_id": "3dac4cc7d1bc5c01a5eca7aebff2af4b9fa3e7f5", - "op_pos": 1, - "op_type_id": 78, - "timestamp": "2016-09-15T03:58:03", - "virtual_op": true, - "operation_id": "21394056735097166", - "trx_in_block": 0 + "block": 4168824, + "trx_id": "e7863cdd210b9907d52515e981d9bb6511147e2d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-17T19:23:18", + "virtual_op": false, + "operation_id": "17904962742780928", + "trx_in_block": 3 } ] } \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml index b9f96ac9d..c7710ef42 100644 --- a/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml +++ b/tests/tavern/get_ops_by_account/positive/corner_case_transacting_account.tavern.yaml @@ -18,7 +18,7 @@ json: account-name: "abit" transacting-account-name: "abit" - participation-mode: "include" + participation-mode: "exclude" page: 1 response: status_code: 200 diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json index cd7ccc925..f8f3fda67 100644 --- a/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json +++ b/tests/tavern/get_ops_by_account/positive/filter_by_transacting_account.pat.json @@ -1,5 +1,5 @@ { - "total_operations": 21, + "total_operations": 11, "total_pages": 1, "block_range": { "from": 1, @@ -24,32 +24,6 @@ "operation_id": "16252409651136780", "trx_in_block": 5 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 1883324796189, - "rshares": 108176539, - "permlink": "bitcoin-payments-accepted-in-20s-soon-to-be-6s", - "pending_payout": { - "nai": "@@000000013", - "amount": "319805", - "precision": 3 - }, - "total_vote_weight": "17313337917951663196" - } - }, - "block": 2887502, - "trx_id": "9729bd39ffede1ad4d461474012f2868b7d4d8a2", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-03T22:43:48", - "virtual_op": true, - "operation_id": "12401726657134920", - "trx_in_block": 0 - }, { "op": { "type": "vote_operation", @@ -69,32 +43,6 @@ "operation_id": "12401726657134592", "trx_in_block": 0 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 26467069, - "permlink": "-blocktrades-adds-support-for-directly-buyingselling-steem", - "pending_payout": { - "nai": "@@000000013", - "amount": "3395497", - "precision": 3 - }, - "total_vote_weight": 37079019999706 - } - }, - "block": 2840599, - "trx_id": "2bf9b0850282ed3867d9a2470dc8d6af55aa4ea4", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T07:34:18", - "virtual_op": true, - "operation_id": "12200279806050632", - "trx_in_block": 0 - }, { "op": { "type": "vote_operation", @@ -114,32 +62,6 @@ "operation_id": "12200279806050304", "trx_in_block": 0 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 26467069, - "permlink": "openledger-pre-sale-of-dao-tokens-is-now-live", - "pending_payout": { - "nai": "@@000000013", - "amount": "1805443", - "precision": 3 - }, - "total_vote_weight": 39555131983403 - } - }, - "block": 2840592, - "trx_id": "5179c7745a8a8e729cf8faab0461e97bc1219ba3", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T07:33:57", - "virtual_op": true, - "operation_id": "12200249741280584", - "trx_in_block": 2 - }, { "op": { "type": "vote_operation", @@ -159,32 +81,6 @@ "operation_id": "12200249741280256", "trx_in_block": 2 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 26467069, - "permlink": "is-vote-changing-an-important-feature-for-steem", - "pending_payout": { - "nai": "@@000000013", - "amount": "1004732", - "precision": 3 - }, - "total_vote_weight": 39522051255407 - } - }, - "block": 2840592, - "trx_id": "4fdfc9bcbc84c0b7d798cf3f0c606269043f14ff", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T07:33:57", - "virtual_op": true, - "operation_id": "12200249741280072", - "trx_in_block": 1 - }, { "op": { "type": "vote_operation", @@ -204,32 +100,6 @@ "operation_id": "12200249741279744", "trx_in_block": 1 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 26467069, - "permlink": "tax-issues-facing-us-based-cryptocurrency-holders-and-miners-intro-and-irs-guidelines", - "pending_payout": { - "nai": "@@000000013", - "amount": "2031797", - "precision": 3 - }, - "total_vote_weight": 38794385435057 - } - }, - "block": 2840592, - "trx_id": "88d2f81c37e1288448b334042c3eee02df6395d9", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T07:33:57", - "virtual_op": true, - "operation_id": "12200249741279560", - "trx_in_block": 0 - }, { "op": { "type": "vote_operation", @@ -249,32 +119,6 @@ "operation_id": "12200249741279232", "trx_in_block": 0 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 27007214, - "permlink": "tax-issues-facing-us-based-cryptocurrency-holders-and-miners-part-1-capital-gainslosses-for-crypto", - "pending_payout": { - "nai": "@@000000013", - "amount": "2428829", - "precision": 3 - }, - "total_vote_weight": 38851983572277 - } - }, - "block": 2840591, - "trx_id": "9174e0f692023ecf91d632f9949a94c808302119", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T07:33:54", - "virtual_op": true, - "operation_id": "12200245446312264", - "trx_in_block": 0 - }, { "op": { "type": "vote_operation", @@ -294,32 +138,6 @@ "operation_id": "12200245446311936", "trx_in_block": 0 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 27007214, - "permlink": "i-find-steemit-posts-with-summariesanalysis-of-3rd-party-content-more-compelling", - "pending_payout": { - "nai": "@@000000013", - "amount": "1386736", - "precision": 3 - }, - "total_vote_weight": 39919636650316 - } - }, - "block": 2840590, - "trx_id": "e909cd27baf117473ec99ec9b875a6916927c55e", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T07:33:51", - "virtual_op": true, - "operation_id": "12200241151344968", - "trx_in_block": 0 - }, { "op": { "type": "vote_operation", @@ -339,32 +157,6 @@ "operation_id": "12200241151344640", "trx_in_block": 0 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 27007214, - "permlink": "blocktrades-now-offering-steem-power-for-cryptocurrency", - "pending_payout": { - "nai": "@@000000013", - "amount": "1439043", - "precision": 3 - }, - "total_vote_weight": 40979209439222 - } - }, - "block": 2840585, - "trx_id": "8726774b3c8d53e9dcb870db6b3561a217871d27", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T07:33:36", - "virtual_op": true, - "operation_id": "12200219676508488", - "trx_in_block": 0 - }, { "op": { "type": "vote_operation", @@ -384,32 +176,6 @@ "operation_id": "12200219676508160", "trx_in_block": 0 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 27007214, - "permlink": "dao-gateway-on-openledger-is-fully-operational", - "pending_payout": { - "nai": "@@000000013", - "amount": "1102767", - "precision": 3 - }, - "total_vote_weight": 37317034722668 - } - }, - "block": 2839669, - "trx_id": "c02b46ca3eced3c6bd5cc43df2114143ce6c2105", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T06:47:45", - "virtual_op": true, - "operation_id": "12196285486465864", - "trx_in_block": 1 - }, { "op": { "type": "vote_operation", @@ -429,32 +195,6 @@ "operation_id": "12196285486465536", "trx_in_block": 1 }, - { - "op": { - "type": "effective_comment_vote_operation", - "value": { - "voter": "gtg", - "author": "blocktrades", - "weight": 0, - "rshares": 27547358, - "permlink": "blocktrades-supports-buyingselling-dao-coins-without-exchange-risk", - "pending_payout": { - "nai": "@@000000013", - "amount": "2715326", - "precision": 3 - }, - "total_vote_weight": 41395120110223 - } - }, - "block": 2839669, - "trx_id": "2b79214e07cffd28c8ee026055d92767229d8b45", - "op_pos": 1, - "op_type_id": 72, - "timestamp": "2016-07-02T06:47:45", - "virtual_op": true, - "operation_id": "12196285486465352", - "trx_in_block": 0 - }, { "op": { "type": "vote_operation", diff --git a/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json index f89fb0414..a401c9095 100644 --- a/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json +++ b/tests/tavern/get_ops_by_account/positive/transacting_account_exclude.pat.json @@ -1,8 +1,8 @@ { - "total_operations": 1001, - "total_pages": 11, + "total_operations": 1000, + "total_pages": 10, "block_range": { - "from": 4576727, + "from": 4514574, "to": 5000000 }, "operations_result": [ @@ -28,6 +28,2140 @@ "virtual_op": false, "operation_id": "21474823595099394", "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "condra", + "memo": "f2c3419c-9522-4bb3-aa41-472c8388f215", + "amount": { + "nai": "@@000000013", + "amount": "400000", + "precision": 3 + } + } + }, + "block": 4999607, + "trx_id": "2577322e21a18f9085cc5dba366b5292824f906b", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T19:26:42", + "virtual_op": false, + "operation_id": "21473148557854722", + "trx_in_block": 5 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "thisisbenbrick", + "memo": "0722aa82-10d0-4001-a286-130b633d58df", + "amount": { + "nai": "@@000000013", + "amount": "431587", + "precision": 3 + } + } + }, + "block": 4996294, + "trx_id": "01de85e061adde226a7ce59071973c9daaeca8ba", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T16:34:45", + "virtual_op": false, + "operation_id": "21458919331201538", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "roelandp", + "memo": "298eafac-95bb-4f27-b256-72df9d0ef222", + "amount": { + "nai": "@@000000021", + "amount": "148056", + "precision": 3 + } + } + }, + "block": 4996091, + "trx_id": "b1aa3d5f9308acd9cde664936c1b08eea77c3e49", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T16:24:36", + "virtual_op": false, + "operation_id": "21458047452841986", + "trx_in_block": 4 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "It just occurred to me that witness updates like this could make for interesting video material. Maybe a segment in our SteemSmart show?", + "title": "", + "author": "piedpiper", + "permlink": "re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160915t161707257z", + "json_metadata": "{\"tags\":[\"witness-category\"]}", + "parent_author": "blocktrades", + "parent_permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4995964, + "trx_id": "3ae419f4d37860c7d2dabec530ccf3ad79e79784", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T16:18:15", + "virtual_op": false, + "operation_id": "21457501991994369", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "macksby", + "memo": "92bff29e-2ee9-4ea4-ace1-6bb0c1331f67", + "amount": { + "nai": "@@000000013", + "amount": "50000", + "precision": 3 + } + } + }, + "block": 4994778, + "trx_id": "f2c59d933ba1fc08bd6f4c79ec52a0aeed6bb9e9", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T15:18:54", + "virtual_op": false, + "operation_id": "21452408160780290", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "good-karma", + "memo": "0c9ca5aa-53c2-445e-912f-d2cf6b111229", + "amount": { + "nai": "@@000000013", + "amount": "1500000", + "precision": 3 + } + } + }, + "block": 4994642, + "trx_id": "15a50977270c3b7e4e97715989f03099375b59bb", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T15:12:06", + "virtual_op": false, + "operation_id": "21451824045228034", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "blackjincrypto", + "memo": "7639138f-62f0-492a-b8e7-bad1add506dd", + "amount": { + "nai": "@@000000021", + "amount": "24838", + "precision": 3 + } + } + }, + "block": 4993122, + "trx_id": "a6e9f45a9b8fb6cd565936f64e13ae5b12ac94f2", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T13:56:03", + "virtual_op": false, + "operation_id": "21445295694938114", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "pakganern", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4987311, + "trx_id": "b89762657465f62895ff3c8acab554a69a5bab1e", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T09:04:45", + "virtual_op": false, + "operation_id": "21420337639982848", + "trx_in_block": 4 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "schro", + "memo": "d70dfb8e-277a-4070-9812-b38cf01579cf", + "amount": { + "nai": "@@000000021", + "amount": "126225", + "precision": 3 + } + } + }, + "block": 4986680, + "trx_id": "68656136a5cff365a0c5ab873a60a3cf7528e47c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T08:32:54", + "virtual_op": false, + "operation_id": "21417627515617282", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "aaronkoenig", + "memo": "b4c499fb-5deb-44dc-9646-e7feb3927e12", + "amount": { + "nai": "@@000000013", + "amount": "48000", + "precision": 3 + } + } + }, + "block": 4985503, + "trx_id": "2c918ba666c06946a792657b27ed18af196dfab5", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T07:34:00", + "virtual_op": false, + "operation_id": "21412572339109890", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "jeremyfromwi", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4984971, + "trx_id": "21b12d2246e1ceb0cedba3b04a504bb58d52b0d5", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T07:07:15", + "virtual_op": false, + "operation_id": "21410287416508684", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "cryptomental", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4984843, + "trx_id": "8c311c43f7dd1ddaa713aa6cb2f9d8dde96141bd", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T07:00:51", + "virtual_op": false, + "operation_id": "21409737660695052", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "I am not sure, but it is not funny anymore because I see the 12 points every time. Maybe my brain just recorded the pattern and remember it. I can not switch back again.\nAlso is truth that I work with crystal simetry pattern daily, so, maybe my brain is trained to see patterns and keep it. Also, in this occasion, I knew what was looking for...\nThis make me think how different we perceive the universe around us... Even when everybody is seeing the same thing...", + "title": "", + "author": "quigua", + "permlink": "re-blocktrades-re-quigua-re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t054809925z", + "json_metadata": "{\"tags\":[\"optical\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-quigua-re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t050900278z" + } + }, + "block": 4983394, + "trx_id": "5824e046a9235be9ba99440e3e8eb99860e8a63a", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T05:48:15", + "virtual_op": false, + "operation_id": "21403514253082625", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "therajmahal", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4982233, + "trx_id": "7df8d151a3c06fb31a6b902d80885d4a6ca5c1ab", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T04:50:09", + "virtual_op": false, + "operation_id": "21398527796051980", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "At first, I couldn't see more than 4 points at the same time. But, then I follow all points with the eyes making a circle pattern during 15 seconds, and surprising!. I can see the 12 points, and now I can not see the blinking points again. That is really crazy...", + "title": "", + "author": "quigua", + "permlink": "re-blocktrades-re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t044305573z", + "json_metadata": "{\"tags\":[\"optical\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-ilovesteemit-can-you-see-all-twelve-dots-in-this-image-nope-you-cannot-20160915t034947752z" + } + }, + "block": 4982094, + "trx_id": "40ae1f796b8d0409a799fe62b3b423972b83c9e5", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T04:43:12", + "virtual_op": false, + "operation_id": "21397930795598081", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "rishi556", + "memo": " 50c8c0c0-c9f6-41c3-ace1-791567e5c1ba", + "amount": { + "nai": "@@000000013", + "amount": "105", + "precision": 3 + } + } + }, + "block": 4980808, + "trx_id": "083fc2207f29a78e907e5865911cf7d62910fd21", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T03:38:48", + "virtual_op": false, + "operation_id": "21392407467656706", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "stackcats", + "memo": "b163536b-4058-4187-96c6-ac9f573088ae", + "amount": { + "nai": "@@000000021", + "amount": "57873", + "precision": 3 + } + } + }, + "block": 4980626, + "trx_id": "5ac596f0c2b61dcffc2aed0d70858b0d36d32b91", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T03:29:42", + "virtual_op": false, + "operation_id": "21391625783608834", + "trx_in_block": 3 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "acidyo", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4980106, + "trx_id": "cf47b1bdf8d3f9a84cbb88931900242a7725f7c1", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-15T03:03:39", + "virtual_op": false, + "operation_id": "21389392400613388", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "ranko-k", + "memo": "59824378-b1af-44ab-a181-a150ace86aa5", + "amount": { + "nai": "@@000000021", + "amount": "29421", + "precision": 3 + } + } + }, + "block": 4977199, + "trx_id": "015a69792b3d1ce6964a656f829d1d0b9ac1fd18", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-15T00:38:18", + "virtual_op": false, + "operation_id": "21376906930683906", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "theb0red1", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4974156, + "trx_id": "706d118879820969cd2056bf7c72cb16f952a952", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T22:06:00", + "virtual_op": false, + "operation_id": "21363837345203724", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "@@ -399,16 +399,17 @@\n nts will\n+,\n too, an\n", + "title": "", + "author": "slammr76", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t203223509z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4972329, + "trx_id": "f66ba76505558234d1532ad9030d349236b7ab85", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T20:34:30", + "virtual_op": false, + "operation_id": "21355990439952897", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Right now, Steem has value because you can exchange it for bitcoin. I don't have to exchange bitcoin for fiat for it to have value for me, even though the merchants accepting it are likely exchanging it for fiat. I can and do spend bitcoin all the time. I've never exchanged it for fiat but have always exchanged dollars for bitcoin. I prefer to have my weath stored in bitcoin. Someday, the merchants will too, and few will care what the exchange rate for bitcoin vs fiat is.", + "title": "", + "author": "slammr76", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t203223509z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4972289, + "trx_id": "34146d0288ea9070d2da2be5e191bb7c1885724e", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T20:32:30", + "virtual_op": false, + "operation_id": "21355818641261057", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "kranartz", + "memo": " 7702e0f5-8ab7-46d1-bbda-29d21c368160", + "amount": { + "nai": "@@000000013", + "amount": "1123", + "precision": 3 + } + } + }, + "block": 4971843, + "trx_id": "6412bb9abeec1f6e5027c11a165fa919fc233f03", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T20:10:12", + "virtual_op": false, + "operation_id": "21353903085846530", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "fatboy", + "memo": " 771b11ac-47f7-4b2f-b50a-71266e9b4026", + "amount": { + "nai": "@@000000013", + "amount": "28350", + "precision": 3 + } + } + }, + "block": 4971577, + "trx_id": "8b39da57e049a4f2d28eac4565183904a8765648", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:56:54", + "virtual_op": false, + "operation_id": "21352760624547330", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "fatboy", + "memo": " 9c0bf334-d8df-40bb-8002-409c03cf230f", + "amount": { + "nai": "@@000000021", + "amount": "22663", + "precision": 3 + } + } + }, + "block": 4971507, + "trx_id": "f817700f21c9c97b06eb61beb6eff948fb7ad07c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:53:24", + "virtual_op": false, + "operation_id": "21352459976835074", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "anasz", + "memo": " 9f6e1027-9d03-4785-90d4-04fe4dd29b5e", + "amount": { + "nai": "@@000000013", + "amount": "16000", + "precision": 3 + } + } + }, + "block": 4971215, + "trx_id": "a21a7bfb210848c0c7d73d4a799a3cd6757d66d3", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:38:48", + "virtual_op": false, + "operation_id": "21351205846385154", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "gomeravibz", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4971093, + "trx_id": "f0a69def7eba73ee3ccd9a92dd915ee3eacc2b6a", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T19:32:39", + "virtual_op": false, + "operation_id": "21350681860375564", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "shaneradliff", + "memo": "7f208b66-5a77-48a5-92fb-bd9fbc5fd50c", + "amount": { + "nai": "@@000000013", + "amount": "1300", + "precision": 3 + } + } + }, + "block": 4970678, + "trx_id": "0fa231ee90f74305cab404aaabac6654050b5df9", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T19:11:21", + "virtual_op": false, + "operation_id": "21348899448947458", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "anasz", + "memo": "314ae1d5-c9e9-4a21-8cb0-48cf6d2a3ccb", + "amount": { + "nai": "@@000000013", + "amount": "10000", + "precision": 3 + } + } + }, + "block": 4969806, + "trx_id": "3fee1c9286faaa4abec711e275f0e897ada9cb5f", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T18:25:36", + "virtual_op": false, + "operation_id": "21345154237465602", + "trx_in_block": 2 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Well, fiat money is worth something because you can use it to pay taxes.", + "title": "", + "author": "svamiva", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t175725339z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4969274, + "trx_id": "c6f8881aba4bc494f32cfffc15ad122b44c8d124", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:57:33", + "virtual_op": false, + "operation_id": "21342869314864129", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Thank you so much! I will remember this \").", + "title": "", + "author": "funny", + "permlink": "re-blocktrades-re-funny-re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t174018203z", + "json_metadata": "{\"tags\":[\"money\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t171338026z" + } + }, + "block": 4968948, + "trx_id": "26b80037ce89febd1c653fcbbbdf09faefc325b1", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:40:24", + "virtual_op": false, + "operation_id": "21341469155525121", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "You´re welcome :). Hehe, it´s always the last bit missing. Like the comments in this example :D", + "title": "", + "author": "lenatramper", + "permlink": "re-blocktrades-re-lenatramper-re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t173256475z", + "json_metadata": "{\"tags\":[\"adolf\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-lenatramper-re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t164216448z" + } + }, + "block": 4968805, + "trx_id": "2daac261fcc68c2461adc8524261bc11de614f3e", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:32:48", + "virtual_op": false, + "operation_id": "21340854975201281", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "good-karma", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4968789, + "trx_id": "07faf6e609944fa59dd2bdfe8fbc0c2270e83a4a", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T17:32:00", + "virtual_op": false, + "operation_id": "21340786255724556", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "mikemacintire", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4968546, + "trx_id": "ddfd6daa8550483afc8158b9926c7d1b1fa1f731", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T17:19:15", + "virtual_op": false, + "operation_id": "21339742578672396", + "trx_in_block": 2 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Hey @blocktrades, thanks for reading \"). \n\nAgreed, that was the point I was making, but with that statement, I meant it as you need a bridge to start. If everyone decided to adopt crypto tomorrow, and picked a few coins that we all used, then yes, you're right, it could work without fiat. \n\nAny chance you can upvote the post, I'm trying to build my account with steemit.", + "title": "", + "author": "funny", + "permlink": "re-blocktrades-re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t170230207z", + "json_metadata": "{\"tags\":[\"money\"],\"users\":[\"blocktrades\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-funny-why-are-bitcoin-steem-and-other-cryptocoins-worth-real-money-20160914t164907864z" + } + }, + "block": 4968231, + "trx_id": "f205fbcc8aee61419ad54982f3d594de07450a2a", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T17:02:36", + "virtual_op": false, + "operation_id": "21338389663973377", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "ziogio", + "memo": "92754b24-3405-434f-88ca-07ad5e74b089", + "amount": { + "nai": "@@000000013", + "amount": "10000", + "precision": 3 + } + } + }, + "block": 4967726, + "trx_id": "f620062399c31a45b339fb6ca2d8d3980a6bf747", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T16:37:03", + "virtual_op": false, + "operation_id": "21336220705488898", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Hi blocktrades,\n\nyou can check it here in the comments :)\nhttps://steemit.com/language/@lenatramper/top-10-hardest-languages-in-the-world-ranking", + "title": "", + "author": "lenatramper", + "permlink": "re-blocktrades-re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t160355256z", + "json_metadata": "{\"tags\":[\"adolf\"],\"links\":[\"https://steemit.com/language/@lenatramper/top-10-hardest-languages-in-the-world-ranking\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-lenatramper-if-the-whole-earth-would-speak-like-adolf-hitler-20160914t155903950z" + } + }, + "block": 4967060, + "trx_id": "120b4917d02d628ae830fb480c1d049274489445", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T16:03:45", + "virtual_op": false, + "operation_id": "21333360257271553", + "trx_in_block": 4 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "juliac", + "memo": "0dba7938-f263-4da8-820e-8d883ddacff7", + "amount": { + "nai": "@@000000013", + "amount": "13334", + "precision": 3 + } + } + }, + "block": 4965170, + "trx_id": "515fca2bc83c7f460f18ec52457c0cd672826358", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T14:29:12", + "virtual_op": false, + "operation_id": "21325242769080322", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "blockchaingirl", + "memo": "6ebbb676-3fd8-4713-acbe-2f1d4da1a0b0", + "amount": { + "nai": "@@000000013", + "amount": "800000", + "precision": 3 + } + } + }, + "block": 4964407, + "trx_id": "cf4264043076e5af34318b9db392ccf469a66563", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T13:51:00", + "virtual_op": false, + "operation_id": "21321965709034498", + "trx_in_block": 2 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "solarguy", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4959174, + "trx_id": "6bd2741483e2659c957cb574b7fec5ba1fec25de", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T09:28:45", + "virtual_op": false, + "operation_id": "21299490145174284", + "trx_in_block": 2 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "royalmacro", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4957445, + "trx_id": "582159a7d6fa988594fe6f947bc73998fc655b14", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T08:02:00", + "virtual_op": false, + "operation_id": "21292064146721292", + "trx_in_block": 5 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "kaylinart", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4957104, + "trx_id": "8ce909995eaf91a2ed2676932000a4c7d4af80ad", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-14T07:44:54", + "virtual_op": false, + "operation_id": "21290599562870796", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "anasz", + "memo": "b16de592-76a1-485d-b8c8-4e8692f9803e", + "amount": { + "nai": "@@000000013", + "amount": "23", + "precision": 3 + } + } + }, + "block": 4954441, + "trx_id": "169310b87bfd1fde6ff207ea39ec09df7760391e", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T05:31:21", + "virtual_op": false, + "operation_id": "21279162064964098", + "trx_in_block": 5 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "bryner", + "memo": "4c93872a-7b82-42f3-b094-a54ab719c34c", + "amount": { + "nai": "@@000000021", + "amount": "8350", + "precision": 3 + } + } + }, + "block": 4952702, + "trx_id": "d7474d597f3cd27c895b477b1a7b1046888851d7", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T04:04:06", + "virtual_op": false, + "operation_id": "21271693116833794", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "theb0red1", + "author": "blocktrades", + "weight": 10000, + "permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z" + } + }, + "block": 4952567, + "trx_id": "182a7686346f290e1bf55d4a8e2474e5bd33697e", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-14T03:57:21", + "virtual_op": false, + "operation_id": "21271113296249344", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "themanualbot", + "memo": "a4f54c6d-bc77-404f-b4ce-8e3433fcc928", + "amount": { + "nai": "@@000000013", + "amount": "484185", + "precision": 3 + } + } + }, + "block": 4950730, + "trx_id": "aa54b0534c3e747051b5e88b620d9f8cd337c983", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T02:25:15", + "virtual_op": false, + "operation_id": "21263223441327618", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Ok, thanks!", + "title": "", + "author": "timcliff", + "permlink": "re-blocktrades-re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t015047838z", + "json_metadata": "{\"tags\":[\"poloniex\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-timcliff-poloniex-transfers-disabled-for-steem-and-sbd-20160914t013605178z" + } + }, + "block": 4950046, + "trx_id": "a1467edcb59b7cf3cff77cd83c4af3ada0c4ffb6", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-14T01:50:51", + "virtual_op": false, + "operation_id": "21260285683696129", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "forrestwillie", + "memo": "34edb0f7-ad6f-4927-84ea-d5faf99f9e6e", + "amount": { + "nai": "@@000000021", + "amount": "66281", + "precision": 3 + } + } + }, + "block": 4949192, + "trx_id": "693841b51e3fe86929f71d5491fba422acbbae54", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T01:08:03", + "virtual_op": false, + "operation_id": "21256617781624834", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "shaneradliff", + "memo": "d1d42c18-b06f-4124-9c81-a4593dcea8cd", + "amount": { + "nai": "@@000000013", + "amount": "13000", + "precision": 3 + } + } + }, + "block": 4948215, + "trx_id": "1134409013de5dd70173d087edfe9763baec70ec", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-14T00:19:03", + "virtual_op": false, + "operation_id": "21252421598576642", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "wefdi", + "approve": false, + "witness": "blocktrades" + } + }, + "block": 4947057, + "trx_id": "b375567add15744604a2ab38d76ebeb82cb0e897", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T23:21:00", + "virtual_op": false, + "operation_id": "21247448026448908", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "lindee-hamner", + "memo": "3ecd1ed7-da35-4497-8106-92e26eff9103", + "amount": { + "nai": "@@000000021", + "amount": "22367", + "precision": 3 + } + } + }, + "block": 4946739, + "trx_id": "74bf8f7190a6a7e7c51692c27a0a8523e33e7821", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T23:05:03", + "virtual_op": false, + "operation_id": "21246082226847746", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "thisisbenbrick", + "memo": "2e62fd10-bd7b-43ee-a2a2-33324e576e93", + "amount": { + "nai": "@@000000021", + "amount": "766741", + "precision": 3 + } + } + }, + "block": 4946006, + "trx_id": "65c72bcffb05588cd274257969bee51f07d266d2", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T22:28:21", + "virtual_op": false, + "operation_id": "21242934015819778", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "mrwang", + "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", + "amount": { + "nai": "@@000000013", + "amount": "71475", + "precision": 3 + } + } + }, + "block": 4945986, + "trx_id": "555cc791ad80d0f025e6f7fa5965657c1e54b063", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T22:27:18", + "virtual_op": false, + "operation_id": "21242848116474882", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "yassinebentour", + "memo": "b9b4574a-220d-49ee-bf4e-6889df4e387c", + "amount": { + "nai": "@@000000021", + "amount": "1775", + "precision": 3 + } + } + }, + "block": 4944673, + "trx_id": "4e78a7c63beff4ffa7c715eae5c523231918d939", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T21:21:30", + "virtual_op": false, + "operation_id": "21237208824414978", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "furion", + "memo": "cffb8a8e-1f88-4654-945a-8888dcdac62a", + "amount": { + "nai": "@@000000021", + "amount": "50000", + "precision": 3 + } + } + }, + "block": 4943900, + "trx_id": "ee10f9357650aeaebfc4b34429b5465642edc41b", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T20:42:45", + "virtual_op": false, + "operation_id": "21233888814694402", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "dmilash", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4943618, + "trx_id": "c8bfb1ae741895c5d9ff90381faef14cb2bd9dc0", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T20:28:39", + "virtual_op": false, + "operation_id": "21232677633917440", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "vetvso", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4943513, + "trx_id": "18d12216537678f958f3e7e0c6550367d01a76fa", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T20:23:21", + "virtual_op": false, + "operation_id": "21232226662351116", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "vetvso", + "author": "blocktrades", + "weight": 10000, + "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" + } + }, + "block": 4943368, + "trx_id": "fb9ee97aaafe8d8f0581a269d5f0ff2ca4c9ffa7", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T20:16:06", + "virtual_op": false, + "operation_id": "21231603892094208", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "vetvso", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4943233, + "trx_id": "596e450517c6f651b77492fc6a9ad3b1e46cf271", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T20:09:21", + "virtual_op": false, + "operation_id": "21231024071507968", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "novium", + "memo": " d48f47eb-5900-4a70-bfb3-a821ba90de30", + "amount": { + "nai": "@@000000013", + "amount": "40000", + "precision": 3 + } + } + }, + "block": 4942698, + "trx_id": "c38b4cf8d260ec43b48c55f3613428e5adb3dc93", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T19:42:33", + "virtual_op": false, + "operation_id": "21228726264005378", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "vasco-el-jim", + "memo": "edc7fa29-31d9-42a0-bf53-353d6c01f1c0", + "amount": { + "nai": "@@000000021", + "amount": "50000", + "precision": 3 + } + } + }, + "block": 4941972, + "trx_id": "c4aaf923be6e77740477d13d2e904cae164caa05", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T19:06:06", + "virtual_op": false, + "operation_id": "21225608117747714", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "trevorjenglish", + "memo": " be40e871-d9c4-494f-a85d-92deae85c97c", + "amount": { + "nai": "@@000000021", + "amount": "52407", + "precision": 3 + } + } + }, + "block": 4940759, + "trx_id": "d2bc1229e4138b9692170b2d23c5f71084dae5c0", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T18:05:21", + "virtual_op": false, + "operation_id": "21220398322417666", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "pathtomydream", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4940594, + "trx_id": "e05d94343442b1ee91910b7c17eef0f2a71eb392", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T17:57:06", + "virtual_op": false, + "operation_id": "21219689652814336", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "expedition", + "author": "blocktrades", + "weight": 10000, + "permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" + } + }, + "block": 4939847, + "trx_id": "f4f666caa5199e09e0c8f29a3e8d8aa40b4b859f", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T17:19:36", + "virtual_op": false, + "operation_id": "21216481312243712", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "@@ -73,16 +73,23 @@\n ugh the \n+coffee \n ocean. J\n", + "title": "", + "author": "phenom", + "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t151302200z", + "json_metadata": "{\"tags\":[\"food\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" + } + }, + "block": 4937336, + "trx_id": "d41b3134e9d0ac8a797d4a534498aa158faa12f5", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T15:13:45", + "virtual_op": false, + "operation_id": "21205696649364225", + "trx_in_block": 2 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "haha, Initially I thought that this blue thing is a whale floating through the ocean. Just realized that it's a symbol of blocktrades platform", + "title": "", + "author": "phenom", + "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t151302200z", + "json_metadata": "{\"tags\":[\"food\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" + } + }, + "block": 4937323, + "trx_id": "7755512e9ec8350494408daa261d7627a04ac87a", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T15:13:06", + "virtual_op": false, + "operation_id": "21205640814789377", + "trx_in_block": 2 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "wefdi", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4937041, + "trx_id": "6cefffe540c5636c5fa9cef5bd29c57cc434121f", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T14:58:57", + "virtual_op": false, + "operation_id": "21204429634011148", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "karsmaxanes", + "memo": " 9823b75c-e743-47e4-bbe9-7d0e9edd914b", + "amount": { + "nai": "@@000000013", + "amount": "44000", + "precision": 3 + } + } + }, + "block": 4936718, + "trx_id": "2be56fa88ee477504d54ab8fb0ee410812daba21", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T14:42:42", + "virtual_op": false, + "operation_id": "21203042359575554", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "mrwang", + "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", + "amount": { + "nai": "@@000000013", + "amount": "2821", + "precision": 3 + } + } + }, + "block": 4936102, + "trx_id": "b254e42f7ee58f909bcb190d6c58d925543cc0a9", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T14:11:48", + "virtual_op": false, + "operation_id": "21200396659720706", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "blockchaingirl", + "memo": "039abf1c-19ed-4242-a267-78bcaf29b6df", + "amount": { + "nai": "@@000000013", + "amount": "800000", + "precision": 3 + } + } + }, + "block": 4935965, + "trx_id": "58943fa0fc2612ecbb0c4733fc85bca2a048a651", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T14:04:57", + "virtual_op": false, + "operation_id": "21199808249201154", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "I see, but I talk about two hidden from eye edges. \nhttps://s9.postimg.org/nny820clr/2016_09_13_1630.png\nIn 3D they will be visible :) or just duplicate symbols Bitcoin and BitShares?", + "title": "", + "author": "smailer", + "permlink": "re-blocktrades-re-smailer-re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t133200497z", + "json_metadata": "{\"tags\":[\"food\"],\"image\":[\"https://s9.postimg.org/nny820clr/2016_09_13_1630.png\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t132556933z" + } + }, + "block": 4935318, + "trx_id": "d600c1d7a2674b8044a9b419792bb5ee88fc8c60", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:32:12", + "virtual_op": false, + "operation_id": "21197029405360897", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "anasz", + "author": "blocktrades", + "weight": 10000, + "permlink": "witness-report-for-blocktrades-for-last-week-of-august" + } + }, + "block": 4935292, + "trx_id": "18c58076b75a07a6bfaebdf28ef0ac0d926fd6b8", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-13T13:30:54", + "virtual_op": false, + "operation_id": "21196917736211200", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "@@ -25,16 +25,30 @@\n missing \n+classic movie \n lol than\n", + "title": "", + "author": "fairz", + "permlink": "re-blocktrades-re-fairz-it-the-clown-parody-20160913t132321388z", + "json_metadata": "{\"tags\":[\"animation\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-fairz-it-the-clown-parody-20160913t114531552z" + } + }, + "block": 4935240, + "trx_id": "e20a2875cef6b7b4b2f8d15af33e57b7f0fae003", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:28:18", + "virtual_op": false, + "operation_id": "21196694397912577", + "trx_in_block": 3 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "they dont no what there missing lol thanks for looking", + "title": "", + "author": "fairz", + "permlink": "re-blocktrades-re-fairz-it-the-clown-parody-20160913t132321388z", + "json_metadata": "{\"tags\":[\"animation\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-fairz-it-the-clown-parody-20160913t114531552z" + } + }, + "block": 4935141, + "trx_id": "35a2153fd3a78744bc149d1b1a77a65aee3d7ff7", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:23:21", + "virtual_op": false, + "operation_id": "21196269196150785", + "trx_in_block": 5 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Glad to hear you! thank you!\nWhen I find the way make more square block I will try add more details.\nCan you say me what the money symbols on another one edges ?", + "title": "", + "author": "smailer", + "permlink": "re-blocktrades-re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131414898z", + "json_metadata": "{\"tags\":[\"food\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-smailer-my-daytime-latte-art-tryings-blocktrades-fan-art-20160913t131146653z" + } + }, + "block": 4934964, + "trx_id": "09845865ddf51d5b61350e7f8864b7bb01a5d514", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T13:14:27", + "virtual_op": false, + "operation_id": "21195508986938625", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "onetree", + "memo": "f5b4968c-2ecc-4bbd-a85c-af1c1541657d", + "amount": { + "nai": "@@000000013", + "amount": "94576", + "precision": 3 + } + } + }, + "block": 4934174, + "trx_id": "b1ef0b05d1913f8c51e52deb7ac2cb836ee222d0", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T12:34:39", + "virtual_op": false, + "operation_id": "21192115962774274", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Sent a followup email, specifically mentioning your comments (as an influential member here) and got this promising response :)\n
", + "title": "", + "author": "ausbitbank", + "permlink": "re-blocktrades-re-krystle-re-blocktrades-re-eight-rad-re-hugothepoet-brexit-rap-battles-of-history-the-irony-of-it-all-new-original-rap-20160913t095540421z", + "json_metadata": "{\"tags\":[\"hugothepoet\"],\"image\":[\"https://www.steemimg.com/images/2016/09/13/hugoemailb7efe.png\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-krystle-re-blocktrades-re-eight-rad-re-hugothepoet-brexit-rap-battles-of-history-the-irony-of-it-all-new-original-rap-20160910t185524205z" + } + }, + "block": 4931009, + "trx_id": "9e67c8a0528a527dce8c6cb450ff236b47822dde", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T09:55:45", + "virtual_op": false, + "operation_id": "21178522391282177", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "slowwalker", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4929491, + "trx_id": "38b0d2d1b33b3f6cd6392a5dd7daf938a4713873", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T08:39:33", + "virtual_op": false, + "operation_id": "21172002630926348", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "stranger27", + "approve": false, + "witness": "blocktrades" + } + }, + "block": 4929005, + "trx_id": "625f1260e080e0f9840bb58d793472dc60cb5dcf", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-13T08:15:15", + "virtual_op": false, + "operation_id": "21169915276821004", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "tinfoilfedora", + "memo": "d03e7b59-2dfb-4e08-8506-5f435cbb522e", + "amount": { + "nai": "@@000000013", + "amount": "25000", + "precision": 3 + } + } + }, + "block": 4927062, + "trx_id": "0b6a7666a14a312f9976e01375656f6a7da1bcd6", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T06:37:48", + "virtual_op": false, + "operation_id": "21161570155364354", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "tinfoilfedora", + "memo": "d03e7b59-2dfb-4e08-8506-5f435cbb522e", + "amount": { + "nai": "@@000000013", + "amount": "120000", + "precision": 3 + } + } + }, + "block": 4926872, + "trx_id": "f21ce3eb2aa1aa47a2f5ba389dd6bac96742016b", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T06:28:18", + "virtual_op": false, + "operation_id": "21160754111578370", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "levycore", + "memo": "5bf6f52a-01f2-4552-93a9-2318ab9c79ae", + "amount": { + "nai": "@@000000013", + "amount": "34000", + "precision": 3 + } + } + }, + "block": 4926832, + "trx_id": "a9449ff148d769878770031c14af8f608522384c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T06:26:15", + "virtual_op": false, + "operation_id": "21160582312886274", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "krypto", + "memo": "931ded82-cd09-4e3f-80ff-5fbba1b54cf7", + "amount": { + "nai": "@@000000021", + "amount": "40000", + "precision": 3 + } + } + }, + "block": 4925898, + "trx_id": "41a66f6d678d0e06100cd62e8a155d70d768a410", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T05:39:27", + "virtual_op": false, + "operation_id": "21156570813432066", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "kennyskitchen", + "memo": "6230441c-1436-4bd7-826b-e78cc86666d0", + "amount": { + "nai": "@@000000013", + "amount": "40151", + "precision": 3 + } + } + }, + "block": 4924611, + "trx_id": "2e75bc3b9f7405317797a37f6908a2042d13c7e1", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T04:34:54", + "virtual_op": false, + "operation_id": "21151043190522882", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "4435fc70-df36-43e3-b79c-dcb75118a90e", + "amount": { + "nai": "@@000000013", + "amount": "25000", + "precision": 3 + } + } + }, + "block": 4922698, + "trx_id": "2a67c362d3d6f1199611a000dbbd899d13d8f46e", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T02:58:33", + "virtual_op": false, + "operation_id": "21142826918084610", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Nice article !", + "title": "", + "author": "alex2016", + "permlink": "re-blocktrades-blocktrades-witness-report-for-3rd-week-of-august-20160913t025753852z", + "json_metadata": "{\"tags\":[\"witness-category\"]}", + "parent_author": "blocktrades", + "parent_permlink": "blocktrades-witness-report-for-3rd-week-of-august" + } + }, + "block": 4922686, + "trx_id": "e5538ed98b4286b3b220c9525582eb606eab8f6c", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-13T02:57:57", + "virtual_op": false, + "operation_id": "21142775378478337", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "12Ht7fzVCmUP8BWx1Nk3ThrsLvEoFhmfm2", + "amount": { + "nai": "@@000000013", + "amount": "23000", + "precision": 3 + } + } + }, + "block": 4922068, + "trx_id": "7b52cc62c5804b40262a74bcb8e8c711253b2462", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T02:27:00", + "virtual_op": false, + "operation_id": "21140121088688898", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "af2ed608-e7fa-4cdc-80b4-bb049c6125e2", + "amount": { + "nai": "@@000000013", + "amount": "24000", + "precision": 3 + } + } + }, + "block": 4921719, + "trx_id": "625f4822303c979e3f404010c59ae992b27458c3", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T02:09:21", + "virtual_op": false, + "operation_id": "21138622145102338", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "b1737718-81cc-46f4-a5de-7cfc25158ab9", + "amount": { + "nai": "@@000000013", + "amount": "30", + "precision": 3 + } + } + }, + "block": 4921269, + "trx_id": "3bd88459ff9b3d0b50dd0ee010ccc99e4da46e0c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T01:46:51", + "virtual_op": false, + "operation_id": "21136689409818626", + "trx_in_block": 0 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "51d939e0-9466-4204-b8ba-ea064ed5ad89", + "amount": { + "nai": "@@000000013", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 4921209, + "trx_id": "ab006f1ed38e768fe8336c08821b9ec832453c2c", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T01:43:51", + "virtual_op": false, + "operation_id": "21136431711781890", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "luzcypher", + "memo": "", + "amount": { + "nai": "@@000000013", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 4920877, + "trx_id": "dc7615967a6dfec38df66ea9a28cbd14db4a47d5", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T01:27:12", + "virtual_op": false, + "operation_id": "21135005782639106", + "trx_in_block": 1 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "johan-nygren", + "memo": " a68ac41f-bc4b-402f-915c-990c5b9de41f", + "amount": { + "nai": "@@000000013", + "amount": "93910", + "precision": 3 + } + } + }, + "block": 4919627, + "trx_id": "1072dabfad4c459ee6da08e1b6ddaa7d1cc8033f", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-13T00:24:33", + "virtual_op": false, + "operation_id": "21129637073519106", + "trx_in_block": 1 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "chitty", + "approve": false, + "witness": "blocktrades" + } + }, + "block": 4915116, + "trx_id": "ebab7cd7f222d5f85539361487fca9e895c1a41c", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-12T20:38:15", + "virtual_op": false, + "operation_id": "21110262476047372", + "trx_in_block": 2 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "soulsistashakti", + "memo": "1af846c5-640b-4296-9d37-ded453c0eeb1", + "amount": { + "nai": "@@000000013", + "amount": "10000", + "precision": 3 + } + } + }, + "block": 4914007, + "trx_id": "b75309ee66fab08cb0ec535595273d5e28b0eb38", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-12T19:42:36", + "virtual_op": false, + "operation_id": "21105499357316354", + "trx_in_block": 3 + }, + { + "op": { + "type": "account_witness_vote_operation", + "value": { + "account": "kingscrown", + "approve": true, + "witness": "blocktrades" + } + }, + "block": 4913253, + "trx_id": "beba6063fd4603a157805cfd5280f25747713bf7", + "op_pos": 0, + "op_type_id": 12, + "timestamp": "2016-09-12T19:04:51", + "virtual_op": false, + "operation_id": "21102260951976204", + "trx_in_block": 4 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "condra", + "memo": "158a5398-1542-4822-a47b-f144ddeef74f", + "amount": { + "nai": "@@000000013", + "amount": "295891", + "precision": 3 + } + } + }, + "block": 4912869, + "trx_id": "f56aa2a449bc90c025c49e489f624aa9bba54917", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-12T18:45:30", + "virtual_op": false, + "operation_id": "21100611684533250", + "trx_in_block": 3 + }, + { + "op": { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "lauralemons", + "memo": "0bd788bc-09bc-45d4-a385-9656061a8418", + "amount": { + "nai": "@@000000021", + "amount": "46672", + "precision": 3 + } + } + }, + "block": 4912813, + "trx_id": "6a466c13ddfcf1a6ec5cacc51d2c0a4c257f420b", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-09-12T18:42:42", + "virtual_op": false, + "operation_id": "21100371166363650", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "@@ -187,8 +187,74 @@\n mpatible\n+, I have buy some steem too with what I have earn here to power up\n", + "title": "", + "author": "alex.gaud", + "permlink": "re-blocktrades-re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160912t173311407z", + "json_metadata": "{\"tags\":[\"witness-category\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" + } + }, + "block": 4911452, + "trx_id": "f21a1ad86d4cd8ab3cb2ee01c8ba60bfd26a57d4", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-12T17:34:24", + "virtual_op": false, + "operation_id": "21094525715874305", + "trx_in_block": 2 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Thank you sir for your answer, sorry if I will ask you again, actually I can't install the steem wallet on my computer I'm using windows 7, I have error message saying that it was not compatible", + "title": "", + "author": "alex.gaud", + "permlink": "re-blocktrades-re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160912t173311407z", + "json_metadata": "{\"tags\":[\"witness-category\"]}", + "parent_author": "blocktrades", + "parent_permlink": "re-alexgaud-re-blocktrades-witness-report-for-blocktrades-for-last-week-of-august-20160902t150436912z" + } + }, + "block": 4911428, + "trx_id": "d21600ff9e8b63ec977e0eb41e72907ed55e20cd", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-12T17:33:12", + "virtual_op": false, + "operation_id": "21094422636658945", + "trx_in_block": 1 } ] } \ No newline at end of file -- GitLab From 3d3f12ce5c8d998e6cd8522e5b2d68882313ccc1 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Thu, 24 Jul 2025 13:52:30 +0000 Subject: [PATCH 19/24] Refactor hafah rest backend functions - move utility functions to seperate directory - expand rest validation and exception handling --- .../account_history/account_history.sql | 7 +- .../hafah_rest_backend/{ => blocks}/block.sql | 0 .../{ => blocks}/block_header.sql | 0 .../{ => blocks}/block_range.sql | 0 .../{ => operations}/acc_op_types.sql | 0 .../{ => operations}/op_types.sql | 0 .../{ => operations}/operation.sql | 0 .../{ => operations}/ops_in_block.sql | 0 .../hafah_rest_backend/utilities/account.sql | 27 ++++++ .../utilities/exceptions.sql | 6 +- .../utilities/function_helpers.sql | 50 +++++++++++ .../utilities/get_operation_types.sql | 45 ++++++++++ .../operation_body_filter.sql} | 51 ----------- .../{account_history => utilities}/paging.sql | 35 -------- .../utilities/path_filters.sql | 53 +++++++++++ .../utilities/validators.sql | 87 +++++++++++++++++++ scripts/install_app.sh | 31 ++++--- 17 files changed, 287 insertions(+), 105 deletions(-) rename queries/hafah_rest_backend/{ => blocks}/block.sql (100%) rename queries/hafah_rest_backend/{ => blocks}/block_header.sql (100%) rename queries/hafah_rest_backend/{ => blocks}/block_range.sql (100%) rename queries/hafah_rest_backend/{ => operations}/acc_op_types.sql (100%) rename queries/hafah_rest_backend/{ => operations}/op_types.sql (100%) rename queries/hafah_rest_backend/{ => operations}/operation.sql (100%) rename queries/hafah_rest_backend/{ => operations}/ops_in_block.sql (100%) create mode 100644 queries/hafah_rest_backend/utilities/account.sql rename postgrest/hafah_rest_exceptions.sql => queries/hafah_rest_backend/utilities/exceptions.sql (88%) create mode 100644 queries/hafah_rest_backend/utilities/function_helpers.sql create mode 100644 queries/hafah_rest_backend/utilities/get_operation_types.sql rename queries/hafah_rest_backend/{path_filters.sql => utilities/operation_body_filter.sql} (51%) rename queries/hafah_rest_backend/{account_history => utilities}/paging.sql (87%) create mode 100644 queries/hafah_rest_backend/utilities/path_filters.sql create mode 100644 queries/hafah_rest_backend/utilities/validators.sql diff --git a/queries/hafah_rest_backend/account_history/account_history.sql b/queries/hafah_rest_backend/account_history/account_history.sql index d4e05b6a1..bd00ee96d 100644 --- a/queries/hafah_rest_backend/account_history/account_history.sql +++ b/queries/hafah_rest_backend/account_history/account_history.sql @@ -20,12 +20,9 @@ DECLARE -- flags _filter_by_account_ids BOOLEAN := (_filter_account_ids != ARRAY[NULL]::INT[]); - _filter_by_single_acc BOOLEAN := (CASE WHEN (_filter_account_ids != ARRAY[NULL]::INT[]) AND (array_length(_filter_account_ids, 1) = 1) THEN TRUE ELSE FALSE END); - _filter_by_op BOOLEAN; + _filter_by_single_acc BOOLEAN := (CASE WHEN (_filter_account_ids != ARRAY[NULL]::INT[]) AND (array_length(_filter_account_ids, 1) = 1) THEN TRUE ELSE FALSE END); + _filter_by_op BOOLEAN := (_operations IS NOT NULL); BEGIN - _operations := hafah_backend.limit_to_only_real_operations(_operations, _participation_mode = 'all'); - _filter_by_op := (_operations IS NOT NULL); - CASE -- If no filters are applied, use the default account history function WHEN (NOT _filter_by_account_ids) AND (NOT _filter_by_op) THEN diff --git a/queries/hafah_rest_backend/block.sql b/queries/hafah_rest_backend/blocks/block.sql similarity index 100% rename from queries/hafah_rest_backend/block.sql rename to queries/hafah_rest_backend/blocks/block.sql diff --git a/queries/hafah_rest_backend/block_header.sql b/queries/hafah_rest_backend/blocks/block_header.sql similarity index 100% rename from queries/hafah_rest_backend/block_header.sql rename to queries/hafah_rest_backend/blocks/block_header.sql diff --git a/queries/hafah_rest_backend/block_range.sql b/queries/hafah_rest_backend/blocks/block_range.sql similarity index 100% rename from queries/hafah_rest_backend/block_range.sql rename to queries/hafah_rest_backend/blocks/block_range.sql diff --git a/queries/hafah_rest_backend/acc_op_types.sql b/queries/hafah_rest_backend/operations/acc_op_types.sql similarity index 100% rename from queries/hafah_rest_backend/acc_op_types.sql rename to queries/hafah_rest_backend/operations/acc_op_types.sql diff --git a/queries/hafah_rest_backend/op_types.sql b/queries/hafah_rest_backend/operations/op_types.sql similarity index 100% rename from queries/hafah_rest_backend/op_types.sql rename to queries/hafah_rest_backend/operations/op_types.sql diff --git a/queries/hafah_rest_backend/operation.sql b/queries/hafah_rest_backend/operations/operation.sql similarity index 100% rename from queries/hafah_rest_backend/operation.sql rename to queries/hafah_rest_backend/operations/operation.sql diff --git a/queries/hafah_rest_backend/ops_in_block.sql b/queries/hafah_rest_backend/operations/ops_in_block.sql similarity index 100% rename from queries/hafah_rest_backend/ops_in_block.sql rename to queries/hafah_rest_backend/operations/ops_in_block.sql diff --git a/queries/hafah_rest_backend/utilities/account.sql b/queries/hafah_rest_backend/utilities/account.sql new file mode 100644 index 000000000..f53e17de6 --- /dev/null +++ b/queries/hafah_rest_backend/utilities/account.sql @@ -0,0 +1,27 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.get_account_id(_account_name TEXT, _required BOOLEAN) +RETURNS INT STABLE +LANGUAGE 'plpgsql' +AS +$$ +DECLARE + _account_id INT := (SELECT av.id FROM hive.accounts_view av WHERE av.name = _account_name); +BEGIN + PERFORM hafah_backend.validate_account(_account_id, _account_name, _required); + + RETURN _account_id; +END +$$; + +CREATE OR REPLACE FUNCTION hafah_backend.get_account_name(_account_id INT) +RETURNS TEXT STABLE +LANGUAGE 'plpgsql' +AS +$$ +BEGIN + RETURN av.name FROM hive.accounts_view av WHERE av.id = _account_id; +END +$$; + +RESET ROLE; diff --git a/postgrest/hafah_rest_exceptions.sql b/queries/hafah_rest_backend/utilities/exceptions.sql similarity index 88% rename from postgrest/hafah_rest_exceptions.sql rename to queries/hafah_rest_backend/utilities/exceptions.sql index 833026f51..0afcec822 100644 --- a/postgrest/hafah_rest_exceptions.sql +++ b/queries/hafah_rest_backend/utilities/exceptions.sql @@ -108,16 +108,14 @@ END $$ ; -CREATE OR REPLACE FUNCTION hafah_backend.validate_participation_mode(_mode hafah_backend.participation_mode, _account_name TEXT) +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_invalid_operation_types(_allowed_operations INT[]) RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - IF _mode = 'all' AND _account_name IS NOT NULL THEN - RAISE EXCEPTION 'For participation mode ''all'', account name should not be provided'; - END IF; + RAISE EXCEPTION 'Invalid operation ID detected. Allowed IDs are: %', _allowed_operations; END $$ ; diff --git a/queries/hafah_rest_backend/utilities/function_helpers.sql b/queries/hafah_rest_backend/utilities/function_helpers.sql new file mode 100644 index 000000000..02bbbd067 --- /dev/null +++ b/queries/hafah_rest_backend/utilities/function_helpers.sql @@ -0,0 +1,50 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.is_block_missing(_block_num INT, _name TEXT DEFAULT 'block-num') +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + IF _block_num IS NULL THEN + PERFORM hafah_backend.rest_raise_missing_arg(_name); + END IF; +END +$$ +; + +CREATE OR REPLACE FUNCTION hafah_backend.is_path_filter_not_empty(_path_filter TEXT[]) +RETURNS BOOLEAN +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + RETURN (_path_filter IS NOT NULL AND _path_filter != '{}'); +END +$$ +; + +CREATE OR REPLACE FUNCTION hafah_backend.get_group_type(_group_type hafah_backend.operation_group_types) +RETURNS BOOLEAN +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + RETURN ( + CASE + WHEN _group_type = 'real' THEN + FALSE + WHEN _group_type = 'virtual' THEN + TRUE + ELSE + NULL + END + ); +END +$$ +; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/utilities/get_operation_types.sql b/queries/hafah_rest_backend/utilities/get_operation_types.sql new file mode 100644 index 000000000..a8fd05832 --- /dev/null +++ b/queries/hafah_rest_backend/utilities/get_operation_types.sql @@ -0,0 +1,45 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.get_operation_types( + _operations TEXT, + _include_virtual BOOLEAN +) +RETURNS INT []-- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +AS +$$ +DECLARE + _non_virtual_ops INT[]; + _all_ops INT[]; + _operation_ids INT[] := (SELECT string_to_array(_operations, ',')::INT[]); +BEGIN + IF _include_virtual IS TRUE THEN + + _all_ops := ( + SELECT array_agg(id)::INT[] + FROM hafd.operation_types + ); + + PERFORM hafah_backend.validate_operation_types(_operation_ids, _all_ops); + + RETURN _operation_ids; + END IF; + + _non_virtual_ops := ( + SELECT array_agg(id)::INT[] + FROM hafd.operation_types + WHERE is_virtual = FALSE + ); + + IF _operation_ids IS NULL THEN + RETURN _non_virtual_ops; + END IF; + + PERFORM hafah_backend.validate_operation_types(_operation_ids, _non_virtual_ops); + + RETURN _operation_ids; +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/path_filters.sql b/queries/hafah_rest_backend/utilities/operation_body_filter.sql similarity index 51% rename from queries/hafah_rest_backend/path_filters.sql rename to queries/hafah_rest_backend/utilities/operation_body_filter.sql index 84c63986b..e166b66ad 100644 --- a/queries/hafah_rest_backend/path_filters.sql +++ b/queries/hafah_rest_backend/utilities/operation_body_filter.sql @@ -1,6 +1,5 @@ SET ROLE hafah_owner; - -- Function used in body returning functions that allows to limit too long operation_body (small.minion), allows FE to set desired length of operation -- Too long operations are being replaced by placeholder with possibility of opening it in another page DROP TYPE IF EXISTS hafah_backend.operation_body_filter_result CASCADE; -- noqa: LT01 @@ -35,54 +34,4 @@ BEGIN END $$; -CREATE OR REPLACE FUNCTION hafah_backend.decode_param(_encoded_param TEXT) -RETURNS TEXT -LANGUAGE 'plpgsql' -STABLE -AS -$$ -BEGIN - RETURN convert_from(decode(_encoded_param, 'base64'), 'UTF8'); -END -$$; - -CREATE OR REPLACE FUNCTION hafah_backend.parse_path_filters(_params TEXT[]) -RETURNS TABLE(param_json JSONB, param_text TEXT[]) -LANGUAGE 'plpgsql' -STABLE -AS -$$ -DECLARE - json_list JSONB := '[]'::JSONB; - text_list TEXT[] := '{}'; - param TEXT; - param_text TEXT; - key_value TEXT; - key_part TEXT[]; - value_part TEXT; -BEGIN - FOREACH param IN ARRAY _params - LOOP - -- Remove "" - param_text := hafah_backend.decode_param(param); - -- Extract everything before the first '=' as key - key_value := split_part(param_text, '=', 1); - - -- Extract everything after the first '=' as value - value_part := replace(param_text,key_value || '=',''); - - -- Split the key into parts based on '.' separator - key_part := string_to_array(key_value, '.'); - - -- Append key parts to the JSONB list - json_list := json_list || jsonb_build_array(key_part); - - -- Append the entire value part to the text array - text_list := array_append(text_list, value_part); - END LOOP; - - RETURN QUERY SELECT json_list, text_list; -END -$$; - RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/paging.sql b/queries/hafah_rest_backend/utilities/paging.sql similarity index 87% rename from queries/hafah_rest_backend/account_history/paging.sql rename to queries/hafah_rest_backend/utilities/paging.sql index e45684cf8..e7e790317 100644 --- a/queries/hafah_rest_backend/account_history/paging.sql +++ b/queries/hafah_rest_backend/utilities/paging.sql @@ -195,39 +195,4 @@ BEGIN END $$; - -CREATE OR REPLACE FUNCTION hafah_backend.limit_to_only_real_operations( - _operations INT [], - _include_virtual BOOLEAN -) -RETURNS INT []-- noqa: LT01, CP05 -LANGUAGE 'plpgsql' STABLE -SET JIT = OFF -AS -$$ -DECLARE - _non_virtual_ops INT[]; -BEGIN - IF _include_virtual IS TRUE THEN - RETURN _operations; - END IF; - - _non_virtual_ops := ( - SELECT array_agg(id)::INT[] - FROM hafd.operation_types - WHERE is_virtual = FALSE - ); - - IF _operations IS NULL THEN - RETURN _non_virtual_ops; - END IF; - - IF NOT _operations <@ _non_virtual_ops THEN - RAISE EXCEPTION 'Invalid operation ID detected. Allowed IDs are: %', _non_virtual_ops; - END IF; - - RETURN _operations; -END -$$; - RESET ROLE; diff --git a/queries/hafah_rest_backend/utilities/path_filters.sql b/queries/hafah_rest_backend/utilities/path_filters.sql new file mode 100644 index 000000000..e2c92e7e3 --- /dev/null +++ b/queries/hafah_rest_backend/utilities/path_filters.sql @@ -0,0 +1,53 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.decode_param(_encoded_param TEXT) +RETURNS TEXT +LANGUAGE 'plpgsql' +STABLE +AS +$$ +BEGIN + RETURN convert_from(decode(_encoded_param, 'base64'), 'UTF8'); +END +$$; + +CREATE OR REPLACE FUNCTION hafah_backend.parse_path_filters(_params TEXT[]) +RETURNS TABLE(param_json JSONB, param_text TEXT[]) +LANGUAGE 'plpgsql' +STABLE +AS +$$ +DECLARE + json_list JSONB := '[]'::JSONB; + text_list TEXT[] := '{}'; + param TEXT; + param_text TEXT; + key_value TEXT; + key_part TEXT[]; + value_part TEXT; +BEGIN + FOREACH param IN ARRAY _params + LOOP + -- Remove "" + param_text := hafah_backend.decode_param(param); + -- Extract everything before the first '=' as key + key_value := split_part(param_text, '=', 1); + + -- Extract everything after the first '=' as value + value_part := replace(param_text,key_value || '=',''); + + -- Split the key into parts based on '.' separator + key_part := string_to_array(key_value, '.'); + + -- Append key parts to the JSONB list + json_list := json_list || jsonb_build_array(key_part); + + -- Append the entire value part to the text array + text_list := array_append(text_list, value_part); + END LOOP; + + RETURN QUERY SELECT json_list, text_list; +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/utilities/validators.sql b/queries/hafah_rest_backend/utilities/validators.sql new file mode 100644 index 000000000..611974e3a --- /dev/null +++ b/queries/hafah_rest_backend/utilities/validators.sql @@ -0,0 +1,87 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.validate_participation_mode(_mode hafah_backend.participation_mode, _account_name TEXT) +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + IF _mode = 'all' AND _account_name IS NOT NULL THEN + RAISE EXCEPTION 'For participation mode ''all'', account name should not be provided'; + END IF; +END +$$ +; + +CREATE OR REPLACE FUNCTION hafah_backend.validate_account(_account_id INT, _account_name TEXT, _required BOOLEAN) +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + IF (_required AND _account_id IS NULL) OR (NOT _required AND _account_name IS NOT NULL AND _account_id IS NULL) THEN + PERFORM hafah_backend.rest_raise_missing_account(_account_name); + END IF; +END +$$ +; + +CREATE OR REPLACE FUNCTION hafah_backend.validate_operation_types(_operations INT[], _allowed_operations INT[]) +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + IF (NOT _operations <@ _allowed_operations) AND _operations IS NOT NULL THEN + PERFORM hafah_backend.rest_raise_invalid_operation_types(_allowed_operations); + END IF; +END +$$ +; + +CREATE OR REPLACE FUNCTION hafah_backend.validate_block_num(_block_num INT) +RETURNS VOID +LANGUAGE 'plpgsql' +STABLE +AS +$$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM hive.blocks_view bv WHERE bv.num = _block_num) THEN + PERFORM hafah_backend.rest_raise_missing_block(_block_num); + END IF; +END +$$ +; + +CREATE OR REPLACE FUNCTION hafah_backend.validate_op_type_id(_op_type INT) +RETURNS VOID +LANGUAGE 'plpgsql' +STABLE +AS +$$ +BEGIN + IF (_op_type > (SELECT MAX(id) FROM hafd.operation_types)) OR _op_type < 0 THEN + PERFORM hafah_backend.rest_raise_missing_op_type(_op_type); + END IF; +END +$$ +; + +CREATE OR REPLACE FUNCTION hafah_backend.validate_operation_id(_operation_id BIGINT) +RETURNS VOID +LANGUAGE 'plpgsql' +STABLE +AS +$$ +BEGIN + IF (SELECT ov.block_num FROM hive.operations_view ov WHERE ov.id = _operation_id) IS NULL THEN + PERFORM hafah_backend.rest_raise_missing_operation_id(_operation_id); + END IF; +END +$$ +; + +RESET ROLE; diff --git a/scripts/install_app.sh b/scripts/install_app.sh index 4be54e5ca..9fe5f501c 100755 --- a/scripts/install_app.sh +++ b/scripts/install_app.sh @@ -80,7 +80,16 @@ psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_R psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/transaction.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/fill_order.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/participation_mode.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/paging.sql" + +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/account.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/exceptions.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/validators.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/get_operation_types.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/paging.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/path_filters.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/operation_body_filter.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/utilities/function_helpers.sql" + psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/account_history.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/default.sql" @@ -88,20 +97,22 @@ psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_res psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql" + psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/recent_trades.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/market_history/trade_history.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/acc_op_types.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/op_types.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/operation.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/block_header.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/block_range.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/block.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/ops_in_block.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/path_filters.sql" + +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/blocks/block_header.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/blocks/block_range.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/blocks/block.sql" + +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/operations/acc_op_types.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/operations/op_types.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/operations/operation.sql" +psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../queries/hafah_rest_backend/operations/ops_in_block.sql" + psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_endpoints.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/set_version_in_sql.pgsql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -c "SET custom.swagger_url = '$SWAGGER_URL';" -f "$SCRIPTPATH/../postgrest/hafah_REST/hafah_openapi.sql" -psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_rest_exceptions.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/blocks/get_block.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/blocks/get_block_range.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/blocks/get_block_header.sql" -- GitLab From 23466742f5ade6c8aff888bf01df9d87c9cf0b89 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Thu, 24 Jul 2025 14:08:33 +0000 Subject: [PATCH 20/24] Adjust endpoints with new validation and helper functions --- .../hafah_REST/accounts/get_acc_op_types.sql | 7 +-- .../accounts/get_ops_by_account.sql | 15 ++---- postgrest/hafah_REST/blocks/get_block.sql | 18 ++++--- .../hafah_REST/blocks/get_block_header.sql | 18 ++++--- .../hafah_REST/blocks/get_block_range.sql | 29 +++++------- .../blocks/get_ops_by_block_paging.sql | 47 +++++-------------- .../market_history/get_trade_history.sql | 10 +--- .../operation_types/get_operation_keys.sql | 13 +++-- .../hafah_REST/operations/get_operation.sql | 15 +----- .../hafah_REST/operations/get_operations.sql | 15 ++---- postgrest/hafah_REST/other/get_block.sql | 3 ++ .../hafah_REST/other/get_head_block_num.sql | 1 - .../transactions/get_transaction.sql | 2 +- .../utilities/exceptions.sql | 12 +++++ .../utilities/validators.sql | 2 +- 15 files changed, 78 insertions(+), 129 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_acc_op_types.sql b/postgrest/hafah_REST/accounts/get_acc_op_types.sql index ce4069da6..e0a34c760 100644 --- a/postgrest/hafah_REST/accounts/get_acc_op_types.sql +++ b/postgrest/hafah_REST/accounts/get_acc_op_types.sql @@ -82,16 +82,11 @@ SET from_collapse_limit = 16 AS $$ DECLARE - _account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); + _account_id INT := hafah_backend.get_account_id("account-name", TRUE); BEGIN - IF _account_id IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_account("account-name"); - END IF; - PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); RETURN hafah_backend.get_acc_op_types(_account_id); - END $$; diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index 5d5e23351..eb604ee57 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -227,24 +227,15 @@ AS $$ DECLARE _block_range hive.blocks_range := hive.convert_to_blocks_range("from-block","to-block"); - _account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); - _transacting_account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "transacting-account-name"); - _operation_types INT[] := (SELECT string_to_array("operation-types", ',')::INT[]); + _account_id INT := hafah_backend.get_account_id("account-name", TRUE); + _transacting_account_id INT := hafah_backend.get_account_id("transacting-account-name", FALSE); + _operation_types INT[] := hafah_backend.get_operation_types("operation-types", "participation-mode" = 'all'); BEGIN - -- Validate inputs PERFORM hafah_backend.validate_participation_mode("participation-mode","transacting-account-name"); PERFORM hafah_python.validate_limit("page-size", 1000, 'page-size'); PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); PERFORM hafah_python.validate_negative_page("page"); - IF _account_id IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_account("account-name"); - END IF; - - IF "transacting-account-name" IS NOT NULL AND _transacting_account_id IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_account("transacting-account-name"); - END IF; - IF (_block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL) THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); ELSE diff --git a/postgrest/hafah_REST/blocks/get_block.sql b/postgrest/hafah_REST/blocks/get_block.sql index d5cc80899..fa76a9bb4 100644 --- a/postgrest/hafah_REST/blocks/get_block.sql +++ b/postgrest/hafah_REST/blocks/get_block.sql @@ -166,18 +166,16 @@ SET from_collapse_limit = 16 AS $$ DECLARE - __block INT := hive.convert_to_block_num("block-num"); - __block_num BIGINT = NULL; - __exception_message TEXT; + __block INT := hive.convert_to_block_num("block-num"); + __block_num BIGINT := NULL; + __exception_message TEXT := NULL; BEGIN -- Required argument: block-num - IF __block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('block-num'); - ELSE - __block_num = __block::BIGINT; - IF __block_num < 0 THEN - __block_num := __block_num + ((POW(2, 31) - 1) :: BIGINT); - END IF; + PERFORM hafah_backend.is_block_missing(__block); + + __block_num = __block::BIGINT; + IF __block_num < 0 THEN + __block_num := __block_num + ((POW(2, 31) - 1) :: BIGINT); END IF; IF __block <= hive.app_get_irreversible_block() AND __block IS NOT NULL THEN diff --git a/postgrest/hafah_REST/blocks/get_block_header.sql b/postgrest/hafah_REST/blocks/get_block_header.sql index 3f3c01726..372226f55 100644 --- a/postgrest/hafah_REST/blocks/get_block_header.sql +++ b/postgrest/hafah_REST/blocks/get_block_header.sql @@ -63,18 +63,16 @@ SET from_collapse_limit = 16 AS $$ DECLARE - __block INT := hive.convert_to_block_num("block-num"); - __block_num BIGINT = NULL; + __block INT := hive.convert_to_block_num("block-num"); + __block_num BIGINT := NULL; BEGIN -- Required argument: block-num - IF __block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('block-num'); - ELSE - __block_num = __block::BIGINT; - IF __block_num < 0 THEN - __block_num := __block_num + ((POW(2, 31) - 1) :: BIGINT); - END IF; - END IF; + PERFORM hafah_backend.is_block_missing(__block); + + __block_num = __block::BIGINT; + IF __block_num < 0 THEN + __block_num := __block_num + ((POW(2, 31) - 1) :: BIGINT); + END IF; IF __block <= hive.app_get_irreversible_block() AND __block IS NOT NULL THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); diff --git a/postgrest/hafah_REST/blocks/get_block_range.sql b/postgrest/hafah_REST/blocks/get_block_range.sql index 9d5043ed0..629e72786 100644 --- a/postgrest/hafah_REST/blocks/get_block_range.sql +++ b/postgrest/hafah_REST/blocks/get_block_range.sql @@ -297,29 +297,22 @@ AS $$ DECLARE _block_range hive.blocks_range := hive.convert_to_blocks_range("from-block","to-block"); - __block_num BIGINT = NULL; - __end_block_num BIGINT = NULL; + __block_num BIGINT := NULL; + __end_block_num BIGINT := NULL; BEGIN -- Required argument: block-num - IF _block_range.first_block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('from-block'); - ELSE - __block_num = _block_range.first_block::BIGINT; - IF __block_num < 0 THEN - __block_num := __block_num + ((POW(2, 31) - 1) :: BIGINT); - END IF; - END IF; + PERFORM hafah_backend.is_block_missing(_block_range.first_block, 'from-block'); - IF _block_range.last_block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('to-block'); - ELSE - __end_block_num = _block_range.last_block::BIGINT; - IF __end_block_num < 0 THEN - __end_block_num := __end_block_num + ((POW(2, 31) - 1) :: BIGINT); - ELSE + __block_num = _block_range.first_block::BIGINT; + IF __block_num < 0 THEN + __block_num := __block_num + ((POW(2, 31) - 1) :: BIGINT); + END IF; - END IF; + PERFORM hafah_backend.is_block_missing(_block_range.last_block, 'to-block'); + __end_block_num = _block_range.last_block::BIGINT; + IF __end_block_num < 0 THEN + __end_block_num := __end_block_num + ((POW(2, 31) - 1) :: BIGINT); END IF; IF _block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL THEN diff --git a/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql b/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql index 672daa0ca..ba719ab3c 100644 --- a/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql +++ b/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql @@ -163,37 +163,24 @@ SET from_collapse_limit = 16 AS $$ DECLARE - __block INT := hive.convert_to_block_num("block-num"); - _operation_types INT[] := (CASE WHEN "operation-types" IS NOT NULL THEN string_to_array("operation-types", ',')::INT[] ELSE NULL END); - _key_content TEXT[] := NULL; - _set_of_keys JSON := NULL; - _result hafah_backend.operation[]; - _account_id INT := NULL; + __block INT := hive.convert_to_block_num("block-num"); + _operation_types INT[] := hafah_backend.get_operation_types("operation-types", TRUE); + _account_id INT := hafah_backend.get_account_id("account-name", FALSE); + + _key_content TEXT[] := NULL; + _set_of_keys JSON := NULL; + _ops_count INT := NULL; + __total_pages INT := NULL; - _ops_count INT; - __total_pages INT; + _result hafah_backend.operation[]; BEGIN PERFORM hafah_python.validate_limit("page-size", 10000, 'page-size'); PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); PERFORM hafah_python.validate_negative_page("page"); + PERFORM hafah_backend.is_block_missing(__block); + PERFORM hafah_backend.validate_block_num(__block); - IF __block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('block-num'); - END IF; - - IF NOT EXISTS (SELECT 1 FROM hive.blocks_view bv WHERE bv.num = __block) THEN - PERFORM hafah_backend.rest_raise_missing_block(__block); - END IF; - - IF "account-name" IS NOT NULL THEN - _account_id := (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); - - IF _account_id IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_account("account-name"); - END IF; - END IF; - - IF "path-filter" IS NOT NULL AND "path-filter" != '{}' THEN + IF hafah_backend.is_path_filter_not_empty("path-filter") THEN SELECT pvpf.param_json::JSON, pvpf.param_text::TEXT[] @@ -207,15 +194,7 @@ BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); END IF; - _ops_count := ( - SELECT hafah_backend.get_ops_by_block_count( - __block, - _operation_types, - _account_id, - _key_content, - _set_of_keys - ) - ); + _ops_count := hafah_backend.get_ops_by_block_count(__block, _operation_types, _account_id, _key_content, _set_of_keys); __total_pages := ( CASE diff --git a/postgrest/hafah_REST/market_history/get_trade_history.sql b/postgrest/hafah_REST/market_history/get_trade_history.sql index 7a5d2c86f..84b7e6929 100644 --- a/postgrest/hafah_REST/market_history/get_trade_history.sql +++ b/postgrest/hafah_REST/market_history/get_trade_history.sql @@ -116,14 +116,8 @@ DECLARE BEGIN PERFORM hafah_python.validate_limit("result-limit", 1000, 'result-limit'); PERFORM hafah_python.validate_negative_limit("result-limit", 'result-limit'); - - IF _block_range.first_block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('from-block'); - END IF; - - IF _block_range.last_block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('to-block'); - END IF; + PERFORM hafah_backend.is_block_missing(_block_range.first_block, 'from-block'); + PERFORM hafah_backend.is_block_missing(_block_range.last_block, 'to-block'); IF _block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); diff --git a/postgrest/hafah_REST/operation_types/get_operation_keys.sql b/postgrest/hafah_REST/operation_types/get_operation_keys.sql index 572ba6fce..5b91e7d2d 100644 --- a/postgrest/hafah_REST/operation_types/get_operation_keys.sql +++ b/postgrest/hafah_REST/operation_types/get_operation_keys.sql @@ -64,13 +64,18 @@ SET enable_bitmapscan = OFF AS $$ DECLARE - _example_key JSON := (SELECT ov.body FROM hive.operations_view ov WHERE ov.op_type_id = "type-id" LIMIT 1); + _example_key JSON := NULL; BEGIN + PERFORM hafah_backend.validate_op_type_id("type-id"); PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); - IF ("type-id" > (SELECT MAX(id) FROM hafd.operation_types)) OR "type-id" < 0 THEN - PERFORM hafah_backend.rest_raise_missing_op_type("type-id"); - END IF; + _example_key := ( + SELECT + ov.body + FROM hive.operations_view ov + WHERE ov.op_type_id = "type-id" + LIMIT 1 + ); RETURN COALESCE( ( diff --git a/postgrest/hafah_REST/operations/get_operation.sql b/postgrest/hafah_REST/operations/get_operation.sql index ed758f297..3bcbc22fc 100644 --- a/postgrest/hafah_REST/operations/get_operation.sql +++ b/postgrest/hafah_REST/operations/get_operation.sql @@ -89,25 +89,14 @@ BEGIN IF _block_num IS NULL THEN PERFORM hafah_backend.rest_raise_missing_operation_id("operation-id"); END IF; - + IF _block_num <= hive.app_get_irreversible_block() THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); ELSE PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); END IF; - RETURN ( - ov.op, - ov.block, - ov.trx_id, - ov.op_pos, - ov.op_type_id, - ov.timestamp, - ov.virtual_op, - ov.operation_id, - ov.trx_in_block - )::hafah_backend.operation - FROM hafah_backend.get_operation("operation-id") ov; + RETURN hafah_backend.get_operation("operation-id"); END $$; diff --git a/postgrest/hafah_REST/operations/get_operations.sql b/postgrest/hafah_REST/operations/get_operations.sql index c1f16c053..89fd497e0 100644 --- a/postgrest/hafah_REST/operations/get_operations.sql +++ b/postgrest/hafah_REST/operations/get_operations.sql @@ -288,12 +288,14 @@ AS $$ DECLARE _block_range hive.blocks_range := hive.convert_to_blocks_range("from-block","to-block"); - _operation_types INT[] := (CASE WHEN "operation-types" IS NOT NULL THEN string_to_array("operation-types", ',')::INT[] ELSE NULL END); - _operation_group_types BOOLEAN := (CASE WHEN "operation-group-type" = 'real' THEN FALSE WHEN "operation-group-type" = 'virtual' THEN TRUE ELSE NULL END); + _operation_types INT[] := hafah_backend.get_operation_types("operation-types", TRUE); + _operation_group_types BOOLEAN := hafah_backend.get_group_type("operation-group-type"); BEGIN PERFORM hafah_python.validate_limit("page-size", 150000, 'page-size'); PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); PERFORM hafah_python.validate_block_range( _block_range.first_block, _block_range.last_block + 1, 2001); + PERFORM hafah_backend.is_block_missing(_block_range.first_block, 'from-block'); + PERFORM hafah_backend.is_block_missing(_block_range.last_block, 'to-block'); IF _block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); @@ -301,15 +303,6 @@ BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); END IF; - -- Required argument: to-block, from-block - IF _block_range.first_block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('from-block'); - END IF; - - IF _block_range.last_block IS NULL THEN - PERFORM hafah_backend.rest_raise_missing_arg('to-block'); - END IF; - RETURN hafah_backend.get_ops_in_blocks( _block_range.first_block, _block_range.last_block, diff --git a/postgrest/hafah_REST/other/get_block.sql b/postgrest/hafah_REST/other/get_block.sql index 462249952..75c581f6f 100644 --- a/postgrest/hafah_REST/other/get_block.sql +++ b/postgrest/hafah_REST/other/get_block.sql @@ -80,6 +80,9 @@ $$ DECLARE __block INT := hive.convert_to_block_num("block-num"); BEGIN + PERFORM hafah_backend.is_block_missing(__block); + PERFORM hafah_backend.validate_block_num(__block); + IF __block <= hive.app_get_irreversible_block() AND __block IS NOT NULL THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); ELSE diff --git a/postgrest/hafah_REST/other/get_head_block_num.sql b/postgrest/hafah_REST/other/get_head_block_num.sql index 4ad681253..7c432d4ce 100644 --- a/postgrest/hafah_REST/other/get_head_block_num.sql +++ b/postgrest/hafah_REST/other/get_head_block_num.sql @@ -43,7 +43,6 @@ $$ BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); RETURN bv.num FROM hive.blocks_view bv ORDER BY bv.num DESC LIMIT 1; - END $$; diff --git a/postgrest/hafah_REST/transactions/get_transaction.sql b/postgrest/hafah_REST/transactions/get_transaction.sql index adefe2c4c..9cdd80b31 100644 --- a/postgrest/hafah_REST/transactions/get_transaction.sql +++ b/postgrest/hafah_REST/transactions/get_transaction.sql @@ -86,7 +86,7 @@ AS $$ DECLARE _transaction_json JSON := hafah_python.get_transaction_json(('\x' || "transaction-id")::BYTEA, TRUE, FALSE, "include-virtual"); - _result JSON; + _result JSON := NULL; BEGIN IF (_transaction_json->>'block_num')::INT <= hive.app_get_irreversible_block() THEN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); diff --git a/queries/hafah_rest_backend/utilities/exceptions.sql b/queries/hafah_rest_backend/utilities/exceptions.sql index 0afcec822..f2053df42 100644 --- a/queries/hafah_rest_backend/utilities/exceptions.sql +++ b/queries/hafah_rest_backend/utilities/exceptions.sql @@ -120,4 +120,16 @@ END $$ ; +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_invalid_participation() +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + RAISE EXCEPTION 'For participation mode ''all'', account name should not be provided'; +END +$$ +; + RESET ROLE; diff --git a/queries/hafah_rest_backend/utilities/validators.sql b/queries/hafah_rest_backend/utilities/validators.sql index 611974e3a..241284d40 100644 --- a/queries/hafah_rest_backend/utilities/validators.sql +++ b/queries/hafah_rest_backend/utilities/validators.sql @@ -8,7 +8,7 @@ AS $$ BEGIN IF _mode = 'all' AND _account_name IS NOT NULL THEN - RAISE EXCEPTION 'For participation mode ''all'', account name should not be provided'; + PERFORM hafah_backend.rest_raise_invalid_participation(); END IF; END $$ -- GitLab From 8b08d2e91adf55462d02871b8d0bae61e31d4156 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Mon, 28 Jul 2025 21:09:08 +0000 Subject: [PATCH 21/24] Instead of filtering out virtual operations by its op_type_id - use transacting_account_id IS NOT NULL --- .../account_history/account_history.sql | 7 ++++--- .../account_history/filtering_functions/by_operations.sql | 8 +++++--- .../account_history/filtering_functions/default.sql | 3 ++- .../hafah_rest_backend/utilities/get_operation_types.sql | 4 ---- queries/hafah_rest_backend/utilities/paging.sql | 8 +++++--- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/queries/hafah_rest_backend/account_history/account_history.sql b/queries/hafah_rest_backend/account_history/account_history.sql index bd00ee96d..7998f6785 100644 --- a/queries/hafah_rest_backend/account_history/account_history.sql +++ b/queries/hafah_rest_backend/account_history/account_history.sql @@ -25,7 +25,7 @@ DECLARE BEGIN CASE -- If no filters are applied, use the default account history function - WHEN (NOT _filter_by_account_ids) AND (NOT _filter_by_op) THEN + WHEN (_participation_mode = 'all') AND (NOT _filter_by_op) THEN _result := hafah_backend.account_history_default( _account_id, _from_block, @@ -36,7 +36,7 @@ BEGIN ); -- If only operations are filtered, use the account history by operations function - WHEN (NOT _filter_by_account_ids) AND (_filter_by_op) THEN + WHEN ((_participation_mode = 'all') AND (_filter_by_op)) OR ((_participation_mode != 'all') AND (NOT _filter_by_account_ids)) THEN _result := hafah_backend.account_history_by_operations( _account_id, _operations, @@ -44,7 +44,8 @@ BEGIN _to_block, _page, _body_limit, - _limit + _limit, + (_participation_mode = 'all') -- include virtual operations if participation mode is 'all' ); -- If accounts are filtered, use the account history by accounts function (include account) WHEN (_participation_mode = 'include') AND (_filter_by_account_ids) AND (_filter_by_single_acc) THEN diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql b/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql index 19b09b385..9e7568756 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/by_operations.sql @@ -7,7 +7,8 @@ CREATE OR REPLACE FUNCTION hafah_backend.account_history_by_operations( _to_block INT, _page INT, _body_limit INT, - _limit INT + _limit INT, + _include_virtual BOOLEAN ) RETURNS hafah_backend.account_operation_history -- noqa: LT01, CP05 LANGUAGE 'plpgsql' STABLE @@ -27,7 +28,7 @@ BEGIN -----------PAGING LOGIC---------------- _account_range := hafah_backend.account_range(_operations, _account_id, _from_block, _to_block); - _ops_count := hafah_backend.get_account_operations_count(_operations, _account_id, _account_range.from_seq, _account_range.to_seq); + _ops_count := hafah_backend.get_account_operations_count(_operations, _account_id, _account_range.from_seq, _account_range.to_seq, _include_virtual); _calculate_pages := hafah_backend.calculate_pages(_ops_count, _page, 'desc', _limit); @@ -46,7 +47,8 @@ BEGIN SELECT aov.operation_id, aov.op_type_id, aov.block_num FROM hive.account_operations_view aov WHERE aov.account_id = _account_id - AND aov.op_type_id = ANY(_operations) + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND (_include_virtual OR aov.transacting_account_id IS NOT NULL) AND aov.account_op_seq_no >= _account_range.from_seq AND aov.account_op_seq_no <= _account_range.to_seq ORDER BY aov.account_op_seq_no DESC diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/default.sql b/queries/hafah_rest_backend/account_history/filtering_functions/default.sql index 42c26ad50..3f8334022 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/default.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/default.sql @@ -26,7 +26,8 @@ BEGIN -----------PAGING LOGIC---------------- _account_range := hafah_backend.account_range(NULL, _account_id, _from_block, _to_block); - _ops_count := hafah_backend.get_account_operations_count(NULL, _account_id, _account_range.from_seq, _account_range.to_seq); + -- always include virtual operations + _ops_count := hafah_backend.get_account_operations_count(NULL, _account_id, _account_range.from_seq, _account_range.to_seq, TRUE); _calculate_pages := hafah_backend.calculate_pages(_ops_count, _page, 'desc', _limit); diff --git a/queries/hafah_rest_backend/utilities/get_operation_types.sql b/queries/hafah_rest_backend/utilities/get_operation_types.sql index a8fd05832..82a23031b 100644 --- a/queries/hafah_rest_backend/utilities/get_operation_types.sql +++ b/queries/hafah_rest_backend/utilities/get_operation_types.sql @@ -32,10 +32,6 @@ BEGIN WHERE is_virtual = FALSE ); - IF _operation_ids IS NULL THEN - RETURN _non_virtual_ops; - END IF; - PERFORM hafah_backend.validate_operation_types(_operation_ids, _non_virtual_ops); RETURN _operation_ids; diff --git a/queries/hafah_rest_backend/utilities/paging.sql b/queries/hafah_rest_backend/utilities/paging.sql index e7e790317..c573063b5 100644 --- a/queries/hafah_rest_backend/utilities/paging.sql +++ b/queries/hafah_rest_backend/utilities/paging.sql @@ -168,7 +168,8 @@ CREATE OR REPLACE FUNCTION hafah_backend.get_account_operations_count( _operations INT [], _account_id INT, _from_seq INT, - _to_seq INT + _to_seq INT, + _include_virtual BOOLEAN ) RETURNS BIGINT -- noqa: LT01, CP05 LANGUAGE 'plpgsql' STABLE @@ -179,7 +180,7 @@ SET JIT = OFF AS $$ BEGIN - IF _operations IS NULL THEN + IF _operations IS NULL AND _include_virtual THEN RETURN _to_seq - _from_seq + 1; END IF; @@ -187,7 +188,8 @@ BEGIN SELECT COUNT(*) FROM hive.account_operations_view aov WHERE aov.account_id = _account_id - AND aov.op_type_id = ANY(_operations) + AND (_operations IS NULL OR aov.op_type_id = ANY(_operations)) + AND (_include_virtual OR aov.transacting_account_id IS NOT NULL) AND aov.account_op_seq_no >= _from_seq AND aov.account_op_seq_no <= _to_seq ); -- GitLab From 8fa0d5fa549cfaf43a6ae8677f4a592104b429bd Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Tue, 29 Jul 2025 09:20:27 +0000 Subject: [PATCH 22/24] Move transactions_view call to subquery - seems to be more stable --- .../account_history/filtering_functions/exclude_account.sql | 5 +++-- .../filtering_functions/excluding_accounts.sql | 5 +++-- .../account_history/filtering_functions/include_account.sql | 5 +++-- .../filtering_functions/including_accounts.sql | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql index 62f11f510..d574202cc 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/exclude_account.sql @@ -176,7 +176,8 @@ BEGIN ls.id, ls.block_num, ov.trx_in_block, - encode(htv.trx_hash, 'hex') AS trx_hash, + -- subquery is more stable than using LEFT JOIN with hive.transactions_view + (SELECT encode(htv.trx_hash, 'hex') FROM hive.transactions_view htv WHERE htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block) AS trx_hash, ov.op_pos, ls.op_type_id, ov.body, @@ -187,7 +188,7 @@ BEGIN ) ls JOIN hive.operations_view ov ON ov.id = ls.id JOIN hafd.operation_types hot ON hot.id = ls.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + --LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block ), -- filter too long operation bodies result_query AS ( diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql index 80131e17f..b4cfb0b80 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/excluding_accounts.sql @@ -192,7 +192,8 @@ BEGIN ls.id, ls.block_num, ov.trx_in_block, - encode(htv.trx_hash, 'hex') AS trx_hash, + -- subquery is more stable than using LEFT JOIN with hive.transactions_view + (SELECT encode(htv.trx_hash, 'hex') FROM hive.transactions_view htv WHERE htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block) AS trx_hash, ov.op_pos, ls.op_type_id, ov.body, @@ -203,7 +204,7 @@ BEGIN ) ls JOIN hive.operations_view ov ON ov.id = ls.id JOIN hafd.operation_types hot ON hot.id = ls.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + --LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block ), -- filter too long operation bodies result_query AS ( diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql b/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql index f4c5c1c3b..d1175d1ca 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/include_account.sql @@ -174,7 +174,8 @@ BEGIN ls.id, ls.block_num, ov.trx_in_block, - encode(htv.trx_hash, 'hex') AS trx_hash, + -- subquery is more stable than using LEFT JOIN with hive.transactions_view + (SELECT encode(htv.trx_hash, 'hex') FROM hive.transactions_view htv WHERE htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block) AS trx_hash, ov.op_pos, ls.op_type_id, ov.body, @@ -185,7 +186,7 @@ BEGIN ) ls JOIN hive.operations_view ov ON ov.id = ls.id JOIN hafd.operation_types hot ON hot.id = ls.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + --LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block ), -- filter too long operation bodies result_query AS ( diff --git a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql index 90e07645d..92416304a 100644 --- a/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql +++ b/queries/hafah_rest_backend/account_history/filtering_functions/including_accounts.sql @@ -174,7 +174,8 @@ BEGIN ls.id, ls.block_num, ov.trx_in_block, - encode(htv.trx_hash, 'hex') AS trx_hash, + -- subquery is more stable than using LEFT JOIN with hive.transactions_view + (SELECT encode(htv.trx_hash, 'hex') FROM hive.transactions_view htv WHERE htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block) AS trx_hash, ov.op_pos, ls.op_type_id, ov.body, @@ -185,7 +186,7 @@ BEGIN ) ls JOIN hive.operations_view ov ON ov.id = ls.id JOIN hafd.operation_types hot ON hot.id = ls.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block + --LEFT JOIN hive.transactions_view htv ON htv.block_num = ls.block_num AND htv.trx_in_block = ov.trx_in_block ), -- filter too long operation bodies result_query AS ( -- GitLab From e1abda3941ae375f3a933322ad94208e5aac1233 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Tue, 29 Jul 2025 10:04:19 +0000 Subject: [PATCH 23/24] Move total_pages calculation to utility function --- .../blocks/get_ops_by_block_paging.sql | 18 +++++------------ .../hafah_rest_backend/utilities/paging.sql | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql b/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql index ba719ab3c..3f03da12e 100644 --- a/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql +++ b/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql @@ -170,7 +170,7 @@ DECLARE _key_content TEXT[] := NULL; _set_of_keys JSON := NULL; _ops_count INT := NULL; - __total_pages INT := NULL; + _total_pages INT := NULL; _result hafah_backend.operation[]; BEGIN @@ -194,18 +194,10 @@ BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); END IF; - _ops_count := hafah_backend.get_ops_by_block_count(__block, _operation_types, _account_id, _key_content, _set_of_keys); + _ops_count := hafah_backend.get_ops_by_block_count(__block, _operation_types, _account_id, _key_content, _set_of_keys); + _total_pages := hafah_backend.total_pages(_ops_count, "page-size"); - __total_pages := ( - CASE - WHEN (_ops_count % "page-size") = 0 THEN - _ops_count/"page-size" - ELSE - (_ops_count/"page-size") + 1 - END - ); - - PERFORM hafah_python.validate_page("page", __total_pages); + PERFORM hafah_python.validate_page("page", _total_pages); _result := array_agg(row ORDER BY (CASE WHEN "page-order" = 'desc' THEN row.operation_id::BIGINT ELSE NULL END) DESC, @@ -236,7 +228,7 @@ BEGIN RETURN ( COALESCE(_ops_count,0), - COALESCE(__total_pages,0), + COALESCE(_total_pages,0), COALESCE(_result, '{}'::hafah_backend.operation[]) )::hafah_backend.operation_history; diff --git a/queries/hafah_rest_backend/utilities/paging.sql b/queries/hafah_rest_backend/utilities/paging.sql index c573063b5..f5388b2d8 100644 --- a/queries/hafah_rest_backend/utilities/paging.sql +++ b/queries/hafah_rest_backend/utilities/paging.sql @@ -163,6 +163,26 @@ BEGIN END $$; +CREATE OR REPLACE FUNCTION hafah_backend.total_pages( + _ops_count INT, + _page_size INT +) +RETURNS INT -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' IMMUTABLE +AS +$$ +BEGIN + RETURN ( + CASE + WHEN (_ops_count % _page_size) = 0 THEN + _ops_count / _page_size + ELSE + (_ops_count / _page_size) + 1 + END + ); +END +$$; + -- used in account page endpoint (not used when filtered by accounts) CREATE OR REPLACE FUNCTION hafah_backend.get_account_operations_count( _operations INT [], -- GitLab From 54f47fb6f366ebabfd87e293b3d05d2027efe5a6 Mon Sep 17 00:00:00 2001 From: Michal Zander Date: Tue, 29 Jul 2025 10:05:09 +0000 Subject: [PATCH 24/24] Bump haf --- haf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haf b/haf index 85e611688..6e97cb607 160000 --- a/haf +++ b/haf @@ -1 +1 @@ -Subproject commit 85e6116889fbbdb9a50909a3350210f21bd4b796 +Subproject commit 6e97cb607fec227d6640918bcad759c4f5d52d92 -- GitLab