From 9a288fb24163a460b009e8c0a601d64465b44188 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Mon, 24 Mar 2025 22:19:39 +0000 Subject: [PATCH 01/22] Rewrite account-history API, return composite type instead of json --- .../accounts/get_ops_by_account.sql | 124 ++++-- .../hafah_rest_backend/account_history.sql | 387 ------------------ .../account_history/account_history.sql | 236 +++++++++++ .../account_history/by_operations.sql | 68 +++ .../account_history/count.sql | 36 ++ .../account_history/default.sql | 64 +++ .../account_history/paging.sql | 144 +++++++ 7 files changed, 629 insertions(+), 430 deletions(-) delete mode 100644 queries/hafah_rest_backend/account_history.sql create mode 100644 queries/hafah_rest_backend/account_history/account_history.sql create mode 100644 queries/hafah_rest_backend/account_history/by_operations.sql create mode 100644 queries/hafah_rest_backend/account_history/count.sql create mode 100644 queries/hafah_rest_backend/account_history/default.sql create mode 100644 queries/hafah_rest_backend/account_history/paging.sql diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index b77f7ae9c..6a19b58a1 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -1,5 +1,30 @@ SET ROLE hafah_owner; +/** openapi:components:schemas +hafah_backend.account_history: + type: object + properties: + total_operations: + type: integer + description: Total number of operations + total_pages: + type: integer + description: Total number of 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_history CASCADE; +CREATE TYPE hafah_backend.account_history AS ( + "total_operations" INT, + "total_pages" INT, + "operations_result" hafah_backend.operation[] +); +-- openapi-generated-code-end + /** openapi:paths /accounts/{account-name}/operations: get: @@ -102,8 +127,7 @@ SET ROLE hafah_owner; content: application/json: schema: - type: string - x-sql-datatype: JSON + $ref: '#/components/schemas/hafah_backend.account_history' example: { "total_operations": 219867, "total_pages": 73289, @@ -189,56 +213,81 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_ops_by_account( "from-block" TEXT = NULL, "to-block" TEXT = NULL ) -RETURNS JSON +RETURNS hafah_backend.account_history -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE SET join_collapse_limit = 16 SET from_collapse_limit = 16 SET JIT = OFF SET enable_hashjoin = OFF -SET plan_cache_mode = force_custom_plan --- force_custom_plan added to every function that uses OFFSET AS $$ DECLARE _block_range hive.blocks_range := hive.convert_to_blocks_range("from-block","to-block"); - _ops_count BIGINT; - _calculate_total_pages INT; + _account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); + _ops_count INT; + _from INT; + _to INT; _operation_types INT[] := (SELECT string_to_array("operation-types", ',')::INT[]); - _page INT; + _result hafah_backend.operation[]; + + __total_pages INT; + __offset INT; + __limit INT; BEGIN -PERFORM hafah_python.validate_limit("page-size", 1000, 'page-size'); -PERFORM hafah_python.validate_negative_limit("page-size", 'page-size'); + IF _account_id IS NULL THEN + RETURN hafah_backend.rest_raise_missing_account("account-name"); + END IF; -SELECT hafah_backend.get_account_operations_count(_operation_types, "account-name", _block_range.first_block, _block_range.last_block) INTO _ops_count; + 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"); -SELECT (CASE WHEN (_ops_count % "page-size") = 0 THEN - _ops_count/"page-size" ELSE ((_ops_count/"page-size") + 1) END)::INT INTO _calculate_total_pages; + -----------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); -IF "page" IS NULL THEN - _page := 1; -ELSE - PERFORM hafah_python.validate_negative_page("page"); - PERFORM hafah_python.validate_page("page", _calculate_total_pages); + SELECT total_pages, offset_filter, limit_filter + INTO __total_pages, __offset, __limit + FROM hafah_backend.calculate_pages(_ops_count, "page", 'desc', "page-size"); - _page := _calculate_total_pages - "page" + 1; -END IF; + 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 + 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; -IF (_block_range.last_block <= hive.app_get_irreversible_block() AND _block_range.last_block IS NOT NULL) OR ("page" IS NOT NULL AND _calculate_total_pages != "page") 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) 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), + _result + )::hafah_backend.account_history; -RETURN ( - SELECT json_build_object( -- ops_count returns number of operations found with current filter - 'total_operations', _ops_count, -- 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 - 'total_pages', _calculate_total_pages, - 'operations_result', - (SELECT to_json(array_agg(row)) FROM ( - SELECT * FROM hafah_backend.get_ops_by_account("account-name", -- there is two diffrent page_nums, internal and external, internal page_num is ascending (first page with the newest operation is number 1) -- external page_num is descending, its given by FE and recalculated by this query to internal @@ -247,18 +296,7 @@ RETURN ( -- page 15 (external first page) 15 - 15 + 1 = 1 (internal first page) -- page 14 (external second page) 15 - 14 + 1 = 2 (internal second page) -- ... page 7, 15 - 7 + 1 = 9 (internal 9th page) - _page, - "page-size", - _operation_types, - _block_range.first_block, - _block_range.last_block, - "data-size-limit", - (_ops_count % "page-size")::INT, - _ops_count::INT) - -- to return the first page with the rest of the division of ops count the number is handed over to backend function - ) row) - )); END $$; diff --git a/queries/hafah_rest_backend/account_history.sql b/queries/hafah_rest_backend/account_history.sql deleted file mode 100644 index 681d004ed..000000000 --- a/queries/hafah_rest_backend/account_history.sql +++ /dev/null @@ -1,387 +0,0 @@ -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 TEXT, - _page_num INT, - _limit INT, - _filter INT [], - _from INT, - _to INT, - _body_limit INT, - _rest_of_division INT, - _ops_count INT -) -RETURNS SETOF hafah_backend.operation -- noqa: LT01, CP05 -LANGUAGE 'plpgsql' STABLE -COST 10000 -SET JIT = OFF -SET join_collapse_limit = 16 -SET from_collapse_limit = 16 -AS -$$ -DECLARE - __account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = _account); - __no_start_date BOOLEAN = (_from IS NULL); - __no_end_date BOOLEAN = (_to IS NULL); - __no_ops_filter BOOLEAN = (_filter IS NULL); - __no_filters BOOLEAN := TRUE; - __offset INT := (((_page_num - 2) * _limit) + (_rest_of_division)); --- offset is calculated only from _page_num = 2, then the offset = _rest_of_division --- on _page_num = 3, offset = _limit + _rest_of_division etc. - __op_seq INT:= 0; -BEGIN -IF __no_start_date AND __no_end_date AND __no_ops_filter THEN - __no_filters = FALSE; - __op_seq := (_ops_count - (((_page_num - 1) * _limit) + _rest_of_division) ); -END IF; - - --- 23726 - (237 * 100 + 26) = 0 >= and < 100 --- 23726 - (236 * 100 + 26) = 100 >= and < 200 - --- 23726 - (0 * 100 + 26) = 23700 >= and < 23800 - -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 ( - WITH op_filter AS MATERIALIZED ( - SELECT ARRAY_AGG(ot.id) as op_id FROM hafd.operation_types ot WHERE (CASE WHEN _filter IS NOT NULL THEN ot.id = ANY(_filter) ELSE TRUE END) - ), --- changing filtering method from block_num to operation_id - ops_from_start_block as MATERIALIZED - ( - SELECT ov.id - FROM hive.operations_view ov - WHERE ov.block_num >= _from - ORDER BY ov.block_num, ov.id - LIMIT 1 - ), - ops_from_end_block as MATERIALIZED - ( - SELECT ov.id - FROM hive.operations_view ov - WHERE ov.block_num <= _to - ORDER BY ov.block_num DESC, ov.id DESC - LIMIT 1 - ) - - /* - we are using 3 diffrent methods of fetching data, - 1. using hive_account_operations_uq_1 (account_id, account_op_seq_no) when __no_filters = FALSE (when 2. and 3. are TRUE) - - when we don't use filter we can page the result by account_op_seq_no, - we need to add ORDER BY account_op_seq_no - 2. using hive_account_operations_uq2 (account_id, operation_id) when __no_end_date = FALSE OR __no_start_date = FALSE - - when we filter operations ONLY by block_num (converted to operation_id), - we need to add ORDER BY operation_id - 3. using hive_account_operations_type_account_id_op_seq_idx (op_type_id, account_id, account_op_seq_no) when __no_ops_filter = FALSE - - when we filter operations by op_type_id - - when we filter operations by op_type_id AND block_num (converted to operation_id) - */ - - SELECT aov.operation_id, aov.op_type_id, aov.block_num - FROM hive.account_operations_view aov - WHERE aov.account_id = __account_id - AND (__no_filters OR account_op_seq_no >= (CASE WHEN (_rest_of_division) != 0 THEN __op_seq ELSE (__op_seq - _limit) END)) - AND (__no_filters OR account_op_seq_no < (CASE WHEN (_rest_of_division) != 0 THEN (__op_seq + _limit) ELSE __op_seq END)) - AND (__no_ops_filter OR aov.op_type_id = ANY(ARRAY[(SELECT of.op_id FROM op_filter of)])) - AND (__no_start_date OR aov.operation_id >= (SELECT * FROM ops_from_start_block)) - AND (__no_end_date OR aov.operation_id < (SELECT * FROM ops_from_end_block)) - ORDER BY (CASE WHEN NOT __no_start_date OR NOT __no_end_date THEN aov.operation_id ELSE aov.account_op_seq_no END) DESC - LIMIT (CASE WHEN _page_num = 1 AND (_rest_of_division) != 0 THEN _rest_of_division ELSE _limit END) - OFFSET (CASE WHEN _page_num = 1 OR NOT __no_filters THEN 0 ELSE __offset END) - ) 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; - -END -$$; - --- used in account page endpoint -CREATE OR REPLACE FUNCTION hafah_backend.get_account_operations_count( - _operations INT [], - _account TEXT, - _from INT, - _to 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 -$$ -DECLARE - __no_start_date BOOLEAN = (_from IS NULL); - __no_end_date BOOLEAN = (_to IS NULL); - __no_ops_filter BOOLEAN = (_operations IS NULL); -BEGIN -IF __no_ops_filter = TRUE AND __no_start_date = TRUE AND __no_end_date = TRUE THEN - RETURN ( - WITH account_id AS MATERIALIZED ( - SELECT av.id FROM hive.accounts_view av WHERE av.name = _account) - - SELECT aov.account_op_seq_no + 1 - FROM hive.account_operations_view aov - WHERE aov.account_id = (SELECT ai.id FROM account_id ai) - ORDER BY aov.account_op_seq_no DESC LIMIT 1); - -ELSE - RETURN ( - WITH op_filter AS MATERIALIZED ( - SELECT ARRAY_AGG(ot.id) as op_id FROM hafd.operation_types ot WHERE (CASE WHEN _operations IS NOT NULL THEN ot.id = ANY(_operations) ELSE TRUE END) - ), - account_id AS MATERIALIZED ( - SELECT av.id FROM hive.accounts_view av WHERE av.name = _account - ), --- changing filtering method from block_num to operation_id - ops_from_start_block as MATERIALIZED - ( - SELECT ov.id - FROM hive.operations_view ov - WHERE ov.block_num >= _from - ORDER BY ov.block_num, ov.id - LIMIT 1 - ), - ops_from_end_block as MATERIALIZED - ( - SELECT ov.id - FROM hive.operations_view ov - WHERE ov.block_num <= _to - ORDER BY ov.block_num DESC, ov.id DESC - LIMIT 1 - ) --- 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 = (SELECT ai.id FROM account_id ai) - AND (__no_ops_filter OR aov.op_type_id = ANY(ARRAY[(SELECT of.op_id FROM op_filter of)])) - AND (__no_start_date OR aov.operation_id >= (SELECT * FROM ops_from_start_block)) - AND (__no_end_date OR aov.operation_id < (SELECT * FROM ops_from_end_block)) - ); - -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 new file mode 100644 index 000000000..327d26b90 --- /dev/null +++ b/queries/hafah_rest_backend/account_history/account_history.sql @@ -0,0 +1,236 @@ +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 [], + _from INT, + _to INT, + _body_limit INT, + _offset INT, + _limit INT +) +RETURNS SETOF hafah_backend.operation -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +AS +$$ +BEGIN + IF _operations IS NULL THEN + RETURN QUERY + SELECT * FROM hafah_backend.account_history_default( + _account_id, + _from, + _to, + _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 + ); + +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/by_operations.sql b/queries/hafah_rest_backend/account_history/by_operations.sql new file mode 100644 index 000000000..7453f9835 --- /dev/null +++ b/queries/hafah_rest_backend/account_history/by_operations.sql @@ -0,0 +1,68 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.account_history_by_operations( + _account_id INT, + _operations INT [], + _from INT, + _to INT, + _body_limit INT, + _offset INT, + _limit INT +) +RETURNS SETOF hafah_backend.operation -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +COST 10000 +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 +AS +$$ +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; + +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/count.sql b/queries/hafah_rest_backend/account_history/count.sql new file mode 100644 index 000000000..42f56e07b --- /dev/null +++ b/queries/hafah_rest_backend/account_history/count.sql @@ -0,0 +1,36 @@ +SET ROLE hafah_owner; + +-- used in account page endpoint +CREATE OR REPLACE FUNCTION hafah_backend.get_account_operations_count( + _operations INT [], + _account_id INT, + _from INT, + _to 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 - _from + 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 + ); + +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/default.sql b/queries/hafah_rest_backend/account_history/default.sql new file mode 100644 index 000000000..dfe730f3c --- /dev/null +++ b/queries/hafah_rest_backend/account_history/default.sql @@ -0,0 +1,64 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.account_history_default( + _account_id INT, + _from INT, + _to INT, + _body_limit INT, + _offset INT, + _limit INT +) +RETURNS SETOF hafah_backend.operation -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +COST 10000 +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 +AS +$$ +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; +END +$$; + +RESET ROLE; diff --git a/queries/hafah_rest_backend/account_history/paging.sql b/queries/hafah_rest_backend/account_history/paging.sql new file mode 100644 index 000000000..8729109ff --- /dev/null +++ b/queries/hafah_rest_backend/account_history/paging.sql @@ -0,0 +1,144 @@ +SET ROLE hafah_owner; + +DROP TYPE IF EXISTS hafah_backend.calculate_pages_return CASCADE; +CREATE TYPE hafah_backend.calculate_pages_return AS +( + rest_of_division INT, + total_pages INT, + page_num INT, + offset_filter INT, + limit_filter INT +); + +CREATE OR REPLACE FUNCTION hafah_backend.calculate_pages( + _count INT, + _page INT, + _order_is hafah_backend.sort_direction, -- noqa: LT01, CP05 + _limit INT +) +RETURNS hafah_backend.calculate_pages_return -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +AS +$$ +DECLARE + __rest_of_division INT; + __total_pages INT; + __page INT; + __offset INT; + __limit INT; +BEGIN + __rest_of_division := (_count % _limit)::INT; + + __total_pages := ( + CASE + WHEN (__rest_of_division = 0) THEN + _count / _limit + ELSE + (_count / _limit) + 1 + END + )::INT; + + __page := ( + CASE + WHEN (_page IS NULL) THEN + 1 + WHEN (_page IS NOT NULL) AND _order_is = 'desc' THEN + __total_pages - _page + 1 + ELSE + _page + END + ); + + __offset := ( + CASE + WHEN _order_is = 'desc' AND __page != 1 AND __rest_of_division != 0 THEN + ((__page - 2) * _limit) + __rest_of_division + WHEN __page = 1 THEN + 0 + ELSE + (__page - 1) * _limit + END + ); + + __limit := ( + CASE + WHEN _order_is = 'desc' AND __page = 1 AND __rest_of_division != 0 THEN + __rest_of_division + WHEN _order_is = 'asc' AND __page = __total_pages AND __rest_of_division != 0 THEN + __rest_of_division + ELSE + _limit + END + ); + + PERFORM hafah_python.validate_page(_page, __total_pages); + + RETURN (__rest_of_division, __total_pages, __page, __offset, __limit)::hafah_backend.calculate_pages_return; +END +$$; + +DROP TYPE IF EXISTS hafah_backend.account_filter_return CASCADE; +CREATE TYPE hafah_backend.account_filter_return AS +( + count INT, + from_seq INT, + to_seq INT +); + +CREATE OR REPLACE FUNCTION hafah_backend.account_range( + _operations INT [], + _account_id INT, + _from INT, + _to INT +) +RETURNS hafah_backend.account_filter_return -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +AS +$$ +DECLARE + __to_seq INT; + __from_seq INT; + __count INT; +BEGIN + /* + we are using 3 diffrent methods of fetching data, + 1. using hive_account_operations_uq_1 (account_id, account_op_seq_no) when __no_filters = FALSE (when 2. and 3. are TRUE) + - when we don't use filter we can page the result by account_op_seq_no, + we need to add ORDER BY account_op_seq_no + 2. using hive_account_operations_uq2 (account_id, operation_id) when __no_end_date = FALSE OR __no_start_date = FALSE + - when we filter operations ONLY by block_num (converted to operation_id), + we need to add ORDER BY operation_id + 3. using hive_account_operations_type_account_id_op_seq_idx (op_type_id, account_id, account_op_seq_no) when __no_ops_filter = FALSE + - when we filter operations by op_type_id + - when we filter operations by op_type_id AND block_num (converted to operation_id) + */ + + __to_seq := ( + SELECT + aov.account_op_seq_no + FROM hive.account_operations_view aov + WHERE + aov.account_id = _account_id AND + (_to IS NULL OR aov.block_num <= _to) + ORDER BY aov.account_op_seq_no DESC LIMIT 1 + ); + + __from_seq := ( + SELECT + aov.account_op_seq_no + FROM hive.account_operations_view aov + WHERE + aov.account_id = _account_id AND + (_from IS NULL OR aov.block_num >= _from) + ORDER BY aov.account_op_seq_no ASC LIMIT 1 + ); + + __count := hafah_backend.get_account_operations_count(_operations, _account_id, __from_seq, __to_seq); + + RETURN (__count, __from_seq, __to_seq)::hafah_backend.account_filter_return; +END +$$; + +RESET ROLE; -- GitLab From 485665dda2a546b6c7bec383855d994382c8c6bc Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Mon, 24 Mar 2025 22:22:56 +0000 Subject: [PATCH 02/22] Rewrite account op types API --- .../hafah_REST/accounts/get_acc_op_types.sql | 26 +++++++------------ .../accounts/get_ops_by_account.sql | 2 +- queries/hafah_rest_backend/acc_op_types.sql | 22 ++++++++++++++++ 3 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 queries/hafah_rest_backend/acc_op_types.sql diff --git a/postgrest/hafah_REST/accounts/get_acc_op_types.sql b/postgrest/hafah_REST/accounts/get_acc_op_types.sql index 894a948e2..4c612fa2d 100644 --- a/postgrest/hafah_REST/accounts/get_acc_op_types.sql +++ b/postgrest/hafah_REST/accounts/get_acc_op_types.sql @@ -27,12 +27,13 @@ SET ROLE hafah_owner; description: | Operation type list - * Returns `JSONB` + * Returns array of `INT` content: application/json: schema: - type: string - x-sql-datatype: JSONB + type: array + items: + type: integer example: [ 0, 1, @@ -72,7 +73,7 @@ DROP FUNCTION IF EXISTS hafah_endpoints.get_acc_op_types; CREATE OR REPLACE FUNCTION hafah_endpoints.get_acc_op_types( "account-name" TEXT ) -RETURNS JSONB +RETURNS INT[] -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE SET JIT = OFF @@ -83,21 +84,14 @@ $$ DECLARE __account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); BEGIN + IF _account_id IS NULL THEN + RETURN hafah_backend.rest_raise_missing_account("account-name"); + END IF; + PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); - RETURN ( - WITH op_types_cte AS - ( - SELECT id - FROM hafd.operation_types hot - WHERE ( - SELECT EXISTS ( - SELECT 1 FROM hive.account_operations_view aov WHERE aov.account_id = __account_id AND aov.op_type_id = hot.id)) - ) + RETURN hafah_backend.get_acc_op_types(__account_id); - SELECT jsonb_agg(to_jsonb(cte.id::INT)) - FROM op_types_cte cte - ); END $$; diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index 6a19b58a1..5de135f1a 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -123,7 +123,7 @@ CREATE TYPE hafah_backend.account_history AS ( Result contains total number of operations, total pages, and the list of operations. - * Returns `JSON` + * Returns `hafah_backend.account_history` content: application/json: schema: diff --git a/queries/hafah_rest_backend/acc_op_types.sql b/queries/hafah_rest_backend/acc_op_types.sql new file mode 100644 index 000000000..cbc8b53a9 --- /dev/null +++ b/queries/hafah_rest_backend/acc_op_types.sql @@ -0,0 +1,22 @@ +SET ROLE hafah_owner; + +-- used in account page endpoint +CREATE OR REPLACE FUNCTION hafah_backend.get_acc_op_types( + _account_id INT +) +RETURNS INT[] -- noqa: LT01, CP05 +LANGUAGE 'plpgsql' STABLE +AS +$$ +BEGIN + RETURN array_agg(hot.id) + FROM hafd.operation_types hot + WHERE EXISTS ( + SELECT 1 FROM hive.account_operations_view aov + WHERE aov.account_id = _account_id AND aov.op_type_id = hot.id + ); + +END +$$; + +RESET ROLE; -- GitLab From 3919e08d7d22c50707f7fc7f009edff4dafc1bbf Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Mon, 24 Mar 2025 22:25:49 +0000 Subject: [PATCH 03/22] Adjust REST exceptions, exceptions can't return json due to composite types --- postgrest/hafah_rest_exceptions.sql | 54 ++++++----------------------- 1 file changed, 10 insertions(+), 44 deletions(-) diff --git a/postgrest/hafah_rest_exceptions.sql b/postgrest/hafah_rest_exceptions.sql index 4bfbdf887..4e607bcc6 100644 --- a/postgrest/hafah_rest_exceptions.sql +++ b/postgrest/hafah_rest_exceptions.sql @@ -1,50 +1,34 @@ SET ROLE hafah_owner; -CREATE FUNCTION hafah_backend.rest_raise_exception(_code INT, _message TEXT) -RETURNS JSON -LANGUAGE 'plpgsql' -AS -$$ -BEGIN - RETURN - REPLACE(error_json::TEXT, ' :', ':') - FROM json_build_object( - 'code', _code, - 'message', _message - ) error_json; -END -$$ -; - -CREATE FUNCTION hafah_backend.rest_wrap_sql_exception(_exception_message TEXT) -RETURNS JSON +CREATE FUNCTION hafah_backend.rest_raise_missing_account(_account_name TEXT) +RETURNS TEXT LANGUAGE 'plpgsql' AS $$ BEGIN - RETURN hafah_backend.rest_raise_exception(-32003, _exception_message); + RAISE EXCEPTION 'Assert Exception:Account ''%s'' does not exist', _account_name; END $$ ; -CREATE FUNCTION hafah_backend.rest_raise_missing_arg(_arg_name TEXT) +CREATE FUNCTION hafah_backend.rest_raise_missing_arg(_account_name TEXT) RETURNS TEXT LANGUAGE 'plpgsql' AS $$ BEGIN - RETURN hafah_backend.rest_raise_exception(-32602, 'Invalid parameters', format('missing a required argument: ''%s''', _arg_name)); + RAISE EXCEPTION 'Assert Exception:Missing a required argument: ''%s''', _arg_name; END $$ ; CREATE FUNCTION hafah_backend.raise_uint_exception() -RETURNS JSON +RETURNS TEXT LANGUAGE 'plpgsql' AS $$ BEGIN - RETURN hafah_backend.rest_raise_exception(-32000, 'Parse Error:Couldn''t parse uint64_t'); + RAISE EXCEPTION 'Assert Exception:Couldn''t parse uint64_t'; END $$ ; @@ -55,25 +39,7 @@ LANGUAGE 'plpgsql' AS $$ BEGIN - RETURN hafah_backend.rest_raise_exception( - -32003, - format( - 'Assert Exception:in_len <= sizeof(data): Input too large: `%s` (%s) for fixed size string: (16)', - _account_name, - LENGTH(_account_name) - ) - ); -END -$$ -; - -CREATE FUNCTION hafah_backend.rest_raise_below_zero_acc_hist() -RETURNS JSON -LANGUAGE 'plpgsql' -AS -$$ -BEGIN - RETURN hafah_backend.rest_wrap_sql_exception('Assert Exception:args.limit <= 1000: limit of 4294967295 is greater than maxmimum allowed'); + RAISE EXCEPTION 'Assert Exception:in_len <= sizeof(data): Input too large: `%s` (%s) for fixed size string: (16)', _account_name, LENGTH(_account_name); END $$ ; @@ -84,7 +50,7 @@ LANGUAGE 'plpgsql' AS $$ BEGIN - RETURN hafah_backend.rest_raise_exception(-32000, format('unspecified:Invalid hex character ''%s''', left(ltrim(_hex, '0123456789abcdefABCDEF'), 1))); + RAISE EXCEPTION 'Assert Exception:Invalid hex character ''%s''', left(ltrim(_hex, '0123456789abcdefABCDEF'), 1); END $$ ; @@ -95,7 +61,7 @@ LANGUAGE 'plpgsql' AS $$ BEGIN - RETURN hafah_backend.rest_raise_exception(-32003, format('Assert Exception:false: Transaction hash ''%s'' has invalid size. Transaction hash should have size of 160 bits', _hex)); + RAISE EXCEPTION 'Assert Exception:false: Transaction hash ''%s'' has invalid size. Transaction hash should have size of 160 bits', _hex; END $$ ; -- GitLab From 9213df82eae784fc99dde1f5230209774a573fd3 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Mon, 24 Mar 2025 23:33:39 +0000 Subject: [PATCH 04/22] Use composite type in block_header API --- .../hafah_REST/blocks/get_block_header.sql | 14 ++-- postgrest/hafah_REST/types/block.sql | 82 ++++++++++++++----- postgrest/hafah_rest_exceptions.sql | 30 +++++-- queries/hafah_rest_backend/block_header.sql | 30 ++++--- 4 files changed, 106 insertions(+), 50 deletions(-) diff --git a/postgrest/hafah_REST/blocks/get_block_header.sql b/postgrest/hafah_REST/blocks/get_block_header.sql index ab1c266c9..5c7bf60f9 100644 --- a/postgrest/hafah_REST/blocks/get_block_header.sql +++ b/postgrest/hafah_REST/blocks/get_block_header.sql @@ -36,12 +36,11 @@ SET ROLE hafah_owner; '200': description: | - * Returns `JSONB` + * Returns `hafah_backend.block_header` content: application/json: schema: - type: string - x-sql-datatype: JSONB + $ref: '#/components/schemas/hafah_backend.block_header' example: { "witness": "ihashfury", "previous": "004c4b3fc6a8735b4ab5433d59f4526e4a042644", @@ -55,7 +54,7 @@ DROP FUNCTION IF EXISTS hafah_endpoints.get_block_header; CREATE OR REPLACE FUNCTION hafah_endpoints.get_block_header( "block-num" TEXT ) -RETURNS JSONB +RETURNS hafah_backend.block_header -- openapi-generated-code-end LANGUAGE 'plpgsql' AS @@ -67,7 +66,7 @@ DECLARE BEGIN -- Required argument: block-num IF __block IS NULL THEN - RETURN hafah_backend.rest_raise_missing_arg('block-num'); + RETURN hafah_backend.rest_raise_missing_arg('block-num'); ELSE __block_num = __block::BIGINT; IF __block_num < 0 THEN @@ -82,14 +81,11 @@ BEGIN END IF; BEGIN - RETURN hafah_python.get_block_header_json(__block_num::INT); + RETURN hafah_backend.get_block_header(__block_num::INT); EXCEPTION WHEN invalid_text_representation THEN RETURN hafah_backend.rest_raise_uint_exception(); - WHEN raise_exception THEN - GET STACKED DIAGNOSTICS __exception_message = message_text; - RETURN hafah_backend.rest_wrap_sql_exception(__exception_message); END; END $$ diff --git a/postgrest/hafah_REST/types/block.sql b/postgrest/hafah_REST/types/block.sql index 77f919b39..f1814efb4 100644 --- a/postgrest/hafah_REST/types/block.sql +++ b/postgrest/hafah_REST/types/block.sql @@ -1,5 +1,17 @@ SET ROLE hafah_owner; +/** openapi:components:schemas +hafah_backend.extensions: + type: array + items: + type: object + properties: + type: + type: string + value: + type: string +*/ + /** openapi:components:schemas hafah_backend.block: type: object @@ -23,7 +35,7 @@ hafah_backend.block: description: >- single hash representing the combined hashes of all transactions in a block extensions: - type: string + $ref: '#/components/schemas/hafah_backend.extensions' x-sql-datatype: JSONB description: >- various additional data/parameters related to the subject at hand. @@ -43,32 +55,26 @@ hafah_backend.block: the interest rate on HBD in savings, expressed in basis points (previously for each HBD), is one of the values determined by the witnesses total_vesting_fund_hive: - type: number - x-sql-datatype: numeric + type: string description: >- the balance of the "counterweight" for these VESTS (total_vesting_shares) in the form of HIVE (the price of VESTS is derived from these two values). A portion of the inflation is added to the balance, ensuring that each block corresponds to more HIVE for the VESTS total_vesting_shares: - type: number - x-sql-datatype: numeric + type: string description: the total amount of VEST present in the system total_reward_fund_hive: - type: number - x-sql-datatype: numeric + type: string description: deprecated after HF17 virtual_supply: - type: number - x-sql-datatype: numeric + type: string description: >- the total amount of HIVE, including the HIVE that would be generated from converting HBD to HIVE at the current price current_supply: - type: number - x-sql-datatype: numeric + type: string description: the total amount of HIVE present in the system current_hbd_supply: - type: number - x-sql-datatype: numeric + type: string description: >- the total amount of HBD present in the system, including what is in the treasury dhf_interval_ledger: @@ -97,15 +103,53 @@ CREATE TYPE hafah_backend.block AS ( "witness_signature" TEXT, "signing_key" TEXT, "hbd_interest_rate" numeric, - "total_vesting_fund_hive" numeric, - "total_vesting_shares" numeric, - "total_reward_fund_hive" numeric, - "virtual_supply" numeric, - "current_supply" numeric, - "current_hbd_supply" numeric, + "total_vesting_fund_hive" TEXT, + "total_vesting_shares" TEXT, + "total_reward_fund_hive" TEXT, + "virtual_supply" TEXT, + "current_supply" TEXT, + "current_hbd_supply" TEXT, "dhf_interval_ledger" numeric, "created_at" TIMESTAMP ); -- openapi-generated-code-end +/** openapi:components:schemas +hafah_backend.block_header: + type: object + properties: + previous: + type: string + description: hash of a previous block + timestamp: + type: string + format: date-time + description: the timestamp when the block was created + witness: + type: string + description: account name of block''s producer + transaction_merkle_root: + type: string + description: >- + single hash representing the combined hashes of all transactions in a block + extensions: + $ref: '#/components/schemas/hafah_backend.extensions' + x-sql-datatype: JSONB + description: >- + various additional data/parameters related to the subject at hand. + Most often, there''s nothing specific, but it''s a mechanism for extending various functionalities + where something might appear in the future. + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.block_header CASCADE; +CREATE TYPE hafah_backend.block_header AS ( + "previous" TEXT, + "timestamp" TIMESTAMP, + "witness" TEXT, + "transaction_merkle_root" TEXT, + "extensions" JSONB +); +-- openapi-generated-code-end + + RESET ROLE; diff --git a/postgrest/hafah_rest_exceptions.sql b/postgrest/hafah_rest_exceptions.sql index 4e607bcc6..1b1b3bdc8 100644 --- a/postgrest/hafah_rest_exceptions.sql +++ b/postgrest/hafah_rest_exceptions.sql @@ -1,8 +1,9 @@ SET ROLE hafah_owner; CREATE FUNCTION hafah_backend.rest_raise_missing_account(_account_name TEXT) -RETURNS TEXT +RETURNS VOID LANGUAGE 'plpgsql' +IMMUTABLE AS $$ BEGIN @@ -11,9 +12,22 @@ END $$ ; +CREATE FUNCTION hafah_backend.rest_raise_missing_block(_block_num INT) +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + RAISE EXCEPTION 'Assert Exception:block_num ''%s'' does not exist', _block_num; +END +$$ +; + CREATE FUNCTION hafah_backend.rest_raise_missing_arg(_account_name TEXT) -RETURNS TEXT +RETURNS VOID LANGUAGE 'plpgsql' +IMMUTABLE AS $$ BEGIN @@ -23,8 +37,9 @@ $$ ; CREATE FUNCTION hafah_backend.raise_uint_exception() -RETURNS TEXT +RETURNS VOID LANGUAGE 'plpgsql' +IMMUTABLE AS $$ BEGIN @@ -34,8 +49,9 @@ $$ ; CREATE FUNCTION hafah_backend.rest_raise_account_name_too_long(_account_name TEXT) -RETURNS TEXT +RETURNS VOID LANGUAGE 'plpgsql' +IMMUTABLE AS $$ BEGIN @@ -45,8 +61,9 @@ $$ ; CREATE FUNCTION hafah_backend.rest_raise_invalid_char_in_hex(_hex TEXT) -RETURNS TEXT +RETURNS VOID LANGUAGE 'plpgsql' +IMMUTABLE AS $$ BEGIN @@ -56,8 +73,9 @@ $$ ; CREATE FUNCTION hafah_backend.rest_raise_transaction_hash_invalid_length(_hex TEXT) -RETURNS TEXT +RETURNS VOID LANGUAGE 'plpgsql' +IMMUTABLE AS $$ BEGIN diff --git a/queries/hafah_rest_backend/block_header.sql b/queries/hafah_rest_backend/block_header.sql index 91914003c..35793cb54 100644 --- a/queries/hafah_rest_backend/block_header.sql +++ b/queries/hafah_rest_backend/block_header.sql @@ -1,30 +1,28 @@ SET ROLE hafah_owner; -CREATE OR REPLACE FUNCTION hafah_python.get_block_header_json( _block_num INT ) - RETURNS JSONB +CREATE OR REPLACE FUNCTION hafah_backend.get_block_header( _block_num INT ) + RETURNS hafah_backend.block_header LANGUAGE plpgsql - VOLATILE + STABLE AS $BODY$ DECLARE __block hive.block_header_type; - __result JSON; BEGIN + SELECT * FROM hive.get_block_header( _block_num ) INTO __block; - SELECT * FROM hive.get_block_header( _block_num ) INTO __block; + IF __block.timestamp IS NULL THEN + RETURN hafah_backend.rest_raise_missing_block(_block_num); + END IF; - IF __block.timestamp IS NULL THEN - RETURN jsonb_build_object(); - END IF; + RETURN ( + encode( __block.previous, 'hex') :: TEXT, + TRIM(both '"' from to_json(__block.timestamp)::text), + __block.witness, + encode( __block.transaction_merkle_root, 'hex'), + COALESCE(__block.extensions, jsonb_build_array()) + )::hafah_backend.block_header; - SELECT jsonb_build_object( - 'previous', encode( __block.previous, 'hex') :: TEXT, - 'timestamp', TRIM(both '"' from to_json(__block.timestamp)::text), - 'witness', __block.witness, - 'transaction_merkle_root', encode( __block.transaction_merkle_root, 'hex'), - 'extensions', COALESCE(__block.extensions, jsonb_build_array()) - ) INTO __result; - RETURN __result; END; $BODY$ ; -- GitLab From ec812a63d5581d611e10b3b3604294b4a0d890c3 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 11:21:24 +0000 Subject: [PATCH 05/22] Add types for transactions and operations objects in openapi, add composite type for get_block_range API --- .../hafah_REST/blocks/get_block_range.sql | 27 +++--- postgrest/hafah_REST/types/block.sql | 82 +++++++++++++++++++ postgrest/hafah_REST/types/operation.sql | 20 ++++- queries/hafah_rest_backend/block_range.sql | 59 +++++++------ 4 files changed, 145 insertions(+), 43 deletions(-) diff --git a/postgrest/hafah_REST/blocks/get_block_range.sql b/postgrest/hafah_REST/blocks/get_block_range.sql index d0b875c5c..e456de1d9 100644 --- a/postgrest/hafah_REST/blocks/get_block_range.sql +++ b/postgrest/hafah_REST/blocks/get_block_range.sql @@ -1,5 +1,12 @@ SET ROLE hafah_owner; +/** openapi:components:schemas +hafah_backend.array_of_block_range: + type: array + items: + $ref: '#/components/schemas/hafah_backend.block_range' +*/ + /** openapi:paths /blocks: get: @@ -55,12 +62,11 @@ SET ROLE hafah_owner; '200': description: | - * Returns `JSONB` + * Returns array of `hafah_backend.block_range` content: application/json: schema: - type: string - x-sql-datatype: JSONB + $ref: '#/components/schemas/hafah_backend.array_of_block_range' example: [ { "witness": "smooth.witness", @@ -281,7 +287,7 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_block_range( "from-block" TEXT = NULL, "to-block" TEXT = NULL ) -RETURNS JSONB +RETURNS SETOF hafah_backend.block_range -- openapi-generated-code-end LANGUAGE 'plpgsql' AS @@ -294,7 +300,7 @@ DECLARE BEGIN -- Required argument: block-num IF _block_range.first_block IS NULL THEN - RETURN hafah_backend.rest_raise_missing_arg('from-block'); + PERFORM hafah_backend.rest_raise_missing_arg('from-block'); ELSE __block_num = _block_range.first_block::BIGINT; IF __block_num < 0 THEN @@ -303,7 +309,7 @@ BEGIN END IF; IF _block_range.last_block IS NULL THEN - RETURN hafah_backend.rest_raise_missing_arg('to-block'); + PERFORM hafah_backend.rest_raise_missing_arg('to-block'); ELSE __end_block_num = _block_range.last_block::BIGINT; IF __end_block_num < 0 THEN @@ -321,14 +327,13 @@ BEGIN END IF; BEGIN - RETURN hafah_python.get_block_range_json(__block_num::INT, __end_block_num::INT); + RETURN QUERY ( + SELECT * FROM hafah_backend.get_block_range(__block_num::INT, __end_block_num::INT) + ); EXCEPTION WHEN invalid_text_representation THEN - RETURN hafah_backend.rest_raise_uint_exception(); - WHEN raise_exception THEN - GET STACKED DIAGNOSTICS __exception_message = message_text; - RETURN hafah_backend.rest_wrap_sql_exception(__exception_message); + PERFORM hafah_backend.rest_raise_uint_exception(); END; END $$ diff --git a/postgrest/hafah_REST/types/block.sql b/postgrest/hafah_REST/types/block.sql index f1814efb4..77fd22c61 100644 --- a/postgrest/hafah_REST/types/block.sql +++ b/postgrest/hafah_REST/types/block.sql @@ -151,5 +151,87 @@ CREATE TYPE hafah_backend.block_header AS ( ); -- openapi-generated-code-end +/** openapi:components:schemas +hafah_backend.transactions: + type: object + x-sql-datatype: JSON + properties: + ref_block_num: + type: integer + ref_block_prefix: + type: integer + expiration: + type: string + operations: + $ref: '#/components/schemas/hafah_backend.array_of_operations' + extensions: + $ref: '#/components/schemas/hafah_backend.extensions' + signatures: + type: array + items: + type: string +*/ + +/** openapi:components:schemas +hafah_backend.block_range: + type: object + properties: + previous: + type: string + description: hash of a previous block + timestamp: + type: string + format: date-time + description: the timestamp when the block was created + witness: + type: string + description: account name of block''s producer + transaction_merkle_root: + type: string + description: >- + single hash representing the combined hashes of all transactions in a block + extensions: + $ref: '#/components/schemas/hafah_backend.extensions' + x-sql-datatype: JSONB + description: >- + various additional data/parameters related to the subject at hand. + Most often, there''s nothing specific, but it''s a mechanism for extending various functionalities + where something might appear in the future. + witness_signature: + type: string + description: witness signature + transactions: + $ref: '#/components/schemas/hafah_backend.transactions' + x-sql-datatype: JSONB + description: transactions in the block + block_id: + type: string + description: >- + block hash in a blockchain is a unique, fixed-length string generated + by applying a cryptographic hash function to a block''s contents + signing_key: + type: string + description: >- + it refers to the public key of the witness used for signing blocks and other witness operations + transaction_ids: + type: array + items: + type: string + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.block_range CASCADE; +CREATE TYPE hafah_backend.block_range AS ( + "previous" TEXT, + "timestamp" TIMESTAMP, + "witness" TEXT, + "transaction_merkle_root" TEXT, + "extensions" JSONB, + "witness_signature" TEXT, + "transactions" JSONB, + "block_id" TEXT, + "signing_key" TEXT, + "transaction_ids" TEXT[] +); +-- openapi-generated-code-end RESET ROLE; diff --git a/postgrest/hafah_REST/types/operation.sql b/postgrest/hafah_REST/types/operation.sql index 79cb9e18b..5a501195e 100644 --- a/postgrest/hafah_REST/types/operation.sql +++ b/postgrest/hafah_REST/types/operation.sql @@ -1,11 +1,29 @@ SET ROLE hafah_owner; +/** openapi:components:schemas +hafah_backend.operation_body: + type: object + x-sql-datatype: JSON + properties: + type: + type: string + value: + type: object +*/ + +/** openapi:components:schemas +hafah_backend.array_of_operations: + type: array + items: + $ref: '#/components/schemas/hafah_backend.operation_body' +*/ + /** openapi:components:schemas hafah_backend.operation: type: object properties: op: - type: string + $ref: '#/components/schemas/hafah_backend.operation_body' x-sql-datatype: JSONB description: operation body block: diff --git a/queries/hafah_rest_backend/block_range.sql b/queries/hafah_rest_backend/block_range.sql index 250ba0638..63acfcc23 100644 --- a/queries/hafah_rest_backend/block_range.sql +++ b/queries/hafah_rest_backend/block_range.sql @@ -1,39 +1,9 @@ SET ROLE hafah_owner; -CREATE OR REPLACE FUNCTION hafah_python.get_block_range_json(_block_num INT, _end_block_num INT) - RETURNS JSONB - LANGUAGE plpgsql - VOLATILE -AS -$BODY$ -DECLARE - __result JSONB; -BEGIN - SELECT jsonb_agg( - hive.build_block_json( - gbr.previous, - gbr.timestamp, - gbr.witness, - gbr.transaction_merkle_root, - gbr.extensions, - gbr.witness_signature, - gbr.transactions, - gbr.block_id, - gbr.signing_key, - gbr.transaction_ids - ) - ) INTO __result - FROM hafah_python.get_block_range(_block_num, _end_block_num) gbr - WHERE gbr.timestamp IS NOT NULL; - RETURN __result; -END; -$BODY$ -; - CREATE OR REPLACE FUNCTION hafah_python.get_block_range( _block_num INT, _end_block_num INT) RETURNS SETOF hive.block_type LANGUAGE plpgsql - VOLATILE + STABLE AS $BODY$ BEGIN @@ -54,4 +24,31 @@ END; $BODY$ ; + +CREATE OR REPLACE FUNCTION hafah_backend.get_block_range(_block_num INT, _end_block_num INT) + RETURNS SETOF hafah_backend.block_range + LANGUAGE plpgsql + STABLE +AS +$BODY$ +BEGIN + RETURN QUERY ( + SELECT + encode( gbr.previous, 'hex')::TEXT, + TRIM(both '"' from to_json(gbr.timestamp)::text)::timestamp, + gbr.witness::TEXT, + encode( gbr.transaction_merkle_root, 'hex')::TEXT, + COALESCE(gbr.extensions, jsonb_build_array()), + encode( gbr.witness_signature, 'hex')::TEXT, + COALESCE(hive.transactions_to_json(gbr.transactions), jsonb_build_array()), + encode( gbr.block_id, 'hex')::TEXT, + gbr.signing_key::TEXT, + (SELECT ARRAY( SELECT encode(unnest(gbr.transaction_ids), 'hex')))::TEXT[] + FROM hafah_python.get_block_range(_block_num, _end_block_num) gbr + WHERE gbr.timestamp IS NOT NULL + ); +END; +$BODY$ +; + RESET ROLE; -- GitLab From d3cf9122a68fec898c3ab78574aee15b7c4ed823 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 11:35:11 +0000 Subject: [PATCH 06/22] Adjust exception messages --- postgrest/hafah_rest_exceptions.sql | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/postgrest/hafah_rest_exceptions.sql b/postgrest/hafah_rest_exceptions.sql index 1b1b3bdc8..501b6e302 100644 --- a/postgrest/hafah_rest_exceptions.sql +++ b/postgrest/hafah_rest_exceptions.sql @@ -1,85 +1,85 @@ SET ROLE hafah_owner; -CREATE FUNCTION hafah_backend.rest_raise_missing_account(_account_name TEXT) +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_missing_account(_account_name TEXT) RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - RAISE EXCEPTION 'Assert Exception:Account ''%s'' does not exist', _account_name; + RAISE EXCEPTION 'Account ''%'' does not exist', _account_name; END $$ ; -CREATE FUNCTION hafah_backend.rest_raise_missing_block(_block_num INT) +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_missing_block(_block_num INT) RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - RAISE EXCEPTION 'Assert Exception:block_num ''%s'' does not exist', _block_num; + RAISE EXCEPTION 'Block_num ''%'' does not exist', _block_num; END $$ ; -CREATE FUNCTION hafah_backend.rest_raise_missing_arg(_account_name TEXT) +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_missing_arg(_account_name TEXT) RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - RAISE EXCEPTION 'Assert Exception:Missing a required argument: ''%s''', _arg_name; + RAISE EXCEPTION 'Missing a required argument: ''%''', _arg_name; END $$ ; -CREATE FUNCTION hafah_backend.raise_uint_exception() +CREATE OR REPLACE FUNCTION hafah_backend.raise_uint_exception() RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - RAISE EXCEPTION 'Assert Exception:Couldn''t parse uint64_t'; + RAISE EXCEPTION 'Couldn''t parse uint64_t'; END $$ ; -CREATE FUNCTION hafah_backend.rest_raise_account_name_too_long(_account_name TEXT) +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_account_name_too_long(_account_name TEXT) RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - RAISE EXCEPTION 'Assert Exception:in_len <= sizeof(data): Input too large: `%s` (%s) for fixed size string: (16)', _account_name, LENGTH(_account_name); + RAISE EXCEPTION 'in_len <= sizeof(data): Input too large: `%` (%) for fixed size string: (16)', _account_name, LENGTH(_account_name); END $$ ; -CREATE FUNCTION hafah_backend.rest_raise_invalid_char_in_hex(_hex TEXT) +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_invalid_char_in_hex(_hex TEXT) RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - RAISE EXCEPTION 'Assert Exception:Invalid hex character ''%s''', left(ltrim(_hex, '0123456789abcdefABCDEF'), 1); + RAISE EXCEPTION 'Invalid hex character ''%''', left(ltrim(_hex, '0123456789abcdefABCDEF'), 1); END $$ ; -CREATE FUNCTION hafah_backend.rest_raise_transaction_hash_invalid_length(_hex TEXT) +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_transaction_hash_invalid_length(_hex TEXT) RETURNS VOID LANGUAGE 'plpgsql' IMMUTABLE AS $$ BEGIN - RAISE EXCEPTION 'Assert Exception:false: Transaction hash ''%s'' has invalid size. Transaction hash should have size of 160 bits', _hex; + RAISE EXCEPTION 'false: Transaction hash ''%'' has invalid size. Transaction hash should have size of 160 bits', _hex; END $$ ; -- GitLab From 0a52db4930dd0ccf375c02d4790e93cb2b0dbb1d Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 11:35:40 +0000 Subject: [PATCH 07/22] Use perform instead of return in exception handling --- postgrest/hafah_REST/accounts/get_acc_op_types.sql | 2 +- postgrest/hafah_REST/accounts/get_ops_by_account.sql | 2 +- postgrest/hafah_REST/blocks/get_block_header.sql | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_acc_op_types.sql b/postgrest/hafah_REST/accounts/get_acc_op_types.sql index 4c612fa2d..60829ffc1 100644 --- a/postgrest/hafah_REST/accounts/get_acc_op_types.sql +++ b/postgrest/hafah_REST/accounts/get_acc_op_types.sql @@ -85,7 +85,7 @@ DECLARE __account_id INT = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); BEGIN IF _account_id IS NULL THEN - RETURN hafah_backend.rest_raise_missing_account("account-name"); + PERFORM hafah_backend.rest_raise_missing_account("account-name"); END IF; PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index 5de135f1a..fd7bf3b87 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -236,7 +236,7 @@ DECLARE __limit INT; BEGIN IF _account_id IS NULL THEN - RETURN hafah_backend.rest_raise_missing_account("account-name"); + PERFORM hafah_backend.rest_raise_missing_account("account-name"); END IF; PERFORM hafah_python.validate_limit("page-size", 1000, 'page-size'); diff --git a/postgrest/hafah_REST/blocks/get_block_header.sql b/postgrest/hafah_REST/blocks/get_block_header.sql index 5c7bf60f9..0b1c35596 100644 --- a/postgrest/hafah_REST/blocks/get_block_header.sql +++ b/postgrest/hafah_REST/blocks/get_block_header.sql @@ -66,7 +66,7 @@ DECLARE BEGIN -- Required argument: block-num IF __block IS NULL THEN - RETURN hafah_backend.rest_raise_missing_arg('block-num'); + PERFORM hafah_backend.rest_raise_missing_arg('block-num'); ELSE __block_num = __block::BIGINT; IF __block_num < 0 THEN @@ -85,7 +85,7 @@ BEGIN EXCEPTION WHEN invalid_text_representation THEN - RETURN hafah_backend.rest_raise_uint_exception(); + PERFORM hafah_backend.rest_raise_uint_exception(); END; END $$ -- GitLab From acd1171fa8bfdde74a50fd620091ca2edc17ce8a Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 11:36:11 +0000 Subject: [PATCH 08/22] Use composity type in get_block API --- postgrest/hafah_REST/blocks/get_block.sql | 24 ++++++------- queries/hafah_rest_backend/block.sql | 43 +++++++++++------------ 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/postgrest/hafah_REST/blocks/get_block.sql b/postgrest/hafah_REST/blocks/get_block.sql index 6b6644310..2e4bc0f53 100644 --- a/postgrest/hafah_REST/blocks/get_block.sql +++ b/postgrest/hafah_REST/blocks/get_block.sql @@ -44,12 +44,11 @@ SET ROLE hafah_owner; '200': description: | - * Returns `JSONB` + * Returns `hafah_backend.block_range` content: application/json: schema: - type: string - x-sql-datatype: JSONB + $ref: '#/components/schemas/hafah_backend.block_range' example: { "witness": "ihashfury", "block_id": "004c4b40245ffb07380a393fb2b3d841b76cdaec", @@ -158,7 +157,7 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_block( "block-num" TEXT, "include-virtual" BOOLEAN = False ) -RETURNS JSONB +RETURNS hafah_backend.block_range -- openapi-generated-code-end LANGUAGE 'plpgsql' AS @@ -170,12 +169,12 @@ DECLARE BEGIN -- Required argument: block-num IF __block IS NULL THEN - RETURN hafah_backend.rest_raise_missing_arg('block-num'); + 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; + __block_num = __block::BIGINT; + IF __block_num < 0 THEN + __block_num := __block_num + ((POW(2, 31) - 1) :: BIGINT); + END IF; END IF; IF __block <= hive.app_get_irreversible_block() AND __block IS NOT NULL THEN @@ -185,14 +184,11 @@ BEGIN END IF; BEGIN - RETURN hafah_python.get_block_json(__block_num::INT, "include-virtual"); + RETURN hafah_backend.get_block(__block_num::INT, "include-virtual")::JSON; EXCEPTION WHEN invalid_text_representation THEN - RETURN hafah_backend.rest_raise_uint_exception(); - WHEN raise_exception THEN - GET STACKED DIAGNOSTICS __exception_message = message_text; - RETURN hafah_backend.rest_wrap_sql_exception(__exception_message); + PERFORM hafah_backend.rest_raise_uint_exception(); END; END $$ diff --git a/queries/hafah_rest_backend/block.sql b/queries/hafah_rest_backend/block.sql index ed9af5246..4ba242dd3 100644 --- a/queries/hafah_rest_backend/block.sql +++ b/queries/hafah_rest_backend/block.sql @@ -1,36 +1,33 @@ SET ROLE hafah_owner; -CREATE OR REPLACE FUNCTION hafah_python.get_block_json( _block_num INT, _include_virtual BOOLEAN = FALSE) - RETURNS JSONB +CREATE OR REPLACE FUNCTION hafah_backend.get_block(_block_num INT, _include_virtual BOOLEAN = FALSE) + RETURNS hafah_backend.block_range LANGUAGE plpgsql - VOLATILE + STABLE AS $BODY$ DECLARE __block hive.block_type; - __result JSON; BEGIN - SELECT * FROM hive.get_block( _block_num, _include_virtual) INTO __block; + SELECT * FROM hive.get_block( _block_num, _include_virtual) INTO __block; - IF __block.timestamp IS NULL THEN - RETURN jsonb_build_object(); - END IF; + IF __block.timestamp IS NULL THEN + PERFORM hafah_backend.rest_raise_missing_block(_block_num); + END IF; + + RETURN ( + encode( __block.previous, 'hex')::TEXT, + TRIM(both '"' from to_json(__block.timestamp)::text)::timestamp, + __block.witness::TEXT, + encode( __block.transaction_merkle_root, 'hex')::TEXT, + COALESCE(__block.extensions, jsonb_build_array()), + encode( __block.witness_signature, 'hex')::TEXT, + COALESCE(hive.transactions_to_json(__block.transactions), jsonb_build_array()), + encode( __block.block_id, 'hex')::TEXT, + __block.signing_key::TEXT, + (SELECT ARRAY( SELECT encode(unnest(__block.transaction_ids), 'hex')))::TEXT[] + )::hafah_backend.block_range; - SELECT to_jsonb( - hive.build_block_json( - __block.previous, - __block.timestamp, - __block.witness, - __block.transaction_merkle_root, - __block.extensions, - __block.witness_signature, - __block.transactions, - __block.block_id, - __block.signing_key, - __block.transaction_ids - ) - ) INTO __result; - RETURN __result; END; $BODY$ ; -- GitLab From 0a302cdb58ae4df7633691c8545b977647993bba Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 12:35:22 +0000 Subject: [PATCH 09/22] Use composite type in get_ops_in_block API --- .../accounts/get_ops_by_account.sql | 33 +--- postgrest/hafah_REST/blocks/get_block.sql | 2 +- .../blocks/get_ops_by_block_paging.sql | 143 ++++++++++-------- queries/hafah_rest_backend/block_header.sql | 2 +- queries/hafah_rest_backend/ops_in_block.sql | 12 +- 5 files changed, 95 insertions(+), 97 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index fd7bf3b87..b93b63e13 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -1,30 +1,5 @@ SET ROLE hafah_owner; -/** openapi:components:schemas -hafah_backend.account_history: - type: object - properties: - total_operations: - type: integer - description: Total number of operations - total_pages: - type: integer - description: Total number of 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_history CASCADE; -CREATE TYPE hafah_backend.account_history AS ( - "total_operations" INT, - "total_pages" INT, - "operations_result" hafah_backend.operation[] -); --- openapi-generated-code-end - /** openapi:paths /accounts/{account-name}/operations: get: @@ -123,11 +98,11 @@ CREATE TYPE hafah_backend.account_history AS ( Result contains total number of operations, total pages, and the list of operations. - * Returns `hafah_backend.account_history` + * Returns `hafah_backend.operation_history` content: application/json: schema: - $ref: '#/components/schemas/hafah_backend.account_history' + $ref: '#/components/schemas/hafah_backend.operation_history' example: { "total_operations": 219867, "total_pages": 73289, @@ -213,7 +188,7 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_ops_by_account( "from-block" TEXT = NULL, "to-block" TEXT = NULL ) -RETURNS hafah_backend.account_history +RETURNS hafah_backend.operation_history -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE SET join_collapse_limit = 16 @@ -284,7 +259,7 @@ BEGIN COALESCE(_ops_count,0), COALESCE(__total_pages,0), _result - )::hafah_backend.account_history; + )::hafah_backend.operation_history; -- 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/postgrest/hafah_REST/blocks/get_block.sql b/postgrest/hafah_REST/blocks/get_block.sql index 2e4bc0f53..69373c526 100644 --- a/postgrest/hafah_REST/blocks/get_block.sql +++ b/postgrest/hafah_REST/blocks/get_block.sql @@ -157,7 +157,7 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_block( "block-num" TEXT, "include-virtual" BOOLEAN = False ) -RETURNS hafah_backend.block_range +RETURNS hafah_backend.block_range -- openapi-generated-code-end LANGUAGE 'plpgsql' AS 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 84bf03bf7..78658fe2c 100644 --- a/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql +++ b/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql @@ -91,7 +91,6 @@ SET ROLE hafah_owner; type: array items: type: string - x-sql-datatype: TEXT[] default: NULL description: | A parameter specifying the expected value in operation body, @@ -102,12 +101,11 @@ SET ROLE hafah_owner; Result contains total operations number, total pages and the list of operations - * Returns `JSON` + * Returns `hafah_backend.operation_history` content: application/json: schema: - type: string - x-sql-datatype: JSON + $ref: '#/components/schemas/hafah_backend.operation_history' example: { "total_operations": 1, "total_pages": 1, @@ -156,7 +154,7 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_ops_by_block_paging( "data-size-limit" INT = 200000, "path-filter" TEXT[] = NULL ) -RETURNS JSON +RETURNS hafah_backend.operation_history -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE SET JIT = OFF @@ -166,72 +164,97 @@ AS $$ DECLARE __block INT := hive.convert_to_block_num("block-num"); - _operation_types INT[] := NULL; + _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; - _calculate_total_pages INT; - _ops_count BIGINT; + _result hafah_backend.operation[]; + _account_id INT := NULL; + + _ops_count INT; + __total_pages INT; 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"); - -IF "path-filter" IS NOT NULL AND "path-filter" != '{}' THEN - SELECT - pvpf.param_json::JSON, - pvpf.param_text::TEXT[] - INTO _set_of_keys, _key_content - FROM hafah_backend.parse_path_filters("path-filter") pvpf; -END IF; - -IF "operation-types" IS NOT NULL THEN - _operation_types := string_to_array("operation-types", ',')::INT[]; -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); -ELSE - PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); -END IF; - --- amount of operations -SELECT hafah_backend.get_ops_by_block_count( - __block, - _operation_types, - "account-name", - _key_content, - _set_of_keys -) INTO _ops_count; - ---amount of pages -SELECT ( - CASE WHEN (_ops_count % "page-size") = 0 THEN - _ops_count/"page-size" - ELSE ((_ops_count/"page-size") + 1) - END -)::INT INTO _calculate_total_pages; - -PERFORM hafah_python.validate_page("page", _calculate_total_pages); - -RETURN ( - SELECT json_build_object( - 'total_operations', _ops_count, - 'total_pages', _calculate_total_pages, - 'operations_result', - (SELECT to_json(array_agg(row)) FROM ( - SELECT * FROM hafah_backend.get_ops_by_block( + 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"); + + 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 + SELECT + pvpf.param_json::JSON, + pvpf.param_text::TEXT[] + INTO _set_of_keys, _key_content + FROM hafah_backend.parse_path_filters("path-filter") pvpf; + 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); + ELSE + 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 + ) + ); + + __total_pages := ( + CASE + WHEN (_ops_count % "page-size") = 0 THEN + _ops_count/"page-size" + ELSE + (_ops_count/"page-size") + 1 + END + ); + + _result := array_agg(row) 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_block( __block, "page", "page-size", _operation_types, "page-order", "data-size-limit", - "account-name", + _account_id, _key_content, _set_of_keys - ) - ) row) - )); + ) ba + ) row; + + RETURN ( + COALESCE(_ops_count,0), + COALESCE(__total_pages,0), + _result + )::hafah_backend.operation_history; END $$; diff --git a/queries/hafah_rest_backend/block_header.sql b/queries/hafah_rest_backend/block_header.sql index 35793cb54..9c7f89a93 100644 --- a/queries/hafah_rest_backend/block_header.sql +++ b/queries/hafah_rest_backend/block_header.sql @@ -12,7 +12,7 @@ BEGIN SELECT * FROM hive.get_block_header( _block_num ) INTO __block; IF __block.timestamp IS NULL THEN - RETURN hafah_backend.rest_raise_missing_block(_block_num); + PERFORM hafah_backend.rest_raise_missing_block(_block_num); END IF; RETURN ( diff --git a/queries/hafah_rest_backend/ops_in_block.sql b/queries/hafah_rest_backend/ops_in_block.sql index 7463f8ef5..0ebb3cf22 100644 --- a/queries/hafah_rest_backend/ops_in_block.sql +++ b/queries/hafah_rest_backend/ops_in_block.sql @@ -239,7 +239,7 @@ CREATE OR REPLACE FUNCTION hafah_backend.get_ops_by_block( _filter INT [], _order_is hafah_backend.sort_direction, -- noqa: LT01, CP05 _body_limit INT, - _account TEXT, + _account_id INT, _key_content TEXT [], _setof_keys JSON ) @@ -258,7 +258,7 @@ DECLARE _third_key BOOLEAN = (_key_content[3] IS NULL); BEGIN -IF _account IS NULL THEN +IF _account_id IS NULL THEN RETURN QUERY WITH operation_range AS MATERIALIZED ( SELECT @@ -338,7 +338,7 @@ ELSE SELECT aov.operation_id FROM hive.account_operations_view aov WHERE - aov.account_id = (SELECT av.id FROM hive.accounts_view av WHERE av.name = _account ) AND + aov.account_id = _account_id AND aov.block_num = _block_num ), operations_in_block AS @@ -397,7 +397,7 @@ $$; CREATE OR REPLACE FUNCTION hafah_backend.get_ops_by_block_count( _block_num INT, _filter INT [], - _account TEXT, + _account_id INT, _key_content TEXT [], _setof_keys JSON ) @@ -415,7 +415,7 @@ DECLARE _third_key BOOLEAN = (_key_content[3] IS NULL); BEGIN -IF _account IS NULL THEN +IF _account_id IS NULL THEN RETURN ( WITH operations_in_block AS ( @@ -442,7 +442,7 @@ ELSE SELECT aov.operation_id FROM hive.account_operations_view aov WHERE - aov.account_id = (SELECT av.id FROM hive.accounts_view av WHERE av.name = _account ) AND + aov.account_id = _account_id AND aov.block_num = _block_num ), operations_in_block AS -- GitLab From f4aeb7b60c388a4197be26b7f3f0b61e4e461118 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 12:49:52 +0000 Subject: [PATCH 10/22] Adjust get_op_types API --- .../operation_types/get_op_types.sql | 20 ++++++--------- postgrest/hafah_REST/types/operation.sql | 25 +++++++++++++++++++ queries/hafah_rest_backend/op_types.sql | 19 ++++++++++++++ 3 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 queries/hafah_rest_backend/op_types.sql diff --git a/postgrest/hafah_REST/operation_types/get_op_types.sql b/postgrest/hafah_REST/operation_types/get_op_types.sql index 745829bc7..d4e0317ab 100644 --- a/postgrest/hafah_REST/operation_types/get_op_types.sql +++ b/postgrest/hafah_REST/operation_types/get_op_types.sql @@ -60,21 +60,17 @@ LANGUAGE 'plpgsql' STABLE AS $$ DECLARE - __operation_name TEXT := NULL; + __operation_name TEXT := '%' || "partial-operation-name" || '%'; BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); - IF "partial-operation-name" IS NOT NULL THEN - __operation_name := '%' || "partial-operation-name" || '%'; - END IF; - - RETURN QUERY SELECT - id::INT, split_part(name, '::', 3), is_virtual - FROM hafd.operation_types - WHERE ((__operation_name IS NULL) OR (name LIKE __operation_name)) - ORDER BY id ASC - ; - + RETURN QUERY ( + SELECT + op_type_id, + operation_name, + is_virtual + FROM hafah_backend.get_op_types(__operation_name) + ); END $$; diff --git a/postgrest/hafah_REST/types/operation.sql b/postgrest/hafah_REST/types/operation.sql index 5a501195e..29caf9be4 100644 --- a/postgrest/hafah_REST/types/operation.sql +++ b/postgrest/hafah_REST/types/operation.sql @@ -72,4 +72,29 @@ CREATE TYPE hafah_backend.operation AS ( ); -- openapi-generated-code-end +/** openapi:components:schemas +hafah_backend.operation_history: + type: object + properties: + total_operations: + type: integer + description: Total number of operations + total_pages: + type: integer + description: Total number of 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.operation_history CASCADE; +CREATE TYPE hafah_backend.operation_history AS ( + "total_operations" INT, + "total_pages" INT, + "operations_result" hafah_backend.operation[] +); +-- openapi-generated-code-end + RESET ROLE; diff --git a/queries/hafah_rest_backend/op_types.sql b/queries/hafah_rest_backend/op_types.sql new file mode 100644 index 000000000..a47b823ef --- /dev/null +++ b/queries/hafah_rest_backend/op_types.sql @@ -0,0 +1,19 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.get_op_types( + _operation_name TEXT +) +RETURNS SETOF hafah_backend.op_types +LANGUAGE 'plpgsql' STABLE +AS +$$ +BEGIN + RETURN QUERY SELECT + id::INT, split_part(name, '::', 3), is_virtual + FROM hafd.operation_types + WHERE ((_operation_name IS NULL) OR (name LIKE _operation_name)) + ORDER BY id ASC; +END +$$; + +RESET ROLE; -- GitLab From ec4340230950ad14fb14c2c7e833408dcb8a061b Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 13:40:31 +0000 Subject: [PATCH 11/22] Adjust openapi type description, add error handling in get_operation_keys API --- .../operation_types/get_operation_keys.sql | 52 +++++++++++-------- postgrest/hafah_rest_exceptions.sql | 12 +++++ 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/postgrest/hafah_REST/operation_types/get_operation_keys.sql b/postgrest/hafah_REST/operation_types/get_operation_keys.sql index f8a3af7cd..572ba6fce 100644 --- a/postgrest/hafah_REST/operation_types/get_operation_keys.sql +++ b/postgrest/hafah_REST/operation_types/get_operation_keys.sql @@ -27,19 +27,23 @@ SET ROLE hafah_owner; description: | Operation json key paths - * Returns `JSONB` + * Returns `JSON` content: application/json: schema: - type: string - x-sql-datatype: JSONB + type: array + items: + type: array + items: + type: string + x-sql-datatype: JSON example: [ ["value","body"], ["value","title"], ["value","author"], ["value","permlink"], ["value","json_metadata"], - ["value","parent_author"] , + ["value","parent_author"], ["value","parent_permlink"] ] */ @@ -48,7 +52,7 @@ DROP FUNCTION IF EXISTS hafah_endpoints.get_operation_keys; CREATE OR REPLACE FUNCTION hafah_endpoints.get_operation_keys( "type-id" INT ) -RETURNS JSONB +RETURNS JSON -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE SET JIT = OFF @@ -64,26 +68,32 @@ DECLARE BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=31536000"}]', true); - RETURN ( - WITH RECURSIVE extract_keys AS ( - SELECT - ARRAY['value']::TEXT[] as key_path, - (json_each(_example_key -> 'value')).* - UNION ALL + 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; + + RETURN COALESCE( + ( + WITH RECURSIVE extract_keys AS ( + SELECT + ARRAY['value']::TEXT[] as key_path, + (json_each(_example_key -> 'value')).* + UNION ALL + SELECT + key_path || key, + (json_each(value)).* + FROM + extract_keys + WHERE + json_typeof(value) = 'object' + ) SELECT - key_path || key, - (json_each(value)).* + json_agg(to_json(key_path || key)) FROM extract_keys WHERE - json_typeof(value) = 'object' - ) - SELECT - jsonb_agg(to_jsonb(key_path || key)) - FROM - extract_keys - WHERE - json_typeof(value) != 'object' + json_typeof(value) != 'object' + ), '[]'::json ); END $$; diff --git a/postgrest/hafah_rest_exceptions.sql b/postgrest/hafah_rest_exceptions.sql index 501b6e302..26248e44b 100644 --- a/postgrest/hafah_rest_exceptions.sql +++ b/postgrest/hafah_rest_exceptions.sql @@ -24,6 +24,18 @@ END $$ ; +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_missing_op_type(id INT) +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + RAISE EXCEPTION 'op_type_id ''%'' does not exist', id; +END +$$ +; + CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_missing_arg(_account_name TEXT) RETURNS VOID LANGUAGE 'plpgsql' -- GitLab From bb8db6ba0e87e1df14819b8d395026bed769beb6 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 13:54:48 +0000 Subject: [PATCH 12/22] Add error handling in get_operation API --- .../hafah_REST/operations/get_operation.sql | 36 +++++++++---------- postgrest/hafah_rest_exceptions.sql | 12 +++++++ queries/hafah_rest_backend/operation.sql | 29 +++++++++++++++ 3 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 queries/hafah_rest_backend/operation.sql diff --git a/postgrest/hafah_REST/operations/get_operation.sql b/postgrest/hafah_REST/operations/get_operation.sql index 9834afca1..539b86b2d 100644 --- a/postgrest/hafah_REST/operations/get_operation.sql +++ b/postgrest/hafah_REST/operations/get_operation.sql @@ -81,32 +81,30 @@ LANGUAGE 'plpgsql' STABLE AS $$ DECLARE - _block_num INT := (SELECT ov.block_num FROM hive.operations_view ov WHERE ov.id = "operation-id"); + _block_num INT := (SELECT ov.block_num FROM hive.operations_view ov WHERE ov.id = "operation-id"); 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; + 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 ( - SELECT ROW ( - ov.body, - ov.block_num, - encode(htv.trx_hash, 'hex'), + RETURN ( + ov.op, + ov.block, + ov.trx_id, ov.op_pos, ov.op_type_id, ov.timestamp, - hot.is_virtual, - ov.id::TEXT, + ov.virtual_op, + ov.operation_id, ov.trx_in_block - ) - FROM hive.operations_view_extended ov - JOIN hafd.operation_types hot ON hot.id = ov.op_type_id - LEFT JOIN hive.transactions_view htv ON htv.block_num = ov.block_num AND htv.trx_in_block = ov.trx_in_block - WHERE ov.id = "operation-id" -); + )::hafah_backend.operation + FROM hafah_backend.get_operation("operation-id"); END $$; diff --git a/postgrest/hafah_rest_exceptions.sql b/postgrest/hafah_rest_exceptions.sql index 26248e44b..b058eb1c9 100644 --- a/postgrest/hafah_rest_exceptions.sql +++ b/postgrest/hafah_rest_exceptions.sql @@ -36,6 +36,18 @@ END $$ ; +CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_missing_operation_id(id BIGINT) +RETURNS VOID +LANGUAGE 'plpgsql' +IMMUTABLE +AS +$$ +BEGIN + RAISE EXCEPTION 'Operation_id ''%'' does not exist', id; +END +$$ +; + CREATE OR REPLACE FUNCTION hafah_backend.rest_raise_missing_arg(_account_name TEXT) RETURNS VOID LANGUAGE 'plpgsql' diff --git a/queries/hafah_rest_backend/operation.sql b/queries/hafah_rest_backend/operation.sql new file mode 100644 index 000000000..8d76b778e --- /dev/null +++ b/queries/hafah_rest_backend/operation.sql @@ -0,0 +1,29 @@ +SET ROLE hafah_owner; + +CREATE OR REPLACE FUNCTION hafah_backend.get_operation( + _operation_id INT +) +RETURNS hafah_backend.operation +LANGUAGE 'plpgsql' STABLE +AS +$$ +BEGIN + RETURN ( + ov.body, + ov.block_num, + encode(htv.trx_hash, 'hex'), + ov.op_pos, + ov.op_type_id, + ov.timestamp, + hot.is_virtual, + ov.id::TEXT, + ov.trx_in_block + )::hafah_backend.operation + FROM hive.operations_view_extended ov + JOIN hafd.operation_types hot ON hot.id = ov.op_type_id + LEFT JOIN hive.transactions_view htv ON htv.block_num = ov.block_num AND htv.trx_in_block = ov.trx_in_block + WHERE ov.id = _operation_id; +END +$$; + +RESET ROLE; -- GitLab From c28c22ae3f2efdb66b6035fd32e5befcd04db8e8 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 20:08:10 +0000 Subject: [PATCH 13/22] Add op_type_id param to get_operations response, use composite type --- .../hafah_REST/operations/get_operations.sql | 43 ++--- postgrest/hafah_REST/types/operation.sql | 25 +++ queries/hafah_rest_backend/ops_in_block.sql | 174 +++++++++--------- 3 files changed, 130 insertions(+), 112 deletions(-) diff --git a/postgrest/hafah_REST/operations/get_operations.sql b/postgrest/hafah_REST/operations/get_operations.sql index 3ff8e8b68..cbe1fc153 100644 --- a/postgrest/hafah_REST/operations/get_operations.sql +++ b/postgrest/hafah_REST/operations/get_operations.sql @@ -102,12 +102,11 @@ SET ROLE hafah_owner; '200': description: | - * Returns `JSON` + * Returns `hafah_backend.operations_in_block_range` content: application/json: schema: - type: string - x-sql-datatype: JSON + $ref: '#/components/schemas/hafah_backend.operations_in_block_range' example: { "ops": [ { @@ -279,19 +278,20 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_operations( "page-size" INT = 1000, "include-reversible" BOOLEAN = False ) -RETURNS JSON +RETURNS hafah_backend.operations_in_block_range -- openapi-generated-code-end LANGUAGE 'plpgsql' AS $$ DECLARE _block_range hive.blocks_range := hive.convert_to_blocks_range("from-block","to-block"); - _operation_types INT[] := NULL; + _operation_types INT[] := (CASE WHEN "operation-types" IS NOT NULL THEN string_to_array("operation-types", ',')::INT[] ELSE NULL END); __exception_message TEXT; _operation_group_types BOOLEAN := (CASE WHEN "operation-group-type" = 'real' THEN FALSE WHEN "operation-group-type" = 'virtual' THEN TRUE ELSE NULL END); 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); 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,33 +301,24 @@ BEGIN -- Required argument: to-block, from-block IF _block_range.first_block IS NULL THEN - RETURN hafah_backend.rest_raise_missing_arg('from-block'); + PERFORM hafah_backend.rest_raise_missing_arg('from-block'); END IF; IF _block_range.last_block IS NULL THEN - RETURN hafah_backend.rest_raise_missing_arg('to-block'); + PERFORM hafah_backend.rest_raise_missing_arg('to-block'); END IF; - IF "operation-types" IS NOT NULL THEN - _operation_types := string_to_array("operation-types", ',')::INT[]; - END IF; + RETURN hafah_backend.get_ops_in_blocks( + _block_range.first_block, + _block_range.last_block, + _operation_group_types, + _operation_types, + "operation-begin", + "page-size", + "include-reversible", + FALSE + ); - BEGIN - RETURN hafah_python.get_rest_ops_in_blocks_json( - _block_range.first_block, - _block_range.last_block, - _operation_group_types, - _operation_types, - "operation-begin", - "page-size", - "include-reversible", - FALSE - ); - EXCEPTION - WHEN raise_exception THEN - GET STACKED DIAGNOSTICS __exception_message = message_text; - RETURN hafah_backend.rest_wrap_sql_exception(__exception_message); - END; END $$ ; diff --git a/postgrest/hafah_REST/types/operation.sql b/postgrest/hafah_REST/types/operation.sql index 29caf9be4..26eb85309 100644 --- a/postgrest/hafah_REST/types/operation.sql +++ b/postgrest/hafah_REST/types/operation.sql @@ -97,4 +97,29 @@ CREATE TYPE hafah_backend.operation_history AS ( ); -- openapi-generated-code-end +/** openapi:components:schemas +hafah_backend.operations_in_block_range: + type: object + properties: + next_block_range_begin: + type: integer + description: Lower bound for the next block number + next_operation_begin: + type: string + description: Lower bound for the next operation id + ops: + type: array + items: + $ref: '#/components/schemas/hafah_backend.operation' + description: List of operation results + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.operations_in_block_range CASCADE; +CREATE TYPE hafah_backend.operations_in_block_range AS ( + "next_block_range_begin" INT, + "next_operation_begin" TEXT, + "ops" hafah_backend.operation[] +); +-- openapi-generated-code-end + RESET ROLE; diff --git a/queries/hafah_rest_backend/ops_in_block.sql b/queries/hafah_rest_backend/ops_in_block.sql index 0ebb3cf22..4d7bf1d0e 100644 --- a/queries/hafah_rest_backend/ops_in_block.sql +++ b/queries/hafah_rest_backend/ops_in_block.sql @@ -1,7 +1,7 @@ SET ROLE hafah_owner; --block range -CREATE OR REPLACE FUNCTION hafah_python.get_rest_ops_in_blocks_json( +CREATE OR REPLACE FUNCTION hafah_backend.get_ops_in_blocks( in _block_num INT, in _end_block_num INT, in _operation_group_types BOOLEAN, @@ -11,94 +11,92 @@ CREATE OR REPLACE FUNCTION hafah_python.get_rest_ops_in_blocks_json( in _include_reversible BOOLEAN, in _is_legacy_style BOOLEAN ) -RETURNS JSON +RETURNS hafah_backend.operations_in_block_range +LANGUAGE 'plpgsql' STABLE AS -$function$ -BEGIN - PERFORM hafah_python.validate_block_range( _block_num, _end_block_num + 1, 2001); +$$ +DECLARE + _operations hafah_backend.operation[]; + _operation_id TEXT; + _next_block_num INT; - RETURN ( - WITH pre_result AS ( - SELECT - hp.__block_num AS "block", - hp._value ::json AS "op", - hp._op_in_trx AS "op_in_trx", - hp._timestamp AS "timestamp", - hp._trx_id AS "trx_id", - hp._trx_in_block AS "trx_in_block", - hp._virtual_op AS "virtual_op", - hp._operation_id AS "operation_id" - FROM - hafah_python.get_rest_ops_in_block( - _block_num, - _end_block_num + 1, - _operation_group_types, - _operation_types, - _operation_begin, - _limit, - _include_reversible, - _is_legacy_style - ) AS hp - ), - pag AS ( - SELECT - ( - CASE - WHEN (SELECT COUNT(*) FROM pre_result) = _limit THEN - pre_result.block - ELSE - _end_block_num - END - ) AS block_num, - pre_result.operation_id AS id - FROM pre_result - WHERE pre_result.operation_id = (SELECT MAX(pre_result.operation_id) FROM pre_result) - LIMIT 1 + _latest_block_num INT := (SELECT num FROM hafd.blocks ORDER BY num DESC LIMIT 1); +BEGIN + WITH pre_result AS ( + SELECT + hp.__block_num AS "block", + hp._value::jsonb AS "op", + hp._op_in_trx AS "op_in_trx", + hp._op_type_id AS "op_type_id", + hp._timestamp AS "timestamp", + hp._trx_id AS "trx_id", + hp._trx_in_block AS "trx_in_block", + hp._virtual_op AS "virtual_op", + hp._operation_id AS "operation_id" + FROM hafah_backend.get_ops_in_blocks_helper( + _block_num, + (CASE WHEN _end_block_num > _latest_block_num THEN _latest_block_num + 1 ELSE _end_block_num + 1 END), + _operation_group_types, + _operation_types, + _operation_begin, + _limit, + _include_reversible, + _is_legacy_style + ) AS hp + ), + count_logic AS MATERIALIZED ( + SELECT COUNT(*) as count FROM pre_result + ), + paging_logic AS MATERIALIZED ( + SELECT ( + CASE + WHEN (SELECT count FROM count_logic) = _limit THEN + pre_result.block + ELSE + _end_block_num + END + ) AS block_num, + ( + CASE + WHEN (SELECT count FROM count_logic) = _limit THEN + pre_result.operation_id + ELSE + 0 + END + ) AS id + FROM pre_result + WHERE pre_result.operation_id = (SELECT MAX(pre_result.operation_id) FROM pre_result) + LIMIT 1 + ) + SELECT + COALESCE((SELECT block_num FROM paging_logic), 0)::INT, + COALESCE((SELECT id FROM paging_logic), 0)::TEXT, + ( + SELECT array_agg(rows) + FROM ( + SELECT + s.op, + s.block, + s.trx_id, + s.op_in_trx::INT, + s.op_type_id, + s.timestamp, + s.virtual_op, + hafah_python.json_stringify_bigint(s.operation_id), + s.trx_in_block::SMALLINT + FROM pre_result s + ) rows ) - SELECT to_jsonb(result) - FROM ( - SELECT - COALESCE((SELECT block_num FROM pag), ( - CASE - WHEN _end_block_num > (SELECT num FROM hafd.blocks ORDER BY num DESC LIMIT 1) THEN 0 - ELSE _end_block_num - END - )) AS next_block_range_begin, - hafah_python.json_stringify_bigint(COALESCE(( - CASE - WHEN (SELECT block_num FROM pag) >= _end_block_num THEN 0 - ELSE (SELECT id FROM pag) - END - ), 0)) AS next_operation_begin, - ( - SELECT ARRAY( - SELECT - CASE - WHEN _is_legacy_style THEN to_jsonb(res) - 'operation_id' - ELSE to_jsonb(res) - END - FROM ( - SELECT - s.block, - s.op, - s.op_in_trx, - hafah_python.json_stringify_bigint(s.operation_id) AS "operation_id", - s.timestamp, - s.trx_id, - s.trx_in_block, - s.virtual_op - FROM pre_result s - ) AS res - ) - ) AS ops - ) AS result - ); -END -$function$ -language plpgsql STABLE; + INTO _next_block_num, _operation_id, _operations; -CREATE OR REPLACE FUNCTION hafah_python.get_rest_ops_in_block( + RETURN (_next_block_num, _operation_id, COALESCE(_operations, '{}'::hafah_backend.operation[]))::hafah_backend.operations_in_block_range; + +END +$$; + +--get_ops_in_blocks json-rpc function reused in hafah REST +CREATE OR REPLACE FUNCTION hafah_backend.get_ops_in_blocks_helper( in _block_num INT, in _end_block_num INT, in _operation_group_types BOOLEAN, @@ -113,6 +111,7 @@ RETURNS TABLE( _trx_id TEXT, _trx_in_block BIGINT, _op_in_trx BIGINT, + _op_type_id INT, _virtual_op BOOLEAN, _timestamp TEXT, _value TEXT, @@ -130,6 +129,7 @@ BEGIN NULL::TEXT, -- _trx_id NULL::BIGINT, -- _trx_in_block NULL::BIGINT, -- _op_in_trx + NULL::INT, -- _op_type_id NULL::BOOLEAN, -- _virtual_op NULL::TEXT, -- _timestamp NULL::TEXT, -- _value @@ -154,11 +154,12 @@ BEGIN ) _trx_id, ( CASE - WHEN T2.trx_in_block IS NULL THEN 4294967295 + WHEN T2.trx_in_block IS NULL THEN -1 ELSE T2.trx_in_block END - ) _trx_in_block, + )::BIGINT _trx_in_block, T.op_pos _op_in_trx, + T.op_type_id _op_type_id, T.virtual_op _virtual_op, ( CASE @@ -219,6 +220,7 @@ BEGIN pre_result._trx_id, pre_result._trx_in_block, pre_result._op_in_trx, + pre_result._op_type_id::INT, pre_result._virtual_op, trim(both '"' from to_json(hb.created_at)::text) _timestamp, pre_result._value, -- GitLab From a61fa2a533f59996c0ae46904cf847e57ee2d110 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 20:17:30 +0000 Subject: [PATCH 14/22] Add error handling in get_global_state API --- postgrest/hafah_REST/other/get_block.sql | 39 +++++----------------- queries/hafah_rest_backend/block.sql | 42 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/postgrest/hafah_REST/other/get_block.sql b/postgrest/hafah_REST/other/get_block.sql index eacac9b55..462249952 100644 --- a/postgrest/hafah_REST/other/get_block.sql +++ b/postgrest/hafah_REST/other/get_block.sql @@ -52,12 +52,12 @@ SET ROLE hafah_owner; "witness_signature": "1f6aa1c6311c768b5225b115eaf5798e5f1d8338af3970d90899cd5ccbe38f6d1f7676c5649bcca18150cbf8f07c0cc7ec3ae40d5936cfc6d5a650e582ba0f8002", "signing_key": "STM8aUs6SGoEmNYMd3bYjE1UBr6NQPxGWmTqTdBaxJYSx244edSB2", "hbd_interest_rate": 1000, - "total_vesting_fund_hive": 149190428013, - "total_vesting_shares": 448144916705468350, - "total_reward_fund_hive": 66003975, - "virtual_supply": 161253662237, - "current_supply": 157464400971, - "current_hbd_supply": 2413759427, + "total_vesting_fund_hive": "149190428013", + "total_vesting_shares": "448144916705468350", + "total_reward_fund_hive": "66003975", + "virtual_supply": "161253662237", + "current_supply": "157464400971", + "current_hbd_supply": "2413759427", "dhf_interval_ledger": 0, "created_at": "2016-09-15T19:47:21" } @@ -78,38 +78,15 @@ SET from_collapse_limit = 16 AS $$ DECLARE - __block INT := hive.convert_to_block_num("block-num"); + __block INT := hive.convert_to_block_num("block-num"); BEGIN - 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 PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); END IF; - RETURN ( - SELECT ROW( - bv.num, - encode(bv.hash,'hex'), - encode(bv.prev,'hex'), - (SELECT av.name FROM hive.accounts_view av WHERE av.id = bv.producer_account_id)::TEXT, - encode(bv.transaction_merkle_root,'hex'), - COALESCE(bv.extensions, '[]'), - encode(bv.witness_signature, 'hex'), - bv.signing_key, - bv.hbd_interest_rate::numeric, - bv.total_vesting_fund_hive::numeric, - bv.total_vesting_shares::numeric, - bv.total_reward_fund_hive::numeric, - bv.virtual_supply::numeric, - bv.current_supply::numeric, - bv.current_hbd_supply::numeric, - bv.dhf_interval_ledger::numeric, - bv.created_at) - FROM hive.blocks_view bv - WHERE bv.num = __block - ); - + RETURN hafah_backend.get_global_state(__block); END $$; diff --git a/queries/hafah_rest_backend/block.sql b/queries/hafah_rest_backend/block.sql index 4ba242dd3..49b740938 100644 --- a/queries/hafah_rest_backend/block.sql +++ b/queries/hafah_rest_backend/block.sql @@ -32,4 +32,46 @@ END; $BODY$ ; +CREATE OR REPLACE FUNCTION hafah_backend.get_global_state(_block_num INT) + RETURNS hafah_backend.block + LANGUAGE plpgsql + STABLE +AS +$BODY$ +DECLARE + __block_type hafah_backend.block; +BEGIN + __block_type := ( + SELECT ( + bv.num, + encode(bv.hash,'hex'), + encode(bv.prev,'hex'), + (SELECT av.name FROM hive.accounts_view av WHERE av.id = bv.producer_account_id)::TEXT, + encode(bv.transaction_merkle_root,'hex'), + COALESCE(bv.extensions, '[]'), + encode(bv.witness_signature, 'hex'), + bv.signing_key, + bv.hbd_interest_rate::numeric, + bv.total_vesting_fund_hive::TEXT, + bv.total_vesting_shares::TEXT, + bv.total_reward_fund_hive::TEXT, + bv.virtual_supply::TEXT, + bv.current_supply::TEXT, + bv.current_hbd_supply::TEXT, + bv.dhf_interval_ledger::numeric, + bv.created_at + )::hafah_backend.block + FROM hive.blocks_view bv + WHERE bv.num = _block_num + ); + + IF __block_type.block_num IS NULL THEN + PERFORM hafah_backend.rest_raise_missing_block(_block_num); + END IF; + + RETURN __block_type; +END; +$BODY$ +; + RESET ROLE; -- GitLab From 773060aa3decc6f1e5c6d554f012fd6ea6c5b64f Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 20:23:02 +0000 Subject: [PATCH 15/22] Use composite type in get_version --- .../hafah_REST/other/get_head_block_num.sql | 1 - postgrest/hafah_REST/other/get_version.sql | 32 ++++++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/postgrest/hafah_REST/other/get_head_block_num.sql b/postgrest/hafah_REST/other/get_head_block_num.sql index 9d6e3d989..cf70bd2b8 100644 --- a/postgrest/hafah_REST/other/get_head_block_num.sql +++ b/postgrest/hafah_REST/other/get_head_block_num.sql @@ -38,7 +38,6 @@ LANGUAGE 'plpgsql' STABLE AS $$ 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; diff --git a/postgrest/hafah_REST/other/get_version.sql b/postgrest/hafah_REST/other/get_version.sql index e6fc11d23..9058bf79c 100644 --- a/postgrest/hafah_REST/other/get_version.sql +++ b/postgrest/hafah_REST/other/get_version.sql @@ -1,5 +1,25 @@ SET ROLE hafah_owner; + +/** openapi:components:schemas +hafah_backend.version_type: + type: object + properties: + app_name: + type: string + description: Application name + commit: + type: string + description: Last commit hash + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.version_type CASCADE; +CREATE TYPE hafah_backend.version_type AS ( + "app_name" TEXT, + "commit" TEXT +); +-- openapi-generated-code-end + /** openapi:paths /version: get: @@ -19,12 +39,11 @@ SET ROLE hafah_owner; '200': description: | - * Returns `JSON` + * Returns `hafah_backend.version_type` content: application/json: schema: - type: string - x-sql-datatype: JSON + $ref: '#/components/schemas/hafah_backend.version_type' example: c2fed8958584511ef1a66dab3dbac8c40f3518f0 '404': description: App not installed @@ -32,7 +51,7 @@ SET ROLE hafah_owner; -- openapi-generated-code-begin DROP FUNCTION IF EXISTS hafah_endpoints.get_version; CREATE OR REPLACE FUNCTION hafah_endpoints.get_version() -RETURNS JSON +RETURNS hafah_backend.version_type -- openapi-generated-code-end LANGUAGE 'plpgsql' AS @@ -40,7 +59,10 @@ $$ BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); - RETURN json_build_object('app_name', 'PostgRESTHAfAH', 'commit', (SELECT * FROM hafah_python.get_version())); + RETURN ( + 'PostgRESTHAfAH', + (SELECT * FROM hafah_python.get_version()) + )::hafah_backend.version_type; END; $$ ; -- GitLab From 32937c436157a1bb65547d250339c4daea1432e3 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 22:58:49 +0000 Subject: [PATCH 16/22] Use composite type in get_transaction API --- .../transactions/get_transaction.sql | 93 +++++++------------ postgrest/hafah_REST/types/transaction.sql | 37 ++++++++ 2 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 postgrest/hafah_REST/types/transaction.sql diff --git a/postgrest/hafah_REST/transactions/get_transaction.sql b/postgrest/hafah_REST/transactions/get_transaction.sql index d8ae7afc2..c58cabe49 100644 --- a/postgrest/hafah_REST/transactions/get_transaction.sql +++ b/postgrest/hafah_REST/transactions/get_transaction.sql @@ -1,38 +1,5 @@ SET ROLE hafah_owner; -/** openapi:components:schemas -hafah_endpoints.transaction: - type: object - properties: - transaction_json: - type: string - x-sql-datatype: JSON - description: contents of the transaction - transaction_id: - type: string - description: hash of the transaction - block_num: - type: integer - description: block containing the transaction - transaction_num: - type: integer - description: number of transactions in the block - timestamp: - type: string - format: date-time - description: time transaction was inlcuded in block - */ --- openapi-generated-code-begin -DROP TYPE IF EXISTS hafah_endpoints.transaction CASCADE; -CREATE TYPE hafah_endpoints.transaction AS ( - "transaction_json" JSON, - "transaction_id" TEXT, - "block_num" INT, - "transaction_num" INT, - "timestamp" TIMESTAMP -); --- openapi-generated-code-end - /** openapi:paths /transactions/{transaction-id}: get: @@ -69,11 +36,11 @@ CREATE TYPE hafah_endpoints.transaction AS ( description: | The transaction body - * Returns `hafah_endpoints.transaction` + * Returns `hafah_backend.transaction` content: application/json: schema: - $ref: '#/components/schemas/hafah_endpoints.transaction' + $ref: '#/components/schemas/hafah_backend.transaction' example: { "transaction_json": { "ref_block_num": 25532, @@ -109,45 +76,55 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_transaction( "transaction-id" TEXT, "include-virtual" BOOLEAN = False ) -RETURNS hafah_endpoints.transaction +RETURNS hafah_backend.transaction -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 AS $$ DECLARE - _get_transaction hafah_endpoints.transaction; + _transaction_type hafah_backend.transaction ; BEGIN WITH select_transaction AS MATERIALIZED ( - SELECT transaction_json::JSON, - bv.created_at - -- _trx_hash TEXT -> BYTEA, __include_reversible = TRUE, __is_legacy_style = FALSE - FROM hafah_python.get_transaction_json(('\x' || "transaction-id")::BYTEA, TRUE, FALSE, "include-virtual") AS transaction_json - JOIN hive.blocks_view bv ON bv.num = (transaction_json->>'block_num')::INT + SELECT + transaction_json::JSON, + bv.created_at + FROM hafah_python.get_transaction_json(\ + ('\x' || "transaction-id")::BYTEA, + TRUE, + FALSE, + "include-virtual" + ) AS transaction_json + JOIN hive.blocks_view bv ON bv.num = (transaction_json->>'block_num')::INT ) - SELECT - json_build_object( - 'ref_block_num', (transaction_json->>'ref_block_num')::BIGINT, - 'ref_block_prefix',(transaction_json->>'ref_block_prefix')::BIGINT, - 'extensions', (transaction_json->>'extensions')::JSON, - 'expiration', transaction_json->>'expiration', - 'operations', (transaction_json->>'operations')::JSON, - 'signatures', (transaction_json->>'signatures')::JSON - ), - transaction_json->>'transaction_id', - (transaction_json->>'block_num')::INT, - (transaction_json->>'transaction_num')::INT, - created_at - INTO _get_transaction + SELECT + ( + json_build_object( + 'ref_block_num', (transaction_json->>'ref_block_num')::BIGINT, + 'ref_block_prefix',(transaction_json->>'ref_block_prefix')::BIGINT, + 'extensions', (transaction_json->>'extensions')::JSON, + 'expiration', (transaction_json->>'expiration')::TEXT, + 'operations', (transaction_json->>'operations')::JSON, + 'signatures', (transaction_json->>'signatures')::JSON + ), + (transaction_json->>'transaction_id')::TEXT, + (transaction_json->>'block_num')::INT, + (transaction_json->>'transaction_num')::INT, + (created_at)::TIMESTAMP + )::hafah_backend.transaction + INTO _transaction_type FROM select_transaction; - IF _get_transaction.block_num <= hive.app_get_irreversible_block() THEN + IF _transaction_type.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 _get_transaction; + RETURN _transaction_type; END $$; diff --git a/postgrest/hafah_REST/types/transaction.sql b/postgrest/hafah_REST/types/transaction.sql new file mode 100644 index 000000000..7d565d3cd --- /dev/null +++ b/postgrest/hafah_REST/types/transaction.sql @@ -0,0 +1,37 @@ +SET ROLE hafah_owner; + +/** openapi:components:schemas +hafah_backend.transaction: + type: object + properties: + transaction_json: + $ref: '#/components/schemas/hafah_backend.transactions' + x-sql-datatype: JSONB + description: transactions in the block + transaction_id: + type: string + description: hash of the transaction + block_num: + type: string + description: block number + transaction_num: + type: integer + description: transaction identifier that indicates its sequence number in block + timestamp: + type: string + format: date-time + description: the timestamp when the block was created + + */ +-- openapi-generated-code-begin +DROP TYPE IF EXISTS hafah_backend.transaction CASCADE; +CREATE TYPE hafah_backend.transaction AS ( + "transaction_json" JSONB, + "transaction_id" TEXT, + "block_num" TEXT, + "transaction_num" INT, + "timestamp" TIMESTAMP +); +-- openapi-generated-code-end + +RESET ROLE; -- GitLab From e2f6333698511e8d30ad69828207b1fb40293c8c Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 23:02:16 +0000 Subject: [PATCH 17/22] Add set params to other endpoints --- postgrest/hafah_REST/accounts/get_ops_by_account.sql | 2 +- postgrest/hafah_REST/blocks/get_block.sql | 5 ++++- postgrest/hafah_REST/blocks/get_block_header.sql | 4 +++- postgrest/hafah_REST/blocks/get_block_range.sql | 4 +++- postgrest/hafah_REST/operation_types/get_op_types.sql | 3 +++ postgrest/hafah_REST/operations/get_operation.sql | 3 +++ postgrest/hafah_REST/operations/get_operations.sql | 4 +++- postgrest/hafah_REST/other/get_head_block_num.sql | 3 +++ postgrest/hafah_REST/transactions/get_transaction.sql | 2 +- 9 files changed, 24 insertions(+), 6 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index b93b63e13..0851e39ca 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -191,9 +191,9 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_ops_by_account( RETURNS hafah_backend.operation_history -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE +SET JIT = OFF SET join_collapse_limit = 16 SET from_collapse_limit = 16 -SET JIT = OFF SET enable_hashjoin = OFF AS $$ diff --git a/postgrest/hafah_REST/blocks/get_block.sql b/postgrest/hafah_REST/blocks/get_block.sql index 69373c526..d5cc80899 100644 --- a/postgrest/hafah_REST/blocks/get_block.sql +++ b/postgrest/hafah_REST/blocks/get_block.sql @@ -160,6 +160,9 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_block( RETURNS hafah_backend.block_range -- openapi-generated-code-end LANGUAGE 'plpgsql' +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 AS $$ DECLARE @@ -184,7 +187,7 @@ BEGIN END IF; BEGIN - RETURN hafah_backend.get_block(__block_num::INT, "include-virtual")::JSON; + RETURN hafah_backend.get_block(__block_num::INT, "include-virtual"); EXCEPTION WHEN invalid_text_representation THEN diff --git a/postgrest/hafah_REST/blocks/get_block_header.sql b/postgrest/hafah_REST/blocks/get_block_header.sql index 0b1c35596..3f3c01726 100644 --- a/postgrest/hafah_REST/blocks/get_block_header.sql +++ b/postgrest/hafah_REST/blocks/get_block_header.sql @@ -57,12 +57,14 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_block_header( RETURNS hafah_backend.block_header -- openapi-generated-code-end LANGUAGE 'plpgsql' +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 AS $$ DECLARE __block INT := hive.convert_to_block_num("block-num"); __block_num BIGINT = NULL; - __exception_message TEXT; BEGIN -- Required argument: block-num IF __block IS NULL THEN diff --git a/postgrest/hafah_REST/blocks/get_block_range.sql b/postgrest/hafah_REST/blocks/get_block_range.sql index e456de1d9..9d5043ed0 100644 --- a/postgrest/hafah_REST/blocks/get_block_range.sql +++ b/postgrest/hafah_REST/blocks/get_block_range.sql @@ -290,13 +290,15 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_block_range( RETURNS SETOF hafah_backend.block_range -- openapi-generated-code-end LANGUAGE 'plpgsql' +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 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; - __exception_message TEXT; BEGIN -- Required argument: block-num IF _block_range.first_block IS NULL THEN diff --git a/postgrest/hafah_REST/operation_types/get_op_types.sql b/postgrest/hafah_REST/operation_types/get_op_types.sql index d4e0317ab..256ab0790 100644 --- a/postgrest/hafah_REST/operation_types/get_op_types.sql +++ b/postgrest/hafah_REST/operation_types/get_op_types.sql @@ -57,6 +57,9 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_op_types( RETURNS SETOF hafah_backend.op_types -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 AS $$ DECLARE diff --git a/postgrest/hafah_REST/operations/get_operation.sql b/postgrest/hafah_REST/operations/get_operation.sql index 539b86b2d..d0181adbe 100644 --- a/postgrest/hafah_REST/operations/get_operation.sql +++ b/postgrest/hafah_REST/operations/get_operation.sql @@ -78,6 +78,9 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_operation( RETURNS hafah_backend.operation -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 AS $$ DECLARE diff --git a/postgrest/hafah_REST/operations/get_operations.sql b/postgrest/hafah_REST/operations/get_operations.sql index cbe1fc153..c1f16c053 100644 --- a/postgrest/hafah_REST/operations/get_operations.sql +++ b/postgrest/hafah_REST/operations/get_operations.sql @@ -281,12 +281,14 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_operations( RETURNS hafah_backend.operations_in_block_range -- openapi-generated-code-end LANGUAGE 'plpgsql' +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 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); - __exception_message TEXT; _operation_group_types BOOLEAN := (CASE WHEN "operation-group-type" = 'real' THEN FALSE WHEN "operation-group-type" = 'virtual' THEN TRUE ELSE NULL END); BEGIN PERFORM hafah_python.validate_limit("page-size", 150000, 'page-size'); diff --git a/postgrest/hafah_REST/other/get_head_block_num.sql b/postgrest/hafah_REST/other/get_head_block_num.sql index cf70bd2b8..4ad681253 100644 --- a/postgrest/hafah_REST/other/get_head_block_num.sql +++ b/postgrest/hafah_REST/other/get_head_block_num.sql @@ -35,6 +35,9 @@ CREATE OR REPLACE FUNCTION hafah_endpoints.get_head_block_num() RETURNS INT -- openapi-generated-code-end LANGUAGE 'plpgsql' STABLE +SET JIT = OFF +SET join_collapse_limit = 16 +SET from_collapse_limit = 16 AS $$ BEGIN diff --git a/postgrest/hafah_REST/transactions/get_transaction.sql b/postgrest/hafah_REST/transactions/get_transaction.sql index c58cabe49..3033721c0 100644 --- a/postgrest/hafah_REST/transactions/get_transaction.sql +++ b/postgrest/hafah_REST/transactions/get_transaction.sql @@ -92,7 +92,7 @@ BEGIN SELECT transaction_json::JSON, bv.created_at - FROM hafah_python.get_transaction_json(\ + FROM hafah_python.get_transaction_json( ('\x' || "transaction-id")::BYTEA, TRUE, FALSE, -- GitLab From c914b658fa108f636ee53f00572791a8d12521ec Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Tue, 25 Mar 2025 23:02:33 +0000 Subject: [PATCH 18/22] Adjust scripts --- scripts/install_app.sh | 10 +++++++++- scripts/openapi_rewrite.sh | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/install_app.sh b/scripts/install_app.sh index 9521bc5e5..204a5087e 100755 --- a/scripts/install_app.sh +++ b/scripts/install_app.sh @@ -75,7 +75,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/operation.sql" psql "$POSTGRES_ACCESS" -v ON_ERROR_STOP=on -f "$SCRIPTPATH/../postgrest/hafah_REST/types/sort_direction.sql" 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/../queries/hafah_rest_backend/account_history.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/../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/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" diff --git a/scripts/openapi_rewrite.sh b/scripts/openapi_rewrite.sh index 286543a13..33e854fbe 100755 --- a/scripts/openapi_rewrite.sh +++ b/scripts/openapi_rewrite.sh @@ -18,6 +18,7 @@ ENDPOINTS_IN_ORDER=" ../$endpoints/types/operation.sql ../$endpoints/types/sort_direction.sql ../$endpoints/types/block.sql +../$endpoints/types/transaction.sql ../$endpoints/hafah_openapi.sql ../$endpoints/blocks/get_block_range.sql ../$endpoints/blocks/get_block.sql -- GitLab From 9613e89701b888d1ec608483e1b2c3d5575d4723 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Wed, 26 Mar 2025 08:57:42 +0000 Subject: [PATCH 19/22] OpenAPI rewrite --- .../hafah_REST/accounts/get_acc_op_types.sql | 4 +- postgrest/hafah_REST/hafah_openapi.sql | 316 ++++++++++++++---- .../hafah_REST/operations/get_operation.sql | 2 +- postgrest/hafah_REST/other/get_version.sql | 5 +- .../transactions/get_transaction.sql | 53 ++- postgrest/hafah_REST/types/transaction.sql | 4 +- queries/hafah_rest_backend/acc_op_types.sql | 3 +- queries/hafah_rest_backend/operation.sql | 2 +- 8 files changed, 285 insertions(+), 104 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_acc_op_types.sql b/postgrest/hafah_REST/accounts/get_acc_op_types.sql index 60829ffc1..ce4069da6 100644 --- a/postgrest/hafah_REST/accounts/get_acc_op_types.sql +++ b/postgrest/hafah_REST/accounts/get_acc_op_types.sql @@ -82,7 +82,7 @@ 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 = (SELECT av.id FROM hive.accounts_view av WHERE av.name = "account-name"); BEGIN IF _account_id IS NULL THEN PERFORM hafah_backend.rest_raise_missing_account("account-name"); @@ -90,7 +90,7 @@ BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); - RETURN hafah_backend.get_acc_op_types(__account_id); + RETURN hafah_backend.get_acc_op_types(_account_id); END $$; diff --git a/postgrest/hafah_REST/hafah_openapi.sql b/postgrest/hafah_REST/hafah_openapi.sql index 27ea9fa50..48f0eb91d 100644 --- a/postgrest/hafah_REST/hafah_openapi.sql +++ b/postgrest/hafah_REST/hafah_openapi.sql @@ -70,11 +70,29 @@ declare "all" ] }, + "hafah_backend.operation_body": { + "type": "object", + "x-sql-datatype": "JSON", + "properties": { + "type": { + "type": "string" + }, + "value": { + "type": "object" + } + } + }, + "hafah_backend.array_of_operations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/hafah_backend.operation_body" + } + }, "hafah_backend.operation": { "type": "object", "properties": { "op": { - "type": "string", + "$ref": "#/components/schemas/hafah_backend.operation_body", "x-sql-datatype": "JSONB", "description": "operation body" }, @@ -114,6 +132,46 @@ declare } } }, + "hafah_backend.operation_history": { + "type": "object", + "properties": { + "total_operations": { + "type": "integer", + "description": "Total number of operations" + }, + "total_pages": { + "type": "integer", + "description": "Total number of 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": { + "next_block_range_begin": { + "type": "integer", + "description": "Lower bound for the next block number" + }, + "next_operation_begin": { + "type": "string", + "description": "Lower bound for the next operation id" + }, + "ops": { + "type": "array", + "items": { + "$ref": "#/components/schemas/hafah_backend.operation" + }, + "description": "List of operation results" + } + } + }, "hafah_backend.sort_direction": { "type": "string", "enum": [ @@ -121,6 +179,20 @@ declare "desc" ] }, + "hafah_backend.extensions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, "hafah_backend.block": { "type": "object", "properties": { @@ -145,7 +217,7 @@ declare "description": "single hash representing the combined hashes of all transactions in a block" }, "extensions": { - "type": "string", + "$ref": "#/components/schemas/hafah_backend.extensions", "x-sql-datatype": "JSONB", "description": "various additional data/parameters related to the subject at hand. Most often, there''s nothing specific, but it''s a mechanism for extending various functionalities where something might appear in the future." }, @@ -163,33 +235,27 @@ declare "description": "the interest rate on HBD in savings, expressed in basis points (previously for each HBD), is one of the values determined by the witnesses" }, "total_vesting_fund_hive": { - "type": "number", - "x-sql-datatype": "numeric", + "type": "string", "description": "the balance of the \"counterweight\" for these VESTS (total_vesting_shares) in the form of HIVE (the price of VESTS is derived from these two values). A portion of the inflation is added to the balance, ensuring that each block corresponds to more HIVE for the VESTS" }, "total_vesting_shares": { - "type": "number", - "x-sql-datatype": "numeric", + "type": "string", "description": "the total amount of VEST present in the system" }, "total_reward_fund_hive": { - "type": "number", - "x-sql-datatype": "numeric", + "type": "string", "description": "deprecated after HF17" }, "virtual_supply": { - "type": "number", - "x-sql-datatype": "numeric", + "type": "string", "description": "the total amount of HIVE, including the HIVE that would be generated from converting HBD to HIVE at the current price" }, "current_supply": { - "type": "number", - "x-sql-datatype": "numeric", + "type": "string", "description": "the total amount of HIVE present in the system" }, "current_hbd_supply": { - "type": "number", - "x-sql-datatype": "numeric", + "type": "string", "description": "the total amount of HBD present in the system, including what is in the treasury" }, "dhf_interval_ledger": { @@ -204,19 +270,117 @@ declare } } }, - "hafah_backend.array_of_op_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/hafah_backend.op_types" + "hafah_backend.block_header": { + "type": "object", + "properties": { + "previous": { + "type": "string", + "description": "hash of a previous block" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "the timestamp when the block was created" + }, + "witness": { + "type": "string", + "description": "account name of block''s producer" + }, + "transaction_merkle_root": { + "type": "string", + "description": "single hash representing the combined hashes of all transactions in a block" + }, + "extensions": { + "$ref": "#/components/schemas/hafah_backend.extensions", + "x-sql-datatype": "JSONB", + "description": "various additional data/parameters related to the subject at hand. Most often, there''s nothing specific, but it''s a mechanism for extending various functionalities where something might appear in the future." + } } }, - "hafah_endpoints.transaction": { + "hafah_backend.transactions": { "type": "object", + "x-sql-datatype": "JSON", "properties": { - "transaction_json": { + "ref_block_num": { + "type": "integer" + }, + "ref_block_prefix": { + "type": "integer" + }, + "expiration": { + "type": "string" + }, + "operations": { + "$ref": "#/components/schemas/hafah_backend.array_of_operations" + }, + "extensions": { + "$ref": "#/components/schemas/hafah_backend.extensions" + }, + "signatures": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "hafah_backend.block_range": { + "type": "object", + "properties": { + "previous": { + "type": "string", + "description": "hash of a previous block" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "the timestamp when the block was created" + }, + "witness": { + "type": "string", + "description": "account name of block''s producer" + }, + "transaction_merkle_root": { + "type": "string", + "description": "single hash representing the combined hashes of all transactions in a block" + }, + "extensions": { + "$ref": "#/components/schemas/hafah_backend.extensions", + "x-sql-datatype": "JSONB", + "description": "various additional data/parameters related to the subject at hand. Most often, there''s nothing specific, but it''s a mechanism for extending various functionalities where something might appear in the future." + }, + "witness_signature": { + "type": "string", + "description": "witness signature" + }, + "transactions": { + "$ref": "#/components/schemas/hafah_backend.transactions", + "x-sql-datatype": "JSONB", + "description": "transactions in the block" + }, + "block_id": { + "type": "string", + "description": "block hash in a blockchain is a unique, fixed-length string generated by applying a cryptographic hash function to a block''s contents" + }, + "signing_key": { "type": "string", - "x-sql-datatype": "JSON", - "description": "contents of the transaction" + "description": "it refers to the public key of the witness used for signing blocks and other witness operations" + }, + "transaction_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "hafah_backend.transaction": { + "type": "object", + "properties": { + "transaction_json": { + "$ref": "#/components/schemas/hafah_backend.transactions", + "x-sql-datatype": "JSONB", + "description": "transactions in the block" }, "transaction_id": { "type": "string", @@ -224,16 +388,41 @@ declare }, "block_num": { "type": "integer", - "description": "block containing the transaction" + "description": "block number" }, "transaction_num": { "type": "integer", - "description": "number of transactions in the block" + "description": "transaction identifier that indicates its sequence number in block" }, "timestamp": { "type": "string", "format": "date-time", - "description": "time transaction was inlcuded in block" + "description": "the timestamp when the block was created" + } + } + }, + "hafah_backend.array_of_block_range": { + "type": "array", + "items": { + "$ref": "#/components/schemas/hafah_backend.block_range" + } + }, + "hafah_backend.array_of_op_types": { + "type": "array", + "items": { + "$ref": "#/components/schemas/hafah_backend.op_types" + } + }, + "hafah_backend.version_type": { + "type": "object", + "properties": { + "app_name": { + "type": "string", + "description": "Application name" + }, + "commit": { + "type": "string", + "description": "Last commit hash" } } } @@ -317,12 +506,11 @@ declare ], "responses": { "200": { - "description": "\n* Returns `JSONB`\n", + "description": "\n* Returns array of `hafah_backend.block_range`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSONB" + "$ref": "#/components/schemas/hafah_backend.array_of_block_range" }, "example": [ { @@ -574,12 +762,11 @@ declare ], "responses": { "200": { - "description": "\n* Returns `JSONB`\n", + "description": "\n* Returns `hafah_backend.block_range`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSONB" + "$ref": "#/components/schemas/hafah_backend.block_range" }, "example": { "witness": "ihashfury", @@ -709,12 +896,11 @@ declare ], "responses": { "200": { - "description": "\n* Returns `JSONB`\n", + "description": "\n* Returns `hafah_backend.block_header`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSONB" + "$ref": "#/components/schemas/hafah_backend.block_header" }, "example": { "witness": "ihashfury", @@ -816,7 +1002,6 @@ declare "items": { "type": "string" }, - "x-sql-datatype": "TEXT[]", "default": null }, "description": "A parameter specifying the expected value in operation body,\nexample: `value.creator=steem`\n" @@ -824,12 +1009,11 @@ declare ], "responses": { "200": { - "description": "Result contains total operations number,\ntotal pages and the list of operations\n\n* Returns `JSON`\n", + "description": "Result contains total operations number,\ntotal pages and the list of operations\n\n* Returns `hafah_backend.operation_history`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSON" + "$ref": "#/components/schemas/hafah_backend.operation_history" }, "example": { "total_operations": 1, @@ -956,12 +1140,11 @@ declare ], "responses": { "200": { - "description": "\n* Returns `JSON`\n", + "description": "\n* Returns `hafah_backend.operations_in_block_range`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSON" + "$ref": "#/components/schemas/hafah_backend.operations_in_block_range" }, "example": { "ops": [ @@ -1248,12 +1431,18 @@ declare ], "responses": { "200": { - "description": "Operation json key paths\n\n* Returns `JSONB`\n", + "description": "Operation json key paths\n\n* Returns `JSON`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSONB" + "type": "array", + "items": { + "type": "array", + "items": { + "type": "string" + } + }, + "x-sql-datatype": "JSON" }, "example": [ [ @@ -1322,11 +1511,11 @@ declare ], "responses": { "200": { - "description": "The transaction body\n\n* Returns `hafah_endpoints.transaction`\n", + "description": "The transaction body\n\n* Returns `hafah_backend.transaction`\n", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/hafah_endpoints.transaction" + "$ref": "#/components/schemas/hafah_backend.transaction" }, "example": { "transaction_json": { @@ -1443,12 +1632,11 @@ declare ], "responses": { "200": { - "description": "Result contains total number of operations,\ntotal pages, and the list of operations.\n\n* Returns `JSON`\n", + "description": "Result contains total number of operations,\ntotal pages, and the list of operations.\n\n* Returns `hafah_backend.operation_history`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSON" + "$ref": "#/components/schemas/hafah_backend.operation_history" }, "example": { "total_operations": 219867, @@ -1551,12 +1739,14 @@ declare ], "responses": { "200": { - "description": "Operation type list\n\n* Returns `JSONB`\n", + "description": "Operation type list\n\n* Returns array of `INT`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSONB" + "type": "array", + "items": { + "type": "integer" + } }, "example": [ 0, @@ -1607,14 +1797,16 @@ declare "operationId": "hafah_endpoints.get_version", "responses": { "200": { - "description": "\n* Returns `JSON`\n", + "description": "\n* Returns `hafah_backend.version_type`\n", "content": { "application/json": { "schema": { - "type": "string", - "x-sql-datatype": "JSON" + "$ref": "#/components/schemas/hafah_backend.version_type" }, - "example": "c2fed8958584511ef1a66dab3dbac8c40f3518f0" + "example": { + "app_name": "PostgRESTHAfAH", + "commit": "136fe35c62cdc0fd7d6ff41cf6c946cadc2a4cd5" + } } } }, @@ -1687,12 +1879,12 @@ declare "witness_signature": "1f6aa1c6311c768b5225b115eaf5798e5f1d8338af3970d90899cd5ccbe38f6d1f7676c5649bcca18150cbf8f07c0cc7ec3ae40d5936cfc6d5a650e582ba0f8002", "signing_key": "STM8aUs6SGoEmNYMd3bYjE1UBr6NQPxGWmTqTdBaxJYSx244edSB2", "hbd_interest_rate": 1000, - "total_vesting_fund_hive": 149190428013, - "total_vesting_shares": 448144916705468350, - "total_reward_fund_hive": 66003975, - "virtual_supply": 161253662237, - "current_supply": 157464400971, - "current_hbd_supply": 2413759427, + "total_vesting_fund_hive": "149190428013", + "total_vesting_shares": "448144916705468350", + "total_reward_fund_hive": "66003975", + "virtual_supply": "161253662237", + "current_supply": "157464400971", + "current_hbd_supply": "2413759427", "dhf_interval_ledger": 0, "created_at": "2016-09-15T19:47:21" } diff --git a/postgrest/hafah_REST/operations/get_operation.sql b/postgrest/hafah_REST/operations/get_operation.sql index d0181adbe..ed758f297 100644 --- a/postgrest/hafah_REST/operations/get_operation.sql +++ b/postgrest/hafah_REST/operations/get_operation.sql @@ -107,7 +107,7 @@ BEGIN ov.operation_id, ov.trx_in_block )::hafah_backend.operation - FROM hafah_backend.get_operation("operation-id"); + FROM hafah_backend.get_operation("operation-id") ov; END $$; diff --git a/postgrest/hafah_REST/other/get_version.sql b/postgrest/hafah_REST/other/get_version.sql index 9058bf79c..78f565512 100644 --- a/postgrest/hafah_REST/other/get_version.sql +++ b/postgrest/hafah_REST/other/get_version.sql @@ -44,7 +44,10 @@ CREATE TYPE hafah_backend.version_type AS ( application/json: schema: $ref: '#/components/schemas/hafah_backend.version_type' - example: c2fed8958584511ef1a66dab3dbac8c40f3518f0 + example: { + "app_name": "PostgRESTHAfAH", + "commit": "136fe35c62cdc0fd7d6ff41cf6c946cadc2a4cd5" + } '404': description: App not installed */ diff --git a/postgrest/hafah_REST/transactions/get_transaction.sql b/postgrest/hafah_REST/transactions/get_transaction.sql index 3033721c0..adefe2c4c 100644 --- a/postgrest/hafah_REST/transactions/get_transaction.sql +++ b/postgrest/hafah_REST/transactions/get_transaction.sql @@ -85,46 +85,31 @@ SET from_collapse_limit = 16 AS $$ DECLARE - _transaction_type hafah_backend.transaction ; + _transaction_json JSON := hafah_python.get_transaction_json(('\x' || "transaction-id")::BYTEA, TRUE, FALSE, "include-virtual"); + _result JSON; BEGIN - WITH select_transaction AS MATERIALIZED - ( - SELECT - transaction_json::JSON, - bv.created_at - FROM hafah_python.get_transaction_json( - ('\x' || "transaction-id")::BYTEA, - TRUE, - FALSE, - "include-virtual" - ) AS transaction_json - JOIN hive.blocks_view bv ON bv.num = (transaction_json->>'block_num')::INT - ) - SELECT - ( - json_build_object( - 'ref_block_num', (transaction_json->>'ref_block_num')::BIGINT, - 'ref_block_prefix',(transaction_json->>'ref_block_prefix')::BIGINT, - 'extensions', (transaction_json->>'extensions')::JSON, - 'expiration', (transaction_json->>'expiration')::TEXT, - 'operations', (transaction_json->>'operations')::JSON, - 'signatures', (transaction_json->>'signatures')::JSON - ), - (transaction_json->>'transaction_id')::TEXT, - (transaction_json->>'block_num')::INT, - (transaction_json->>'transaction_num')::INT, - (created_at)::TIMESTAMP - )::hafah_backend.transaction - INTO _transaction_type - FROM select_transaction; - - IF _transaction_type.block_num <= hive.app_get_irreversible_block() THEN + IF (_transaction_json->>'block_num')::INT <= 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 _transaction_type; + _result := json_build_object( + 'ref_block_num', (_transaction_json->>'ref_block_num')::BIGINT, + 'ref_block_prefix',(_transaction_json->>'ref_block_prefix')::BIGINT, + 'extensions', (_transaction_json->>'extensions')::JSON, + 'expiration', (_transaction_json->>'expiration')::TEXT, + 'operations', (_transaction_json->>'operations')::JSON, + 'signatures', (_transaction_json->>'signatures')::JSON + ); + + RETURN ( + _result, + (_transaction_json->>'transaction_id')::TEXT, + (_transaction_json->>'block_num')::INT, + (_transaction_json->>'transaction_num')::INT, + (SELECT bv.created_at FROM hive.blocks_view bv WHERE bv.num = (_transaction_json->>'block_num')::INT) + )::hafah_backend.transaction; END $$; diff --git a/postgrest/hafah_REST/types/transaction.sql b/postgrest/hafah_REST/types/transaction.sql index 7d565d3cd..4f88bbf68 100644 --- a/postgrest/hafah_REST/types/transaction.sql +++ b/postgrest/hafah_REST/types/transaction.sql @@ -12,7 +12,7 @@ hafah_backend.transaction: type: string description: hash of the transaction block_num: - type: string + type: integer description: block number transaction_num: type: integer @@ -28,7 +28,7 @@ DROP TYPE IF EXISTS hafah_backend.transaction CASCADE; CREATE TYPE hafah_backend.transaction AS ( "transaction_json" JSONB, "transaction_id" TEXT, - "block_num" TEXT, + "block_num" INT, "transaction_num" INT, "timestamp" TIMESTAMP ); diff --git a/queries/hafah_rest_backend/acc_op_types.sql b/queries/hafah_rest_backend/acc_op_types.sql index cbc8b53a9..490beb8fc 100644 --- a/queries/hafah_rest_backend/acc_op_types.sql +++ b/queries/hafah_rest_backend/acc_op_types.sql @@ -9,11 +9,12 @@ LANGUAGE 'plpgsql' STABLE AS $$ BEGIN - RETURN array_agg(hot.id) + RETURN array_agg(hot.id) FROM hafd.operation_types hot WHERE EXISTS ( SELECT 1 FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND aov.op_type_id = hot.id + ORDER BY hot.id ); END diff --git a/queries/hafah_rest_backend/operation.sql b/queries/hafah_rest_backend/operation.sql index 8d76b778e..b6a9828fb 100644 --- a/queries/hafah_rest_backend/operation.sql +++ b/queries/hafah_rest_backend/operation.sql @@ -1,7 +1,7 @@ SET ROLE hafah_owner; CREATE OR REPLACE FUNCTION hafah_backend.get_operation( - _operation_id INT + _operation_id BIGINT ) RETURNS hafah_backend.operation LANGUAGE 'plpgsql' STABLE -- GitLab From 0dc11c293ecb0d95040bd34b8a0c09ac4f4b5ec8 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Wed, 26 Mar 2025 11:08:11 +0000 Subject: [PATCH 20/22] Ensure that aggregated result is in correct order --- .../accounts/get_ops_by_account.sql | 2 +- .../blocks/get_ops_by_block_paging.sql | 47 ++++++++++--------- .../operation_types/get_op_types.sql | 1 + queries/hafah_rest_backend/acc_op_types.sql | 3 +- queries/hafah_rest_backend/ops_in_block.sql | 2 +- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index 0851e39ca..24e753f33 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -233,7 +233,7 @@ BEGIN PERFORM set_config('response.headers', '[{"Cache-Control": "public, max-age=2"}]', true); END IF; - _result := array_agg(row) FROM ( + _result := array_agg(row ORDER BY row.operation_id::BIGINT DESC) FROM ( SELECT ba.op, ba.block, 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 78658fe2c..0b1fdf587 100644 --- a/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql +++ b/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql @@ -226,28 +226,31 @@ BEGIN END ); - _result := array_agg(row) 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_block( - __block, - "page", - "page-size", - _operation_types, - "page-order", - "data-size-limit", - _account_id, - _key_content, - _set_of_keys - ) ba + _result := array_agg(row ORDER BY + (CASE WHEN "page-order" = 'desc' THEN row.operation_id::BIGINT ELSE NULL END) DESC, + (CASE WHEN "page-order" = 'asc' THEN row.operation_id::BIGINT ELSE NULL END) ASC + ) 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_block( + __block, + "page", + "page-size", + _operation_types, + "page-order", + "data-size-limit", + _account_id, + _key_content, + _set_of_keys + ) ba ) row; RETURN ( diff --git a/postgrest/hafah_REST/operation_types/get_op_types.sql b/postgrest/hafah_REST/operation_types/get_op_types.sql index 256ab0790..bd4d54611 100644 --- a/postgrest/hafah_REST/operation_types/get_op_types.sql +++ b/postgrest/hafah_REST/operation_types/get_op_types.sql @@ -73,6 +73,7 @@ BEGIN operation_name, is_virtual FROM hafah_backend.get_op_types(__operation_name) + ORDER BY op_type_id ); END $$; diff --git a/queries/hafah_rest_backend/acc_op_types.sql b/queries/hafah_rest_backend/acc_op_types.sql index 490beb8fc..ec8302c28 100644 --- a/queries/hafah_rest_backend/acc_op_types.sql +++ b/queries/hafah_rest_backend/acc_op_types.sql @@ -9,12 +9,11 @@ LANGUAGE 'plpgsql' STABLE AS $$ BEGIN - RETURN array_agg(hot.id) + RETURN array_agg(hot.id ORDER BY hot.id) FROM hafd.operation_types hot WHERE EXISTS ( SELECT 1 FROM hive.account_operations_view aov WHERE aov.account_id = _account_id AND aov.op_type_id = hot.id - ORDER BY hot.id ); END diff --git a/queries/hafah_rest_backend/ops_in_block.sql b/queries/hafah_rest_backend/ops_in_block.sql index 4d7bf1d0e..7739a8230 100644 --- a/queries/hafah_rest_backend/ops_in_block.sql +++ b/queries/hafah_rest_backend/ops_in_block.sql @@ -72,7 +72,7 @@ BEGIN COALESCE((SELECT block_num FROM paging_logic), 0)::INT, COALESCE((SELECT id FROM paging_logic), 0)::TEXT, ( - SELECT array_agg(rows) + SELECT array_agg(rows ORDER BY rows.json_stringify_bigint::BIGINT) FROM ( SELECT s.op, -- GitLab From 320371ae93c274392b439ceacddf5b95fbd63cfe Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Wed, 26 Mar 2025 12:21:58 +0000 Subject: [PATCH 21/22] Add pattern test job --- .gitlab-ci.yml | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 77ce8197a..fb24f8923 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -339,6 +339,7 @@ postgrest_rest_benchmark_tests: - job: prepare_postgrest_hafah_image artifacts: true script: + - sleep 10 - timeout -k 1m 10m ./tests/performance/run_performance_tests.sh --backend-host=app --backend-port=$APP_PORT - tar -czvf tests/performance/results.tar.gz $(pwd)/tests/performance/*result.* @@ -350,6 +351,7 @@ postgrest_rest_benchmark_tests: - tests/performance/result_report/ - tests/performance/results.tar.gz - jmeter.log + when: always reports: junit: tests/performance/junit-result.xml tags: @@ -479,6 +481,76 @@ prepare_haf_image_testnet: tags: - public-runner-docker +hafah_pytest_rest_api_pattern_tests: + extends: .pytest_based_template + stage: test + needs: + - job: prepare_haf_data + artifacts: true + - job: prepare_postgrest_hafah_image + artifacts: true + services: + - *hfm-only-service + - name: ${HAF_APP_IMAGE} + alias: app-setup + variables: + # intentionally use setup way chosed in haf_api_node compose scripts + POSTGRES_URL: "postgresql://haf_admin@hfm-only-instance/haf_block_log" + command: ["install_app"] + entrypoint: + - '/bin/bash' + - '-c' + - | + set -xeuo pipefail + echo "Attempting to perform application setup..." + # pass control to the default image entrypoint + "./docker_entrypoint.sh" "$@" + echo "Application setup completed, starting to listed app port to satisfy Gitlab health checker..." + # Once setup completed, just listen on container/app port to satisfy GitlabCI HealthChecker + nc -v -l -p $(echo "${HAF_APP_PORT}") + # arg $0 should be explicitly passed when using 'bash -c' entrypoints + - '/bin/bash' + + - name: ${HAF_APP_IMAGE} + alias: app + command: ["--postgres-url=postgresql://hafah_user@hfm-only-instance/haf_block_log"] + entrypoint: + - '/bin/bash' + - '-c' + - | + set -xeuo pipefail + # since Gitlab services startup order is undefined, we need to wait for app setup completion + "/home/hafah_user/app/scripts/wait_for_setup_completed.sh" "$@" + echo "Application setup finished - continue app-service spawn..." + # pass control to the default image entrypoint + /home/hafah_user/docker_entrypoint.sh "$@" + # arg $0 should be explicitly passed when using 'bash -c' entrypoints + - '/bin/bash' + variables: + DATA_SOURCE: "${DATA_CACHE_HAF_PREFIX}_${HAF_COMMIT}" + JUNIT_REPORT: $CI_PROJECT_DIR/tests/tavern/report.xml + PYTEST_BASED_IMAGE_NAME: $BUILDER_IMAGE_PATH + POETRY_INSTALL_ROOT_DIR: $CI_PROJECT_DIR/haf/hive/tests/python/hive-local-tools + TAVERN_DIR: $CI_PROJECT_DIR/tests/tavern + DB_NAME: haf_block_log + DB_URL: "postgresql://haf_admin@hfm-only-instance:5432/$DB_NAME" + HAF_APP_IMAGE: $HAFAH_IMAGE_NAME + HAF_APP_PORT: ${APP_PORT} + HAF_APP_HOST: app + DIRECT_CALLS: 0 + POSTGRES_URL: $DB_URL + script: + - | + echo "HAfAH image name $HAF_APP_IMAGE" + echo "HAF image name $HAF_IMAGE_NAME" + cd $CI_PROJECT_DIR/tests/tavern + pytest -n $PYTEST_NUMBER_OF_PROCESSES --junitxml report.xml . + artifacts: + paths: + - "**/*.out.json" + tags: + - data-cache-storage + hafah_pytest_fuctional_tests_part1: extends: .hafah_pytest_fuctional_tests_base variables: -- GitLab From 58c692e0b9e77396909f52c6b35de840c38b2e17 Mon Sep 17 00:00:00 2001 From: Michal Zander <mzander@syncad.com> Date: Thu, 27 Mar 2025 12:44:21 +0000 Subject: [PATCH 22/22] Add patterns for REST endpoints --- .../accounts/get_ops_by_account.sql | 2 +- .../blocks/get_ops_by_block_paging.sql | 4 +- queries/hafah_rest_backend/ops_in_block.sql | 4 +- tests/tavern/common.yaml | 9 + .../negative/non_existent_witness.pat.json | 6 + .../negative/non_existent_witness.tavern.yaml | 26 + .../positive/blocktrades.pat.json | 33 + .../positive/blocktrades.tavern.yaml | 23 + .../get_acc_op_types/positive/gtg.pat.json | 32 + .../get_acc_op_types/positive/gtg.tavern.yaml | 23 + .../get_block/negative/non_existent.pat.json | 6 + .../negative/non_existent.tavern.yaml | 26 + .../get_block/positive/first_block.pat.json | 12 + .../positive/first_block.tavern.yaml | 23 + .../positive/include_virtual.pat.json | 161 +++ .../positive/include_virtual.tavern.yaml | 24 + tests/tavern/get_block/positive/last.pat.json | 101 ++ .../get_block/positive/last.tavern.yaml | 23 + .../negative/non_existent.pat.json | 6 + .../negative/non_existent.tavern.yaml | 26 + .../positive/first_block.pat.json | 7 + .../positive/first_block.tavern.yaml | 23 + .../get_block_header/positive/last.pat.json | 7 + .../positive/last.tavern.yaml | 23 + .../positive/first_blocks.pat.json | 242 ++++ .../positive/first_blocks.tavern.yaml | 24 + .../positive/latest_blocks.pat.json | 1279 +++++++++++++++++ .../positive/latest_blocks.tavern.yaml | 24 + .../positive/non_existent_range.pat.json | 1 + .../positive/non_existent_range.tavern.yaml | 24 + .../negative/non_existent.pat.json | 6 + .../negative/non_existent.tavern.yaml | 26 + .../positive/first_block.pat.json | 19 + .../positive/first_block.tavern.yaml | 23 + .../get_global_state/positive/last.pat.json | 19 + .../positive/last.tavern.yaml | 23 + .../get_head_block_num/default.pat.json | 1 + .../get_head_block_num/default.tavern.yaml | 21 + tests/tavern/get_op_types/default.pat.json | 467 ++++++ tests/tavern/get_op_types/default.tavern.yaml | 21 + .../get_op_types/non_existent_name.pat.json | 1 + .../non_existent_name.tavern.yaml | 23 + .../tavern/get_op_types/partial_name.pat.json | 87 ++ .../get_op_types/partial_name.tavern.yaml | 23 + .../negative/non_existent_op.pat.json | 6 + .../negative/non_existent_op.tavern.yaml | 26 + .../get_operation/positive/first_op.pat.json | 21 + .../positive/first_op.tavern.yaml | 23 + .../get_operation/positive/second_op.pat.json | 33 + .../positive/second_op.tavern.yaml | 23 + .../negative/non_existent.pat.json | 6 + .../negative/non_existent.tavern.yaml | 26 + .../positive/comment.pat.json | 30 + .../positive/comment.tavern.yaml | 23 + .../get_operation_keys/positive/vote.pat.json | 18 + .../positive/vote.tavern.yaml | 23 + .../positive/filter_by_op.pat.json | 196 +++ .../positive/filter_by_op.tavern.yaml | 26 + .../positive/filter_by_op_next_page.pat.json | 196 +++ .../filter_by_op_next_page.tavern.yaml | 27 + .../positive/first_blocks.pat.json | 477 ++++++ .../positive/first_blocks.tavern.yaml | 25 + .../positive/latest_blocks.pat.json | 425 ++++++ .../positive/latest_blocks.tavern.yaml | 25 + .../positive/non_existent_range.pat.json | 5 + .../positive/non_existent_range.tavern.yaml | 24 + .../positive/only_real.pat.json | 396 +++++ .../positive/only_real.tavern.yaml | 26 + .../positive/only_virtual.pat.json | 213 +++ .../positive/only_virtual.tavern.yaml | 26 + .../negative/exceeds_page_size.pat.json | 6 + .../negative/exceeds_page_size.tavern.yaml | 27 + .../negative/invalid_block_num.pat.json | 6 + .../negative/invalid_block_num.tavern.yaml | 27 + .../negative/invalid_timestamp.pat.json | 6 + .../negative/invalid_timestamp.tavern.yaml | 27 + .../negative/negative_page.pat.json | 6 + .../negative/negative_page.tavern.yaml | 27 + .../negative/negative_page_size.pat.json | 6 + .../negative/negative_page_size.tavern.yaml | 27 + .../negative/non_existent_witness.pat.json | 6 + .../negative/non_existent_witness.tavern.yaml | 27 + .../positive/blocktrades_first_page.pat.json | 160 +++ .../blocktrades_first_page.tavern.yaml | 24 + .../positive/blocktrades_last_page.pat.json | 444 ++++++ .../blocktrades_last_page.tavern.yaml | 25 + .../positive/filter_by_op.pat.json | 142 ++ .../positive/filter_by_op.tavern.yaml | 25 + .../positive/filter_by_range.pat.json | 112 ++ .../positive/filter_by_range.tavern.yaml | 25 + .../negative/exceeds_page_size.pat.json | 6 + .../negative/exceeds_page_size.tavern.yaml | 27 + .../negative/invalid_block_num.pat.json | 6 + .../negative/invalid_block_num.tavern.yaml | 26 + .../negative/invalid_timestamp.pat.json | 6 + .../negative/invalid_timestamp.tavern.yaml | 26 + .../negative/negative_page.pat.json | 6 + .../negative/negative_page.tavern.yaml | 27 + .../negative/negative_page_size.pat.json | 6 + .../negative/negative_page_size.tavern.yaml | 27 + .../negative/non_existent.pat.json | 6 + .../negative/non_existent.tavern.yaml | 26 + .../positive/change_direction.pat.json | 117 ++ .../positive/change_direction.tavern.yaml | 25 + .../positive/filter_by_account.pat.json | 28 + .../positive/filter_by_account.tavern.yaml | 24 + .../positive/filter_by_op.pat.json | 120 ++ .../positive/filter_by_op.tavern.yaml | 24 + .../positive/first_page.pat.json | 56 + .../positive/first_page.tavern.yaml | 24 + .../positive/last_page.pat.json | 87 ++ .../positive/last_page.tavern.yaml | 25 + .../negative/invalid_hash.pat.json | 6 + .../negative/invalid_hash.tavern.yaml | 26 + .../negative/non_existent_trx.pat.json | 6 + .../negative/non_existent_trx.tavern.yaml | 26 + .../get_transaction/positive/by_trx.pat.json | 61 + .../positive/by_trx.tavern.yaml | 23 + .../positive/include_virtual.pat.json | 78 + .../positive/include_virtual.tavern.yaml | 24 + tests/tavern/pytest.ini | 4 + 121 files changed, 7459 insertions(+), 4 deletions(-) create mode 100644 tests/tavern/common.yaml create mode 100644 tests/tavern/get_acc_op_types/negative/non_existent_witness.pat.json create mode 100644 tests/tavern/get_acc_op_types/negative/non_existent_witness.tavern.yaml create mode 100644 tests/tavern/get_acc_op_types/positive/blocktrades.pat.json create mode 100644 tests/tavern/get_acc_op_types/positive/blocktrades.tavern.yaml create mode 100644 tests/tavern/get_acc_op_types/positive/gtg.pat.json create mode 100644 tests/tavern/get_acc_op_types/positive/gtg.tavern.yaml create mode 100644 tests/tavern/get_block/negative/non_existent.pat.json create mode 100644 tests/tavern/get_block/negative/non_existent.tavern.yaml create mode 100644 tests/tavern/get_block/positive/first_block.pat.json create mode 100644 tests/tavern/get_block/positive/first_block.tavern.yaml create mode 100644 tests/tavern/get_block/positive/include_virtual.pat.json create mode 100644 tests/tavern/get_block/positive/include_virtual.tavern.yaml create mode 100644 tests/tavern/get_block/positive/last.pat.json create mode 100644 tests/tavern/get_block/positive/last.tavern.yaml create mode 100644 tests/tavern/get_block_header/negative/non_existent.pat.json create mode 100644 tests/tavern/get_block_header/negative/non_existent.tavern.yaml create mode 100644 tests/tavern/get_block_header/positive/first_block.pat.json create mode 100644 tests/tavern/get_block_header/positive/first_block.tavern.yaml create mode 100644 tests/tavern/get_block_header/positive/last.pat.json create mode 100644 tests/tavern/get_block_header/positive/last.tavern.yaml create mode 100644 tests/tavern/get_block_range/positive/first_blocks.pat.json create mode 100644 tests/tavern/get_block_range/positive/first_blocks.tavern.yaml create mode 100644 tests/tavern/get_block_range/positive/latest_blocks.pat.json create mode 100644 tests/tavern/get_block_range/positive/latest_blocks.tavern.yaml create mode 100644 tests/tavern/get_block_range/positive/non_existent_range.pat.json create mode 100644 tests/tavern/get_block_range/positive/non_existent_range.tavern.yaml create mode 100644 tests/tavern/get_global_state/negative/non_existent.pat.json create mode 100644 tests/tavern/get_global_state/negative/non_existent.tavern.yaml create mode 100644 tests/tavern/get_global_state/positive/first_block.pat.json create mode 100644 tests/tavern/get_global_state/positive/first_block.tavern.yaml create mode 100644 tests/tavern/get_global_state/positive/last.pat.json create mode 100644 tests/tavern/get_global_state/positive/last.tavern.yaml create mode 100644 tests/tavern/get_head_block_num/default.pat.json create mode 100644 tests/tavern/get_head_block_num/default.tavern.yaml create mode 100644 tests/tavern/get_op_types/default.pat.json create mode 100644 tests/tavern/get_op_types/default.tavern.yaml create mode 100644 tests/tavern/get_op_types/non_existent_name.pat.json create mode 100644 tests/tavern/get_op_types/non_existent_name.tavern.yaml create mode 100644 tests/tavern/get_op_types/partial_name.pat.json create mode 100644 tests/tavern/get_op_types/partial_name.tavern.yaml create mode 100644 tests/tavern/get_operation/negative/non_existent_op.pat.json create mode 100644 tests/tavern/get_operation/negative/non_existent_op.tavern.yaml create mode 100644 tests/tavern/get_operation/positive/first_op.pat.json create mode 100644 tests/tavern/get_operation/positive/first_op.tavern.yaml create mode 100644 tests/tavern/get_operation/positive/second_op.pat.json create mode 100644 tests/tavern/get_operation/positive/second_op.tavern.yaml create mode 100644 tests/tavern/get_operation_keys/negative/non_existent.pat.json create mode 100644 tests/tavern/get_operation_keys/negative/non_existent.tavern.yaml create mode 100644 tests/tavern/get_operation_keys/positive/comment.pat.json create mode 100644 tests/tavern/get_operation_keys/positive/comment.tavern.yaml create mode 100644 tests/tavern/get_operation_keys/positive/vote.pat.json create mode 100644 tests/tavern/get_operation_keys/positive/vote.tavern.yaml create mode 100644 tests/tavern/get_operations/positive/filter_by_op.pat.json create mode 100644 tests/tavern/get_operations/positive/filter_by_op.tavern.yaml create mode 100644 tests/tavern/get_operations/positive/filter_by_op_next_page.pat.json create mode 100644 tests/tavern/get_operations/positive/filter_by_op_next_page.tavern.yaml create mode 100644 tests/tavern/get_operations/positive/first_blocks.pat.json create mode 100644 tests/tavern/get_operations/positive/first_blocks.tavern.yaml create mode 100644 tests/tavern/get_operations/positive/latest_blocks.pat.json create mode 100644 tests/tavern/get_operations/positive/latest_blocks.tavern.yaml create mode 100644 tests/tavern/get_operations/positive/non_existent_range.pat.json create mode 100644 tests/tavern/get_operations/positive/non_existent_range.tavern.yaml create mode 100644 tests/tavern/get_operations/positive/only_real.pat.json create mode 100644 tests/tavern/get_operations/positive/only_real.tavern.yaml create mode 100644 tests/tavern/get_operations/positive/only_virtual.pat.json create mode 100644 tests/tavern/get_operations/positive/only_virtual.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/negative/exceeds_page_size.pat.json create mode 100644 tests/tavern/get_ops_by_account/negative/exceeds_page_size.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/negative/invalid_block_num.pat.json create mode 100644 tests/tavern/get_ops_by_account/negative/invalid_block_num.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/negative/invalid_timestamp.pat.json create mode 100644 tests/tavern/get_ops_by_account/negative/invalid_timestamp.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/negative/negative_page.pat.json create mode 100644 tests/tavern/get_ops_by_account/negative/negative_page.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/negative/negative_page_size.pat.json create mode 100644 tests/tavern/get_ops_by_account/negative/negative_page_size.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/negative/non_existent_witness.pat.json create mode 100644 tests/tavern/get_ops_by_account/negative/non_existent_witness.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/positive/blocktrades_first_page.pat.json create mode 100644 tests/tavern/get_ops_by_account/positive/blocktrades_first_page.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/positive/blocktrades_last_page.pat.json create mode 100644 tests/tavern/get_ops_by_account/positive/blocktrades_last_page.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/positive/filter_by_op.pat.json create mode 100644 tests/tavern/get_ops_by_account/positive/filter_by_op.tavern.yaml create mode 100644 tests/tavern/get_ops_by_account/positive/filter_by_range.pat.json create mode 100644 tests/tavern/get_ops_by_account/positive/filter_by_range.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/negative/negative_page.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/negative/negative_page.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/negative/negative_page_size.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/negative/negative_page_size.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/negative/non_existent.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/negative/non_existent.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/positive/change_direction.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/positive/change_direction.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/positive/filter_by_account.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/positive/filter_by_account.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/positive/filter_by_op.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/positive/filter_by_op.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/positive/first_page.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/positive/first_page.tavern.yaml create mode 100644 tests/tavern/get_ops_by_block_paging/positive/last_page.pat.json create mode 100644 tests/tavern/get_ops_by_block_paging/positive/last_page.tavern.yaml create mode 100644 tests/tavern/get_transaction/negative/invalid_hash.pat.json create mode 100644 tests/tavern/get_transaction/negative/invalid_hash.tavern.yaml create mode 100644 tests/tavern/get_transaction/negative/non_existent_trx.pat.json create mode 100644 tests/tavern/get_transaction/negative/non_existent_trx.tavern.yaml create mode 100644 tests/tavern/get_transaction/positive/by_trx.pat.json create mode 100644 tests/tavern/get_transaction/positive/by_trx.tavern.yaml create mode 100644 tests/tavern/get_transaction/positive/include_virtual.pat.json create mode 100644 tests/tavern/get_transaction/positive/include_virtual.tavern.yaml create mode 100644 tests/tavern/pytest.ini diff --git a/postgrest/hafah_REST/accounts/get_ops_by_account.sql b/postgrest/hafah_REST/accounts/get_ops_by_account.sql index 24e753f33..5c6ebb595 100644 --- a/postgrest/hafah_REST/accounts/get_ops_by_account.sql +++ b/postgrest/hafah_REST/accounts/get_ops_by_account.sql @@ -258,7 +258,7 @@ BEGIN RETURN ( COALESCE(_ops_count,0), COALESCE(__total_pages,0), - _result + COALESCE(_result, '{}'::hafah_backend.operation[]) )::hafah_backend.operation_history; -- ops_count returns number of operations found with current filter 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 0b1fdf587..672daa0ca 100644 --- a/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql +++ b/postgrest/hafah_REST/blocks/get_ops_by_block_paging.sql @@ -226,6 +226,8 @@ BEGIN END ); + 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, (CASE WHEN "page-order" = 'asc' THEN row.operation_id::BIGINT ELSE NULL END) ASC @@ -256,7 +258,7 @@ BEGIN RETURN ( COALESCE(_ops_count,0), COALESCE(__total_pages,0), - _result + COALESCE(_result, '{}'::hafah_backend.operation[]) )::hafah_backend.operation_history; END diff --git a/queries/hafah_rest_backend/ops_in_block.sql b/queries/hafah_rest_backend/ops_in_block.sql index 7739a8230..99d850e71 100644 --- a/queries/hafah_rest_backend/ops_in_block.sql +++ b/queries/hafah_rest_backend/ops_in_block.sql @@ -72,7 +72,7 @@ BEGIN COALESCE((SELECT block_num FROM paging_logic), 0)::INT, COALESCE((SELECT id FROM paging_logic), 0)::TEXT, ( - SELECT array_agg(rows ORDER BY rows.json_stringify_bigint::BIGINT) + SELECT array_agg(rows ORDER BY rows.operation_id::BIGINT) FROM ( SELECT s.op, @@ -82,7 +82,7 @@ BEGIN s.op_type_id, s.timestamp, s.virtual_op, - hafah_python.json_stringify_bigint(s.operation_id), + s.operation_id::TEXT, s.trx_in_block::SMALLINT FROM pre_result s ) rows diff --git a/tests/tavern/common.yaml b/tests/tavern/common.yaml new file mode 100644 index 000000000..40926b53e --- /dev/null +++ b/tests/tavern/common.yaml @@ -0,0 +1,9 @@ +--- + name: Common test values + description: Common values for tests + + variables: + service: + proto: http + server: "{tavern.env_vars.HAF_APP_HOST}" + port: "{tavern.env_vars.HAF_APP_PORT}" diff --git a/tests/tavern/get_acc_op_types/negative/non_existent_witness.pat.json b/tests/tavern/get_acc_op_types/negative/non_existent_witness.pat.json new file mode 100644 index 000000000..fe05f1292 --- /dev/null +++ b/tests/tavern/get_acc_op_types/negative/non_existent_witness.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Account 'themarkymark' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_acc_op_types/negative/non_existent_witness.tavern.yaml b/tests/tavern/get_acc_op_types/negative/non_existent_witness.tavern.yaml new file mode 100644 index 000000000..e4fe59c85 --- /dev/null +++ b/tests/tavern/get_acc_op_types/negative/non_existent_witness.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_acc_op_types" + method: POST + headers: + content-type: application/json + accept: application/json + json: + account-name: "themarkymark" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_acc_op_types/positive/blocktrades.pat.json b/tests/tavern/get_acc_op_types/positive/blocktrades.pat.json new file mode 100644 index 000000000..0a0bb0ed2 --- /dev/null +++ b/tests/tavern/get_acc_op_types/positive/blocktrades.pat.json @@ -0,0 +1,33 @@ +[ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 10, + 11, + 12, + 13, + 14, + 15, + 18, + 20, + 51, + 52, + 53, + 55, + 56, + 57, + 61, + 64, + 72, + 77, + 78, + 79, + 80, + 85, + 86 +] \ No newline at end of file diff --git a/tests/tavern/get_acc_op_types/positive/blocktrades.tavern.yaml b/tests/tavern/get_acc_op_types/positive/blocktrades.tavern.yaml new file mode 100644 index 000000000..898e203a5 --- /dev/null +++ b/tests/tavern/get_acc_op_types/positive/blocktrades.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_acc_op_types" + method: POST + headers: + content-type: application/json + accept: application/json + json: + account-name: "blocktrades" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_acc_op_types/positive/gtg.pat.json b/tests/tavern/get_acc_op_types/positive/gtg.pat.json new file mode 100644 index 000000000..bedd9fbbc --- /dev/null +++ b/tests/tavern/get_acc_op_types/positive/gtg.pat.json @@ -0,0 +1,32 @@ +[ + 0, + 1, + 2, + 3, + 5, + 6, + 7, + 8, + 10, + 11, + 12, + 13, + 14, + 18, + 24, + 25, + 50, + 51, + 52, + 53, + 55, + 57, + 61, + 64, + 72, + 77, + 78, + 80, + 85, + 86 +] \ No newline at end of file diff --git a/tests/tavern/get_acc_op_types/positive/gtg.tavern.yaml b/tests/tavern/get_acc_op_types/positive/gtg.tavern.yaml new file mode 100644 index 000000000..b2ce060a2 --- /dev/null +++ b/tests/tavern/get_acc_op_types/positive/gtg.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_acc_op_types" + method: POST + headers: + content-type: application/json + accept: application/json + json: + account-name: "gtg" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block/negative/non_existent.pat.json b/tests/tavern/get_block/negative/non_existent.pat.json new file mode 100644 index 000000000..7d466aa44 --- /dev/null +++ b/tests/tavern/get_block/negative/non_existent.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Block_num '5000001' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_block/negative/non_existent.tavern.yaml b/tests/tavern/get_block/negative/non_existent.tavern.yaml new file mode 100644 index 000000000..6643c21f4 --- /dev/null +++ b/tests/tavern/get_block/negative/non_existent.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_block" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000001" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_block/positive/first_block.pat.json b/tests/tavern/get_block/positive/first_block.pat.json new file mode 100644 index 000000000..5f574b0a5 --- /dev/null +++ b/tests/tavern/get_block/positive/first_block.pat.json @@ -0,0 +1,12 @@ +{ + "witness": "initminer", + "block_id": "0000000109833ce528d5bbfb3f6225b39ee10086", + "previous": "0000000000000000000000000000000000000000", + "timestamp": "2016-03-24T16:05:00", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "204f8ad56a8f5cf722a02b035a61b500aa59b9519b2c33c77a80c0a714680a5a5a7a340d909d19996613c5e4ae92146b9add8a7a663eef37d837ef881477313043", + "transaction_merkle_root": "0000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/tests/tavern/get_block/positive/first_block.tavern.yaml b/tests/tavern/get_block/positive/first_block.tavern.yaml new file mode 100644 index 000000000..32e50ada6 --- /dev/null +++ b/tests/tavern/get_block/positive/first_block.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_block" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "1" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block/positive/include_virtual.pat.json b/tests/tavern/get_block/positive/include_virtual.pat.json new file mode 100644 index 000000000..2473e4f8e --- /dev/null +++ b/tests/tavern/get_block/positive/include_virtual.pat.json @@ -0,0 +1,161 @@ +{ + "witness": "smooth.witness", + "block_id": "004c4b3fc6a8735b4ab5433d59f4526e4a042644", + "previous": "004c4b3e03ea2eac2494790786bfb9e41a8669d9", + "timestamp": "2016-09-15T19:47:18", + "extensions": [], + "signing_key": "STM5jtPaM5G2jemsqTY8xYgy3CVUgzygKn7vUVpFozr6nWcCJ8mDW", + "transactions": [ + { + "expiration": "2016-09-15T19:47:27", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "rkpl", + "author": "thedevil", + "weight": -10000, + "permlink": "re-rkpl-how-to-make-a-good-picture-of-the-moon-my-guide-and-photos-20160915t193128824z" + } + }, + { + "type": "effective_comment_vote_operation", + "value": { + "voter": "rkpl", + "author": "thedevil", + "weight": 0, + "rshares": -1383373254, + "permlink": "re-rkpl-how-to-make-a-good-picture-of-the-moon-my-guide-and-photos-20160915t193128824z", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": 590910411298246 + } + } + ], + "signatures": [ + "2046cca841a2c84caf416ccec47f4d894732236505c21964ca092a4bf83b755979402486e49f4f6c116fc7e8d8525df14592d2993365b54ac26cb4bc52d3611e50" + ], + "ref_block_num": 19245, + "ref_block_prefix": 325640405 + }, + { + "expiration": "2016-09-15T19:47:45", + "extensions": [], + "operations": [ + { + "type": "limit_order_cancel_operation", + "value": { + "owner": "cvk", + "orderid": 1473968539 + } + }, + { + "type": "limit_order_cancelled_operation", + "value": { + "seller": "cvk", + "orderid": 1473968539, + "amount_back": { + "nai": "@@000000021", + "amount": "9941", + "precision": 3 + } + } + } + ], + "signatures": [ + "20388171dcf8401b9ca74a79991fa2aaeff26729a28c3acb5510663a930e51f15e180e712e0e7fd3a65b2082ea89583b5155239259fc37c9a0c2b0ec4aacfb6963" + ], + "ref_block_num": 19262, + "ref_block_prefix": 2888755715 + }, + { + "expiration": "2016-09-15T20:47:15", + "extensions": [], + "operations": [ + { + "type": "pow2_operation", + "value": { + "work": { + "type": "pow2", + "value": { + "input": { + "nonce": "12906882138532220661", + "prev_block": "004c4b3e03ea2eac2494790786bfb9e41a8669d9", + "worker_account": "rabbit-25" + }, + "pow_summary": 3818441282 + } + }, + "props": { + "hbd_interest_rate": 1000, + "maximum_block_size": 131072, + "account_creation_fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + } + } + } + }, + { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5031442145", + "precision": 6 + }, + "worker": "smooth.witness" + } + } + ], + "signatures": [ + "200cecb32d535041c061ea00ec8092c4ab12bf1453035c52987beffb53099f4d5045b29946037b15f9cdde3cbbe0f6e72b8f2f42027cafbeeee54cb8e780f8b07f" + ], + "ref_block_num": 19262, + "ref_block_prefix": 2888755715 + }, + { + "expiration": "2016-09-15T19:47:45", + "extensions": [], + "operations": [ + { + "type": "limit_order_cancel_operation", + "value": { + "owner": "paco-steem", + "orderid": 1243424767 + } + }, + { + "type": "limit_order_cancelled_operation", + "value": { + "seller": "paco-steem", + "orderid": 1243424767, + "amount_back": { + "nai": "@@000000013", + "amount": "19276", + "precision": 3 + } + } + } + ], + "signatures": [ + "1f7de4d1ea38b5ddb2de499242aacc92d3fff529a74264c568114a48bf4182e4e775bd757cd718cb31b92017279bc781d7282be48abf615aa856bf6828a53b7fe1" + ], + "ref_block_num": 19262, + "ref_block_prefix": 2888755715 + } + ], + "transaction_ids": [ + "9f4639be729f8ca436ac5bd01b5684cbc126d44d", + "8f2a70dbe09902473eac39ffbd8ff626cb49bb51", + "a9596ee741bd4b4b7d3d8cadd15416bfe854209e", + "b664e368d117e0b0d4b1b32325a18044f47b5ca5" + ], + "witness_signature": "1f4a3e6e868c4b729790e64b0656cf12996f35010dd07b535a502b019080c849c75f370642b00e302d003def5e6b2280246b08ee8ab37824af4664ab740a79b940", + "transaction_merkle_root": "708e4d6a2a722ef7fecc58d1f177a2826e54edd3" + } \ No newline at end of file diff --git a/tests/tavern/get_block/positive/include_virtual.tavern.yaml b/tests/tavern/get_block/positive/include_virtual.tavern.yaml new file mode 100644 index 000000000..d47720c85 --- /dev/null +++ b/tests/tavern/get_block/positive/include_virtual.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_block" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "4999999" + include-virtual: true + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block/positive/last.pat.json b/tests/tavern/get_block/positive/last.pat.json new file mode 100644 index 000000000..81bca845f --- /dev/null +++ b/tests/tavern/get_block/positive/last.pat.json @@ -0,0 +1,101 @@ +{ + "witness": "ihashfury", + "block_id": "004c4b40245ffb07380a393fb2b3d841b76cdaec", + "previous": "004c4b3fc6a8735b4ab5433d59f4526e4a042644", + "timestamp": "2016-09-15T19:47:21", + "extensions": [], + "signing_key": "STM8aUs6SGoEmNYMd3bYjE1UBr6NQPxGWmTqTdBaxJYSx244edSB2", + "transactions": [ + { + "expiration": "2016-09-15T19:47:33", + "extensions": [], + "operations": [ + { + "type": "account_create_operation", + "value": { + "fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + }, + "owner": { + "key_auths": [ + [ + "STM871wj5KKnbwwiRv3scVcxQ26ynPnE1uaZr6dPpqVu9F4zJZgjZ", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "active": { + "key_auths": [ + [ + "STM73bAnWEwkdUa7Lp4ovNzyu4soHUCaCNSz79YHQsDqscNdSe1E8", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "creator": "steem", + "posting": { + "key_auths": [ + [ + "STM7fXKrnQN3xhgFTQBFMgR9TU8CxfgAJrLvSDjGuM2bFkiuKfwZg", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "memo_key": "STM8i93Zznxu2QRNLCHBDXt5yyiMW1c3GEyVKV9XAs8H5wEWwdJaM", + "json_metadata": "", + "new_account_name": "kefadex" + } + } + ], + "signatures": [ + "1f63c75cc966916ea705a6fdef0821a810bdabb07118a3721f4cd52c972b9e4522534248c45ac908c1498752165a1d937eaf55ab6c028d7ee0ad893d3d4330d066" + ], + "ref_block_num": 19263, + "ref_block_prefix": 1534306502 + }, + { + "expiration": "2016-09-15T19:47:48", + "extensions": [], + "operations": [ + { + "type": "limit_order_create_operation", + "value": { + "owner": "cvk", + "orderid": 1473968838, + "expiration": "2035-10-29T06:32:22", + "fill_or_kill": false, + "amount_to_sell": { + "nai": "@@000000021", + "amount": "10324", + "precision": 3 + }, + "min_to_receive": { + "nai": "@@000000013", + "amount": "6819", + "precision": 3 + } + } + } + ], + "signatures": [ + "203e8ef6d16005180dc06756462bd867513a929bc4fa7c45f24ca2b0763cafdb06678812d777216f46d205e68a740dd19e32a1aa1a1df022500c0f1ef97800d0e0" + ], + "ref_block_num": 19263, + "ref_block_prefix": 1534306502 + } + ], + "transaction_ids": [ + "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "973290d26bac31335c000c7a3d3fe058ce3dbb9f" + ], + "witness_signature": "1f6aa1c6311c768b5225b115eaf5798e5f1d8338af3970d90899cd5ccbe38f6d1f7676c5649bcca18150cbf8f07c0cc7ec3ae40d5936cfc6d5a650e582ba0f8002", + "transaction_merkle_root": "97a8f2b04848b860f1792dc07bf58efcb15aeb8c" +} \ No newline at end of file diff --git a/tests/tavern/get_block/positive/last.tavern.yaml b/tests/tavern/get_block/positive/last.tavern.yaml new file mode 100644 index 000000000..fbf253ca8 --- /dev/null +++ b/tests/tavern/get_block/positive/last.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_block" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block_header/negative/non_existent.pat.json b/tests/tavern/get_block_header/negative/non_existent.pat.json new file mode 100644 index 000000000..7d466aa44 --- /dev/null +++ b/tests/tavern/get_block_header/negative/non_existent.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Block_num '5000001' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_block_header/negative/non_existent.tavern.yaml b/tests/tavern/get_block_header/negative/non_existent.tavern.yaml new file mode 100644 index 000000000..244407961 --- /dev/null +++ b/tests/tavern/get_block_header/negative/non_existent.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_block_header" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000001" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_block_header/positive/first_block.pat.json b/tests/tavern/get_block_header/positive/first_block.pat.json new file mode 100644 index 000000000..ba57df3c1 --- /dev/null +++ b/tests/tavern/get_block_header/positive/first_block.pat.json @@ -0,0 +1,7 @@ +{ + "witness": "initminer", + "previous": "0000000000000000000000000000000000000000", + "timestamp": "2016-03-24T16:05:00", + "extensions": [], + "transaction_merkle_root": "0000000000000000000000000000000000000000" +} \ No newline at end of file diff --git a/tests/tavern/get_block_header/positive/first_block.tavern.yaml b/tests/tavern/get_block_header/positive/first_block.tavern.yaml new file mode 100644 index 000000000..9e0d65810 --- /dev/null +++ b/tests/tavern/get_block_header/positive/first_block.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_block_header" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "1" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block_header/positive/last.pat.json b/tests/tavern/get_block_header/positive/last.pat.json new file mode 100644 index 000000000..3ec4debf8 --- /dev/null +++ b/tests/tavern/get_block_header/positive/last.pat.json @@ -0,0 +1,7 @@ +{ + "witness": "ihashfury", + "previous": "004c4b3fc6a8735b4ab5433d59f4526e4a042644", + "timestamp": "2016-09-15T19:47:21", + "extensions": [], + "transaction_merkle_root": "97a8f2b04848b860f1792dc07bf58efcb15aeb8c" +} \ No newline at end of file diff --git a/tests/tavern/get_block_header/positive/last.tavern.yaml b/tests/tavern/get_block_header/positive/last.tavern.yaml new file mode 100644 index 000000000..7d857ecd5 --- /dev/null +++ b/tests/tavern/get_block_header/positive/last.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_block_header" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block_range/positive/first_blocks.pat.json b/tests/tavern/get_block_range/positive/first_blocks.pat.json new file mode 100644 index 000000000..71918615a --- /dev/null +++ b/tests/tavern/get_block_range/positive/first_blocks.pat.json @@ -0,0 +1,242 @@ +[ + { + "witness": "initminer", + "block_id": "0000000109833ce528d5bbfb3f6225b39ee10086", + "previous": "0000000000000000000000000000000000000000", + "timestamp": "2016-03-24T16:05:00", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "204f8ad56a8f5cf722a02b035a61b500aa59b9519b2c33c77a80c0a714680a5a5a7a340d909d19996613c5e4ae92146b9add8a7a663eef37d837ef881477313043", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000002ed04e3c3def0238f693931ee7eebbdf1", + "previous": "0000000109833ce528d5bbfb3f6225b39ee10086", + "timestamp": "2016-03-24T16:05:36", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f3e85ab301a600f391f11e859240f090a9404f8ebf0bf98df58eb17f455156e2d16e1dcfc621acb3a7acbedc86b6d2560fdd87ce5709e80fa333a2bbb92966df3", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "000000035b094a812646289c622dba0ba67d1ffe", + "previous": "00000002ed04e3c3def0238f693931ee7eebbdf1", + "timestamp": "2016-03-24T16:05:39", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "205ad1d3f0d42abcfdacb179de1acecf873be432cc546dde6b35184d261868b47b17dc1717b78a1572843fdd71a654e057db03f2df5d846b71606ec80455a199a6", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000004f9de0cfeb08c9d7d9d1fe536d902dc4a", + "previous": "000000035b094a812646289c622dba0ba67d1ffe", + "timestamp": "2016-03-24T16:05:42", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "202c7e5cada5104170365a83734a229eac0e427af5ed03fe2268e79bb9b05903d55cb96547987b57cd1ba5ed1a5ae1a9372f0ee6becfd871c2fcc26dc8b057149e", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000005014b5562a1133070d8bee536de615329", + "previous": "00000004f9de0cfeb08c9d7d9d1fe536d902dc4a", + "timestamp": "2016-03-24T16:05:45", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f508f1124db7f1442946b5e3b3a5f822812e54e18dffcda83385a9664b825d27214f0cdd0a0a7e7aeb6467f428fbc291c6f64b60da29e8ad182c20daf71b68b8b", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000006e323e35687e160b8aec86f1e56d4c902", + "previous": "00000005014b5562a1133070d8bee536de615329", + "timestamp": "2016-03-24T16:05:48", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f6bcfe700cc88f5c91fbc82fdd46623fed31c95071dbfedafa9faaad76ac788527658fb11ae57a602feac3d8a5b8d2ec4c47ef361b9f64d5b9db267642fc78bc3", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "000000079ff02a2dea6c4d9a27f752233d4a66b4", + "previous": "00000006e323e35687e160b8aec86f1e56d4c902", + "timestamp": "2016-03-24T16:05:51", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f5202b4570f1b0d8b197a5f5729389e762ca7e6b74d179d54c51cf4f79694eb130c2cc39d31fa29e2d54dc9aa9fab83fedba981d415e0b341f0040183e2d1997c", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "000000084f957cc170a27c8330293a3343f82c23", + "previous": "000000079ff02a2dea6c4d9a27f752233d4a66b4", + "timestamp": "2016-03-24T16:05:54", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "2050e555bd40af001737ccebc03d4b6e104eaa9f46f1acac03f9d4dd1b7af3cf1c45c6e232364fda7f6c72ff2942d0a35d148ee4b6ba52332c11c3b528cd01d8c3", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000009f35198cfd8a866868538bed3482d61a4", + "previous": "000000084f957cc170a27c8330293a3343f82c23", + "timestamp": "2016-03-24T16:05:57", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "2044cd87f6f0a98b37c520b61349de4b36ab82aa8cc799c7ce0f14635ae2a266b02412af616deecba6cda06bc1f3823b2abd252cfe592643920e67ccdc73aef6f9", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "0000000aae44a2f4d57170dab16fb1619f9e1d0e", + "previous": "00000009f35198cfd8a866868538bed3482d61a4", + "timestamp": "2016-03-24T16:06:00", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f6ac53a8bb6ca885e988baafb1363b98e8807f62e6256462269b7288c568010096402d9bd2d8a69549568477f79570e8a41474daee2b7d29c623a0b5649081417", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "0000000bdf319c4c568d696ab4e58b935a20d343", + "previous": "0000000aae44a2f4d57170dab16fb1619f9e1d0e", + "timestamp": "2016-03-24T16:06:03", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f4deed32395e69b61df58aeee6fc0aa0a7025cbe78c8c45b8b0d59fa154fbae585831579727b315292fa81aba7b624f463894eaa67bb2cba105516abe3a9a2686", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "0000000ca60eb6a46126502eaf50eaed19d3a6ed", + "previous": "0000000bdf319c4c568d696ab4e58b935a20d343", + "timestamp": "2016-03-24T16:06:06", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f6a4896277d9b15d7f027ba6846b320c75973c63a73901d5ca8217f8f851af2ec4024f1f14a2f3330f5bd7e1a1f0b1b49bb1adf4785b6a129fadb77443c51dc37", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "0000000dee90bb7feb94b7c15a6dcd84e79e8706", + "previous": "0000000ca60eb6a46126502eaf50eaed19d3a6ed", + "timestamp": "2016-03-24T16:06:09", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f1505a740f3c5fa2559a3213aab9b60e26b929e5fc6b5c21ea052f64d33a7f6026899051fddd52d57cad1a1806a55f1b71a4c1783a49dd9208e00b3b9fe1ba653", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "0000000ecbc2984c4505a1957e55de29facbc7f9", + "previous": "0000000dee90bb7feb94b7c15a6dcd84e79e8706", + "timestamp": "2016-03-24T16:06:12", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "2005cfb2f3291102daa5d73bc524e1084b1743a2851f762d0c417db2ec59e53400715ec2de64953e8cc3487b963465adbbe388a367207bc36d6c4139973fb0a558", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "0000000feabd7814909670c6c166c2c535b1be55", + "previous": "0000000ecbc2984c4505a1957e55de29facbc7f9", + "timestamp": "2016-03-24T16:06:15", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "204fc34697dba2f7082ee6af736a12dbbcc22d9adcea54d4c038407102c73fe2997a08204d548bb9c1bd43bbdfd3c377dab1b328a0223197f7911154a3dfb10a54", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "000000105ae15ac3352ef72102bb6d8685ada410", + "previous": "0000000feabd7814909670c6c166c2c535b1be55", + "timestamp": "2016-03-24T16:06:18", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f420e04824a7fda51354f712a899afe1ee5f1f8519904b252f2dfd9ae755a10880cebeb9decaf1fb3fd7401b7366805a11a1ebd0ef5aa39435f0e58489bdc1afe", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000011cb45000fd0731cb5031e8cf91b894475", + "previous": "000000105ae15ac3352ef72102bb6d8685ada410", + "timestamp": "2016-03-24T16:06:21", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "204caa902b1992aaf152e8f6d4df8e6dc05f11cafd6ae6dae2fbaac4d747f4e32f38b11d10f7494a70c32dd530003ce98f463f7b71ae540319d54f6659454389be", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000012ae4e30d0f532ad03430e939306a24caf", + "previous": "00000011cb45000fd0731cb5031e8cf91b894475", + "timestamp": "2016-03-24T16:06:24", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f0166390c118aa17414acce47f076acad1f3693d290b04e4b17f6edf78558f1134a7518a1fa4c3964660943363693e7b63f061dbcb60b24927f22f5c0c6e7cadc", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "000000138828e4c4633cc0f1c9f5eb56b2988c54", + "previous": "00000012ae4e30d0f532ad03430e939306a24caf", + "timestamp": "2016-03-24T16:06:27", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "201b7fc9347546a6631385267c45bb836aa0fe80f33a6fd53fdf773c6dfd98c9ec4754297afd701cae2779ec735f996594da5588c9d188490f237ddba6133bcfbe", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "initminer", + "block_id": "00000014d3da0c77ff9f19abbba6a7e6b7a91240", + "previous": "000000138828e4c4633cc0f1c9f5eb56b2988c54", + "timestamp": "2016-03-24T16:06:30", + "extensions": [], + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f3c677d45038e42b9d28cb12cb9d058ebd6726d31fc0a0cca0ed71f07e5cef83a6979fdf6c85648790ea111eb65653347abe92e9240435f9c491bf651b2251765", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + } +] \ No newline at end of file diff --git a/tests/tavern/get_block_range/positive/first_blocks.tavern.yaml b/tests/tavern/get_block_range/positive/first_blocks.tavern.yaml new file mode 100644 index 000000000..1d3492307 --- /dev/null +++ b/tests/tavern/get_block_range/positive/first_blocks.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_block_range" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "1" + to-block: "20" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block_range/positive/latest_blocks.pat.json b/tests/tavern/get_block_range/positive/latest_blocks.pat.json new file mode 100644 index 000000000..d21ec750d --- /dev/null +++ b/tests/tavern/get_block_range/positive/latest_blocks.pat.json @@ -0,0 +1,1279 @@ +[ + { + "witness": "riverhead", + "block_id": "004c4b2dd5e06813a7336029ef10bf2b485c0bf4", + "previous": "004c4b2c7d5efe1a22b6afca7989c2230d8cc48c", + "timestamp": "2016-09-15T19:46:21", + "extensions": [], + "signing_key": "STM7iHUr9PfAmWphaP6QniRUWwJp8yrL9UF2z1Wos155aUCcsi5Ly", + "transactions": [ + { + "expiration": "2016-09-15T19:46:30", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "What about tobacco for rolies and dry milk ;-)", + "title": "", + "author": "serejandmyself", + "permlink": "re-charlieshrem-mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem-20160915t194635924z", + "json_metadata": "{\"tags\":[\"story\"]}", + "parent_author": "charlieshrem", + "parent_permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + } + ], + "signatures": [ + "202543ea42b695e5a9512fb1c2774ecfcf39334b91cf5257d30a4901209a417e53269f3cf36963a4cafc134145f40c47ce95b120cc964fcec7837a83837bfc9db0" + ], + "ref_block_num": 19139, + "ref_block_prefix": 985313708 + }, + { + "expiration": "2016-09-15T19:46:33", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "alienbutt", + "author": "moon32walker", + "weight": 10000, + "permlink": "top-10-game-development-studios" + } + } + ], + "signatures": [ + "1f41c8bb37f2e5536d1aac9762d4e21bfe0bd3100c649cc803adc59a954dce5d091c1ed96144d8874dea0825fdee8539ac688cfcfc09ae2282a4fa37b9da3b950d" + ], + "ref_block_num": 19238, + "ref_block_prefix": 1041742178 + } + ], + "transaction_ids": [ + "b65a665ee5638f3fbb32158a1ce78d5dd8d88099", + "b34c25913379195bf0aa146f337c03f56aea2758" + ], + "witness_signature": "200f8ca2611ce7c6e4973428c01252ea097e5378b4187c91d5b37aaf003db27f1473d24d38ae276f070f2fd508d903412a7636088d0f9d83bb15dbbe26d9e29f64", + "transaction_merkle_root": "ffc40795342466a471ec1586397b8922d8652850" + }, + { + "witness": "complexring", + "block_id": "004c4b2e6fcc40a9bc6fb88b5a007c53f323667e", + "previous": "004c4b2dd5e06813a7336029ef10bf2b485c0bf4", + "timestamp": "2016-09-15T19:46:24", + "extensions": [], + "signing_key": "STM6t7b3G3B5d81yoqqFdHzSPgvAHeZd1dZk4nq2CN57TM5pqi3vt", + "transactions": [ + { + "expiration": "2016-09-15T19:46:36", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "gtg", + "author": "skypilot", + "weight": 10000, + "permlink": "sunset-at-point-sur-california" + } + } + ], + "signatures": [ + "1f4bb3676ab7ecf0c6240c038e9d04db595f2019fdc2459f9d72487ee116e204164b26cb2fb0ea1b1f45462c3ed1797c184869884e39e663b16b40640bbf59e53d" + ], + "ref_block_num": 18508, + "ref_block_prefix": 3262261547 + } + ], + "transaction_ids": [ + "fa7c8ac738b4c1fdafd4e20ee6ca6e431b641de3" + ], + "witness_signature": "1f04f65af98d2a9bf0e9b861bc8a3ac5704b84bc7059dd1f5d2e4d8bab14cca48103d3af9952309ac75179b9e97f27250fd583082d1f9136f13b5a72616e6d1fcc", + "transaction_merkle_root": "4a90ef9213fa7455ffc802d54d1acf52e398460f" + }, + { + "witness": "xeldal", + "block_id": "004c4b2fcc33024688d4b37dd3e19f95d62da55e", + "previous": "004c4b2e6fcc40a9bc6fb88b5a007c53f323667e", + "timestamp": "2016-09-15T19:46:27", + "extensions": [], + "signing_key": "STM79MPWvm711VWvXfY7Y3FYtsLgwyN55bSEZQqxxMN8m2W9ygQtR", + "transactions": [ + { + "expiration": "2016-09-15T19:46:39", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "andrew0", + "author": "acidyo", + "weight": 10000, + "permlink": "drew-an-avatar-signature-for-my-posts" + } + } + ], + "signatures": [ + "1f1e2806118f3f5cb001c407ef19130620d761d451fd02710dd112c4715429de757ad38a977083a2140bbb3cffe06c8a6bcfbc8c436baa3bba6a11cf4b631b3431" + ], + "ref_block_num": 19243, + "ref_block_prefix": 4274362616 + } + ], + "transaction_ids": [ + "919f249ed5e40fd86f71d216921ff85ad281ffc7" + ], + "witness_signature": "1f7e9a4834e55d08faa8999fe7433154958cab79793e48ae4d3f89797b979d95da69ca61adcd26a68226474c06ac0a606111db57e648e047fc0b3674e8d9bb05e8", + "transaction_merkle_root": "33ec63c31d4a88b992e0828320e971dda60f3b0e" + }, + { + "witness": "smooth.witness", + "block_id": "004c4b30aacfa0e68a46850c147df1a57f02ef75", + "previous": "004c4b2fcc33024688d4b37dd3e19f95d62da55e", + "timestamp": "2016-09-15T19:46:30", + "extensions": [], + "signing_key": "STM5jtPaM5G2jemsqTY8xYgy3CVUgzygKn7vUVpFozr6nWcCJ8mDW", + "transactions": [ + { + "expiration": "2016-09-15T19:46:39", + "extensions": [], + "operations": [ + { + "type": "limit_order_create_operation", + "value": { + "owner": "hyiparena", + "orderid": 1473968769, + "expiration": "1969-12-31T23:59:59", + "fill_or_kill": false, + "amount_to_sell": { + "nai": "@@000000021", + "amount": "100000", + "precision": 3 + }, + "min_to_receive": { + "nai": "@@000000013", + "amount": "66100", + "precision": 3 + } + } + } + ], + "signatures": [ + "1f793234b3e74cf0d1a1f219f646d08db87c5bd4db54bfa090804d4ca4519423f54d19d2a27e6ff1b694d884bf2b8a34170aa2a96f4147cf4f7d463bc7b20462f8" + ], + "ref_block_num": 17990, + "ref_block_prefix": 4150570573 + } + ], + "transaction_ids": [ + "4414458344d2cf3391059d3ede608df02480cdb4" + ], + "witness_signature": "20305d9e44cd9fa54d2377ac5ea99b0eb34a61c98d70847b882261d0f783016ab052a72e3e47481e1f907a706d7eb3f951656bab29ee46bd961ac61af20e72a500", + "transaction_merkle_root": "ad80c77b38bc7edc448e07919f329f87979f5952" + }, + { + "witness": "rabbit-28", + "block_id": "004c4b31058c762d25d74036a50ffbe045c82ff5", + "previous": "004c4b30aacfa0e68a46850c147df1a57f02ef75", + "timestamp": "2016-09-15T19:46:33", + "extensions": [], + "signing_key": "STM6wAGpCZPRsy4bx2YxbpBEKAeTnLe4vcC9EuQ6fgYFzswrpABC9", + "transactions": [ + { + "expiration": "2016-09-15T19:46:42", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "The Texas Rangers are 33-10 (.767) in one-run games this season. This would stand as a modern record for winning percentage in one-run games, besting the 2012 Orioles, who were 29-9 (.763).\n\n<h1><center>http://images.performgroup.com/di/library/sporting_news/a3/fa/texasrangers-getty-ftr-091516jpg_9u1oo1fjvsue1twr2494i9qcn.jpg?t=766994815</center></h1>\n\nBut if we dig deep into the archives of baseball history, we learn that this is actually the best record since the 1890 Brooklyn Bridegrooms, who were 14-4 (.778) in one-run games en route to an overall 86-43 (.667) record and the National League pennant.\n\n**Source / Read More...** <a href='http://www.sportingnews.com/mlb/news/texas-rangers-record-in-one-run-games-brooklyn-bridegrooms/irlcvzvv8fui1vgogevkmomch\n'>sportingnews.com</a> \n\n<hr>\n\n<center><img src='https://ipfs.pics/ipfs/QmUo1EuVPSs3prLRdJH95Lg97vyvzSfhH6srZH5bqRh7p6'></center>\n\n**NEWS FEED** \n*Get the latest headlines from around the world right on your Steemit Feed! With @newsfeed you always stay in the know about all sorts of topics ranging from Politics & Finance to Sports*\n\n**Currently In Beta**\n*Full news feed from hand picked creditable sources from all sides of the political and social realm. Although not fully operational, posts will be random while testing BUT do have real headlines!*", + "title": "Rangers' record in one-run games nearing truly historic level", + "author": "newsfeed", + "permlink": "rangers-record-in-one-run-games-nearing-truly-historic-level", + "json_metadata": "{\"tags\":[\"newsfeed\",\"news\",\"sports\",\"rangers\",\"baseball\"],\"users\":[\"newsfeed\"],\"image\":[\"http://images.performgroup.com/di/library/sporting_news/a3/fa/texasrangers-getty-ftr-091516jpg_9u1oo1fjvsue1twr2494i9qcn.jpg?t=766994815\",\"https://ipfs.pics/ipfs/QmUo1EuVPSs3prLRdJH95Lg97vyvzSfhH6srZH5bqRh7p6\"],\"links\":[\"http://www.sportingnews.com/mlb/news/texas-rangers-record-in-one-run-games-brooklyn-bridegrooms/irlcvzvv8fui1vgogevkmomch\\n\"]}", + "parent_author": "", + "parent_permlink": "newsfeed" + } + }, + { + "type": "vote_operation", + "value": { + "voter": "newsfeed", + "author": "newsfeed", + "weight": 10000, + "permlink": "rangers-record-in-one-run-games-nearing-truly-historic-level" + } + }, + { + "type": "comment_options_operation", + "value": { + "author": "newsfeed", + "permlink": "rangers-record-in-one-run-games-nearing-truly-historic-level", + "extensions": [], + "allow_votes": true, + "percent_hbd": 0, + "max_accepted_payout": { + "nai": "@@000000013", + "amount": "1000000000", + "precision": 3 + }, + "allow_curation_rewards": true + } + } + ], + "signatures": [ + "204ebc722331263b2dcff0ca1a54dc647c2b945c3a4dda19ba76ace743b673cc315b6e656aa35e765632345177e6e1c484e03fcf7f09cf8d2adef3a388351a9243" + ], + "ref_block_num": 19207, + "ref_block_prefix": 353650013 + }, + { + "expiration": "2016-09-15T19:46:45", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "<html>\n<h2>Model of Skeleton hands,without scissors and glue.</h2>\n<a href='https://postimg.org/image/byivq2oqt/' target='_blank'><img src='https://s18.postimg.org/fi4tfvrgp/image.jpg' border='0' alt='1'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n<a href='https://postimg.org/image/ivepluv0b/' target='_blank'><img src='https://s9.postimg.org/kn7ogredb/image.jpg' border='0' alt='2'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n\n<p><br></p>\n<h2>I need a piece of paper.</h2>\n<a href='https://postimg.org/image/efv1n0qmt/' target='_blank'><img src='https://s10.postimg.org/nnna3pxp5/image.jpg' border='0' alt='3'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n<a href='https://postimg.org/image/u9lgfmvnt/' target='_blank'><img src='https://s12.postimg.org/dltyd50wd/image.jpg' border='0' alt='4'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n<a href='https://postimg.org/image/gzhee9knd/' target='_blank'><img src='https://s12.postimg.org/qwsf7bs99/image.jpg' border='0' alt='5'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n<a href='https://postimg.org/image/gwtumvm6n/' target='_blank'><img src='https://s3.postimg.org/7p1m66f4j/image.jpg' border='0' alt='6'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n<a href='https://postimg.org/image/55ifcrhhp/' target='_blank'><img src='https://s22.postimg.org/4388u7yoh/image.jpg' border='0' alt='7'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n<a href='https://postimg.org/image/4cbh56p1p/' target='_blank'><img src='https://s14.postimg.org/qo99yko5t/image.jpg' border='0' alt='1'/><br /><a target='_blank' href='https://postimage.org/index.php?lang=russian'></a><br /><br />\n<h2><a href=\"https://steemit.com/art/@anton333/origami-start-with-the-simplest\">Part 1</a> <a href=\"https://steemit.com/art/@anton333/origami-part-two-do-a-swan\">Part 2 </a><a href=\"https://steemit.com/art/@anton333/origami-part-3-the-model-of-a-mouse\">Part 3 </a><a href=\"https://steemit.com/art/@anton333/origami-part-4-the-model-of-a-rose-petals\">Part4 </a><a href=\"https://steemit.com/art/@anton333/origami-part-5-the-model-of-master-yoda\">Part5 </a><a href=\"https://steemit.com/art/@anton333/origami-part-6-the-model-of-eagle\">Part6 </a><a href=\"https://steemit.com/art/@anton333/origami-part-7-the-model-of-dagger\">Part7 </a><a href=\"https://steemit.com/art/@anton333/origami-part-8-the-model-of-spider\">Part8 </a><a href=\"https://steemit.com/art/@anton333/origami-part-9-the-model-of-tooth\">Part9 </a><a href=\"https://steemit.com/art/@anton333/origami-part-10-the-model-of-flower\">Part10</a></h2>\n</html>", + "title": "Origami Part 11, the model of Skeleton hands.", + "author": "anton333", + "permlink": "origami-part-11-the-model-of-skeleton-hands", + "json_metadata": "{\"tags\":[\"art\",\"photography\",\"origami\"],\"image\":[\"https://s18.postimg.org/fi4tfvrgp/image.jpg\",\"https://s9.postimg.org/kn7ogredb/image.jpg\",\"https://s10.postimg.org/nnna3pxp5/image.jpg\",\"https://s12.postimg.org/dltyd50wd/image.jpg\",\"https://s12.postimg.org/qwsf7bs99/image.jpg\",\"https://s3.postimg.org/7p1m66f4j/image.jpg\",\"https://s22.postimg.org/4388u7yoh/image.jpg\",\"https://s14.postimg.org/qo99yko5t/image.jpg\"],\"links\":[\"https://postimg.org/image/byivq2oqt/\",\"https://postimage.org/index.php?lang=russian\",\"https://postimg.org/image/ivepluv0b/\",\"https://postimg.org/image/efv1n0qmt/\",\"https://postimg.org/image/u9lgfmvnt/\",\"https://postimg.org/image/gzhee9knd/\",\"https://postimg.org/image/gwtumvm6n/\",\"https://postimg.org/image/55ifcrhhp/\",\"https://postimg.org/image/4cbh56p1p/\",\"https://steemit.com/art/@anton333/origami-start-with-the-simplest\",\"https://steemit.com/art/@anton333/origami-part-two-do-a-swan\",\"https://steemit.com/art/@anton333/origami-part-3-the-model-of-a-mouse\",\"https://steemit.com/art/@anton333/origami-part-4-the-model-of-a-rose-petals\",\"https://steemit.com/art/@anton333/origami-part-5-the-model-of-master-yoda\",\"https://steemit.com/art/@anton333/origami-part-6-the-model-of-eagle\",\"https://steemit.com/art/@anton333/origami-part-7-the-model-of-dagger\",\"https://steemit.com/art/@anton333/origami-part-8-the-model-of-spider\",\"https://steemit.com/art/@anton333/origami-part-9-the-model-of-tooth\",\"https://steemit.com/art/@anton333/origami-part-10-the-model-of-flower\"]}", + "parent_author": "", + "parent_permlink": "art" + } + }, + { + "type": "vote_operation", + "value": { + "voter": "anton333", + "author": "anton333", + "weight": 10000, + "permlink": "origami-part-11-the-model-of-skeleton-hands" + } + } + ], + "signatures": [ + "1f1d5c7ba208b684cd17289214fe37666c25f241ec51cb254e9d7655103fe3f21f14995a14a1047060ae92030d00a25a54afc797250cf8a2220dc2c06a421d18b1" + ], + "ref_block_num": 19027, + "ref_block_prefix": 2360052300 + } + ], + "transaction_ids": [ + "9a2986faad9224a69be77cc42c0cfa1348da9bc0", + "6d5f64d6a3bffd1872f1c48c479467a1fab2852c" + ], + "witness_signature": "1f77aa6b272d03641c1f528aca26081582841cf35da11501c3ae30d28672732fc51f941757095e030385084a05689437cca09e23920f538e1de09af9f26401f78e", + "transaction_merkle_root": "f941d53ce6227aecbce48145196d79483205a679" + }, + { + "witness": "roadscape", + "block_id": "004c4b32e32a6e465b2c8b1fe29fba6fc47bfda3", + "previous": "004c4b31058c762d25d74036a50ffbe045c82ff5", + "timestamp": "2016-09-15T19:46:36", + "extensions": [], + "signing_key": "STM5AS7ZS33pzTf1xbTi8ZUaUeVAZBsD7QXGrA51HvKmvUDwVbFP9", + "transactions": [ + { + "expiration": "2016-09-15T19:46:45", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "Doctor have feelings to husband?", + "title": "", + "author": "vi1son", + "permlink": "re-mcsvi-black-story-challenge-2-can-you-solve-the-riddle-20160915t194632254z", + "json_metadata": "{\"tags\":[\"story\"]}", + "parent_author": "mcsvi", + "parent_permlink": "black-story-challenge-2-can-you-solve-the-riddle" + } + } + ], + "signatures": [ + "200f86435237a2ebd9e7f15ad95332ed88924317bd0fd596f7c0f8a841badb6399571c9de981bc4908d0c1cb303fbe12e20421405054bfcc3d26ee56730c106efa" + ], + "ref_block_num": 19232, + "ref_block_prefix": 2490936436 + }, + { + "expiration": "2016-09-15T19:46:45", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "mohamedmashaal", + "author": "larrytom", + "weight": -10000, + "permlink": "my-brother-s-heroin-addiction-destroyed-our-family" + } + } + ], + "signatures": [ + "202a4b53acc28b74332b29645b0820c406bda89ec2cd9e24f3453ef8b0e755a68a6506ae1c0f880eb63a8f652b41ea1a32542f0d573c2034cdf1cd6fe85c92c4c0" + ], + "ref_block_num": 19246, + "ref_block_prefix": 2839596143 + } + ], + "transaction_ids": [ + "015cc6c168603beaab75c3cda37fa8c47fc5c226", + "e48c5952287770faea58cbf13b30773d2b90f442" + ], + "witness_signature": "20449a998c10a377f7555f7adbffabe1c4e758c7dd1ba989a6da93251b771e69642b52d22ee9b257387748ca816b803abddd538a95d872fe4bf876a12f1e941d97", + "transaction_merkle_root": "8dd25b7ea0bb0aaeb331339f49d971da1145e732" + }, + { + "witness": "steemed", + "block_id": "004c4b33bbaffe2c15dd55c7346c6ef1d064e0fb", + "previous": "004c4b32e32a6e465b2c8b1fe29fba6fc47bfda3", + "timestamp": "2016-09-15T19:46:42", + "extensions": [], + "signing_key": "STM8RR6DMdcehSLgvbDcWsCaYowkvKGYv4EVaubtNZyb2gBst7kS2", + "transactions": [ + { + "expiration": "2016-09-15T19:46:48", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "honeythief", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + } + ], + "signatures": [ + "1f7af24d64c8d1545286c67be48835cfaef727be9d1c32672231e8c8e02a8435621377f6bb4486efbf04bd178f5016ee3bffd651c08c0d3bb3dde852b35b6f3112" + ], + "ref_block_num": 19247, + "ref_block_prefix": 1174549452 + }, + { + "expiration": "2016-09-15T19:46:51", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "Yes! Motivation is always what kills it for me. Having the potential for rewards and a crew at my back (pushing me up that damn hill) will change everything!", + "title": "", + "author": "reneenouveau", + "permlink": "re-herpetologyguy-re-reneenouveau-nanowrimo-6-weeks-away-come-join-a-steemit-writing-team-20160915t194633638z", + "json_metadata": "{\"tags\":[\"nanowrimo\"]}", + "parent_author": "herpetologyguy", + "parent_permlink": "re-reneenouveau-nanowrimo-6-weeks-away-come-join-a-steemit-writing-team-20160915t194346152z" + } + } + ], + "signatures": [ + "20669252d29cf315efb79b05b467c8b144ec13539bdf4e6195cca285c336e01cea192a11052f093376cbd128d77e18be2e2746d443f897d9f5a457e65168e2a568" + ], + "ref_block_num": 19234, + "ref_block_prefix": 2598030115 + }, + { + "expiration": "2016-09-15T19:46:51", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "satoshifund", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + } + ], + "signatures": [ + "2033886dd7b264bcec1b44efad2aa250532377817836ce0160c62ec28deb8647672f3540cbedc03facd7fbeae1cc0891320e7a95a4d7b0a5fe27b4d9af9e390633" + ], + "ref_block_num": 19248, + "ref_block_prefix": 3869298602 + }, + { + "expiration": "2016-09-15T19:46:48", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "Many killed in the Tel Aviv cafe attacks a few months ago....Errrr...YES!", + "title": "", + "author": "mindhunter", + "permlink": "re-lifeworship-re-mindhunter-the-mindhunter-fuel-required-for-another-creative-steemit-day-is-20160915t194633904z", + "json_metadata": "{\"tags\":[\"life\"]}", + "parent_author": "lifeworship", + "parent_permlink": "re-mindhunter-the-mindhunter-fuel-required-for-another-creative-steemit-day-is-20160915t163258559z" + } + } + ], + "signatures": [ + "207930210a54d0f0f774a036e2c7c4175e13060d5b46007f6ddab21bbdcaaec0437a504a80d624cad9cba46146fbfd8a03a991803f81ec27d7c9d29753e72d467c" + ], + "ref_block_num": 19217, + "ref_block_prefix": 942178671 + } + ], + "transaction_ids": [ + "4710584d7e76e319c525de0cf147c9a7d04e37d7", + "9a2060802b5263097443e63fe0ebd1f81791015a", + "dd6cab312671414542a2343bd006e7af2113a9e0", + "24ea3a4cdc4f5b1e0fad44628fba13fbaece3575" + ], + "witness_signature": "1f6154df530e0a70e7f60f61ab06584b1fd6169ce67b85efc3cfe8db1fffd3c1ff7d3ee079ae4406ce96f6ff122c0b6407463a0d67049b3b09d98c3f6f108ba2e7", + "transaction_merkle_root": "1e30363e05ff6dc732ecb25a3e1b5ad98d1e799f" + }, + { + "witness": "wackou", + "block_id": "004c4b34b3a880d62418087e6be8b96a926316fd", + "previous": "004c4b33bbaffe2c15dd55c7346c6ef1d064e0fb", + "timestamp": "2016-09-15T19:46:45", + "extensions": [], + "signing_key": "STM6b4ip3YpujNeyDKPsi1LE9h3sbmH7fNYUPFwmQXwrUS6SMmvq2", + "transactions": [], + "transaction_ids": [], + "witness_signature": "1f6e1d56f1112a115b234d335677cd8215ab33a6c29b7abe2405eda4a0142d629a01306663ae0a8175a49af76bf3e7eab5ba5e9f7a36d663f1ea5f50c3d85a2ddd", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "steemychicken1", + "block_id": "004c4b354a6e75723e55a9f51648db69a3ae758b", + "previous": "004c4b34b3a880d62418087e6be8b96a926316fd", + "timestamp": "2016-09-15T19:46:48", + "extensions": [], + "signing_key": "STM8c3RoBrpP3Xy4PNqT6T3pny3FiXu5qpoNPMEi15BQkLHK69zsA", + "transactions": [ + { + "expiration": "2016-09-15T19:46:57", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "alienbutt", + "author": "naquoya", + "weight": 10000, + "permlink": "original-fiction-bad-trip-part-two-the-gamemaster" + } + } + ], + "signatures": [ + "1f75e382f8a87e9676ec4b81fe9d68cd628000faf0fc403e1acf2a4383c277c87c712eddf6b7b09028c5f59b445318f123c1437440a9a88f21e0d486d49c9064b2" + ], + "ref_block_num": 19247, + "ref_block_prefix": 1174549452 + }, + { + "expiration": "2016-09-15T19:47:15", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "karen13", + "author": "charlieshrem", + "weight": 4000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + } + ], + "signatures": [ + "207bbbd01025397a89faa5b150b46c56d2f70c23d814671565ce9f769985bfefb4625853c00d6e16d6ea6744af99a37b83678559ccd8ef660beabefbc0da89bc4e" + ], + "ref_block_num": 19252, + "ref_block_prefix": 3598756019 + }, + { + "expiration": "2016-09-15T19:47:00", + "extensions": [], + "operations": [ + { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "[\"follow\",{\"follower\":\"abol\",\"following\":\"armanibadboy\",\"what\":[\"blog\"]}]", + "required_auths": [], + "required_posting_auths": [ + "abol" + ] + } + } + ], + "signatures": [ + "205133bb360217cff37d988206c50854d1a44ff47d580ef9ab780d378c7a167a0775f6e3e1b4dfbbd3351c163f7f23317d119044b1ec2ee3178d2f29cabdcb336e" + ], + "ref_block_num": 19248, + "ref_block_prefix": 3869298602 + } + ], + "transaction_ids": [ + "a61ac1e718624a9fa7f364bf77de5ede7766fe3d", + "36b0bc22b0749aba48c1dff9c0e1ef6c58037cc2", + "52cfdf79d9e9127ba0b8f9bcf0a866e3344d9ceb" + ], + "witness_signature": "1f70d595e89ac6c80b97e8170a0e8038ef8e3d1631b4bc43aab62b24d83bbc88b8723f172bde90ff05cd34057f3e0cf7d8b40ab6f9da6200e111103aa903f42b4c", + "transaction_merkle_root": "14f5751b9a0444aa65eada00483c7e90b38d0676" + }, + { + "witness": "jesta", + "block_id": "004c4b368c79d827e49dc904b6003d2cde917e94", + "previous": "004c4b354a6e75723e55a9f51648db69a3ae758b", + "timestamp": "2016-09-15T19:46:51", + "extensions": [], + "signing_key": "STM6hb6eCjQKtrPwkZcCGvLXchEkJHksHjUakbWzNHDeoBrVTgiUS", + "transactions": [ + { + "expiration": "2016-09-15T19:47:03", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "It was great, and the chimichurri made it super fresh and bright! Even the sweet potato leaf is edible!", + "title": "", + "author": "gardenofeden", + "permlink": "re-justtryme90-re-gardenofeden-mouthgasmic-steemy-food-love-wild-crafted-frittata-with-lemon-thai-basil-chimichurri-on-sweet-potato-leaves-from-our-free-5-20160915t194648613z", + "json_metadata": "{\"tags\":[\"food\"]}", + "parent_author": "justtryme90", + "parent_permlink": "re-gardenofeden-mouthgasmic-steemy-food-love-wild-crafted-frittata-with-lemon-thai-basil-chimichurri-on-sweet-potato-leaves-from-our-free-5-20160915t190246657z" + } + } + ], + "signatures": [ + "1f1f47419f46fe095dc8c77e79a2525e3b39dd5fb7b10a9d88568b91044921800b772a47216904ddc62a4eb07500413c8a8faa3d049185e2456e6008748772346b" + ], + "ref_block_num": 19219, + "ref_block_prefix": 3580998407 + }, + { + "expiration": "2016-09-15T19:47:18", + "extensions": [], + "operations": [ + { + "type": "transfer_operation", + "value": { + "to": "poloniex", + "from": "dantheman", + "memo": "bca2c4750fec82c9", + "amount": { + "nai": "@@000000021", + "amount": "28941000", + "precision": 3 + } + } + } + ], + "signatures": [ + "1f045b655ac1e3b2c8c35623d883371418bce42f96b1273e0cfa0c42e93af0b3cf0981cf205bd04f35ff77da1795844edde624888e99f52a9c2b590df6a14df917" + ], + "ref_block_num": 19253, + "ref_block_prefix": 1920298570 + }, + { + "expiration": "2016-09-15T19:47:03", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "This is cool, I would also change brightness contrast to have it on white background :)", + "title": "", + "author": "andrew0", + "permlink": "re-acidyo-drew-an-avatar-signature-for-my-posts-20160915t194706779z", + "json_metadata": "{\"tags\":[\"avatar\"]}", + "parent_author": "acidyo", + "parent_permlink": "drew-an-avatar-signature-for-my-posts" + } + } + ], + "signatures": [ + "1f61f6b87e7daef3b58880e132e0f57cc2d26e06e3316d51a63fbc70f5793332892252b5c10fa0e8dab332ca4a9376d6ab79fb91b224dbe1d01d82ad116a808869" + ], + "ref_block_num": 19243, + "ref_block_prefix": 4274362616 + } + ], + "transaction_ids": [ + "641b458efb92db5c6dc01fe8a9bb8ccf734caf83", + "13eb4b4b86ac951da54858815fbb527b27fce2c1", + "cd8c708c55c06606e80ccc1d7f68fde8ed314e37" + ], + "witness_signature": "20082df045c45dfd7c15978c02ec2bf5263692f1d81fc801affd130ee8048d47432b18eb9912a3868b36c43ba952f28b68276da82918398bdd3895b5efb5040a8e", + "transaction_merkle_root": "19f8234ed67df4283a317a919bb86b286e162a02" + }, + { + "witness": "pharesim", + "block_id": "004c4b3711994b2d2878be9fafec07d1190bfa52", + "previous": "004c4b368c79d827e49dc904b6003d2cde917e94", + "timestamp": "2016-09-15T19:46:54", + "extensions": [], + "signing_key": "STM7furk5jA9uBd2BUP65uoVKPfWtHC9JTAke5rgUhVJmjUY9V1yK", + "transactions": [ + { + "expiration": "2016-09-15T19:47:03", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "Thank you so much for the kind words. A lot of people single out Hitler as this wicked man (which he was) but they don't look at FDR, Churchill and the rest of the allied leaders and take them for the monsters the were. Statism by any other name is still immoral. \n\nI appreciate you reading/watching!", + "title": "", + "author": "highimpactflix", + "permlink": "re-merej99-re-highimpactflix-some-crazy-facts-about-hitler-and-world-war-2-that-may-surprise-you-20160915t194651604z", + "json_metadata": "{\"tags\":[\"forgottenhistory\"]}", + "parent_author": "merej99", + "parent_permlink": "re-highimpactflix-some-crazy-facts-about-hitler-and-world-war-2-that-may-surprise-you-20160915t151222492z" + } + } + ], + "signatures": [ + "2010d3c5f7c224bbbc08abb78189a6ae7d53d0d0c2368401eecc3a396b0d2f04bb13f7cf491fd0fe3e9da8ba295a344a5595c57e7b0c928c3cf19724bd704c284f" + ], + "ref_block_num": 19188, + "ref_block_prefix": 726992950 + }, + { + "expiration": "2016-09-15T19:47:00", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "mindhunter", + "author": "lifeworship", + "weight": 10000, + "permlink": "re-mindhunter-the-mindhunter-fuel-required-for-another-creative-steemit-day-is-20160915t163258559z" + } + } + ], + "signatures": [ + "206ae270203d26cf68ffdee2a2d0e5e46a8ade0d2d853abc16bc394580283be83477e68d816c3070079b70ad50e998725098ccc4229422119ab3ff8349cafae9b5" + ], + "ref_block_num": 19217, + "ref_block_prefix": 942178671 + }, + { + "expiration": "2016-09-15T19:47:06", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "murch", + "author": "fairytalelife", + "weight": 10000, + "permlink": "the-prison-of-depression" + } + } + ], + "signatures": [ + "1f16044be8c31b08494baa4f47a9d57ad731bd0f1ae2157ff843b9fbef726230d849362365063fa8703defeb09d9aaa48e5087c80a80a73cd30aa088994a707b31" + ], + "ref_block_num": 19144, + "ref_block_prefix": 1526510796 + }, + { + "expiration": "2016-09-15T19:47:06", + "extensions": [], + "operations": [ + { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "[\"follow\",{\"follower\":\"jens-jung\",\"following\":\"elyaque\",\"what\":[\"blog\"]}]", + "required_auths": [], + "required_posting_auths": [ + "jens-jung" + ] + } + } + ], + "signatures": [ + "1f473c512d5eaf3b87b7f5bb5a48484245ef0355c493c7f23295c90769c31e11bd049019261824a05ba3d445c0cd007e7c48d93c33a9f826c035a48fd3abc7717a" + ], + "ref_block_num": 19253, + "ref_block_prefix": 1920298570 + } + ], + "transaction_ids": [ + "0a8ef345c69e1401ca4ac849d932436799043241", + "4b9ef86001ea34d4d1c3be9a307b2b9e8e996189", + "014f18b60008d4f5985b3acd6703072d89beb2ac", + "b9506b77439b70980a59d5f202ec3722082033b8" + ], + "witness_signature": "20691c2e46697d4a118018d8ae975c6c0451ea85ee11feded93b396504a9c5893a74b5fab4add8fd4c75a409971f8d5a59a07793491a7b633c369055fae75b187b", + "transaction_merkle_root": "980536ffe2e0db1878def5e63412c0e2f3d71ba0" + }, + { + "witness": "blocktrades", + "block_id": "004c4b380a7c13ffc35af7d31fb0ca69ea6fe7b8", + "previous": "004c4b3711994b2d2878be9fafec07d1190bfa52", + "timestamp": "2016-09-15T19:46:57", + "extensions": [], + "signing_key": "STM4vmVc3rErkueyWNddyGfmjmLs3Rr4i7YJi8Z7gFeWhakXM4nEz", + "transactions": [ + { + "expiration": "2016-09-15T19:47:09", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "uwe69", + "author": "saamychristen", + "weight": 3000, + "permlink": "zitate-007-konfuzius" + } + } + ], + "signatures": [ + "1f4332f7d696ab9ebfad32e4eb082bf58d7b4fc0ef0611e105d40d04ec32a3396b297421050aad6dc6cfe2a5bc5fa787dac71eb0cf14241dd76bcf8e44f661e16f" + ], + "ref_block_num": 19246, + "ref_block_prefix": 2839596143 + } + ], + "transaction_ids": [ + "5b8100ffb6414e774de15752e0b2873b70cfdeea" + ], + "witness_signature": "203abc79a52a3c835ca68f50fe394dc6b8852e114858c060a3e36d0099c15314e93876252f7a9895e52e509167327836bf5d0c4aea22f8b29c1d9cc5546e0cc09b", + "transaction_merkle_root": "4a9d13311929e3787e9161620fb45ac565b9ea23" + }, + { + "witness": "arhag", + "block_id": "004c4b39994bee03aa28ad6cdad72f3f0e524f80", + "previous": "004c4b380a7c13ffc35af7d31fb0ca69ea6fe7b8", + "timestamp": "2016-09-15T19:47:00", + "extensions": [], + "signing_key": "STM8kvk4JH2m6ZyHBGNor4qk2Zwdi2MJAjMYUpfqiicCKu7HqAeZh", + "transactions": [], + "transaction_ids": [], + "witness_signature": "204e8773ef8a7d235f17b8496ac6472ac59b79ac20238082308f8b8015baacc2d766a3abdb6f3e4ffa33c6ecca554d04922b753b9cc6121896cbcc8716dcf773cf", + "transaction_merkle_root": "0000000000000000000000000000000000000000" + }, + { + "witness": "boatymcboatface", + "block_id": "004c4b3ad84474c750655d1771b59529497991e5", + "previous": "004c4b39994bee03aa28ad6cdad72f3f0e524f80", + "timestamp": "2016-09-15T19:47:03", + "extensions": [], + "signing_key": "STM7NBnGbujS9ttCjnuJajYNDEbB1mj9uvpzFnL2NUmHwLFYSZxTG", + "transactions": [ + { + "expiration": "2016-09-15T19:47:15", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "**ICONOMI found management platform** is currently in ICO and you can still invest. \n\nThat is most anticipated platform of 2016 why You may ask me. I will give you some graph and explanation. Solutions like ICONOMI are very popular in old economy people want be rich and wanted get more profit so they tried give money to people who know more about trading. Found management platforms preforms much better than average investors. Big guys just want invest not day trading. In crypto ICOMI will be 1st such project - such needed project.\n\nNow true facts and everything that I show you, is now publicly available on web. Graphs taken from coinmarketcap.com are showing us, what is going on cryptocurrency markets right now:\n \n \n \n\nYou see on won eyes that: Bitcoin is loosing over time market share to other alt coins. There is many multiple reasons for that. Without ICONOMI getting on cryptocurrency board for new investors will be VERY hard. \nThat is:\n \n- choose right one coin. \n- skip scams \n- buy valuable coins \n- crypto markets are getting bigger and bigger all time, there is about over 700coins tradable now\n\n\nICONOMI will be platform that for **every investor looking for big profits**. \nICONOMI will give us 2 founds:\n\n- **The ICONOMI.INDEX FUND** - a \"Passive\" - Coin Traded Fund (CTF). This fund operates on special rules, variables that manage the fund through automation. This Found will be the fastest available to investors at launch in Q4 2016 - The ICONOMI.PERFORMANCE FUND - an \"\nActive\"\n- **Coin Managed Fund (CMF)**, Operated by and managed by best investors. This fund will be invitation only available. If you invest in ICO you will get you invitation for free. I bet is worth its price. Those found will be carefully managed by ICONOMI experts and will provide best profits available.\n\nGraphs shows that volume of alt coins is rising heavily and will move up. Without ICONOMI founds many investors will probably lose cash on market, while rypto currency market will rise as whole. **If buy some ICO shares you will get dividends forever as share holder.**\n Soon real professional traders will come to cryptocurrency and you as investor in order to get big profits will have to use service of ICONOMI. \n\nPersonally I have invested in ICO and believe that **ICONOMI is future of crypto trading**. Don't miss a chance and invest here:[ico.iconomi.net](ico.iconomi.net) \n\nIf you want invest in ICO:  \n\nOfficial Links:\n \n- [ico.iconomi.net](ico.iconomi.net \"Main site\") \n- [https://www.facebook.com/iconomi.net/](https://www.facebook.com/iconomi.net/ \"Facebook\") \n- [https://twitter.com/iconominet](https://twitter.com/iconominet\"twitter.com\")\n- [https://www.linkedin.com/company/iconomi-the-financial-services-for-decentralised-economy/](https://www.linkedin.com/company/iconomi-the-financial-services-for-decentralised-economy/) \n- [https://telegram.me/iconomi](https://telegram.me/iconomi)\n- [https://medium.com/iconominet](https://medium.com/iconominet)\n- [https://iconominet.herokuapp.com](https://iconominet.herokuapp.com)", + "title": "ICONOMI - why we need found management explained on graphs.", + "author": "szklaneczka", + "permlink": "iconomi-why-we-need-found-management-explained-on-graphs", + "json_metadata": "{\"tags\":[\"cryptocurrency\",\"bitcoin\",\"profit\",\"altcoin\"],\"image\":[\"http://i.imgur.com/FLe0WeF.jpg\",\"http://i.imgur.com/s6Aeke2.jpg\",\"http://i.imgur.com/RX0JK1z.jpg\",\"http://i.imgur.com/iqDpTag.png\"],\"links\":[\"ico.iconomi.net\",\"https://www.facebook.com/iconomi.net/\",\"https://twitter.com/iconominet\\\"twitter.com\\\"\",\"https://www.linkedin.com/company/iconomi-the-financial-services-for-decentralised-economy/\",\"https://telegram.me/iconomi\",\"https://medium.com/iconominet\",\"https://iconominet.herokuapp.com\"]}", + "parent_author": "", + "parent_permlink": "cryptocurrency" + } + }, + { + "type": "vote_operation", + "value": { + "voter": "szklaneczka", + "author": "szklaneczka", + "weight": 10000, + "permlink": "iconomi-why-we-need-found-management-explained-on-graphs" + } + } + ], + "signatures": [ + "2032f5c135a0bd6a94d43bb29ea957d718c2e8e27293261dbb5adbb7fb6aad2e025e980a0bf1a3f6da237de088f83ed40d7a28be4373e5e11b074ea1755b9335eb" + ], + "ref_block_num": 19145, + "ref_block_prefix": 3670825722 + } + ], + "transaction_ids": [ + "14669f700014276a681ac09b0df046362b5bc7d1" + ], + "witness_signature": "2043077f093901476bafc6f900872a9a6de305bd22f29d64025819a016f89494786bb267bd87afd458c7b289a22f69bfec1ea9b22805e1501f3081ab8e41a8583c", + "transaction_merkle_root": "2eba954626ea68034864ace8343efe2f25f07b8e" + }, + { + "witness": "ihashfury", + "block_id": "004c4b3bd268694ea02f24de50c50c9e7a831e60", + "previous": "004c4b3ad84474c750655d1771b59529497991e5", + "timestamp": "2016-09-15T19:47:06", + "extensions": [], + "signing_key": "STM8aUs6SGoEmNYMd3bYjE1UBr6NQPxGWmTqTdBaxJYSx244edSB2", + "transactions": [ + { + "expiration": "2016-09-15T19:48:54", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "southbaybits", + "author": "craig-grant", + "weight": 10000, + "permlink": "re-stellabelle-artificial-intelligence-has-made-usd21-307-in-blogging-rewards-what-is-the-future-of-ai-on-steemit-20160915t193113703z" + } + } + ], + "signatures": [ + "1f3f6c09b4994fcb4bade16e3384d5c07d782e8c3175b31c02ab79cdf493498de31dac6b99e572aa14c2defb4fcdad76ffe487404e5658a8e752dc308d46fb8208" + ], + "ref_block_num": 19258, + "ref_block_prefix": 3346285784 + } + ], + "transaction_ids": [ + "d2362369316bf2175093d3f3eda43badd7342627" + ], + "witness_signature": "20438378efc3f06cec1b228c4f1e13d2053b396c8a3f70910c01b9b44690e7555d0802d8877ec5c4ce1f57da62e69f330113832c4eb6cf461613234b884f35a1db", + "transaction_merkle_root": "f284fbf9c7cb0fd77fce89b78c4f15b638ac7b5b" + }, + { + "witness": "riverhead", + "block_id": "004c4b3c51ee947feceeb1812702816114aea6e4", + "previous": "004c4b3bd268694ea02f24de50c50c9e7a831e60", + "timestamp": "2016-09-15T19:47:09", + "extensions": [], + "signing_key": "STM7iHUr9PfAmWphaP6QniRUWwJp8yrL9UF2z1Wos155aUCcsi5Ly", + "transactions": [ + { + "expiration": "2016-09-15T19:47:37", + "extensions": [], + "operations": [ + { + "type": "limit_order_cancel_operation", + "value": { + "owner": "fnait", + "orderid": 593165115 + } + } + ], + "signatures": [ + "2051cc4422b7b2a59568c7aaca3fc6c9540ebdcc852e1459e74942d8b644f037de61b18041f60df7a90306b43eecb61a7608c172fec4b48cd2f741b9a819ba8c64" + ], + "ref_block_num": 19259, + "ref_block_prefix": 1315530962 + }, + { + "expiration": "2016-09-15T19:47:38", + "extensions": [], + "operations": [ + { + "type": "limit_order_cancel_operation", + "value": { + "owner": "fnait", + "orderid": 2160157607 + } + } + ], + "signatures": [ + "1f4d906f6f7f34ee0e52c336aceaea0e399797bde5eee2803e6c49c3e807014b035e360814a9b7f51e9bc06aafece9ec92a794faf378020a00e05bc87ceab8fcfc" + ], + "ref_block_num": 19259, + "ref_block_prefix": 1315530962 + } + ], + "transaction_ids": [ + "28bdee506698f5b5780e75724ed8fe2daede2cef", + "f8f06c7eb2853d247a040bf01b1a16421895b29f" + ], + "witness_signature": "207ee65f71338f4fec1fefb69f44a6b1fc769d20d1685d8e16d7c4dadd80e1bd0c46c081bb3349cce1494ddd15f2b43706a2fb7226abdf939fb2e6c1d7a8be23e4", + "transaction_merkle_root": "f05525d3b903c273785f6fea08a479e3bd2dace9" + }, + { + "witness": "clayop", + "block_id": "004c4b3d6c34ebe3eb75dad04ce0a13b5f8a08cf", + "previous": "004c4b3c51ee947feceeb1812702816114aea6e4", + "timestamp": "2016-09-15T19:47:12", + "extensions": [], + "signing_key": "STM5SZ8DRytVTmWTbhVEoVwcj8vS4NcpvuaFi5KoLaRVSTCwqtCdy", + "transactions": [ + { + "expiration": "2016-09-15T19:47:21", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "uwe69", + "author": "pollux.one", + "weight": 10000, + "permlink": "showing-off-some-cooking-skills-1-black-truffle-with-cream-sauce-and-spelt-pasta-uebersetzung" + } + } + ], + "signatures": [ + "2037da9b27409fc50df6f9aa29cde3a21908bd9773c6644455649b45f0fadab5ab0b6e527721c3a16db3b04fce5450b81ba4bd4deb59a8011cd5675de41dd55f3b" + ], + "ref_block_num": 19246, + "ref_block_prefix": 2839596143 + }, + { + "expiration": "2016-09-15T19:47:38", + "extensions": [], + "operations": [ + { + "type": "limit_order_create_operation", + "value": { + "owner": "fnait", + "orderid": 1564419683, + "expiration": "2016-09-15T19:48:58", + "fill_or_kill": false, + "amount_to_sell": { + "nai": "@@000000021", + "amount": "71243", + "precision": 3 + }, + "min_to_receive": { + "nai": "@@000000013", + "amount": "47056", + "precision": 3 + } + } + } + ], + "signatures": [ + "2018b4501fe5f0594eba741e275c03b84253953f7d0c2a6e3b36dd14d03cc8bf36150f2d44f9265bfff4cbec34b2c0184728143b3f3133015960c18d331d47b5b0" + ], + "ref_block_num": 19259, + "ref_block_prefix": 1315530962 + }, + { + "expiration": "2016-09-15T19:47:21", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "blendplayz", + "author": "oflyhigh", + "weight": 10000, + "permlink": "the-happy-life-of-crabs-happy-mid-autumn-festival" + } + } + ], + "signatures": [ + "2002c787fd3b7f7a334bb6f66b2ab1e8110ebd50157a9291a7540660ffc44037251e725550845753bb0cceb5f6d6ea521e4de37c8dda6bc3b2ea0826eaf3f3e9d9" + ], + "ref_block_num": 19248, + "ref_block_prefix": 3869298602 + }, + { + "expiration": "2016-09-15T19:47:24", + "extensions": [], + "operations": [ + { + "type": "transfer_operation", + "value": { + "to": "blocktrades", + "from": "mrwang", + "memo": "a79c09cd-0084-4cd4-ae63-bf6d2514fef9", + "amount": { + "nai": "@@000000013", + "amount": "1633", + "precision": 3 + } + } + } + ], + "signatures": [ + "1f1ae854da2b2ddb888dcec2fd16e996cdc10f948f473489c99e604e83cb2744d00e31ebad65dbd320612826ef4b960e6e800a7788a29fdd6c69d1e67449e89ccd" + ], + "ref_block_num": 19250, + "ref_block_prefix": 1181625059 + } + ], + "transaction_ids": [ + "402de988705ea3deb2f0e1ab0411157c7d4656fc", + "c7ff9544c82b87d9aea811bbcacbd887c40d71f8", + "cd37ff668ffd5f304d91787463642145686fee4c", + "e75f833ceb62570c25504b55d0f23d86d9d76423" + ], + "witness_signature": "20530ed38085159135ac628fe7f53166e17cd820ad9ff20b069789530185aaa1fc6b94c60929b9de3dc437e585f7dd4b44b20b673a9fb8dda0f0674fd6401606ef", + "transaction_merkle_root": "2fd274b75f14a5ac095359ef1f04c014f54f7eac" + }, + { + "witness": "steemed", + "block_id": "004c4b3e03ea2eac2494790786bfb9e41a8669d9", + "previous": "004c4b3d6c34ebe3eb75dad04ce0a13b5f8a08cf", + "timestamp": "2016-09-15T19:47:15", + "extensions": [], + "signing_key": "STM8RR6DMdcehSLgvbDcWsCaYowkvKGYv4EVaubtNZyb2gBst7kS2", + "transactions": [ + { + "expiration": "2016-09-15T19:47:21", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "beanz", + "author": "irit", + "weight": -10000, + "permlink": "re-steemrocket-is-now-on-steemit-the-place-to-find-tips-and-tricks-on-improving-and-making-the-most-out-of-your-steemit-experience" + } + } + ], + "signatures": [ + "1f17c709fd3283154fe207db5c02cf6d2300b00a76ed8b4114bef34d37c78bacc6799195e374dc1fe817814194392b73d2f2ca88d3fefab4d441350f948830f89d" + ], + "ref_block_num": 19256, + "ref_block_prefix": 4279467018 + }, + { + "expiration": "2016-09-15T19:47:27", + "extensions": [], + "operations": [ + { + "type": "comment_operation", + "value": { + "body": "our planet is pure beauty .", + "title": "", + "author": "abol", + "permlink": "re-armanibadboy-space-video-online-channel-chat-20160915t194712863z", + "json_metadata": "{\"tags\":[\"space\"]}", + "parent_author": "armanibadboy", + "parent_permlink": "space-video-online-channel-chat" + } + } + ], + "signatures": [ + "201efb04a349ea722fec7fea63360b1c8ee88dbb18468c60a94b62e06a44e9638610a3cbdc8324d12930c21b9fd81d0088a27cb36bc5aaf234f106ad7ceed4cc1d" + ], + "ref_block_num": 19248, + "ref_block_prefix": 3869298602 + } + ], + "transaction_ids": [ + "05d54bc0413172f4b65e350c2a2677d392b1b936", + "f72b66e67933f652381a888f42f8cb9b0cb2ab57" + ], + "witness_signature": "1f6242ae0c57bba150c276f452dca2c5cd6c53a0995c6344683569313de2dcc14b3355f096a061672cd0603b352e616c7bf8586eb3d2e8e24a1ea3acd411f81cfa", + "transaction_merkle_root": "1df34ba86733dc44df4a3a0a89bc449c0aeb7fcb" + }, + { + "witness": "smooth.witness", + "block_id": "004c4b3fc6a8735b4ab5433d59f4526e4a042644", + "previous": "004c4b3e03ea2eac2494790786bfb9e41a8669d9", + "timestamp": "2016-09-15T19:47:18", + "extensions": [], + "signing_key": "STM5jtPaM5G2jemsqTY8xYgy3CVUgzygKn7vUVpFozr6nWcCJ8mDW", + "transactions": [ + { + "expiration": "2016-09-15T19:47:27", + "extensions": [], + "operations": [ + { + "type": "vote_operation", + "value": { + "voter": "rkpl", + "author": "thedevil", + "weight": -10000, + "permlink": "re-rkpl-how-to-make-a-good-picture-of-the-moon-my-guide-and-photos-20160915t193128824z" + } + } + ], + "signatures": [ + "2046cca841a2c84caf416ccec47f4d894732236505c21964ca092a4bf83b755979402486e49f4f6c116fc7e8d8525df14592d2993365b54ac26cb4bc52d3611e50" + ], + "ref_block_num": 19245, + "ref_block_prefix": 325640405 + }, + { + "expiration": "2016-09-15T19:47:45", + "extensions": [], + "operations": [ + { + "type": "limit_order_cancel_operation", + "value": { + "owner": "cvk", + "orderid": 1473968539 + } + } + ], + "signatures": [ + "20388171dcf8401b9ca74a79991fa2aaeff26729a28c3acb5510663a930e51f15e180e712e0e7fd3a65b2082ea89583b5155239259fc37c9a0c2b0ec4aacfb6963" + ], + "ref_block_num": 19262, + "ref_block_prefix": 2888755715 + }, + { + "expiration": "2016-09-15T20:47:15", + "extensions": [], + "operations": [ + { + "type": "pow2_operation", + "value": { + "work": { + "type": "pow2", + "value": { + "input": { + "nonce": "12906882138532220661", + "prev_block": "004c4b3e03ea2eac2494790786bfb9e41a8669d9", + "worker_account": "rabbit-25" + }, + "pow_summary": 3818441282 + } + }, + "props": { + "hbd_interest_rate": 1000, + "maximum_block_size": 131072, + "account_creation_fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + } + } + } + } + ], + "signatures": [ + "200cecb32d535041c061ea00ec8092c4ab12bf1453035c52987beffb53099f4d5045b29946037b15f9cdde3cbbe0f6e72b8f2f42027cafbeeee54cb8e780f8b07f" + ], + "ref_block_num": 19262, + "ref_block_prefix": 2888755715 + }, + { + "expiration": "2016-09-15T19:47:45", + "extensions": [], + "operations": [ + { + "type": "limit_order_cancel_operation", + "value": { + "owner": "paco-steem", + "orderid": 1243424767 + } + } + ], + "signatures": [ + "1f7de4d1ea38b5ddb2de499242aacc92d3fff529a74264c568114a48bf4182e4e775bd757cd718cb31b92017279bc781d7282be48abf615aa856bf6828a53b7fe1" + ], + "ref_block_num": 19262, + "ref_block_prefix": 2888755715 + } + ], + "transaction_ids": [ + "9f4639be729f8ca436ac5bd01b5684cbc126d44d", + "8f2a70dbe09902473eac39ffbd8ff626cb49bb51", + "a9596ee741bd4b4b7d3d8cadd15416bfe854209e", + "b664e368d117e0b0d4b1b32325a18044f47b5ca5" + ], + "witness_signature": "1f4a3e6e868c4b729790e64b0656cf12996f35010dd07b535a502b019080c849c75f370642b00e302d003def5e6b2280246b08ee8ab37824af4664ab740a79b940", + "transaction_merkle_root": "708e4d6a2a722ef7fecc58d1f177a2826e54edd3" + }, + { + "witness": "ihashfury", + "block_id": "004c4b40245ffb07380a393fb2b3d841b76cdaec", + "previous": "004c4b3fc6a8735b4ab5433d59f4526e4a042644", + "timestamp": "2016-09-15T19:47:21", + "extensions": [], + "signing_key": "STM8aUs6SGoEmNYMd3bYjE1UBr6NQPxGWmTqTdBaxJYSx244edSB2", + "transactions": [ + { + "expiration": "2016-09-15T19:47:33", + "extensions": [], + "operations": [ + { + "type": "account_create_operation", + "value": { + "fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + }, + "owner": { + "key_auths": [ + [ + "STM871wj5KKnbwwiRv3scVcxQ26ynPnE1uaZr6dPpqVu9F4zJZgjZ", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "active": { + "key_auths": [ + [ + "STM73bAnWEwkdUa7Lp4ovNzyu4soHUCaCNSz79YHQsDqscNdSe1E8", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "creator": "steem", + "posting": { + "key_auths": [ + [ + "STM7fXKrnQN3xhgFTQBFMgR9TU8CxfgAJrLvSDjGuM2bFkiuKfwZg", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "memo_key": "STM8i93Zznxu2QRNLCHBDXt5yyiMW1c3GEyVKV9XAs8H5wEWwdJaM", + "json_metadata": "", + "new_account_name": "kefadex" + } + } + ], + "signatures": [ + "1f63c75cc966916ea705a6fdef0821a810bdabb07118a3721f4cd52c972b9e4522534248c45ac908c1498752165a1d937eaf55ab6c028d7ee0ad893d3d4330d066" + ], + "ref_block_num": 19263, + "ref_block_prefix": 1534306502 + }, + { + "expiration": "2016-09-15T19:47:48", + "extensions": [], + "operations": [ + { + "type": "limit_order_create_operation", + "value": { + "owner": "cvk", + "orderid": 1473968838, + "expiration": "2035-10-29T06:32:22", + "fill_or_kill": false, + "amount_to_sell": { + "nai": "@@000000021", + "amount": "10324", + "precision": 3 + }, + "min_to_receive": { + "nai": "@@000000013", + "amount": "6819", + "precision": 3 + } + } + } + ], + "signatures": [ + "203e8ef6d16005180dc06756462bd867513a929bc4fa7c45f24ca2b0763cafdb06678812d777216f46d205e68a740dd19e32a1aa1a1df022500c0f1ef97800d0e0" + ], + "ref_block_num": 19263, + "ref_block_prefix": 1534306502 + } + ], + "transaction_ids": [ + "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "973290d26bac31335c000c7a3d3fe058ce3dbb9f" + ], + "witness_signature": "1f6aa1c6311c768b5225b115eaf5798e5f1d8338af3970d90899cd5ccbe38f6d1f7676c5649bcca18150cbf8f07c0cc7ec3ae40d5936cfc6d5a650e582ba0f8002", + "transaction_merkle_root": "97a8f2b04848b860f1792dc07bf58efcb15aeb8c" + } +] \ No newline at end of file diff --git a/tests/tavern/get_block_range/positive/latest_blocks.tavern.yaml b/tests/tavern/get_block_range/positive/latest_blocks.tavern.yaml new file mode 100644 index 000000000..0d2b05f32 --- /dev/null +++ b/tests/tavern/get_block_range/positive/latest_blocks.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_block_range" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "4999981" + to-block: "5000000" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_block_range/positive/non_existent_range.pat.json b/tests/tavern/get_block_range/positive/non_existent_range.pat.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/tests/tavern/get_block_range/positive/non_existent_range.pat.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/tavern/get_block_range/positive/non_existent_range.tavern.yaml b/tests/tavern/get_block_range/positive/non_existent_range.tavern.yaml new file mode 100644 index 000000000..1d143d031 --- /dev/null +++ b/tests/tavern/get_block_range/positive/non_existent_range.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_block_range" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "5000001" + to-block: "5000020" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_global_state/negative/non_existent.pat.json b/tests/tavern/get_global_state/negative/non_existent.pat.json new file mode 100644 index 000000000..7d466aa44 --- /dev/null +++ b/tests/tavern/get_global_state/negative/non_existent.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Block_num '5000001' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_global_state/negative/non_existent.tavern.yaml b/tests/tavern/get_global_state/negative/non_existent.tavern.yaml new file mode 100644 index 000000000..79ee5f489 --- /dev/null +++ b/tests/tavern/get_global_state/negative/non_existent.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_global_state" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000001" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_global_state/positive/first_block.pat.json b/tests/tavern/get_global_state/positive/first_block.pat.json new file mode 100644 index 000000000..430620297 --- /dev/null +++ b/tests/tavern/get_global_state/positive/first_block.pat.json @@ -0,0 +1,19 @@ +{ + "block_num": 1, + "hash": "0000000109833ce528d5bbfb3f6225b39ee10086", + "prev": "0000000000000000000000000000000000000000", + "producer_account": "initminer", + "transaction_merkle_root": "0000000000000000000000000000000000000000", + "extensions": [], + "witness_signature": "204f8ad56a8f5cf722a02b035a61b500aa59b9519b2c33c77a80c0a714680a5a5a7a340d909d19996613c5e4ae92146b9add8a7a663eef37d837ef881477313043", + "signing_key": "STM8GC13uCZbP44HzMLV6zPZGwVQ8Nt4Kji8PapsPiNq1BK153XTX", + "hbd_interest_rate": 0, + "total_vesting_fund_hive": "1000", + "total_vesting_shares": "1000000", + "total_reward_fund_hive": "2000", + "virtual_supply": "3000", + "current_supply": "3000", + "current_hbd_supply": "0", + "dhf_interval_ledger": 0, + "created_at": "2016-03-24T16:05:00" +} \ No newline at end of file diff --git a/tests/tavern/get_global_state/positive/first_block.tavern.yaml b/tests/tavern/get_global_state/positive/first_block.tavern.yaml new file mode 100644 index 000000000..686039a04 --- /dev/null +++ b/tests/tavern/get_global_state/positive/first_block.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_global_state" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "1" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_global_state/positive/last.pat.json b/tests/tavern/get_global_state/positive/last.pat.json new file mode 100644 index 000000000..0371088e8 --- /dev/null +++ b/tests/tavern/get_global_state/positive/last.pat.json @@ -0,0 +1,19 @@ +{ + "block_num": 5000000, + "hash": "004c4b40245ffb07380a393fb2b3d841b76cdaec", + "prev": "004c4b3fc6a8735b4ab5433d59f4526e4a042644", + "producer_account": "ihashfury", + "transaction_merkle_root": "97a8f2b04848b860f1792dc07bf58efcb15aeb8c", + "extensions": [], + "witness_signature": "1f6aa1c6311c768b5225b115eaf5798e5f1d8338af3970d90899cd5ccbe38f6d1f7676c5649bcca18150cbf8f07c0cc7ec3ae40d5936cfc6d5a650e582ba0f8002", + "signing_key": "STM8aUs6SGoEmNYMd3bYjE1UBr6NQPxGWmTqTdBaxJYSx244edSB2", + "hbd_interest_rate": 1000, + "total_vesting_fund_hive": "149190428013", + "total_vesting_shares": "448144916705468383", + "total_reward_fund_hive": "66003975", + "virtual_supply": "161253662237", + "current_supply": "157464400971", + "current_hbd_supply": "2413759427", + "dhf_interval_ledger": 0, + "created_at": "2016-09-15T19:47:21" +} \ No newline at end of file diff --git a/tests/tavern/get_global_state/positive/last.tavern.yaml b/tests/tavern/get_global_state/positive/last.tavern.yaml new file mode 100644 index 000000000..acb33e6fd --- /dev/null +++ b/tests/tavern/get_global_state/positive/last.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_global_state" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_head_block_num/default.pat.json b/tests/tavern/get_head_block_num/default.pat.json new file mode 100644 index 000000000..d4375a28a --- /dev/null +++ b/tests/tavern/get_head_block_num/default.pat.json @@ -0,0 +1 @@ +5000000 \ No newline at end of file diff --git a/tests/tavern/get_head_block_num/default.tavern.yaml b/tests/tavern/get_head_block_num/default.tavern.yaml new file mode 100644 index 000000000..bc4f4f9eb --- /dev/null +++ b/tests/tavern/get_head_block_num/default.tavern.yaml @@ -0,0 +1,21 @@ +--- + 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_head_block_num" + method: POST + headers: + content-type: application/json + accept: application/json + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_op_types/default.pat.json b/tests/tavern/get_op_types/default.pat.json new file mode 100644 index 000000000..242e11201 --- /dev/null +++ b/tests/tavern/get_op_types/default.pat.json @@ -0,0 +1,467 @@ +[ + { + "is_virtual": false, + "op_type_id": 0, + "operation_name": "vote_operation" + }, + { + "is_virtual": false, + "op_type_id": 1, + "operation_name": "comment_operation" + }, + { + "is_virtual": false, + "op_type_id": 2, + "operation_name": "transfer_operation" + }, + { + "is_virtual": false, + "op_type_id": 3, + "operation_name": "transfer_to_vesting_operation" + }, + { + "is_virtual": false, + "op_type_id": 4, + "operation_name": "withdraw_vesting_operation" + }, + { + "is_virtual": false, + "op_type_id": 5, + "operation_name": "limit_order_create_operation" + }, + { + "is_virtual": false, + "op_type_id": 6, + "operation_name": "limit_order_cancel_operation" + }, + { + "is_virtual": false, + "op_type_id": 7, + "operation_name": "feed_publish_operation" + }, + { + "is_virtual": false, + "op_type_id": 8, + "operation_name": "convert_operation" + }, + { + "is_virtual": false, + "op_type_id": 9, + "operation_name": "account_create_operation" + }, + { + "is_virtual": false, + "op_type_id": 10, + "operation_name": "account_update_operation" + }, + { + "is_virtual": false, + "op_type_id": 11, + "operation_name": "witness_update_operation" + }, + { + "is_virtual": false, + "op_type_id": 12, + "operation_name": "account_witness_vote_operation" + }, + { + "is_virtual": false, + "op_type_id": 13, + "operation_name": "account_witness_proxy_operation" + }, + { + "is_virtual": false, + "op_type_id": 14, + "operation_name": "pow_operation" + }, + { + "is_virtual": false, + "op_type_id": 15, + "operation_name": "custom_operation" + }, + { + "is_virtual": false, + "op_type_id": 16, + "operation_name": "witness_block_approve_operation" + }, + { + "is_virtual": false, + "op_type_id": 17, + "operation_name": "delete_comment_operation" + }, + { + "is_virtual": false, + "op_type_id": 18, + "operation_name": "custom_json_operation" + }, + { + "is_virtual": false, + "op_type_id": 19, + "operation_name": "comment_options_operation" + }, + { + "is_virtual": false, + "op_type_id": 20, + "operation_name": "set_withdraw_vesting_route_operation" + }, + { + "is_virtual": false, + "op_type_id": 21, + "operation_name": "limit_order_create2_operation" + }, + { + "is_virtual": false, + "op_type_id": 22, + "operation_name": "claim_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 23, + "operation_name": "create_claimed_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 24, + "operation_name": "request_account_recovery_operation" + }, + { + "is_virtual": false, + "op_type_id": 25, + "operation_name": "recover_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 26, + "operation_name": "change_recovery_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 27, + "operation_name": "escrow_transfer_operation" + }, + { + "is_virtual": false, + "op_type_id": 28, + "operation_name": "escrow_dispute_operation" + }, + { + "is_virtual": false, + "op_type_id": 29, + "operation_name": "escrow_release_operation" + }, + { + "is_virtual": false, + "op_type_id": 30, + "operation_name": "pow2_operation" + }, + { + "is_virtual": false, + "op_type_id": 31, + "operation_name": "escrow_approve_operation" + }, + { + "is_virtual": false, + "op_type_id": 32, + "operation_name": "transfer_to_savings_operation" + }, + { + "is_virtual": false, + "op_type_id": 33, + "operation_name": "transfer_from_savings_operation" + }, + { + "is_virtual": false, + "op_type_id": 34, + "operation_name": "cancel_transfer_from_savings_operation" + }, + { + "is_virtual": false, + "op_type_id": 35, + "operation_name": "custom_binary_operation" + }, + { + "is_virtual": false, + "op_type_id": 36, + "operation_name": "decline_voting_rights_operation" + }, + { + "is_virtual": false, + "op_type_id": 37, + "operation_name": "reset_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 38, + "operation_name": "set_reset_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 39, + "operation_name": "claim_reward_balance_operation" + }, + { + "is_virtual": false, + "op_type_id": 40, + "operation_name": "delegate_vesting_shares_operation" + }, + { + "is_virtual": false, + "op_type_id": 41, + "operation_name": "account_create_with_delegation_operation" + }, + { + "is_virtual": false, + "op_type_id": 42, + "operation_name": "witness_set_properties_operation" + }, + { + "is_virtual": false, + "op_type_id": 43, + "operation_name": "account_update2_operation" + }, + { + "is_virtual": false, + "op_type_id": 44, + "operation_name": "create_proposal_operation" + }, + { + "is_virtual": false, + "op_type_id": 45, + "operation_name": "update_proposal_votes_operation" + }, + { + "is_virtual": false, + "op_type_id": 46, + "operation_name": "remove_proposal_operation" + }, + { + "is_virtual": false, + "op_type_id": 47, + "operation_name": "update_proposal_operation" + }, + { + "is_virtual": false, + "op_type_id": 48, + "operation_name": "collateralized_convert_operation" + }, + { + "is_virtual": false, + "op_type_id": 49, + "operation_name": "recurrent_transfer_operation" + }, + { + "is_virtual": true, + "op_type_id": 50, + "operation_name": "fill_convert_request_operation" + }, + { + "is_virtual": true, + "op_type_id": 51, + "operation_name": "author_reward_operation" + }, + { + "is_virtual": true, + "op_type_id": 52, + "operation_name": "curation_reward_operation" + }, + { + "is_virtual": true, + "op_type_id": 53, + "operation_name": "comment_reward_operation" + }, + { + "is_virtual": true, + "op_type_id": 54, + "operation_name": "liquidity_reward_operation" + }, + { + "is_virtual": true, + "op_type_id": 55, + "operation_name": "interest_operation" + }, + { + "is_virtual": true, + "op_type_id": 56, + "operation_name": "fill_vesting_withdraw_operation" + }, + { + "is_virtual": true, + "op_type_id": 57, + "operation_name": "fill_order_operation" + }, + { + "is_virtual": true, + "op_type_id": 58, + "operation_name": "shutdown_witness_operation" + }, + { + "is_virtual": true, + "op_type_id": 59, + "operation_name": "fill_transfer_from_savings_operation" + }, + { + "is_virtual": true, + "op_type_id": 60, + "operation_name": "hardfork_operation" + }, + { + "is_virtual": true, + "op_type_id": 61, + "operation_name": "comment_payout_update_operation" + }, + { + "is_virtual": true, + "op_type_id": 62, + "operation_name": "return_vesting_delegation_operation" + }, + { + "is_virtual": true, + "op_type_id": 63, + "operation_name": "comment_benefactor_reward_operation" + }, + { + "is_virtual": true, + "op_type_id": 64, + "operation_name": "producer_reward_operation" + }, + { + "is_virtual": true, + "op_type_id": 65, + "operation_name": "clear_null_account_balance_operation" + }, + { + "is_virtual": true, + "op_type_id": 66, + "operation_name": "proposal_pay_operation" + }, + { + "is_virtual": true, + "op_type_id": 67, + "operation_name": "dhf_funding_operation" + }, + { + "is_virtual": true, + "op_type_id": 68, + "operation_name": "hardfork_hive_operation" + }, + { + "is_virtual": true, + "op_type_id": 69, + "operation_name": "hardfork_hive_restore_operation" + }, + { + "is_virtual": true, + "op_type_id": 70, + "operation_name": "delayed_voting_operation" + }, + { + "is_virtual": true, + "op_type_id": 71, + "operation_name": "consolidate_treasury_balance_operation" + }, + { + "is_virtual": true, + "op_type_id": 72, + "operation_name": "effective_comment_vote_operation" + }, + { + "is_virtual": true, + "op_type_id": 73, + "operation_name": "ineffective_delete_comment_operation" + }, + { + "is_virtual": true, + "op_type_id": 74, + "operation_name": "dhf_conversion_operation" + }, + { + "is_virtual": true, + "op_type_id": 75, + "operation_name": "expired_account_notification_operation" + }, + { + "is_virtual": true, + "op_type_id": 76, + "operation_name": "changed_recovery_account_operation" + }, + { + "is_virtual": true, + "op_type_id": 77, + "operation_name": "transfer_to_vesting_completed_operation" + }, + { + "is_virtual": true, + "op_type_id": 78, + "operation_name": "pow_reward_operation" + }, + { + "is_virtual": true, + "op_type_id": 79, + "operation_name": "vesting_shares_split_operation" + }, + { + "is_virtual": true, + "op_type_id": 80, + "operation_name": "account_created_operation" + }, + { + "is_virtual": true, + "op_type_id": 81, + "operation_name": "fill_collateralized_convert_request_operation" + }, + { + "is_virtual": true, + "op_type_id": 82, + "operation_name": "system_warning_operation" + }, + { + "is_virtual": true, + "op_type_id": 83, + "operation_name": "fill_recurrent_transfer_operation" + }, + { + "is_virtual": true, + "op_type_id": 84, + "operation_name": "failed_recurrent_transfer_operation" + }, + { + "is_virtual": true, + "op_type_id": 85, + "operation_name": "limit_order_cancelled_operation" + }, + { + "is_virtual": true, + "op_type_id": 86, + "operation_name": "producer_missed_operation" + }, + { + "is_virtual": true, + "op_type_id": 87, + "operation_name": "proposal_fee_operation" + }, + { + "is_virtual": true, + "op_type_id": 88, + "operation_name": "collateralized_convert_immediate_conversion_operation" + }, + { + "is_virtual": true, + "op_type_id": 89, + "operation_name": "escrow_approved_operation" + }, + { + "is_virtual": true, + "op_type_id": 90, + "operation_name": "escrow_rejected_operation" + }, + { + "is_virtual": true, + "op_type_id": 91, + "operation_name": "proxy_cleared_operation" + }, + { + "is_virtual": true, + "op_type_id": 92, + "operation_name": "declined_voting_rights_operation" + } +] \ No newline at end of file diff --git a/tests/tavern/get_op_types/default.tavern.yaml b/tests/tavern/get_op_types/default.tavern.yaml new file mode 100644 index 000000000..3cd35bb47 --- /dev/null +++ b/tests/tavern/get_op_types/default.tavern.yaml @@ -0,0 +1,21 @@ +--- + 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_op_types" + method: POST + headers: + content-type: application/json + accept: application/json + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_op_types/non_existent_name.pat.json b/tests/tavern/get_op_types/non_existent_name.pat.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/tests/tavern/get_op_types/non_existent_name.pat.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/tavern/get_op_types/non_existent_name.tavern.yaml b/tests/tavern/get_op_types/non_existent_name.tavern.yaml new file mode 100644 index 000000000..5acf4bb0d --- /dev/null +++ b/tests/tavern/get_op_types/non_existent_name.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_op_types" + method: POST + headers: + content-type: application/json + accept: application/json + json: + partial-operation-name: "non_existent_name" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_op_types/partial_name.pat.json b/tests/tavern/get_op_types/partial_name.pat.json new file mode 100644 index 000000000..226a6047c --- /dev/null +++ b/tests/tavern/get_op_types/partial_name.pat.json @@ -0,0 +1,87 @@ +[ + { + "is_virtual": false, + "op_type_id": 9, + "operation_name": "account_create_operation" + }, + { + "is_virtual": false, + "op_type_id": 10, + "operation_name": "account_update_operation" + }, + { + "is_virtual": false, + "op_type_id": 12, + "operation_name": "account_witness_vote_operation" + }, + { + "is_virtual": false, + "op_type_id": 13, + "operation_name": "account_witness_proxy_operation" + }, + { + "is_virtual": false, + "op_type_id": 22, + "operation_name": "claim_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 23, + "operation_name": "create_claimed_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 24, + "operation_name": "request_account_recovery_operation" + }, + { + "is_virtual": false, + "op_type_id": 25, + "operation_name": "recover_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 26, + "operation_name": "change_recovery_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 37, + "operation_name": "reset_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 38, + "operation_name": "set_reset_account_operation" + }, + { + "is_virtual": false, + "op_type_id": 41, + "operation_name": "account_create_with_delegation_operation" + }, + { + "is_virtual": false, + "op_type_id": 43, + "operation_name": "account_update2_operation" + }, + { + "is_virtual": true, + "op_type_id": 65, + "operation_name": "clear_null_account_balance_operation" + }, + { + "is_virtual": true, + "op_type_id": 75, + "operation_name": "expired_account_notification_operation" + }, + { + "is_virtual": true, + "op_type_id": 76, + "operation_name": "changed_recovery_account_operation" + }, + { + "is_virtual": true, + "op_type_id": 80, + "operation_name": "account_created_operation" + } +] \ No newline at end of file diff --git a/tests/tavern/get_op_types/partial_name.tavern.yaml b/tests/tavern/get_op_types/partial_name.tavern.yaml new file mode 100644 index 000000000..477c2e9dd --- /dev/null +++ b/tests/tavern/get_op_types/partial_name.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_op_types" + method: POST + headers: + content-type: application/json + accept: application/json + json: + partial-operation-name: "account" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operation/negative/non_existent_op.pat.json b/tests/tavern/get_operation/negative/non_existent_op.pat.json new file mode 100644 index 000000000..716253600 --- /dev/null +++ b/tests/tavern/get_operation/negative/non_existent_op.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Operation_id '42145' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_operation/negative/non_existent_op.tavern.yaml b/tests/tavern/get_operation/negative/non_existent_op.tavern.yaml new file mode 100644 index 000000000..73d99646a --- /dev/null +++ b/tests/tavern/get_operation/negative/non_existent_op.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_operation" + method: POST + headers: + content-type: application/json + accept: application/json + json: + operation-id: "42145" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_operation/positive/first_op.pat.json b/tests/tavern/get_operation/positive/first_op.pat.json new file mode 100644 index 000000000..2f505fbd7 --- /dev/null +++ b/tests/tavern/get_operation/positive/first_op.pat.json @@ -0,0 +1,21 @@ +{ + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 803, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:45:39", + "virtual_op": true, + "operation_id": "3448858738752", + "trx_in_block": -1 +} \ No newline at end of file diff --git a/tests/tavern/get_operation/positive/first_op.tavern.yaml b/tests/tavern/get_operation/positive/first_op.tavern.yaml new file mode 100644 index 000000000..3242e0a1c --- /dev/null +++ b/tests/tavern/get_operation/positive/first_op.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_operation" + method: POST + headers: + content-type: application/json + accept: application/json + json: + operation-id: "3448858738752" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operation/positive/second_op.pat.json b/tests/tavern/get_operation/positive/second_op.pat.json new file mode 100644 index 000000000..3225eb9da --- /dev/null +++ b/tests/tavern/get_operation/positive/second_op.pat.json @@ -0,0 +1,33 @@ +{ + "op": { + "type": "pow_operation", + "value": { + "work": { + "work": "000000021be1b6ff7db72546e38f84c3e27b74c92caa78b3d58101ec23590e06", + "input": "a66710befb1da6af7ee045d73cb3b0aaa2dae0ddd79b824991298a35f6e51707", + "worker": "STM58dnqTLPrybB3eR3vuAEgsmF73N5raACK6ceGynXYHziCg9kSJ", + "signature": "20a118dd4ae99f5028d5b39ff225a75892311feb26962878d23afd296e0ec8880e254b5b4148c26646fcb60ecf85f0165edfa993d2d38fefe5c55847e6539f3507" + }, + "nonce": "15388158104033372400", + "props": { + "hbd_interest_rate": 1000, + "maximum_block_size": 131072, + "account_creation_fee": { + "nai": "@@000000021", + "amount": "1", + "precision": 3 + } + }, + "block_id": "0034483d9f5f41e48c842c0aff31aea140868ce6", + "worker_account": "catfish" + } + }, + "block": 3426366, + "trx_id": "03fb2153261c9bc33fb245ab2ee9d0f8cb952b5d", + "op_pos": 0, + "op_type_id": 14, + "timestamp": "2016-07-22T20:42:51", + "virtual_op": false, + "operation_id": "14716129914127118", + "trx_in_block": 2 +} \ No newline at end of file diff --git a/tests/tavern/get_operation/positive/second_op.tavern.yaml b/tests/tavern/get_operation/positive/second_op.tavern.yaml new file mode 100644 index 000000000..911b4a46e --- /dev/null +++ b/tests/tavern/get_operation/positive/second_op.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_operation" + method: POST + headers: + content-type: application/json + accept: application/json + json: + operation-id: "14716129914127118" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operation_keys/negative/non_existent.pat.json b/tests/tavern/get_operation_keys/negative/non_existent.pat.json new file mode 100644 index 000000000..ac58b0001 --- /dev/null +++ b/tests/tavern/get_operation_keys/negative/non_existent.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "op_type_id '-1' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_operation_keys/negative/non_existent.tavern.yaml b/tests/tavern/get_operation_keys/negative/non_existent.tavern.yaml new file mode 100644 index 000000000..1a5d915f8 --- /dev/null +++ b/tests/tavern/get_operation_keys/negative/non_existent.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_operation_keys" + method: POST + headers: + content-type: application/json + accept: application/json + json: + type-id: -1 + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_operation_keys/positive/comment.pat.json b/tests/tavern/get_operation_keys/positive/comment.pat.json new file mode 100644 index 000000000..46bfa65ed --- /dev/null +++ b/tests/tavern/get_operation_keys/positive/comment.pat.json @@ -0,0 +1,30 @@ +[ + [ + "value", + "body" + ], + [ + "value", + "title" + ], + [ + "value", + "author" + ], + [ + "value", + "permlink" + ], + [ + "value", + "json_metadata" + ], + [ + "value", + "parent_author" + ], + [ + "value", + "parent_permlink" + ] + ] \ No newline at end of file diff --git a/tests/tavern/get_operation_keys/positive/comment.tavern.yaml b/tests/tavern/get_operation_keys/positive/comment.tavern.yaml new file mode 100644 index 000000000..0eb7709ed --- /dev/null +++ b/tests/tavern/get_operation_keys/positive/comment.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_operation_keys" + method: POST + headers: + content-type: application/json + accept: application/json + json: + type-id: 1 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operation_keys/positive/vote.pat.json b/tests/tavern/get_operation_keys/positive/vote.pat.json new file mode 100644 index 000000000..137ed2b5c --- /dev/null +++ b/tests/tavern/get_operation_keys/positive/vote.pat.json @@ -0,0 +1,18 @@ +[ + [ + "value", + "voter" + ], + [ + "value", + "author" + ], + [ + "value", + "weight" + ], + [ + "value", + "permlink" + ] +] \ No newline at end of file diff --git a/tests/tavern/get_operation_keys/positive/vote.tavern.yaml b/tests/tavern/get_operation_keys/positive/vote.tavern.yaml new file mode 100644 index 000000000..ea77d9e28 --- /dev/null +++ b/tests/tavern/get_operation_keys/positive/vote.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_operation_keys" + method: POST + headers: + content-type: application/json + accept: application/json + json: + type-id: 0 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operations/positive/filter_by_op.pat.json b/tests/tavern/get_operations/positive/filter_by_op.pat.json new file mode 100644 index 000000000..cf334d930 --- /dev/null +++ b/tests/tavern/get_operations/positive/filter_by_op.pat.json @@ -0,0 +1,196 @@ +{ + "next_block_range_begin": 4999901, + "next_operation_begin": "21474411278239744", + "ops": [ + { + "op": { + "type": "vote_operation", + "value": { + "voter": "snowden", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999900, + "trx_id": "2e41d3ed7f52b211bc40c5684b12bbfd01217d95", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:06", + "virtual_op": false, + "operation_id": "21474406983270656", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "wildchild", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999900, + "trx_id": "22e457b14aa8b400fc5ad8a82c359f67135eb526", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:06", + "virtual_op": false, + "operation_id": "21474406983271168", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "adm", + "author": "larrytom", + "weight": -2000, + "permlink": "8-reasons-why-we-need-human-touch-more-than-ever" + } + }, + "block": 4999900, + "trx_id": "ba93f0eaf2f514022c0ea88414adde969f6f1640", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:06", + "virtual_op": false, + "operation_id": "21474406983271680", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "storage", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999900, + "trx_id": "86fdc359c124c94d55a89f2b69d2cec6d78eca07", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:06", + "virtual_op": false, + "operation_id": "21474406983272192", + "trx_in_block": 4 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "brains", + "author": "charlieshrem", + "weight": 5000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999900, + "trx_id": "04d99e732c384755eefa3ed9dcc59c5c291e8328", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:06", + "virtual_op": false, + "operation_id": "21474406983272704", + "trx_in_block": 5 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "zettar", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999901, + "trx_id": "353a78116f11629d74a937032bb3919c77ef19c5", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:09", + "virtual_op": false, + "operation_id": "21474411278237696", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "dolpo777", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999901, + "trx_id": "73a17905012e3e583eabafc30a9426a672a5a79d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:09", + "virtual_op": false, + "operation_id": "21474411278238208", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "mikehere", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999901, + "trx_id": "4a49ce6879b897a6c50ccaeb56118595b4ffcd14", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:09", + "virtual_op": false, + "operation_id": "21474411278238720", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "rimann", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999901, + "trx_id": "df2e3338a20251cbfd0375ae20b4d23180c0737d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:09", + "virtual_op": false, + "operation_id": "21474411278239232", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "blackmarket", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999901, + "trx_id": "f1b6f85124838310e4aa2708c5f0853072595c0d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:09", + "virtual_op": false, + "operation_id": "21474411278239744", + "trx_in_block": 4 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_operations/positive/filter_by_op.tavern.yaml b/tests/tavern/get_operations/positive/filter_by_op.tavern.yaml new file mode 100644 index 000000000..45a5f8b4d --- /dev/null +++ b/tests/tavern/get_operations/positive/filter_by_op.tavern.yaml @@ -0,0 +1,26 @@ +--- + 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_operations" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "4999900" + to-block: "5000000" + operation-types: "0" + page-size: 10 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operations/positive/filter_by_op_next_page.pat.json b/tests/tavern/get_operations/positive/filter_by_op_next_page.pat.json new file mode 100644 index 000000000..1a85b3d56 --- /dev/null +++ b/tests/tavern/get_operations/positive/filter_by_op_next_page.pat.json @@ -0,0 +1,196 @@ +{ + "next_block_range_begin": 4999902, + "next_operation_begin": "21474415573208576", + "ops": [ + { + "op": { + "type": "vote_operation", + "value": { + "voter": "valtr", + "author": "acidyo", + "weight": 10000, + "permlink": "drew-an-avatar-signature-for-my-posts" + } + }, + "block": 4999901, + "trx_id": "76777ac49f75cb3caf59185bd59938d3b2327226", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:09", + "virtual_op": false, + "operation_id": "21474411278240256", + "trx_in_block": 5 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "zaebars", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999901, + "trx_id": "314838c1761e0dff5d02f25a1669acb09f4d3881", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:09", + "virtual_op": false, + "operation_id": "21474411278240768", + "trx_in_block": 6 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "steemlift", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999902, + "trx_id": "5b1747a1d233d1c3ef914870ac074f008d664332", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573204992", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "xanoxt", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999902, + "trx_id": "daae44cc2e10aeb7c25c2a78f82e816efd5c7082", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573205504", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "marinaz", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999902, + "trx_id": "1ce163b5e05974dfdf99dfab5185c72aff659139", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573206016", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "ysa", + "author": "alexandrapop", + "weight": 10000, + "permlink": "new-introduce-yourself-post-with-more-info-about-me-and-more-pictures-with-me" + } + }, + "block": 4999902, + "trx_id": "0c4d24c07124301f3bfe0ce68ae5a3fd24422a6f", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573206528", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "lindseylambz", + "author": "richardcrill", + "weight": 10000, + "permlink": "re-lyndsaybowes-just-picked-and-pulled-these-beautiful-organic-vegetables-to-add-to-my-soup-20160915t193454706z" + } + }, + "block": 4999902, + "trx_id": "afe6f43684d53ef3e15e8a54b6f94633d29e5703", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573207040", + "trx_in_block": 4 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "steemchain", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999902, + "trx_id": "037bdc9c9b54087d97e8251c6d2a2e07a05e0530", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573207552", + "trx_in_block": 5 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "alwayzgame", + "author": "charlieshrem", + "weight": 10000, + "permlink": "mackerelcoin-and-my-socioeconomic-observations-from-prison-part-1-by-charlie-shrem" + } + }, + "block": 4999902, + "trx_id": "ebc0967b5a44193141b0444fe2ea4808f7c62c01", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573208064", + "trx_in_block": 6 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "alienbutt", + "author": "verbal-d", + "weight": 10000, + "permlink": "melodious-music-memoirs-2-impact" + } + }, + "block": 4999902, + "trx_id": "fc3b86dc094866a81f4e88f9957be8c1e236e589", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:12", + "virtual_op": false, + "operation_id": "21474415573208576", + "trx_in_block": 7 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_operations/positive/filter_by_op_next_page.tavern.yaml b/tests/tavern/get_operations/positive/filter_by_op_next_page.tavern.yaml new file mode 100644 index 000000000..37c90dd84 --- /dev/null +++ b/tests/tavern/get_operations/positive/filter_by_op_next_page.tavern.yaml @@ -0,0 +1,27 @@ +--- + 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_operations" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "4999900" + to-block: "5000000" + operation-types: "0" + page-size: 10 + operation-begin: "21474411278239744" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operations/positive/first_blocks.pat.json b/tests/tavern/get_operations/positive/first_blocks.pat.json new file mode 100644 index 000000000..6c2a3329c --- /dev/null +++ b/tests/tavern/get_operations/positive/first_blocks.pat.json @@ -0,0 +1,477 @@ +{ + "next_block_range_begin": 16, + "next_operation_begin": "68719476800", + "ops": [ + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "miners", + "new_account_name": "miners", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + } + } + }, + "block": 1, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 80, + "timestamp": "2016-03-24T16:05:00", + "virtual_op": true, + "operation_id": "4294967376", + "trx_in_block": -1 + }, + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "null", + "new_account_name": "null", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + } + } + }, + "block": 1, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 2, + "op_type_id": 80, + "timestamp": "2016-03-24T16:05:00", + "virtual_op": true, + "operation_id": "4294967632", + "trx_in_block": -1 + }, + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "temp", + "new_account_name": "temp", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + } + } + }, + "block": 1, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 3, + "op_type_id": 80, + "timestamp": "2016-03-24T16:05:00", + "virtual_op": true, + "operation_id": "4294967888", + "trx_in_block": -1 + }, + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "initminer", + "new_account_name": "initminer", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + } + } + }, + "block": 1, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 4, + "op_type_id": 80, + "timestamp": "2016-03-24T16:05:00", + "virtual_op": true, + "operation_id": "4294968144", + "trx_in_block": -1 + }, + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "steem", + "new_account_name": "steem", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + } + } + }, + "block": 1, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 5, + "op_type_id": 80, + "timestamp": "2016-03-24T16:05:00", + "virtual_op": true, + "operation_id": "4294968400", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000037", + "amount": "1000000", + "precision": 6 + } + } + }, + "block": 1, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:00", + "virtual_op": true, + "operation_id": "4294968640", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 2, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:36", + "virtual_op": true, + "operation_id": "8589934656", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 3, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:39", + "virtual_op": true, + "operation_id": "12884901952", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 4, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:42", + "virtual_op": true, + "operation_id": "17179869248", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 5, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:45", + "virtual_op": true, + "operation_id": "21474836544", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 6, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:48", + "virtual_op": true, + "operation_id": "25769803840", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 7, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:51", + "virtual_op": true, + "operation_id": "30064771136", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 8, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:54", + "virtual_op": true, + "operation_id": "34359738432", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 9, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:05:57", + "virtual_op": true, + "operation_id": "38654705728", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 10, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:06:00", + "virtual_op": true, + "operation_id": "42949673024", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 11, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:06:03", + "virtual_op": true, + "operation_id": "47244640320", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 12, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:06:06", + "virtual_op": true, + "operation_id": "51539607616", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 13, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:06:09", + "virtual_op": true, + "operation_id": "55834574912", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 14, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:06:12", + "virtual_op": true, + "operation_id": "60129542208", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 15, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:06:15", + "virtual_op": true, + "operation_id": "64424509504", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "initminer", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 16, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-24T16:06:18", + "virtual_op": true, + "operation_id": "68719476800", + "trx_in_block": -1 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_operations/positive/first_blocks.tavern.yaml b/tests/tavern/get_operations/positive/first_blocks.tavern.yaml new file mode 100644 index 000000000..c94ea79a8 --- /dev/null +++ b/tests/tavern/get_operations/positive/first_blocks.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_operations" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "1" + to-block: "20" + page-size: 21 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operations/positive/latest_blocks.pat.json b/tests/tavern/get_operations/positive/latest_blocks.pat.json new file mode 100644 index 000000000..847d80ebe --- /dev/null +++ b/tests/tavern/get_operations/positive/latest_blocks.pat.json @@ -0,0 +1,425 @@ +{ + "next_block_range_begin": 5000000, + "next_operation_begin": "0", + "ops": [ + { + "op": { + "type": "vote_operation", + "value": { + "voter": "beanz", + "author": "irit", + "weight": -10000, + "permlink": "re-steemrocket-is-now-on-steemit-the-place-to-find-tips-and-tricks-on-improving-and-making-the-most-out-of-your-steemit-experience" + } + }, + "block": 4999998, + "trx_id": "05d54bc0413172f4b65e350c2a2677d392b1b936", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:47:15", + "virtual_op": false, + "operation_id": "21474827890065408", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "beanz", + "author": "irit", + "weight": 0, + "rshares": -5068724760, + "permlink": "re-steemrocket-is-now-on-steemit-the-place-to-find-tips-and-tricks-on-improving-and-making-the-most-out-of-your-steemit-experience", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": 0 + } + }, + "block": 4999998, + "trx_id": "05d54bc0413172f4b65e350c2a2677d392b1b936", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T19:47:15", + "virtual_op": true, + "operation_id": "21474827890065736", + "trx_in_block": 0 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "our planet is pure beauty .", + "title": "", + "author": "abol", + "permlink": "re-armanibadboy-space-video-online-channel-chat-20160915t194712863z", + "json_metadata": "{\"tags\":[\"space\"]}", + "parent_author": "armanibadboy", + "parent_permlink": "space-video-online-channel-chat" + } + }, + "block": 4999998, + "trx_id": "f72b66e67933f652381a888f42f8cb9b0cb2ab57", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T19:47:15", + "virtual_op": false, + "operation_id": "21474827890065921", + "trx_in_block": 1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "steemed", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003846904", + "precision": 6 + } + } + }, + "block": 4999998, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:47:15", + "virtual_op": true, + "operation_id": "21474827890066240", + "trx_in_block": -1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "rkpl", + "author": "thedevil", + "weight": -10000, + "permlink": "re-rkpl-how-to-make-a-good-picture-of-the-moon-my-guide-and-photos-20160915t193128824z" + } + }, + "block": 4999999, + "trx_id": "9f4639be729f8ca436ac5bd01b5684cbc126d44d", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": false, + "operation_id": "21474832185032704", + "trx_in_block": 0 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "rkpl", + "author": "thedevil", + "weight": 0, + "rshares": -1383373254, + "permlink": "re-rkpl-how-to-make-a-good-picture-of-the-moon-my-guide-and-photos-20160915t193128824z", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": 590910411298246 + } + }, + "block": 4999999, + "trx_id": "9f4639be729f8ca436ac5bd01b5684cbc126d44d", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185033032", + "trx_in_block": 0 + }, + { + "op": { + "type": "limit_order_cancel_operation", + "value": { + "owner": "cvk", + "orderid": 1473968539 + } + }, + "block": 4999999, + "trx_id": "8f2a70dbe09902473eac39ffbd8ff626cb49bb51", + "op_pos": 0, + "op_type_id": 6, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": false, + "operation_id": "21474832185033222", + "trx_in_block": 1 + }, + { + "op": { + "type": "limit_order_cancelled_operation", + "value": { + "seller": "cvk", + "orderid": 1473968539, + "amount_back": { + "nai": "@@000000021", + "amount": "9941", + "precision": 3 + } + } + }, + "block": 4999999, + "trx_id": "8f2a70dbe09902473eac39ffbd8ff626cb49bb51", + "op_pos": 1, + "op_type_id": 85, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185033557", + "trx_in_block": 1 + }, + { + "op": { + "type": "pow2_operation", + "value": { + "work": { + "type": "pow2", + "value": { + "input": { + "nonce": "12906882138532220661", + "prev_block": "004c4b3e03ea2eac2494790786bfb9e41a8669d9", + "worker_account": "rabbit-25" + }, + "pow_summary": 3818441282 + } + }, + "props": { + "hbd_interest_rate": 1000, + "maximum_block_size": 131072, + "account_creation_fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + } + } + } + }, + "block": 4999999, + "trx_id": "a9596ee741bd4b4b7d3d8cadd15416bfe854209e", + "op_pos": 0, + "op_type_id": 30, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": false, + "operation_id": "21474832185033758", + "trx_in_block": 2 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5031442145", + "precision": 6 + }, + "worker": "smooth.witness" + } + }, + "block": 4999999, + "trx_id": "a9596ee741bd4b4b7d3d8cadd15416bfe854209e", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185034062", + "trx_in_block": 2 + }, + { + "op": { + "type": "limit_order_cancel_operation", + "value": { + "owner": "paco-steem", + "orderid": 1243424767 + } + }, + "block": 4999999, + "trx_id": "b664e368d117e0b0d4b1b32325a18044f47b5ca5", + "op_pos": 0, + "op_type_id": 6, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": false, + "operation_id": "21474832185034246", + "trx_in_block": 3 + }, + { + "op": { + "type": "limit_order_cancelled_operation", + "value": { + "seller": "paco-steem", + "orderid": 1243424767, + "amount_back": { + "nai": "@@000000013", + "amount": "19276", + "precision": 3 + } + } + }, + "block": 4999999, + "trx_id": "b664e368d117e0b0d4b1b32325a18044f47b5ca5", + "op_pos": 1, + "op_type_id": 85, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185034581", + "trx_in_block": 3 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "smooth.witness", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003846056", + "precision": 6 + } + } + }, + "block": 4999999, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185034816", + "trx_in_block": -1 + }, + { + "op": { + "type": "account_create_operation", + "value": { + "fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + }, + "owner": { + "key_auths": [ + [ + "STM871wj5KKnbwwiRv3scVcxQ26ynPnE1uaZr6dPpqVu9F4zJZgjZ", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "active": { + "key_auths": [ + [ + "STM73bAnWEwkdUa7Lp4ovNzyu4soHUCaCNSz79YHQsDqscNdSe1E8", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "creator": "steem", + "posting": { + "key_auths": [ + [ + "STM7fXKrnQN3xhgFTQBFMgR9TU8CxfgAJrLvSDjGuM2bFkiuKfwZg", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "memo_key": "STM8i93Zznxu2QRNLCHBDXt5yyiMW1c3GEyVKV9XAs8H5wEWwdJaM", + "json_metadata": "", + "new_account_name": "kefadex" + } + }, + "block": 5000000, + "trx_id": "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "op_pos": 0, + "op_type_id": 9, + "timestamp": "2016-09-15T19:47:21", + "virtual_op": false, + "operation_id": "21474836480000009", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "steem", + "new_account_name": "kefadex", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "30038455132", + "precision": 6 + } + } + }, + "block": 5000000, + "trx_id": "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "op_pos": 1, + "op_type_id": 80, + "timestamp": "2016-09-15T19:47:21", + "virtual_op": true, + "operation_id": "21474836480000336", + "trx_in_block": 0 + }, + { + "op": { + "type": "limit_order_create_operation", + "value": { + "owner": "cvk", + "orderid": 1473968838, + "expiration": "2035-10-29T06:32:22", + "fill_or_kill": false, + "amount_to_sell": { + "nai": "@@000000021", + "amount": "10324", + "precision": 3 + }, + "min_to_receive": { + "nai": "@@000000013", + "amount": "6819", + "precision": 3 + } + } + }, + "block": 5000000, + "trx_id": "973290d26bac31335c000c7a3d3fe058ce3dbb9f", + "op_pos": 0, + "op_type_id": 5, + "timestamp": "2016-09-15T19:47:21", + "virtual_op": false, + "operation_id": "21474836480000517", + "trx_in_block": 1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "ihashfury", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003845513", + "precision": 6 + } + } + }, + "block": 5000000, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:47:21", + "virtual_op": true, + "operation_id": "21474836480000832", + "trx_in_block": -1 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_operations/positive/latest_blocks.tavern.yaml b/tests/tavern/get_operations/positive/latest_blocks.tavern.yaml new file mode 100644 index 000000000..eedd5d30a --- /dev/null +++ b/tests/tavern/get_operations/positive/latest_blocks.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_operations" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "4999998" + to-block: "5000000" + page-size: 21 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operations/positive/non_existent_range.pat.json b/tests/tavern/get_operations/positive/non_existent_range.pat.json new file mode 100644 index 000000000..d137f9262 --- /dev/null +++ b/tests/tavern/get_operations/positive/non_existent_range.pat.json @@ -0,0 +1,5 @@ +{ + "ops": [], + "next_operation_begin": "0", + "next_block_range_begin": 0 +} \ No newline at end of file diff --git a/tests/tavern/get_operations/positive/non_existent_range.tavern.yaml b/tests/tavern/get_operations/positive/non_existent_range.tavern.yaml new file mode 100644 index 000000000..367e77bbd --- /dev/null +++ b/tests/tavern/get_operations/positive/non_existent_range.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_operations" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "5000001" + to-block: "5000020" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operations/positive/only_real.pat.json b/tests/tavern/get_operations/positive/only_real.pat.json new file mode 100644 index 000000000..b435e2ed2 --- /dev/null +++ b/tests/tavern/get_operations/positive/only_real.pat.json @@ -0,0 +1,396 @@ +{ + "next_block_range_begin": 4000000, + "next_operation_begin": "0", + "ops": [ + { + "op": { + "type": "transfer_operation", + "value": { + "to": "bittrex", + "from": "arslan7544", + "memo": "dd89f5efa7ad4e0db00", + "amount": { + "nai": "@@000000021", + "amount": "1016201", + "precision": 3 + } + } + }, + "block": 3999998, + "trx_id": "98f2953d5da2edebafcf8219ec94a0d65ed03e07", + "op_pos": 0, + "op_type_id": 2, + "timestamp": "2016-08-11T22:00:00", + "virtual_op": false, + "operation_id": "17179860594065410", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "cryptobarry", + "author": "blakemiles84", + "weight": 10000, + "permlink": "re-cryptobarry-re-breck0882-re-cryptobarry-re-blakemiles84-compilation-of-cnn-cutting-guests-mics-to-protect-hillary-clinton-20160811t194401779z" + } + }, + "block": 3999998, + "trx_id": "bc0836cc44f1eddeade4fb1d602c5f0d42fedacb", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:00", + "virtual_op": false, + "operation_id": "17179860594065664", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "This Piece Of Music & visualisation Together Really Go Together Absolutely Beautiful To The Ears & Eyes, I Hope You Enjoy This As Much As I Do Each Time I Listen To This :) \n\n\n\nhttps://www.youtube.com/watch?v=Sia31xQBWAM", + "title": "Awesome Violin Beat visualisation [Video Music]", + "author": "stillsafe", + "permlink": "awesome-violin-beat-visualisation-video-music", + "json_metadata": "{\"tags\":[\"video\",\"music\",\"violin\",\"beautiful\",\"awesome\"],\"links\":[\"https://www.youtube.com/watch?v=Sia31xQBWAM\"]}", + "parent_author": "", + "parent_permlink": "video" + } + }, + "block": 3999998, + "trx_id": "5730e4b0d34ee35b86e463b1b81b4ae8e6e7d97c", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-11T22:00:00", + "virtual_op": false, + "operation_id": "17179860594066177", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "stillsafe", + "author": "stillsafe", + "weight": 10000, + "permlink": "awesome-violin-beat-visualisation-video-music" + } + }, + "block": 3999998, + "trx_id": "5730e4b0d34ee35b86e463b1b81b4ae8e6e7d97c", + "op_pos": 1, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:00", + "virtual_op": false, + "operation_id": "17179860594066432", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "pinkisland", + "author": "alexbeyman", + "weight": 10000, + "permlink": "the-charming-old-home-robots-of-the-1980s" + } + }, + "block": 3999999, + "trx_id": "4a8d65184379dc67f00b0f59972bbd4c640b80aa", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:03", + "virtual_op": false, + "operation_id": "17179864889032704", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "steemitstreamer", + "author": "funny", + "weight": 10000, + "permlink": "19-tips-for-new-users-of-steemit" + } + }, + "block": 3999999, + "trx_id": "20c33917a81e58dfd9b411573e453e073d5db8ec", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:03", + "virtual_op": false, + "operation_id": "17179864889033216", + "trx_in_block": 1 + }, + { + "op": { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "{\"follower\":\"markrmorrisjr\",\"following\":\"mkglock\",\"what\":[\"blog\"]}", + "required_auths": [], + "required_posting_auths": [ + "markrmorrisjr" + ] + } + }, + "block": 3999999, + "trx_id": "33b92fa99c1eedf3b0825396e0782e58d1f1c3b0", + "op_pos": 0, + "op_type_id": 18, + "timestamp": "2016-08-11T22:00:03", + "virtual_op": false, + "operation_id": "17179864889033746", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "creator", + "author": "lauralemons", + "weight": 10000, + "permlink": "contest-share-a-photo-and-i-will-pick-a-winner-to-illustrate" + } + }, + "block": 3999999, + "trx_id": "3943348dec59c80423c88a453baca8229d90e305", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:03", + "virtual_op": false, + "operation_id": "17179864889033984", + "trx_in_block": 3 + }, + { + "op": { + "type": "account_update_operation", + "value": { + "active": { + "key_auths": [ + [ + "STM5ZMXmCeTe7bM4q3q3wwihZoFfDD1RKdbJAZHqyLDGQGxRvLdZj", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 0 + }, + "account": "supercomputing05", + "memo_key": "STM7myUzFgMrc5w2jRc3LH2cTwcs96q74Kj6GJ3DyKHyrHFPDP96N", + "json_metadata": "" + } + }, + "block": 3999999, + "trx_id": "f99cbba24b260e59ce05cb2787b8709dd581b6b9", + "op_pos": 0, + "op_type_id": 10, + "timestamp": "2016-08-11T22:00:03", + "virtual_op": false, + "operation_id": "17179864889034506", + "trx_in_block": 4 + }, + { + "op": { + "type": "pow_operation", + "value": { + "work": { + "work": "00000000796a473ea5629be3f62d81b57e2be7c903f0fb071e5a417c7665e766", + "input": "5faa3f9a099afa9b5d7d935bca1ac0d1f80544ff33b670789a18c2ceef932766", + "worker": "STM5ZMXmCeTe7bM4q3q3wwihZoFfDD1RKdbJAZHqyLDGQGxRvLdZj", + "signature": "1f5cf7b0a06153181aa7470ef65233b65e9cde83a29a533878fbf8084eb40db2849619f1cf122c6d4b8252570bc2ce97bcc795d4e78b1a50ce03df4067b99c7acc" + }, + "nonce": 494771052, + "props": { + "hbd_interest_rate": 1000, + "maximum_block_size": 131072, + "account_creation_fee": { + "nai": "@@000000021", + "amount": "1", + "precision": 3 + } + }, + "block_id": "003d08fe8ba0b0088ab898feb07024115f8d3f2d", + "worker_account": "supercomputing05" + } + }, + "block": 3999999, + "trx_id": "3d110167e37e440ecf608a22af7c3c9b42bec68e", + "op_pos": 0, + "op_type_id": 14, + "timestamp": "2016-08-11T22:00:03", + "virtual_op": false, + "operation_id": "17179864889034766", + "trx_in_block": 5 + }, + { + "op": { + "type": "witness_update_operation", + "value": { + "fee": { + "nai": "@@000000021", + "amount": "0", + "precision": 3 + }, + "url": "http://fxxk.com", + "owner": "supercomputing05", + "props": { + "hbd_interest_rate": 1000, + "maximum_block_size": 65536, + "account_creation_fee": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + }, + "block_signing_key": "STM5b3wkzd5cPuW8tYbHpsM6qo26R5eympAQsBaoEfeMDxxUCLvsY" + } + }, + "block": 4000000, + "trx_id": "9e19c9082fea1a87f9dede8c9854a243185402b8", + "op_pos": 0, + "op_type_id": 11, + "timestamp": "2016-08-11T22:00:06", + "virtual_op": false, + "operation_id": "17179869184000011", + "trx_in_block": 0 + }, + { + "op": { + "type": "account_update_operation", + "value": { + "active": { + "key_auths": [ + [ + "STM5ZMXmCeTe7bM4q3q3wwihZoFfDD1RKdbJAZHqyLDGQGxRvLdZj", + 1 + ], + [ + "STM5sP9GUuExPzK35F1MLjN2dTY7fqqP7dSpMWqnzCoU3je64gm6q", + 2 + ] + ], + "account_auths": [], + "weight_threshold": 2 + }, + "account": "supercomputing05", + "memo_key": "STM7myUzFgMrc5w2jRc3LH2cTwcs96q74Kj6GJ3DyKHyrHFPDP96N", + "json_metadata": "" + } + }, + "block": 4000000, + "trx_id": "474adb8193fe247bb4a0cbb78b6b00ec51b22e40", + "op_pos": 0, + "op_type_id": 10, + "timestamp": "2016-08-11T22:00:06", + "virtual_op": false, + "operation_id": "17179869184000266", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "murh", + "author": "kaylinart", + "weight": 3301, + "permlink": "how-to-be-creative-because-anyone-can-be" + } + }, + "block": 4000000, + "trx_id": "1b03563da7e121222e87486c8e9c2716d3872fa1", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:06", + "virtual_op": false, + "operation_id": "17179869184000512", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "knozaki2015", + "author": "timsaid", + "weight": 10000, + "permlink": "steem-survivors-fictional-series-episode-2" + } + }, + "block": 4000000, + "trx_id": "21b4f4f1d4803c6f0cfb33b64d729b55daf1bf34", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:06", + "virtual_op": false, + "operation_id": "17179869184001024", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "bigman100", + "author": "keithsmih", + "weight": 10000, + "permlink": "cryptowars-sparks-of-revolution-chapter-1" + } + }, + "block": 4000000, + "trx_id": "69febf64ef51a002f49792658fa9798e8b6cd96f", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:06", + "virtual_op": false, + "operation_id": "17179869184001536", + "trx_in_block": 4 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "pinkisland", + "author": "aboundlessworld", + "weight": 10000, + "permlink": "can-you-make-a-full-time-living-from-steemit-let-s-find-out" + } + }, + "block": 4000000, + "trx_id": "764656b56b0887b2a5a06aae94c410d17132d024", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-08-11T22:00:06", + "virtual_op": false, + "operation_id": "17179869184002048", + "trx_in_block": 5 + }, + { + "op": { + "type": "account_update_operation", + "value": { + "active": { + "key_auths": [ + [ + "STM7t97bmNzbVruhH3yGQ7yFR58UJyPTb7Jh6ugmPfH1zqzJpngQH", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 0 + }, + "account": "supercomputing06", + "memo_key": "STM7myUzFgMrc5w2jRc3LH2cTwcs96q74Kj6GJ3DyKHyrHFPDP96N", + "json_metadata": "" + } + }, + "block": 4000000, + "trx_id": "43e786cc38f78c162807859606ed57bfb2bb6264", + "op_pos": 0, + "op_type_id": 10, + "timestamp": "2016-08-11T22:00:06", + "virtual_op": false, + "operation_id": "17179869184002570", + "trx_in_block": 6 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_operations/positive/only_real.tavern.yaml b/tests/tavern/get_operations/positive/only_real.tavern.yaml new file mode 100644 index 000000000..ca668595c --- /dev/null +++ b/tests/tavern/get_operations/positive/only_real.tavern.yaml @@ -0,0 +1,26 @@ +--- + 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_operations" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "3999998" + to-block: "4000000" + page-size: 21 + operation-group-type: "real" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_operations/positive/only_virtual.pat.json b/tests/tavern/get_operations/positive/only_virtual.pat.json new file mode 100644 index 000000000..677cabd9b --- /dev/null +++ b/tests/tavern/get_operations/positive/only_virtual.pat.json @@ -0,0 +1,213 @@ +{ + "next_block_range_begin": 5000000, + "next_operation_begin": "0", + "ops": [ + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "beanz", + "author": "irit", + "weight": 0, + "rshares": -5068724760, + "permlink": "re-steemrocket-is-now-on-steemit-the-place-to-find-tips-and-tricks-on-improving-and-making-the-most-out-of-your-steemit-experience", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": 0 + } + }, + "block": 4999998, + "trx_id": "05d54bc0413172f4b65e350c2a2677d392b1b936", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T19:47:15", + "virtual_op": true, + "operation_id": "21474827890065736", + "trx_in_block": 0 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "steemed", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003846904", + "precision": 6 + } + } + }, + "block": 4999998, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:47:15", + "virtual_op": true, + "operation_id": "21474827890066240", + "trx_in_block": -1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "rkpl", + "author": "thedevil", + "weight": 0, + "rshares": -1383373254, + "permlink": "re-rkpl-how-to-make-a-good-picture-of-the-moon-my-guide-and-photos-20160915t193128824z", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": 590910411298246 + } + }, + "block": 4999999, + "trx_id": "9f4639be729f8ca436ac5bd01b5684cbc126d44d", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185033032", + "trx_in_block": 0 + }, + { + "op": { + "type": "limit_order_cancelled_operation", + "value": { + "seller": "cvk", + "orderid": 1473968539, + "amount_back": { + "nai": "@@000000021", + "amount": "9941", + "precision": 3 + } + } + }, + "block": 4999999, + "trx_id": "8f2a70dbe09902473eac39ffbd8ff626cb49bb51", + "op_pos": 1, + "op_type_id": 85, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185033557", + "trx_in_block": 1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5031442145", + "precision": 6 + }, + "worker": "smooth.witness" + } + }, + "block": 4999999, + "trx_id": "a9596ee741bd4b4b7d3d8cadd15416bfe854209e", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185034062", + "trx_in_block": 2 + }, + { + "op": { + "type": "limit_order_cancelled_operation", + "value": { + "seller": "paco-steem", + "orderid": 1243424767, + "amount_back": { + "nai": "@@000000013", + "amount": "19276", + "precision": 3 + } + } + }, + "block": 4999999, + "trx_id": "b664e368d117e0b0d4b1b32325a18044f47b5ca5", + "op_pos": 1, + "op_type_id": 85, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185034581", + "trx_in_block": 3 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "smooth.witness", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003846056", + "precision": 6 + } + } + }, + "block": 4999999, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:47:18", + "virtual_op": true, + "operation_id": "21474832185034816", + "trx_in_block": -1 + }, + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "steem", + "new_account_name": "kefadex", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "30038455132", + "precision": 6 + } + } + }, + "block": 5000000, + "trx_id": "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "op_pos": 1, + "op_type_id": 80, + "timestamp": "2016-09-15T19:47:21", + "virtual_op": true, + "operation_id": "21474836480000336", + "trx_in_block": 0 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "ihashfury", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003845513", + "precision": 6 + } + } + }, + "block": 5000000, + "trx_id": "0000000000000000000000000000000000000000", + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:47:21", + "virtual_op": true, + "operation_id": "21474836480000832", + "trx_in_block": -1 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_operations/positive/only_virtual.tavern.yaml b/tests/tavern/get_operations/positive/only_virtual.tavern.yaml new file mode 100644 index 000000000..b06ef3657 --- /dev/null +++ b/tests/tavern/get_operations/positive/only_virtual.tavern.yaml @@ -0,0 +1,26 @@ +--- + 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_operations" + method: POST + headers: + content-type: application/json + accept: application/json + json: + from-block: "4999998" + to-block: "5000000" + page-size: 21 + operation-group-type: "virtual" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_ops_by_account/negative/exceeds_page_size.pat.json b/tests/tavern/get_ops_by_account/negative/exceeds_page_size.pat.json new file mode 100644 index 000000000..ff50124c2 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/exceeds_page_size.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Assert Exception:args.page-size <= 1000: page-size of 1001 is greater than maxmimum allowed" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/negative/exceeds_page_size.tavern.yaml b/tests/tavern/get_ops_by_account/negative/exceeds_page_size.tavern.yaml new file mode 100644 index 000000000..2f2040f78 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/exceeds_page_size.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + 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" + page-size: 1001 + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_account/negative/invalid_block_num.pat.json b/tests/tavern/get_ops_by_account/negative/invalid_block_num.pat.json new file mode 100644 index 000000000..1aefaaf32 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/invalid_block_num.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Invalid format: d400000" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/negative/invalid_block_num.tavern.yaml b/tests/tavern/get_ops_by_account/negative/invalid_block_num.tavern.yaml new file mode 100644 index 000000000..4d7f61d09 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/invalid_block_num.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + 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" + from-block: "d400000" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_account/negative/invalid_timestamp.pat.json b/tests/tavern/get_ops_by_account/negative/invalid_timestamp.pat.json new file mode 100644 index 000000000..cb5c93483 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/invalid_timestamp.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Invalid format: 201608-12T19:38:51" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/negative/invalid_timestamp.tavern.yaml b/tests/tavern/get_ops_by_account/negative/invalid_timestamp.tavern.yaml new file mode 100644 index 000000000..655090ccd --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/invalid_timestamp.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + 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" + from-block: "201608-12T19:38:51" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_account/negative/negative_page.pat.json b/tests/tavern/get_ops_by_account/negative/negative_page.pat.json new file mode 100644 index 000000000..6a889fe56 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/negative_page.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Assert Exception:page <= 0: page of -1 is lesser or equal 0" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/negative/negative_page.tavern.yaml b/tests/tavern/get_ops_by_account/negative/negative_page.tavern.yaml new file mode 100644 index 000000000..a7988ee34 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/negative_page.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + 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" + page: -1 + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_account/negative/negative_page_size.pat.json b/tests/tavern/get_ops_by_account/negative/negative_page_size.pat.json new file mode 100644 index 000000000..6b85b0820 --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/negative_page_size.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Assert Exception:page-size > 0: page-size of -1 is lesser or equal 0" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/negative/negative_page_size.tavern.yaml b/tests/tavern/get_ops_by_account/negative/negative_page_size.tavern.yaml new file mode 100644 index 000000000..4ba88d76d --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/negative_page_size.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + 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" + page-size: -1 + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_account/negative/non_existent_witness.pat.json b/tests/tavern/get_ops_by_account/negative/non_existent_witness.pat.json new file mode 100644 index 000000000..37631495b --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/non_existent_witness.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Account 'themarkymark' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/negative/non_existent_witness.tavern.yaml b/tests/tavern/get_ops_by_account/negative/non_existent_witness.tavern.yaml new file mode 100644 index 000000000..2992ba26a --- /dev/null +++ b/tests/tavern/get_ops_by_account/negative/non_existent_witness.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + 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: "themarkymark" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true + 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 new file mode 100644 index 000000000..7d011f370 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.pat.json @@ -0,0 +1,160 @@ +{ + "total_operations": 219867, + "total_pages": 10994, + "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": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003850165", + "precision": 6 + } + } + }, + "block": 4999992, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:46:57", + "virtual_op": true, + "operation_id": "21474802120262208", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003868105", + "precision": 6 + } + } + }, + "block": 4999959, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:45:12", + "virtual_op": true, + "operation_id": "21474660386343488", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003872998", + "precision": 6 + } + } + }, + "block": 4999950, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:44:42", + "virtual_op": true, + "operation_id": "21474621731637824", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000037", + "amount": "5031487272", + "precision": 6 + }, + "worker": "blocktrades" + } + }, + "block": 4999950, + "trx_id": "aa7d35a97a0df4a3ba5c696005c0bd6f5123ae5f", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-09-15T19:44:42", + "virtual_op": true, + "operation_id": "21474621731637070", + "trx_in_block": 3 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3003892392", + "precision": 6 + } + } + }, + "block": 4999916, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-09-15T19:42:54", + "virtual_op": true, + "operation_id": "21474475702752064", + "trx_in_block": -1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "blocktrades", + "author": "larrytom", + "weight": 0, + "rshares": 817253263497, + "permlink": "my-brother-s-heroin-addiction-destroyed-our-family", + "pending_payout": { + "nai": "@@000000013", + "amount": "0", + "precision": 3 + }, + "total_vote_weight": "65813785392141567" + } + }, + "block": 4999915, + "trx_id": "db81c06d8d156efbb8e4627feabe8093abdcaf3b", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-15T19:42:51", + "virtual_op": true, + "operation_id": "21474471407780680", + "trx_in_block": 1 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.tavern.yaml b/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.tavern.yaml new file mode 100644 index 000000000..fbd9ce109 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/blocktrades_first_page.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" + page-size: 20 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern 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 new file mode 100644 index 000000000..f90f0404c --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.pat.json @@ -0,0 +1,444 @@ +{ + "total_operations": 219867, + "total_pages": 10994, + "operations_result": [ + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154434, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:45:06", + "virtual_op": true, + "operation_id": "663288979390528", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154412, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:44:00", + "virtual_op": true, + "operation_id": "663194490110016", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154377, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:42:15", + "virtual_op": true, + "operation_id": "663044166254656", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154369, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:41:51", + "virtual_op": true, + "operation_id": "663009806516288", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154335, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:40:09", + "virtual_op": true, + "operation_id": "662863777628224", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154326, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:39:42", + "virtual_op": true, + "operation_id": "662825122922560", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154296, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:38:12", + "virtual_op": true, + "operation_id": "662696273903680", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154269, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:36:48", + "virtual_op": true, + "operation_id": "662580309786688", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154264, + "trx_id": null, + "op_pos": 2, + "op_type_id": 64, + "timestamp": "2016-03-30T01:36:33", + "virtual_op": true, + "operation_id": "662558834950464", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154230, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:34:45", + "virtual_op": true, + "operation_id": "662412806062144", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154207, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:33:33", + "virtual_op": true, + "operation_id": "662314021814848", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000021", + "amount": "21000", + "precision": 3 + }, + "worker": "blocktrades" + } + }, + "block": 154207, + "trx_id": "d99615f7c225e363a004f7ebf98d8b800b68d5c8", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-03-30T01:33:33", + "virtual_op": true, + "operation_id": "662314021814606", + "trx_in_block": 0 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154200, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:33:12", + "virtual_op": true, + "operation_id": "662283957043776", + "trx_in_block": -1 + }, + { + "op": { + "type": "pow_reward_operation", + "value": { + "reward": { + "nai": "@@000000021", + "amount": "21000", + "precision": 3 + }, + "worker": "blocktrades" + } + }, + "block": 154200, + "trx_id": "1991f6c80c31cb8a8f9b8e0c8f8e1e64d29fd035", + "op_pos": 1, + "op_type_id": 78, + "timestamp": "2016-03-30T01:33:12", + "virtual_op": true, + "operation_id": "662283957043534", + "trx_in_block": 0 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154168, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:31:30", + "virtual_op": true, + "operation_id": "662146518089792", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154153, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:30:42", + "virtual_op": true, + "operation_id": "662082093580352", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000021", + "amount": "1000", + "precision": 3 + } + } + }, + "block": 154138, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:29:54", + "virtual_op": true, + "operation_id": "662017669070912", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "1000000", + "precision": 6 + } + } + }, + "block": 154117, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-03-30T01:28:48", + "virtual_op": true, + "operation_id": "661927474757696", + "trx_in_block": -1 + }, + { + "op": { + "type": "account_created_operation", + "value": { + "creator": "blocktrades", + "new_account_name": "blocktrades", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + } + } + }, + "block": 152447, + "trx_id": "bdb74f0af41fb6ac1d4745d9f30b50768bd41bfe", + "op_pos": 1, + "op_type_id": 80, + "timestamp": "2016-03-30T00:04:36", + "virtual_op": true, + "operation_id": "654754879373648", + "trx_in_block": 0 + }, + { + "op": { + "type": "pow_operation", + "value": { + "work": { + "work": "0000000635993a69081f52f6401293e2b73b283d37eacc07e0d786fb0107aaef", + "input": "38c4bdc32a2ffc585f817be42f2c84a6cc29876128791e7b083cc006f1da9cfa", + "worker": "STM6sK2WuCasEYXK5gbVjGQZMdNcTNuFghr9Uj2CAKKdDH6ucVUqu", + "signature": "2071b73b17987ab392ee8138a6ddf88cd52459e75b596508b349659573db8006ad443e1dbfab563a8cf15074c2b11699b8e6ac0de315d98623306641dbfe016ab7" + }, + "nonce": "7375180734000095590", + "props": { + "hbd_interest_rate": 1000, + "maximum_block_size": 131072, + "account_creation_fee": { + "nai": "@@000000021", + "amount": "100000", + "precision": 3 + } + }, + "block_id": "0002537ef28b6258e68882944162060d236e3f36", + "worker_account": "blocktrades" + } + }, + "block": 152447, + "trx_id": "bdb74f0af41fb6ac1d4745d9f30b50768bd41bfe", + "op_pos": 0, + "op_type_id": 14, + "timestamp": "2016-03-30T00:04:36", + "virtual_op": false, + "operation_id": "654754879373326", + "trx_in_block": 0 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.tavern.yaml b/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.tavern.yaml new file mode 100644 index 000000000..3aebf5aa5 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/blocktrades_last_page.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" + page: 1 + page-size: 20 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern 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 new file mode 100644 index 000000000..ce745ec50 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/filter_by_op.pat.json @@ -0,0 +1,142 @@ +{ + "total_operations": 7947, + "total_pages": 398, + "operations_result": [ + { + "op": { + "type": "vote_operation", + "value": { + "voter": "blocktrades", + "author": "larrytom", + "weight": 0, + "permlink": "my-brother-s-heroin-addiction-destroyed-our-family" + } + }, + "block": 4999915, + "trx_id": "db81c06d8d156efbb8e4627feabe8093abdcaf3b", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:42:51", + "virtual_op": false, + "operation_id": "21474471407780352", + "trx_in_block": 1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "When will the t-shirt ship?", + "title": "", + "author": "blocktrades", + "permlink": "re-cryptojoycom-help-steem-buy-steemit-apparel-day-2-20160915t193858376z", + "json_metadata": "{\"tags\":[\"steem\"]}", + "parent_author": "cryptojoy.com", + "parent_permlink": "help-steem-buy-steemit-apparel-day-2" + } + }, + "block": 4999840, + "trx_id": "ef94aba27f9875d6da33b26dae44ee63f06f89a2", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-09-15T19:38:54", + "virtual_op": false, + "operation_id": "21474149285233153", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "blocktrades", + "author": "jackgallenhall", + "weight": 10000, + "permlink": "how-to-make-paper-flowers" + } + }, + "block": 4999714, + "trx_id": "48ce10a00e845ffe9a33728d71c6506f1e6f5f95", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:32:18", + "virtual_op": false, + "operation_id": "21473608119353344", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "blocktrades", + "author": "juanmiguelsalas", + "weight": 10000, + "permlink": "how-the-number-pi-sounds-on-a-piano" + } + }, + "block": 4999574, + "trx_id": "e80b9af41ff4d110e4087cf8d6874a35d7734c51", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T19:24:57", + "virtual_op": false, + "operation_id": "21473006823933440", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "blocktrades", + "author": "abudar", + "weight": 10000, + "permlink": "artwork-from-cigarette-wrap" + } + }, + "block": 4998907, + "trx_id": "749c2f29cdfd5dd4395f728ff4aff73c3791fcba", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T18:49:48", + "virtual_op": false, + "operation_id": "21470142080747008", + "trx_in_block": 3 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "blocktrades", + "author": "mihaiart", + "weight": 10000, + "permlink": "the-queen-of-amazon-drawing-a-visual-progression" + } + }, + "block": 4998814, + "trx_id": "754e4acdbeb088480544639901e38352e844eedb", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T18:44:48", + "virtual_op": false, + "operation_id": "21469742648787968", + "trx_in_block": 2 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "blocktrades", + "author": "titusfrost", + "weight": 10000, + "permlink": "new-mr-robot-episode-introduces-e-corp-s-new-ecoin" + } + }, + "block": 4998749, + "trx_id": "ba5ea077814fce3c9360d815635301a14167c8b7", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-15T18:41:21", + "virtual_op": false, + "operation_id": "21469463475913728", + "trx_in_block": 2 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_op.tavern.yaml b/tests/tavern/get_ops_by_account/positive/filter_by_op.tavern.yaml new file mode 100644 index 000000000..d0ca273c1 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/filter_by_op.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" + operation-types: "0,1" + page-size: 20 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern 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 new file mode 100644 index 000000000..e1864a764 --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/filter_by_range.pat.json @@ -0,0 +1,112 @@ +{ + "total_operations": 158805, + "total_pages": 7941, + "operations_result": [ + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3683262830", + "precision": 6 + } + } + }, + "block": 3999980, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-08-11T21:59:06", + "virtual_op": true, + "operation_id": "17179783284656192", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3683272570", + "precision": 6 + } + } + }, + "block": 3999968, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-08-11T21:58:30", + "virtual_op": true, + "operation_id": "17179731745050432", + "trx_in_block": -1 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3683301154", + "precision": 6 + } + } + }, + "block": 3999935, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-08-11T21:56:51", + "virtual_op": true, + "operation_id": "17179590011129664", + "trx_in_block": -1 + }, + { + "op": { + "type": "comment_operation", + "value": { + "body": "Heh, I just read your related post. Sorry to burst your bubble, but the vote on that article wasn't even really by me, it was by my wife using the account. And I'm quite sure she doesn't know the author. But this account's vote power is really large. You're just going to have to accept that there's some \"lottery effect\" in posting right now. Your best chance is to post more often.", + "title": "", + "author": "blocktrades", + "permlink": "re-sardonyx-re-blocktrades-is-vote-changing-an-important-feature-for-steem-20160811t215649239z", + "json_metadata": "{\"tags\":[\"steem\"]}", + "parent_author": "sardonyx", + "parent_permlink": "re-blocktrades-is-vote-changing-an-important-feature-for-steem-20160811t202953999z" + } + }, + "block": 3999933, + "trx_id": "7051c43d063e1c11715ecf239c5e8ce34feaa0d4", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-08-11T21:56:45", + "virtual_op": false, + "operation_id": "17179581421192705", + "trx_in_block": 3 + }, + { + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "blocktrades", + "vesting_shares": { + "nai": "@@000000037", + "amount": "3683314142", + "precision": 6 + } + } + }, + "block": 3999919, + "trx_id": null, + "op_pos": 1, + "op_type_id": 64, + "timestamp": "2016-08-11T21:56:03", + "virtual_op": true, + "operation_id": "17179521291655488", + "trx_in_block": -1 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_account/positive/filter_by_range.tavern.yaml b/tests/tavern/get_ops_by_account/positive/filter_by_range.tavern.yaml new file mode 100644 index 000000000..dd9bcc21f --- /dev/null +++ b/tests/tavern/get_ops_by_account/positive/filter_by_range.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" + page-size: 20 + to-block: "4000000" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.pat.json b/tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.pat.json new file mode 100644 index 000000000..ff6646ac2 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Assert Exception:args.page-size <= 10000: page-size of 10001 is greater than maxmimum allowed" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.tavern.yaml b/tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.tavern.yaml new file mode 100644 index 000000000..7443180c0 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/exceeds_page_size.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + page-size: 10001 + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.pat.json b/tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.pat.json new file mode 100644 index 000000000..1aefaaf32 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Invalid format: d400000" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.tavern.yaml b/tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.tavern.yaml new file mode 100644 index 000000000..21a78f89d --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/invalid_block_num.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "d400000" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.pat.json b/tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.pat.json new file mode 100644 index 000000000..cb5c93483 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Invalid format: 201608-12T19:38:51" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.tavern.yaml b/tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.tavern.yaml new file mode 100644 index 000000000..8f4607d56 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/invalid_timestamp.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "201608-12T19:38:51" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_block_paging/negative/negative_page.pat.json b/tests/tavern/get_ops_by_block_paging/negative/negative_page.pat.json new file mode 100644 index 000000000..6a889fe56 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/negative_page.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Assert Exception:page <= 0: page of -1 is lesser or equal 0" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/negative/negative_page.tavern.yaml b/tests/tavern/get_ops_by_block_paging/negative/negative_page.tavern.yaml new file mode 100644 index 000000000..abee4424c --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/negative_page.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + page: -1 + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_block_paging/negative/negative_page_size.pat.json b/tests/tavern/get_ops_by_block_paging/negative/negative_page_size.pat.json new file mode 100644 index 000000000..6b85b0820 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/negative_page_size.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Assert Exception:page-size > 0: page-size of -1 is lesser or equal 0" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/negative/negative_page_size.tavern.yaml b/tests/tavern/get_ops_by_block_paging/negative/negative_page_size.tavern.yaml new file mode 100644 index 000000000..fb66832c8 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/negative_page_size.tavern.yaml @@ -0,0 +1,27 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + page-size: -1 + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_block_paging/negative/non_existent.pat.json b/tests/tavern/get_ops_by_block_paging/negative/non_existent.pat.json new file mode 100644 index 000000000..4f8bfcf39 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/non_existent.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Block_num '5000001' does not exist" +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/negative/non_existent.tavern.yaml b/tests/tavern/get_ops_by_block_paging/negative/non_existent.tavern.yaml new file mode 100644 index 000000000..20f55c0ec --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/negative/non_existent.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafah PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_ops_by_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000001" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_ops_by_block_paging/positive/change_direction.pat.json b/tests/tavern/get_ops_by_block_paging/positive/change_direction.pat.json new file mode 100644 index 000000000..139d8cd73 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/change_direction.pat.json @@ -0,0 +1,117 @@ +{ + "total_operations": 15, + "total_pages": 3, + "operations_result": [ + { + "op": { + "type": "custom_json_operation", + "value": { + "id": "follow", + "json": "[\"follow\",{\"follower\":\"seanmclellan\",\"following\":\"rb3coins\",\"what\":[\"blog\"]}]", + "required_auths": [], + "required_posting_auths": [ + "seanmclellan" + ] + } + }, + "block": 4862666, + "trx_id": "5093327e382cb81b571cb959746ad09dd388b999", + "op_pos": 0, + "op_type_id": 18, + "timestamp": "2016-09-11T00:42:54", + "virtual_op": false, + "operation_id": "20884991441371154", + "trx_in_block": 0 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "hedge-x", + "author": "sweetsssj", + "weight": 10000, + "permlink": "memoirs-of-malta-popeye-village-and-it-s-crazy-water-dance-party-party" + } + }, + "block": 4862666, + "trx_id": "0615c386f659ab80ebdadf68edb6f80306999b14", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-11T00:42:54", + "virtual_op": false, + "operation_id": "20884991441371392", + "trx_in_block": 1 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "hedge-x", + "author": "sweetsssj", + "weight": "17188667389647363", + "rshares": 390490129783, + "permlink": "memoirs-of-malta-popeye-village-and-it-s-crazy-water-dance-party-party", + "pending_payout": { + "nai": "@@000000013", + "amount": "135224", + "precision": 3 + }, + "total_vote_weight": "16653105694311316861" + } + }, + "block": 4862666, + "trx_id": "0615c386f659ab80ebdadf68edb6f80306999b14", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-11T00:42:54", + "virtual_op": true, + "operation_id": "20884991441371720", + "trx_in_block": 1 + }, + { + "op": { + "type": "vote_operation", + "value": { + "voter": "salebored", + "author": "doitvoluntarily", + "weight": 10000, + "permlink": "a-business-in-giving-away-to-others" + } + }, + "block": 4862666, + "trx_id": "be78996637ef6dd965f3611cca76991fa8ce6f27", + "op_pos": 0, + "op_type_id": 0, + "timestamp": "2016-09-11T00:42:54", + "virtual_op": false, + "operation_id": "20884991441371904", + "trx_in_block": 2 + }, + { + "op": { + "type": "effective_comment_vote_operation", + "value": { + "voter": "salebored", + "author": "doitvoluntarily", + "weight": 133167893033795, + "rshares": 50215700, + "permlink": "a-business-in-giving-away-to-others", + "pending_payout": { + "nai": "@@000000013", + "amount": "10", + "precision": 3 + }, + "total_vote_weight": "131666730283547418" + } + }, + "block": 4862666, + "trx_id": "be78996637ef6dd965f3611cca76991fa8ce6f27", + "op_pos": 1, + "op_type_id": 72, + "timestamp": "2016-09-11T00:42:54", + "virtual_op": true, + "operation_id": "20884991441372232", + "trx_in_block": 2 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/positive/change_direction.tavern.yaml b/tests/tavern/get_ops_by_block_paging/positive/change_direction.tavern.yaml new file mode 100644 index 000000000..2c27f46ea --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/change_direction.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_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "4862666" + page-size: 5 + page-order: "asc" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_ops_by_block_paging/positive/filter_by_account.pat.json b/tests/tavern/get_ops_by_block_paging/positive/filter_by_account.pat.json new file mode 100644 index 000000000..667db2448 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/filter_by_account.pat.json @@ -0,0 +1,28 @@ +{ + "total_operations": 1, + "total_pages": 1, + "operations_result": [ + { + "op": { + "type": "comment_operation", + "value": { + "body": "I need your help to solve this problem with Mr. justin o'connell: https://steemit.com/steemit/@luisucv34/i-would-like-to-publicly-apologize-to-justin-oconnell-from-cryptocoinsnews", + "title": "", + "author": "luisucv34", + "permlink": "re-carlos-cabeza-steemit-enables-user-accounts-after-hacking-into-their-systems-20160722t204333625z", + "json_metadata": "{\"tags\":[\"steemit\"],\"links\":[\"https://steemit.com/steemit/@luisucv34/i-would-like-to-publicly-apologize-to-justin-oconnell-from-cryptocoinsnews\"]}", + "parent_author": "carlos-cabeza", + "parent_permlink": "steemit-enables-user-accounts-after-hacking-into-their-systems" + } + }, + "block": 3426366, + "trx_id": "8cb06dc4ad7ca0142208a7094e61f72ca7746388", + "op_pos": 0, + "op_type_id": 1, + "timestamp": "2016-07-22T20:42:51", + "virtual_op": false, + "operation_id": "14716129914126337", + "trx_in_block": 0 + } + ] +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/positive/filter_by_account.tavern.yaml b/tests/tavern/get_ops_by_block_paging/positive/filter_by_account.tavern.yaml new file mode 100644 index 000000000..0708cf135 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/filter_by_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_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "3426366" + account-name: "luisucv34" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_ops_by_block_paging/positive/filter_by_op.pat.json b/tests/tavern/get_ops_by_block_paging/positive/filter_by_op.pat.json new file mode 100644 index 000000000..cac1f3d08 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/filter_by_op.pat.json @@ -0,0 +1,120 @@ +{ + "operations_result": [ + { + "block": 4421146, + "op": { + "type": "vote_operation", + "value": { + "author": "kafkanarchy84", + "permlink": "my-unschooling-path-to-deprogramming-a-list-of-books-movies-and-resources-for-the-pilgrim-in-freedom", + "voter": "sitaru", + "weight": 10000 + } + }, + "op_pos": 0, + "op_type_id": 0, + "operation_id": "18988677480844288", + "timestamp": "2016-08-26T15:29:45", + "trx_id": "d1b5f593c3a0bace69ebe883bf86c3afb4cf842c", + "trx_in_block": 7, + "virtual_op": false + }, + { + "block": 4421146, + "op": { + "type": "vote_operation", + "value": { + "author": "dana-edwards", + "permlink": "mso-u", + "voter": "lee3", + "weight": 10000 + } + }, + "op_pos": 0, + "op_type_id": 0, + "operation_id": "18988677480843776", + "timestamp": "2016-08-26T15:29:45", + "trx_id": "0030b41cb3b79474e7779cf5b4b061f903422c9d", + "trx_in_block": 6, + "virtual_op": false + }, + { + "block": 4421146, + "op": { + "type": "vote_operation", + "value": { + "author": "rittr", + "permlink": "auf-die-groesse-kommt-es-an-tipps-fuer-ein-gutes-vorschaubild-auf-steemit", + "voter": "doggnostic", + "weight": 10000 + } + }, + "op_pos": 0, + "op_type_id": 0, + "operation_id": "18988677480843264", + "timestamp": "2016-08-26T15:29:45", + "trx_id": "4d427ec22606e3a9b263213d3c79bdafe49fe4c2", + "trx_in_block": 5, + "virtual_op": false + }, + { + "block": 4421146, + "op": { + "type": "vote_operation", + "value": { + "author": "jpiper20", + "permlink": "the-first-and-only-time-i-grew-a-cannabis-plant-the-whole-experience", + "voter": "matthewtiii", + "weight": 10000 + } + }, + "op_pos": 0, + "op_type_id": 0, + "operation_id": "18988677480842496", + "timestamp": "2016-08-26T15:29:45", + "trx_id": "729424799feb86d4951fd06942ddb0b6cba82d5c", + "trx_in_block": 3, + "virtual_op": false + }, + { + "block": 4421146, + "op": { + "type": "vote_operation", + "value": { + "author": "rittr", + "permlink": "auf-die-groesse-kommt-es-an-tipps-fuer-ein-gutes-vorschaubild-auf-steemit", + "voter": "jenny-talls", + "weight": 10000 + } + }, + "op_pos": 0, + "op_type_id": 0, + "operation_id": "18988677480841984", + "timestamp": "2016-08-26T15:29:45", + "trx_id": "05375a709a42b2a2b25b08db0df8aa4c46f6956e", + "trx_in_block": 2, + "virtual_op": false + }, + { + "block": 4421146, + "op": { + "type": "vote_operation", + "value": { + "author": "ratel", + "permlink": "devoted-to-believers-who-have-not-yet-rotted", + "voter": "litrbooh", + "weight": 10000 + } + }, + "op_pos": 0, + "op_type_id": 0, + "operation_id": "18988677480841472", + "timestamp": "2016-08-26T15:29:45", + "trx_id": "4ab53f2d45dab8c1430a2c3c0a0ce7f43cf26c87", + "trx_in_block": 1, + "virtual_op": false + } + ], + "total_operations": 6, + "total_pages": 1 +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/positive/filter_by_op.tavern.yaml b/tests/tavern/get_ops_by_block_paging/positive/filter_by_op.tavern.yaml new file mode 100644 index 000000000..e045c5741 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/filter_by_op.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_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "4421146" + operation-types: "0" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_ops_by_block_paging/positive/first_page.pat.json b/tests/tavern/get_ops_by_block_paging/positive/first_page.pat.json new file mode 100644 index 000000000..f0ef1d76f --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/first_page.pat.json @@ -0,0 +1,56 @@ +{ + "operations_result": [ + { + "block": 5000000, + "op": { + "type": "producer_reward_operation", + "value": { + "producer": "ihashfury", + "vesting_shares": { + "amount": "3003845513", + "nai": "@@000000037", + "precision": 6 + } + } + }, + "op_pos": 1, + "op_type_id": 64, + "operation_id": "21474836480000832", + "timestamp": "2016-09-15T19:47:21", + "trx_id": null, + "trx_in_block": -1, + "virtual_op": true + }, + { + "block": 5000000, + "op": { + "type": "limit_order_create_operation", + "value": { + "amount_to_sell": { + "amount": "10324", + "nai": "@@000000021", + "precision": 3 + }, + "expiration": "2035-10-29T06:32:22", + "fill_or_kill": false, + "min_to_receive": { + "amount": "6819", + "nai": "@@000000013", + "precision": 3 + }, + "orderid": 1473968838, + "owner": "cvk" + } + }, + "op_pos": 0, + "op_type_id": 5, + "operation_id": "21474836480000517", + "timestamp": "2016-09-15T19:47:21", + "trx_id": "973290d26bac31335c000c7a3d3fe058ce3dbb9f", + "trx_in_block": 1, + "virtual_op": false + } + ], + "total_operations": 4, + "total_pages": 2 +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/positive/first_page.tavern.yaml b/tests/tavern/get_ops_by_block_paging/positive/first_page.tavern.yaml new file mode 100644 index 000000000..614d11504 --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/first_page.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_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + page-size: 2 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_ops_by_block_paging/positive/last_page.pat.json b/tests/tavern/get_ops_by_block_paging/positive/last_page.pat.json new file mode 100644 index 000000000..9d1aa86ad --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/last_page.pat.json @@ -0,0 +1,87 @@ +{ + "operations_result": [ + { + "block": 5000000, + "op": { + "type": "account_created_operation", + "value": { + "creator": "steem", + "initial_delegation": { + "amount": "0", + "nai": "@@000000037", + "precision": 6 + }, + "initial_vesting_shares": { + "amount": "30038455132", + "nai": "@@000000037", + "precision": 6 + }, + "new_account_name": "kefadex" + } + }, + "op_pos": 1, + "op_type_id": 80, + "operation_id": "21474836480000336", + "timestamp": "2016-09-15T19:47:21", + "trx_id": "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "trx_in_block": 0, + "virtual_op": true + }, + { + "block": 5000000, + "op": { + "type": "account_create_operation", + "value": { + "active": { + "account_auths": [], + "key_auths": [ + [ + "STM73bAnWEwkdUa7Lp4ovNzyu4soHUCaCNSz79YHQsDqscNdSe1E8", + 1 + ] + ], + "weight_threshold": 1 + }, + "creator": "steem", + "fee": { + "amount": "10000", + "nai": "@@000000021", + "precision": 3 + }, + "json_metadata": "", + "memo_key": "STM8i93Zznxu2QRNLCHBDXt5yyiMW1c3GEyVKV9XAs8H5wEWwdJaM", + "new_account_name": "kefadex", + "owner": { + "account_auths": [], + "key_auths": [ + [ + "STM871wj5KKnbwwiRv3scVcxQ26ynPnE1uaZr6dPpqVu9F4zJZgjZ", + 1 + ] + ], + "weight_threshold": 1 + }, + "posting": { + "account_auths": [], + "key_auths": [ + [ + "STM7fXKrnQN3xhgFTQBFMgR9TU8CxfgAJrLvSDjGuM2bFkiuKfwZg", + 1 + ] + ], + "weight_threshold": 1 + } + } + }, + "op_pos": 0, + "op_type_id": 9, + "operation_id": "21474836480000009", + "timestamp": "2016-09-15T19:47:21", + "trx_id": "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "trx_in_block": 0, + "virtual_op": false + } + ], + "total_operations": 4, + "total_pages": 2 +} \ No newline at end of file diff --git a/tests/tavern/get_ops_by_block_paging/positive/last_page.tavern.yaml b/tests/tavern/get_ops_by_block_paging/positive/last_page.tavern.yaml new file mode 100644 index 000000000..2cc7a473c --- /dev/null +++ b/tests/tavern/get_ops_by_block_paging/positive/last_page.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_block_paging" + method: POST + headers: + content-type: application/json + accept: application/json + json: + block-num: "5000000" + page-size: 2 + page: 2 + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_transaction/negative/invalid_hash.pat.json b/tests/tavern/get_transaction/negative/invalid_hash.pat.json new file mode 100644 index 000000000..cb74f8194 --- /dev/null +++ b/tests/tavern/get_transaction/negative/invalid_hash.pat.json @@ -0,0 +1,6 @@ +{ + "code": "22023", + "details": null, + "hint": null, + "message": "invalid hexadecimal data: odd number of digits" +} \ No newline at end of file diff --git a/tests/tavern/get_transaction/negative/invalid_hash.tavern.yaml b/tests/tavern/get_transaction/negative/invalid_hash.tavern.yaml new file mode 100644 index 000000000..a0aa39a27 --- /dev/null +++ b/tests/tavern/get_transaction/negative/invalid_hash.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_transaction" + method: POST + headers: + content-type: application/json + accept: application/json + json: + transaction-id: "3448858738752" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_transaction/negative/non_existent_trx.pat.json b/tests/tavern/get_transaction/negative/non_existent_trx.pat.json new file mode 100644 index 000000000..55815c8ad --- /dev/null +++ b/tests/tavern/get_transaction/negative/non_existent_trx.pat.json @@ -0,0 +1,6 @@ +{ + "code": "P0001", + "details": null, + "hint": null, + "message": "Assert Exception:false: Unknown Transaction 954f6de36e6715d128fa8eb5a053fc254b05ded1" + } \ No newline at end of file diff --git a/tests/tavern/get_transaction/negative/non_existent_trx.tavern.yaml b/tests/tavern/get_transaction/negative/non_existent_trx.tavern.yaml new file mode 100644 index 000000000..2d03210d3 --- /dev/null +++ b/tests/tavern/get_transaction/negative/non_existent_trx.tavern.yaml @@ -0,0 +1,26 @@ +--- + test_name: Hafbe PostgREST + + marks: + - patterntest + - negative + + includes: + - !include ../../common.yaml + + stages: + - name: test + request: + url: "{service.proto:s}://{service.server:s}:{service.port}/rpc/get_transaction" + method: POST + headers: + content-type: application/json + accept: application/json + json: + transaction-id: "954f6de36e6715d128fa8eb5a053fc254b05ded1" + response: + status_code: 400 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern + extra_kwargs: + error_response: true diff --git a/tests/tavern/get_transaction/positive/by_trx.pat.json b/tests/tavern/get_transaction/positive/by_trx.pat.json new file mode 100644 index 000000000..d6f101132 --- /dev/null +++ b/tests/tavern/get_transaction/positive/by_trx.pat.json @@ -0,0 +1,61 @@ +{ + "transaction_json": { + "ref_block_num": 19263, + "ref_block_prefix": 1534306502, + "extensions": [], + "expiration": "2016-09-15T19:47:33", + "operations": [ + { + "type": "account_create_operation", + "value": { + "fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + }, + "owner": { + "key_auths": [ + [ + "STM871wj5KKnbwwiRv3scVcxQ26ynPnE1uaZr6dPpqVu9F4zJZgjZ", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "active": { + "key_auths": [ + [ + "STM73bAnWEwkdUa7Lp4ovNzyu4soHUCaCNSz79YHQsDqscNdSe1E8", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "creator": "steem", + "posting": { + "key_auths": [ + [ + "STM7fXKrnQN3xhgFTQBFMgR9TU8CxfgAJrLvSDjGuM2bFkiuKfwZg", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "memo_key": "STM8i93Zznxu2QRNLCHBDXt5yyiMW1c3GEyVKV9XAs8H5wEWwdJaM", + "json_metadata": "", + "new_account_name": "kefadex" + } + } + ], + "signatures": [ + "1f63c75cc966916ea705a6fdef0821a810bdabb07118a3721f4cd52c972b9e4522534248c45ac908c1498752165a1d937eaf55ab6c028d7ee0ad893d3d4330d066" + ] + }, + "transaction_id": "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "block_num": 5000000, + "transaction_num": 0, + "timestamp": "2016-09-15T19:47:21" +} \ No newline at end of file diff --git a/tests/tavern/get_transaction/positive/by_trx.tavern.yaml b/tests/tavern/get_transaction/positive/by_trx.tavern.yaml new file mode 100644 index 000000000..81a25abe2 --- /dev/null +++ b/tests/tavern/get_transaction/positive/by_trx.tavern.yaml @@ -0,0 +1,23 @@ +--- + 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_transaction" + method: POST + headers: + content-type: application/json + accept: application/json + json: + transaction-id: "6707feb450da66dc223ab5cb3e259937b2fef6bf" + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/get_transaction/positive/include_virtual.pat.json b/tests/tavern/get_transaction/positive/include_virtual.pat.json new file mode 100644 index 000000000..d37153af6 --- /dev/null +++ b/tests/tavern/get_transaction/positive/include_virtual.pat.json @@ -0,0 +1,78 @@ +{ + "transaction_json": { + "ref_block_num": 19263, + "ref_block_prefix": 1534306502, + "extensions": [], + "expiration": "2016-09-15T19:47:33", + "operations": [ + { + "type": "account_create_operation", + "value": { + "fee": { + "nai": "@@000000021", + "amount": "10000", + "precision": 3 + }, + "owner": { + "key_auths": [ + [ + "STM871wj5KKnbwwiRv3scVcxQ26ynPnE1uaZr6dPpqVu9F4zJZgjZ", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "active": { + "key_auths": [ + [ + "STM73bAnWEwkdUa7Lp4ovNzyu4soHUCaCNSz79YHQsDqscNdSe1E8", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "creator": "steem", + "posting": { + "key_auths": [ + [ + "STM7fXKrnQN3xhgFTQBFMgR9TU8CxfgAJrLvSDjGuM2bFkiuKfwZg", + 1 + ] + ], + "account_auths": [], + "weight_threshold": 1 + }, + "memo_key": "STM8i93Zznxu2QRNLCHBDXt5yyiMW1c3GEyVKV9XAs8H5wEWwdJaM", + "json_metadata": "", + "new_account_name": "kefadex" + } + }, + { + "type": "account_created_operation", + "value": { + "creator": "steem", + "new_account_name": "kefadex", + "initial_delegation": { + "nai": "@@000000037", + "amount": "0", + "precision": 6 + }, + "initial_vesting_shares": { + "nai": "@@000000037", + "amount": "30038455132", + "precision": 6 + } + } + } + ], + "signatures": [ + "1f63c75cc966916ea705a6fdef0821a810bdabb07118a3721f4cd52c972b9e4522534248c45ac908c1498752165a1d937eaf55ab6c028d7ee0ad893d3d4330d066" + ] + }, + "transaction_id": "6707feb450da66dc223ab5cb3e259937b2fef6bf", + "block_num": 5000000, + "transaction_num": 0, + "timestamp": "2016-09-15T19:47:21" +} \ No newline at end of file diff --git a/tests/tavern/get_transaction/positive/include_virtual.tavern.yaml b/tests/tavern/get_transaction/positive/include_virtual.tavern.yaml new file mode 100644 index 000000000..e197a013f --- /dev/null +++ b/tests/tavern/get_transaction/positive/include_virtual.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_transaction" + method: POST + headers: + content-type: application/json + accept: application/json + json: + transaction-id: "6707feb450da66dc223ab5cb3e259937b2fef6bf" + include-virtual: true + response: + status_code: 200 + verify_response_with: + function: validate_response:compare_rest_response_with_pattern diff --git a/tests/tavern/pytest.ini b/tests/tavern/pytest.ini new file mode 100644 index 000000000..6bdcaf047 --- /dev/null +++ b/tests/tavern/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +markers = + patterntest: Mark tests using patterns to compare results + negative: Mark error tests -- GitLab