Compare commits

..

185 Commits

Author SHA1 Message Date
Dark Sun d3290d5b1b fix 2023-12-19 22:16:33 +03:00
Dark Sun 576ba19e76 fix 2023-12-19 22:12:26 +03:00
Dark Sun 09fb3c0eba update 2023-12-19 22:08:38 +03:00
Dark Sun 2303fcea9e rollback 2023-12-18 22:22:57 +03:00
Dark Sun e0bf1b534b update 2023-12-18 22:01:35 +03:00
Dark Sun 4481ebcbc0 update 2023-12-18 18:42:44 +03:00
Dark Sun f3ab699f83 update 2023-12-18 17:31:42 +03:00
Dark Sun 7bae572ec9 update 2023-12-18 14:16:00 +03:00
Dark Sun 5f1fb9490c push 2023-12-18 13:50:48 +03:00
Dark Sun 33ec53dc27 update 2023-12-09 20:29:20 +03:00
Dark Sun ad3ca3e988 update 2023-12-08 23:53:35 +03:00
Dark Sun a02917b922 update indexes 2023-12-08 23:25:38 +03:00
Dark Sun c49e6c20e7 update 2023-12-07 23:27:30 +03:00
Dark Sun e557e7d618 update 2023-12-07 17:48:31 +03:00
Dark Sun d84642e8be push 2023-12-07 16:58:28 +03:00
Dark Sun c0c857bc5b update 2023-12-07 16:55:00 +03:00
Dark Sun 20856ecec4 update 2023-12-07 16:48:37 +03:00
Dark Sun c9e821d2f4 update 2023-12-07 16:23:42 +03:00
Dark Sun fe48b146b3 fix typo 2023-12-07 14:39:24 +03:00
Dark Sun 1ef1514b15 update template 2023-12-07 14:02:05 +03:00
Igor Lins e Silva 32145b6e1c Update README.md 2023-10-10 21:21:35 -03:00
Bruno Leal 90d489b600 fix: repair fork index not found 2023-09-27 16:54:35 -03:00
Igor Lins e Silva 69646d9660 cleanup 2023-09-25 21:56:41 -03:00
Bruno Leal fb2fc20d1d Merge branch 'main' of https://github.com/eosrio/hyperion-history-api into main 2023-09-25 15:07:17 -03:00
Bruno Leal b7e17f9dc7 fix: fix progress status by amout of lines not chunks 2023-09-25 15:07:00 -03:00
Igor Lins e Silva b94f99d552 Merge pull request #142 from eosrio/large-tx-fix
Large tx-sig fix
2023-09-25 01:33:31 -03:00
Igor Lins e Silva 76807c6c86 cleanup 2023-09-25 01:29:53 -03:00
Igor Lins e Silva 69bcbaad18 flow control 2023-09-25 01:25:40 -03:00
Igor Lins e Silva e5d0126d08 Revert "include amqp-connection-manager"
This reverts commit 0579da66
2023-09-25 01:05:33 -03:00
Igor Lins e Silva e804aff53c log cleanup 2023-09-25 01:03:35 -03:00
Igor Lins e Silva 5d3b248bcd Revert "include amqp-connection-manager"
This reverts commit 4dcb607fcc.
2023-09-25 01:03:04 -03:00
Igor Lins e Silva d1eca214ae log cleanup 2023-09-25 00:54:41 -03:00
Igor Lins e Silva 4dcb607fcc include amqp-connection-manager 2023-09-25 00:45:23 -03:00
Igor Lins e Silva 0579da6613 include amqp-connection-manager 2023-09-25 00:29:07 -03:00
Igor Lins e Silva b8faf2ef70 package updates 2023-09-24 19:33:55 -03:00
Igor Lins e Silva bc98cecb52 send signatures on payload 2023-09-24 19:30:40 -03:00
Igor Lins e Silva 29ed9d372d add logs 2023-09-24 19:14:52 -03:00
Igor Lins e Silva d259008cb4 add logs 2023-09-24 19:13:08 -03:00
Igor Lins e Silva ce6f307bbe add logs 2023-09-24 18:32:15 -03:00
Igor Lins e Silva 44062fbe0e add logs 2023-09-24 18:28:07 -03:00
Igor Lins e Silva 94547ce8fd add logs 2023-09-24 18:02:49 -03:00
Igor Lins e Silva c59005bba0 make ingest clients public 2023-09-23 14:13:03 -03:00
Igor Lins e Silva bee1948f19 make ingest clients public 2023-09-23 14:12:45 -03:00
Bruno Leal 616133dab8 fix: repair chunk file 2023-09-13 18:34:04 -03:00
Igor Lins e Silva 28ade29d00 implement v2/stats/get_api_usage 2023-09-01 00:45:25 -03:00
Igor Lins e Silva 6fe3acce7e update v1/chain/abi_bin_to_json interface 2023-06-23 12:18:43 -03:00
Igor Lins e Silva 572b2b11e5 update socket.io to 4.7.0 2023-06-23 12:16:00 -03:00
Igor Lins e Silva 2fbee90b73 update v1/chain/abi_json_to_bin interface 2023-06-23 12:13:30 -03:00
Igor Lins e Silva e79cad82a4 update socket.io 2023-06-11 03:08:29 -03:00
Igor Lins e Silva e087c2971e Merge branch 'main' of https://github.com/eosrio/hyperion-history-api 2023-06-11 03:04:59 -03:00
Igor Lins e Silva 74072bd6cb prevent a conflict between disable_reading and the repair mode 2023-06-11 03:04:15 -03:00
Igor Lins e Silva ee3bf26263 package update 2023-05-26 04:54:38 +00:00
Igor Lins e Silva 367f37e989 hyperion repair cli v0.2.2 2023-05-26 04:53:07 +00:00
Igor Lins e Silva 65698c344d on-demand delta filtering for streams 2023-05-20 08:56:46 +00:00
Igor Lins e Silva b5f17b0133 cleanup 2023-05-20 07:26:07 +00:00
Igor Lins e Silva 5b65bd7d7b cleanup 2023-05-20 07:22:21 +00:00
Igor Lins e Silva b289036b0c - multiple streaming improvements
- stream-client v2.0.0 compatibility
- improved transitions on high volume streams
- added api.stream_scroll_limit (default -1 -> unlimited)
specify the maximum number of documents that can be requested during a history request in the streaming api
- added api.stream_scroll_batch (default 500)
specify the number of documents per streamed history request
2023-05-20 07:20:46 +00:00
Igor Lins e Silva a2a040ab55 allow date formats with space between date and time, replace %20 with T 2023-05-20 04:53:58 +00:00
Igor Lins e Silva 480e29f278 don't sort producers on get_schedule response 2023-05-15 16:19:27 -03:00
Igor Lins e Silva ce9dc8524e wait for ES to be available on api start 2023-05-11 06:16:23 -03:00
Igor Lins e Silva bc2d25394c wait for nodeos to be available on api start, prevent fastify plugin timeout 2023-05-11 03:01:29 -03:00
Igor Lins e Silva 88493248e1 wait for services to be available on indexer start 2023-05-11 02:10:35 -03:00
Igor Lins e Silva 7ceb009d31 wait for nodeos to be available on indexer start 2023-05-11 01:46:53 -03:00
Igor Lins e Silva 81606e6252 add indexing of proposed schedules on dedicated chain-schedule-* index, improve api endpoint (v2/history/get_schedule) 2023-05-08 04:42:55 -03:00
Igor Lins e Silva a9fb4b5b80 cleanup 2023-05-08 02:25:58 -03:00
Igor Lins e Silva f426a3dd4e use default control port 7002 if not defined on connections.json 2023-05-08 01:50:02 -03:00
Igor Lins e Silva 99c2772781 ignore repair tool build files 2023-05-08 01:42:44 -03:00
Igor Lins e Silva 8876213ecc update repair tool 2023-05-08 01:41:35 -03:00
Igor Lins e Silva 0798b08e2e fix lib event forwarding on shared api hosts 2023-05-07 19:42:58 -03:00
Igor Lins e Silva eb6fb9827a v18 is still supported 2023-05-05 08:31:07 -03:00
Igor Lins e Silva 44e487272a v3.3.9-5
- Node.js 20 compatibility
- added last_indexed_block/time on API responses
- fix index progress monitoring
2023-05-05 08:15:20 -03:00
Igor Lins e Silva bbbbf91f79 Update hyp-repair script and other deserializer cleanups 2023-05-05 03:54:04 +00:00
Igor Lins e Silva cd277b4f12 merge repair tool 2023-05-04 16:49:26 -03:00
Igor Lins e Silva 16e870135b merge repair tool 2023-05-04 16:48:44 -03:00
Igor Lins e Silva aa989dc5e6 merge repair tool 2023-05-04 16:45:11 -03:00
Igor Lins e Silva 4555112b9c merge repair tool 2023-05-04 16:24:32 -03:00
Igor Lins e Silva 89f0bf586b update packages 2023-05-04 05:48:10 -03:00
Igor Lins e Silva be13e81437 fix resource handler on deltas 2023-05-04 05:45:29 -03:00
Igor Lins e Silva 70bab7545b Merge pull request #140 from ankh2054/patch-1
Update fix-missing-blocks.py
2023-04-10 19:52:28 -03:00
Charles Holtzkampf 3c1d9fcc2f Update fix-missing-blocks.py
Updated to work with all versions of Hyperion
2023-03-27 11:18:11 +01:00
Igor Lins e Silva 498bc8ec75 Update example.config.json
remove `bypass_index_map`
2023-03-01 18:17:02 -03:00
Igor Lins e Silva 58f40531fe remove deprecated index mapping 2023-03-01 18:15:55 -03:00
Igor Lins e Silva 57e4492556 v3.3.9-4
- patch for https://github.com/advisories/GHSA-rc47-6667-2j5j
2023-03-01 18:09:02 -03:00
Igor Lins e Silva 832da15808 fix v1 get_actions to match receipts var 2023-03-01 18:02:45 -03:00
Igor Lins e Silva 4107daa621 ignore example chain config 2023-01-26 20:26:45 -03:00
Igor Lins e Silva b3adad54d8 Update package.json 2023-01-26 20:06:14 -03:00
Igor Lins e Silva 176932a78c avoid failed tsc builds 2023-01-26 20:05:05 -03:00
Igor Lins e Silva 3a5997ca98 set default health cache to 10s 2023-01-26 13:56:54 -03:00
Igor Lins e Silva ea8dd6d3f7 add cache to cat/health 2023-01-26 13:54:58 -03:00
Igor Lins e Silva 8c0be344a6 fix notified list on simple action output 2023-01-26 13:42:47 -03:00
Igor Lins e Silva fbd5904e25 fix act_digest output on v1 2023-01-26 12:57:15 -03:00
Igor Lins e Silva 05b7ab0f3a v.3.3.9-2 2023-01-25 22:11:20 -03:00
Igor Lins e Silva da34871f09 add settings.use_global_agent as optional
- global-agent was interfering with default self-signed certificates on secure elasticsearch setup
2023-01-25 22:09:00 -03:00
Igor Lins e Silva fa3c2cb878 Update hyp-config.ts 2023-01-25 20:49:14 -03:00
Igor Lins e Silva ea5f6d0be0 fix backup directory creation 2023-01-25 20:43:17 -03:00
Igor Lins e Silva 88598ea551 remove temp files 2023-01-25 20:43:05 -03:00
Igor Lins e Silva b06a422b54 Update .gitignore 2023-01-25 20:42:54 -03:00
Igor Lins e Silva 29ff9824c8 Update .gitignore 2023-01-25 20:42:00 -03:00
Igor Lins e Silva f2f0d0f41c fix paths 2023-01-25 20:38:35 -03:00
Igor Lins e Silva 7830b11eaf backport "hyp-config connections init" command 2023-01-25 20:26:46 -03:00
Igor Lins e Silva 55cb7ca74a re-include @timestamp 2023-01-20 03:10:48 -03:00
Igor Lins e Silva 9eea8d4a99 v3.3.9 2023-01-18 14:24:42 -03:00
Igor Lins e Silva 2827f85f3e v3.3.8 stable
- fix readers stopping before having finished
2023-01-18 14:20:56 -03:00
Igor Lins e Silva 2ee60bc276 v3.3.8 2022-12-09 17:25:17 -03:00
Igor Lins e Silva da295aa2d2 v3.3.8
- removed redundant notifications array, since receipts.receiver was already indexed
- updated get_action output to include all fields
- removed unused fields to save raw data storage
- added block_id as a searchable field to get_actions
- added parser 3.2 as default for the latest Antelope versions, removed deprecated v1.7 parser
- fastify security updates
- get_actions/get_deltas `before` and `after` now support block_num input as well as timestamps
2022-12-08 19:33:46 -03:00
Igor Lins e Silva 4035de3dac add pino-pretty package 2022-11-15 03:08:44 +00:00
Igor Lins e Silva 3b3483333d update bundled stream client 2022-11-14 23:03:55 +00:00
Igor Lins e Silva a66b3e63e1 add stream port to chain config 2022-11-14 18:05:06 +00:00
Igor Lins e Silva 80c57ca4a8 add stream port to chain config 2022-11-14 18:02:27 +00:00
Igor Lins e Silva c9ac57cbb6 remove redundant parse 2022-11-14 15:11:07 +00:00
Igor Lins e Silva 57ea9717f5 v3.3.7, upgrade deprecated fastify plugins 2022-11-09 13:01:22 -03:00
Igor Lins e Silva 40fa86f6d8 update packages for v3.3.7 2022-11-09 12:55:59 -03:00
Igor Lins e Silva e21554a239 make the indexer behavior clearer when using rewrite: true 2022-11-09 12:48:14 -03:00
Igor Lins e Silva 160b2ebd32 add logging 2022-11-09 12:00:12 -03:00
Igor Lins e Silva bb28ac7139 update packages 2022-11-09 11:54:27 -03:00
Igor Lins e Silva 4139cd02c1 fix proposal execution flag 2022-11-03 17:22:04 -03:00
Igor Lins e Silva c66e71df0e Update get_actions.ts 2022-10-26 17:19:00 -03:00
Igor Lins e Silva 7f15648b38 patch API queries for nested indexed data 2022-10-26 17:18:15 -03:00
Igor Lins e Silva 04c738fffe fix nested act data on failed abieos deserialization 2022-10-26 17:08:18 -03:00
Igor Lins e Silva c6b3afc1d1 Update index.ts 2022-10-26 09:54:26 -03:00
Igor Lins e Silva 91fd57bd83 Update get_deltas.ts 2022-10-26 09:41:40 -03:00
Igor Lins e Silva 2d3a46d0fe fix get_deltas param parsing 2022-10-26 09:40:05 -03:00
Igor Lins e Silva d99e1cdd8a Merge pull request #126 from ankh2054/main
Update fix-missing-blocks.py
2022-10-20 12:39:53 -03:00
Igor Lins e Silva 24ad40c889 use uWebsockets.js as Socket.IO engine 2022-10-17 01:20:31 +00:00
Charles Holtzkampf db9dd56b9a Update fix-missing-blocks.py 2022-10-04 14:10:59 +01:00
Igor Lins e Silva f7a18b55ab Update get_actions.ts 2022-09-22 13:56:58 -03:00
Igor Lins e Silva 91b6da103b Update get_actions.ts 2022-09-22 13:55:37 -03:00
Igor Lins e Silva f6aef13f88 Update get_actions.ts 2022-09-22 13:52:28 -03:00
Igor Lins e Silva 61c69d0ab6 Update get_actions.ts 2022-09-22 13:51:23 -03:00
Igor Lins e Silva 061d7a443d add optional hex_data 2022-09-22 13:46:02 -03:00
Igor Lins e Silva b7e2ead86d remove wrong encoding for hex_data 2022-09-22 13:21:39 -03:00
Igor Lins e Silva 3b74decbe6 add error output on get_tokens 2022-09-12 12:34:33 -03:00
Igor Lins e Silva b2b3a9d674 cleanup 2022-09-12 12:28:28 -03:00
Igor Lins e Silva 8b6fd9a1a8 Update health.ts 2022-09-12 12:22:57 -03:00
Igor Lins e Silva bc19f2caae Update health.ts 2022-09-12 12:19:09 -03:00
Igor Lins e Silva 82160c72ad fix calculation for total indexed 2022-09-12 12:15:29 -03:00
Igor Lins e Silva 3f4fd975a2 Update README.md 2022-09-11 23:48:17 -03:00
Igor Lins e Silva 86de28aadd Update README.md 2022-09-11 23:38:16 -03:00
Igor Lins e Silva 2ac15b0e5b Update README.md 2022-09-11 20:42:29 -03:00
Igor Lins e Silva 4fcee923bd Update README.md 2022-09-11 20:38:04 -03:00
Igor Lins e Silva 89c6cd280d Update README.md 2022-09-11 20:29:44 -03:00
Igor Lins e Silva f372d8318e Update README.md 2022-09-11 20:22:20 -03:00
Igor Lins e Silva 8af456d155 Update health.ts 2022-09-11 06:42:57 -03:00
Igor Lins e Silva 0696e81f6d Update health.ts 2022-09-11 05:42:48 -03:00
Igor Lins e Silva fbf0f634c9 add more information and interfaces 2022-09-11 05:40:44 -03:00
Igor Lins e Silva ac9fafd3be add redis cache for firstIndexedBlock to speed-up the health endpoint 2022-09-11 05:07:51 -03:00
Igor Lins e Silva a467b81404 Update get_creator.ts 2022-09-11 05:07:20 -03:00
Igor Lins e Silva 3c11a5109a add first_indexed_block to v2/health 2022-09-11 04:53:45 -03:00
Igor Lins e Silva 640eccb7bd Update get_creator.ts 2022-09-11 04:30:38 -03:00
Igor Lins e Silva de981f32b8 revert swagger to 6.1 2022-09-11 04:26:31 -03:00
Igor Lins e Silva 91821b6365 Update get_creator.ts 2022-09-11 04:24:34 -03:00
Igor Lins e Silva 5801801967 update deprecated swagger plugin 2022-09-11 04:24:29 -03:00
Igor Lins e Silva 206d92034b update packages + cleanup 2022-09-11 03:55:35 -03:00
Igor Lins e Silva 49bf80b57f Delete connections-demo.json 2022-09-11 03:42:58 -03:00
Igor Lins e Silva 279f5d9474 merge 3.3.5 to master 2022-09-11 03:42:18 -03:00
Igor Lins e Silva 7cf9f0613c rollback fastify-elasticsearch 2021-12-21 19:47:38 -03:00
Igor Lins e Silva a816efe82a 3.1.5 2021-12-21 19:13:04 -03:00
Igor Lins e Silva 56305d4138 update fastify-oas 2021-12-21 19:09:15 -03:00
Igor Lins e Silva 1aaeb6b78f update TS to fix elasticsearch.js build 2021-12-21 18:43:05 -03:00
Igor Lins e Silva a68aeb79c6 use alias to speedup search 2021-12-20 19:48:26 -03:00
Igor Lins e Silva 1ced41dfc6 Update master.ts 2021-12-20 19:43:46 -03:00
Igor Lins e Silva 0c3dad17cd update debug logs 2021-12-20 19:41:13 -03:00
Igor Lins e Silva c39b1df4a0 add extra logging 2021-12-20 19:18:36 -03:00
Igor Lins e Silva af59050e0b Update package.json 2021-12-20 18:55:31 -03:00
Igor Lins e Silva f7f5c2b738 Update ecosystem_settings.js 2021-08-20 00:17:05 -03:00
Igor Lins e Silva 994025c2c4 Merge pull request #61 from xebb82/patch-5
API logs need timestamp
2021-08-20 00:14:49 -03:00
Eric f859840318 API logs need timestamp
This fix will make sure the api logs gets timestamped.
2021-08-19 08:52:46 +02:00
Igor Lins e Silva c80eaaa9fc deprecate install env + package updates 2021-08-05 22:13:02 -03:00
Igor Lins e Silva c98f2dc431 remove unlisted worker logging 2021-07-31 05:12:33 -03:00
Igor Lins e Silva 797fb867b1 improve tx_cache 2021-07-31 04:59:05 -03:00
Igor Lins e Silva 38e939a640 Update .gitignore 2021-07-31 04:48:51 -03:00
Igor Lins e Silva 88a24c579f Update package.json 2021-07-21 10:16:55 -03:00
Igor Lins e Silva e17d6e8209 Merge pull request #59 from eosrio/3.1.4
v3.1.4
2021-07-21 10:12:42 -03:00
Igor Lins e Silva 787b5aba65 implementing preemptive caching on redis for get_transaction
TTL is configurable via `api.tx_cache_expiration_sec`
2021-07-21 10:10:10 -03:00
Igor Lins e Silva 6494e57b7f remove node-fetch 2021-07-21 08:03:13 -03:00
Igor Lins e Silva fc03425190 Update package.json 2021-07-21 08:01:11 -03:00
Igor Lins e Silva 630f0e286c update packages 2021-07-21 07:52:18 -03:00
Igor Lins e Silva 54d446adc3 bump to 3.1.3
added get_supported_apis
2021-07-20 11:28:22 -03:00
Igor Lins e Silva 5d40aadbac improve ignore list 2021-07-20 06:27:03 -03:00
Igor Lins e Silva b3ae01b2c7 fix typings 2021-07-20 06:23:56 -03:00
Igor Lins e Silva 5d73e452dc add enhanced /v1/node/get_supported_apis 2021-07-20 06:19:55 -03:00
Igor Lins e Silva e3c7342b4d remove full log on amqp http fail 2021-06-03 15:45:17 -03:00
Igor Lins e Silva 6531c7bf8a [indexer/amqp] allow frameMax connection param 2021-05-21 14:28:42 -03:00
Igor Lins e Silva 612f373725 [api] fix get_transaction to return only the highest block_num, in case of fork/duplicates 2021-04-28 18:25:49 -03:00
Igor Lins e Silva b386be795e Update get_transaction.ts 2021-04-28 18:20:25 -03:00
289 changed files with 21012 additions and 10025 deletions
+80 -17
View File
@@ -1,8 +1,9 @@
node_modules/
.npm
.idea
package-lock.json
*.tsbuildinfo
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
@@ -10,27 +11,89 @@ pids
*.seed
*.pid.lock
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# dotenv environment variables file
.env
.idea
*.pem
package-lock.json
connections.json
connections.json2
api_access.log
api_error.log
explorer
api/explorer
.ecosystem.config.js.swp
# plugins
plugins
chains/*
!chains/example.config.json
api/**/*.js
api/**/*.js.map
api/tests
hyperion-launcher.js
hyperion-launcher.js.map
launcher.js
launcher.js.map
connections/**/*.js
connections/**/*.js.map
definitions/**/*.js
definitions/**/*.js.map
workers/**/*.js
workers/**/*.js.map
helpers/**/*.js
helpers/**/*.js.map
interfaces/**/*.js
interfaces/**/*.js.map
#modules/**/*.js
#modules/**/*.js.map
addons/**/*.js
addons/**/*.js.map
scripts/hpm.js
scripts/hpm.js.map
plugins/.state.json
plugins/repos
plugins/*.js
.gitmodules
# docker storage
docker/redis/data
docker/elasticsearch/data
docker/rabbitmq/data
docker/eosio/data
# transpiled output
dist
configuration_backups
# configuration
config
!config/chains/example.config.json
scripts/hyp-config.js
scripts/hyp-config.js.map
# logging
logs
scripts/hyp-repair.js
scripts/hyp-repair.js.map
# chain state temp files
state
scripts/repair-cli/*.js
scripts/repair-cli/*.js.map
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019-2022 Rio Blocks
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+73 -28
View File
@@ -1,54 +1,99 @@
# Hyperion History API
<!--suppress HtmlUnknownTarget, HtmlDeprecatedAttribute -->
<br></br>
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://eosrio.io/hyperion-white.png">
<img alt="Hyperion Logo"
src="https://eosrio.io/hyperion.png">
</picture>
</p>
<img alt="hyperion logo" height="64" src="https://eosrio.io/hyperion.png">
<br/>
Scalable Full History API Solution for EOSIO based blockchains
<h4 align="center">
Scalable Full History API Solution for
<a href="https://antelope.io">
Antelope
</a>
(former EOSIO) based blockchains
</h4>
Made with ♥ by [EOS Rio](https://eosrio.io/)
<br>
Official documentation: https://hyperion.docs.eosrio.io/
Made with ♥ by [Rio Blocks / EOS Rio](https://rioblocks.io/?lang=en)
### [Official documentation](https://hyperion.docs.eosrio.io)
### How to use
- [For Providers](https://hyperion.docs.eosrio.io/manual_installation/)
- [For Developers](https://hyperion.docs.eosrio.io/howtouse/)
### Official plugins:
- [Hyperion Lightweight Explorer](https://github.com/eosrio/hyperion-explorer-plugin)
### 1. Overview
Hyperion is a full history solution for indexing, storing and retrieving EOSIO blockchain`s historical data. EOSIO protocol is highly scalable reaching up to tens of thousands of transactions per second demanding high performance indexing and optimized storage and querying solutions. Hyperion is developed to tackle those challenges providing open source software to be operated by block producers, infrastructure providers and dApp developers.
Focused on delivering faster search times, lower bandwidth overhead and easier usability for UI/UX developers, Hyperion implements an improved data structure
actions are stored in a flattened format
a parent field is added to the inline actions to point to the parent global sequence
if the inline action data is identical to the parent it is considered a notification and thus removed from the database
no blocks or transaction data is stored, all information can be reconstructed from actions
Hyperion is a full history solution for indexing, storing and retrieving Antelope blockchain's historical data.
Antelope protocol is highly scalable reaching up to tens of thousands of transactions per second demanding high
performance indexing and optimized storage and querying solutions. Hyperion is developed to tackle those challenges
providing open source software to be operated by block producers, infrastructure providers and dApp developers.
Focused on delivering faster search times, lower bandwidth overhead and easier usability for UI/UX developers,
Hyperion implements an improved data structure. Actions are stored in a flattened format, transaction ids are added to
all inline actions, allowing to group by transaction without storing a full transaction index. Besides that if the inline
action data is identical to the parent, it is considered a notification and thus removed from the database.
No full block or transaction data is stored, all information can be reconstructed from actions and deltas, only a block
header index is stored.
### 2. Architecture
The following components are required in order to have a fully functional Hyperion API deployment,
for small use cases its absolutely fine to run all components on a single machine. For larger chains and
production environments we recommend setting them up into different servers under a high-speed local network.
The following components are required in order to have a fully functional Hyperion API deployment.
* For small use cases, it is absolutely fine to run all components on a single machine.
* For larger chains and production environments, we recommend setting them up into different servers under a high-speed local network.
#### 2.1 Elasticsearch Cluster
The ES cluster is responsible for storing all indexed data.
Direct access to the Hyperion API and Indexer must be provided. We recommend nodes in the
cluster to have at least 32 GB of RAM and 8 cpu cores. SSD/NVME drives are recommended for
maximum indexing throughput. For production environments a multi-node cluster is highly recommended.
Direct access to the Hyperion API and Indexer must be provided. We recommend nodes in the
cluster to have at least 32 GB of RAM and 8 cpu cores. SSD/NVME drives are recommended for
maximum indexing throughput, although HDDs can be used for cold storage nodes.
For production environments, a multi-node cluster is highly recommended.
#### 2.2 Hyperion Indexer
The Indexer is a Node.js based app that process data from the state history plugin and allows it to be indexed.
The PM2 process manager is used to launch and operate the indexer. The configuration flexibility is very extensive,
so system recommendations will depend on the use case and data load. It will require access to at least one ES node,
The [PM2 process manager](https://pm2.keymetrics.io) is used to launch and operate the indexer. The configuration
flexibility is very extensive,
so system recommendations will depend on the use case and data load. It will require access to at least one ES node,
RabbitMQ and the state history node.
#### 2.3 Hyperion API
Parallelizable API server that provides the V2 and V1 (legacy history plugin) endpoints.
It is launched by PM2 and can also operate in cluster mode. It requires direct access to
It is launched by PM2 and can also operate in cluster mode. It requires direct access to
at least one ES node for the queries and all other services for full healthcheck
#### 2.4 RabbitMQ
Use as messaging queue and data transport between the indexer stages
#### 2.5 EOSIO State History
Nodeos plugin used to collect action traces and state deltas. Provides data via websocket to the indexer
Used as messaging queue and data transport between the indexer stages and for real-time data streaming
### 3. How to use
#### 2.5 Redis
#### 3.1 [For Providers](https://eosrio.github.io/hyperion-docs/quickstart/)
Used for transient data storage across processes and for the preemptive transaction caching used on
the `v2/history/get_transaction` and `v2/history/check_transaction` endpoints
#### 3.2 [For Developers](https://eosrio.github.io/hyperion-docs/howtouse/)
#### 2.6 Leap State History
[Leap / Nodeos](https://github.com/AntelopeIO/leap/tree/main/plugins/state_history_plugin) plugin used
to collect action traces and state deltas. Provides data via websocket to the indexer
#### 2.7 Hyperion Stream Client (optional)
Web and Node.js client for real-time streaming on enabled hyperion
providers. [Documentation](https://hyperion.docs.eosrio.io/dev/stream_client/)
#### 2.8 Hyperion Plugins (optional)
Hyperion includes a flexible plugin architecture to allow further customization.
Plugins are managed by the `hpm` (hyperion plugin manager) command line tool.
+50
View File
@@ -0,0 +1,50 @@
import { Abi, PushTransactionArgs } from './eosjs-rpc-interfaces';
/** Arguments to `getRequiredKeys` */
export interface AuthorityProviderArgs {
/** Transaction that needs to be signed */
transaction: any;
/** Public keys associated with the private keys that the `SignatureProvider` holds */
availableKeys: string[];
}
/** Get subset of `availableKeys` needed to meet authorities in `transaction` */
export interface AuthorityProvider {
/** Get subset of `availableKeys` needed to meet authorities in `transaction` */
getRequiredKeys: (args: AuthorityProviderArgs) => Promise<string[]>;
}
/** Retrieves raw ABIs for a specified accountName */
export interface AbiProvider {
/** Retrieve the BinaryAbi */
getRawAbi: (accountName: string) => Promise<BinaryAbi>;
}
/** Structure for the raw form of ABIs */
export interface BinaryAbi {
/** account which has deployed the ABI */
accountName: string;
/** abi in binary form */
abi: Uint8Array;
}
/** Holds a fetched abi */
export interface CachedAbi {
/** abi in binary form */
rawAbi: Uint8Array;
/** abi in structured form */
abi: Abi;
}
/** Arguments to `sign` */
export interface SignatureProviderArgs {
/** Chain transaction is for */
chainId: string;
/** Public keys associated with the private keys needed to sign the transaction */
requiredKeys: string[];
/** Transaction to sign */
serializedTransaction: Uint8Array;
/** ABIs for all contracts with actions included in `serializedTransaction` */
abis: BinaryAbi[];
}
/** Signs transactions */
export interface SignatureProvider {
/** Public keys associated with the private keys that the `SignatureProvider` holds */
getAvailableKeys: () => Promise<string[]>;
/** Sign a transaction */
sign: (args: SignatureProviderArgs) => Promise<PushTransactionArgs>;
}
@@ -0,0 +1,4 @@
"use strict";
// copyright defined in eosjs/LICENSE.txt
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=eosjs-api-interfaces.js.map
@@ -0,0 +1 @@
{"version":3,"file":"eosjs-api-interfaces.js","sourceRoot":"","sources":["../src/eosjs-api-interfaces.ts"],"names":[],"mappings":";AAAA,yCAAyC"}
+92
View File
@@ -0,0 +1,92 @@
/**
* @module API
*/
import { AbiProvider, AuthorityProvider, BinaryAbi, CachedAbi, SignatureProvider } from './eosjs-api-interfaces';
import { JsonRpc } from './eosjs-jsonrpc';
import { Abi, PushTransactionArgs } from './eosjs-rpc-interfaces';
import * as ser from './eosjs-serialize';
export declare class Api {
/** Issues RPC calls */
rpc: JsonRpc;
/** Get subset of `availableKeys` needed to meet authorities in a `transaction` */
authorityProvider: AuthorityProvider;
/** Supplies ABIs in raw form (binary) */
abiProvider: AbiProvider;
/** Signs transactions */
signatureProvider: SignatureProvider;
/** Identifies chain */
chainId: string;
textEncoder: TextEncoder;
textDecoder: TextDecoder;
/** Converts abi files between binary and structured form (`abi.abi.json`) */
abiTypes: Map<string, ser.Type>;
/** Converts transactions between binary and structured form (`transaction.abi.json`) */
transactionTypes: Map<string, ser.Type>;
/** Holds information needed to serialize contract actions */
contracts: Map<string, ser.Contract>;
/** Fetched abis */
cachedAbis: Map<string, CachedAbi>;
/**
* @param args
* * `rpc`: Issues RPC calls
* * `authorityProvider`: Get public keys needed to meet authorities in a transaction
* * `abiProvider`: Supplies ABIs in raw form (binary)
* * `signatureProvider`: Signs transactions
* * `chainId`: Identifies chain
* * `textEncoder`: `TextEncoder` instance to use. Pass in `null` if running in a browser
* * `textDecoder`: `TextDecoder` instance to use. Pass in `null` if running in a browser
*/
constructor(args: {
rpc: JsonRpc;
authorityProvider?: AuthorityProvider;
abiProvider?: AbiProvider;
signatureProvider: SignatureProvider;
chainId?: string;
textEncoder?: TextEncoder;
textDecoder?: TextDecoder;
});
/** Decodes an abi as Uint8Array into json. */
rawAbiToJson(rawAbi: Uint8Array): Abi;
/** Get abi in both binary and structured forms. Fetch when needed. */
getCachedAbi(accountName: string, reload?: boolean): Promise<CachedAbi>;
/** Get abi in structured form. Fetch when needed. */
getAbi(accountName: string, reload?: boolean): Promise<Abi>;
/** Get abis needed by a transaction */
getTransactionAbis(transaction: any, reload?: boolean): Promise<BinaryAbi[]>;
/** Get data needed to serialize actions in a contract */
getContract(accountName: string, reload?: boolean): Promise<ser.Contract>;
/** Convert `value` to binary form. `type` must be a built-in abi type or in `transaction.abi.json`. */
serialize(buffer: ser.SerialBuffer, type: string, value: any): void;
/** Convert data in `buffer` to structured form. `type` must be a built-in abi type or in `transaction.abi.json`. */
deserialize(buffer: ser.SerialBuffer, type: string): any;
/** Convert a transaction to binary */
serializeTransaction(transaction: any): Uint8Array;
/** Convert a transaction from binary. Leaves actions in hex. */
deserializeTransaction(transaction: Uint8Array): any;
/** Convert actions to hex */
serializeActions(actions: ser.Action[]): Promise<ser.SerializedAction[]>;
/** Convert actions from hex */
deserializeActions(actions: ser.Action[]): Promise<ser.Action[]>;
/** Convert a transaction from binary. Also deserializes actions. */
deserializeTransactionWithActions(transaction: Uint8Array | string): Promise<any>;
/**
* Create and optionally broadcast a transaction.
*
* Named Parameters:
* * `broadcast`: broadcast this transaction?
* * `sign`: sign this transaction?
* * If both `blocksBehind` and `expireSeconds` are present,
* then fetch the block which is `blocksBehind` behind head block,
* use it as a reference for TAPoS, and expire the transaction `expireSeconds` after that block's time.
* @returns node response if `broadcast`, `{signatures, serializedTransaction}` if `!broadcast`
*/
transact(transaction: any, { broadcast, sign, blocksBehind, expireSeconds }?: {
broadcast?: boolean;
sign?: boolean;
blocksBehind?: number;
expireSeconds?: number;
}): Promise<any>;
/** Broadcast a signed transaction */
pushSignedTransaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any>;
private hasRequiredTaposFields;
}
+427
View File
@@ -0,0 +1,427 @@
"use strict";
/**
* @module API
*/
// copyright defined in eosjs/LICENSE.txt
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });
var ser = require("./eosjs-serialize");
var abiAbi = require('./src/abi.abi.json');
var transactionAbi = require('./src/transaction.abi.json');
var Api = /** @class */ (function () {
/**
* @param args
* * `rpc`: Issues RPC calls
* * `authorityProvider`: Get public keys needed to meet authorities in a transaction
* * `abiProvider`: Supplies ABIs in raw form (binary)
* * `signatureProvider`: Signs transactions
* * `chainId`: Identifies chain
* * `textEncoder`: `TextEncoder` instance to use. Pass in `null` if running in a browser
* * `textDecoder`: `TextDecoder` instance to use. Pass in `null` if running in a browser
*/
function Api(args) {
/** Holds information needed to serialize contract actions */
this.contracts = new Map();
/** Fetched abis */
this.cachedAbis = new Map();
this.rpc = args.rpc;
this.authorityProvider = args.authorityProvider || args.rpc;
this.abiProvider = args.abiProvider || args.rpc;
this.signatureProvider = args.signatureProvider;
this.chainId = args.chainId;
this.textEncoder = args.textEncoder;
this.textDecoder = args.textDecoder;
this.abiTypes = ser.getTypesFromAbi(ser.createInitialTypes(), abiAbi);
this.transactionTypes = ser.getTypesFromAbi(ser.createInitialTypes(), transactionAbi);
}
/** Decodes an abi as Uint8Array into json. */
Api.prototype.rawAbiToJson = function (rawAbi) {
var buffer = new ser.SerialBuffer({
textEncoder: this.textEncoder,
textDecoder: this.textDecoder,
array: rawAbi,
});
if (!ser.supportedAbiVersion(buffer.getString())) {
throw new Error('Unsupported abi version');
}
buffer.restartRead();
return this.abiTypes.get('abi_def').deserialize(buffer);
};
/** Get abi in both binary and structured forms. Fetch when needed. */
Api.prototype.getCachedAbi = function (accountName, reload) {
if (reload === void 0) { reload = false; }
return __awaiter(this, void 0, void 0, function () {
var cachedAbi, rawAbi, abi, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!reload && this.cachedAbis.get(accountName)) {
return [2 /*return*/, this.cachedAbis.get(accountName)];
}
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.abiProvider.getRawAbi(accountName)];
case 2:
rawAbi = (_a.sent()).abi;
abi = this.rawAbiToJson(rawAbi);
cachedAbi = { rawAbi: rawAbi, abi: abi };
return [3 /*break*/, 4];
case 3:
e_1 = _a.sent();
e_1.message = "fetching abi for " + accountName + ": " + e_1.message;
throw e_1;
case 4:
if (!cachedAbi) {
throw new Error("Missing abi for " + accountName);
}
this.cachedAbis.set(accountName, cachedAbi);
return [2 /*return*/, cachedAbi];
}
});
});
};
/** Get abi in structured form. Fetch when needed. */
Api.prototype.getAbi = function (accountName, reload) {
if (reload === void 0) { reload = false; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getCachedAbi(accountName, reload)];
case 1: return [2 /*return*/, (_a.sent()).abi];
}
});
});
};
/** Get abis needed by a transaction */
Api.prototype.getTransactionAbis = function (transaction, reload) {
if (reload === void 0) { reload = false; }
return __awaiter(this, void 0, void 0, function () {
var accounts, uniqueAccounts, actionPromises;
var _this = this;
return __generator(this, function (_a) {
accounts = transaction.actions.map(function (action) { return action.account; });
uniqueAccounts = new Set(accounts);
actionPromises = __spread(uniqueAccounts).map(function (account) { return __awaiter(_this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = {
accountName: account
};
return [4 /*yield*/, this.getCachedAbi(account, reload)];
case 1: return [2 /*return*/, (_a.abi = (_b.sent()).rawAbi,
_a)];
}
});
}); });
return [2 /*return*/, Promise.all(actionPromises)];
});
});
};
/** Get data needed to serialize actions in a contract */
Api.prototype.getContract = function (accountName, reload) {
if (reload === void 0) { reload = false; }
return __awaiter(this, void 0, void 0, function () {
var e_2, _a, abi, types, actions, _b, _c, _d, name_1, type, result;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
if (!reload && this.contracts.get(accountName)) {
return [2 /*return*/, this.contracts.get(accountName)];
}
return [4 /*yield*/, this.getAbi(accountName, reload)];
case 1:
abi = _e.sent();
types = ser.getTypesFromAbi(ser.createInitialTypes(), abi);
actions = new Map();
try {
for (_b = __values(abi.actions), _c = _b.next(); !_c.done; _c = _b.next()) {
_d = _c.value, name_1 = _d.name, type = _d.type;
actions.set(name_1, ser.getType(types, type));
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
result = { types: types, actions: actions };
this.contracts.set(accountName, result);
return [2 /*return*/, result];
}
});
});
};
/** Convert `value` to binary form. `type` must be a built-in abi type or in `transaction.abi.json`. */
Api.prototype.serialize = function (buffer, type, value) {
this.transactionTypes.get(type).serialize(buffer, value);
};
/** Convert data in `buffer` to structured form. `type` must be a built-in abi type or in `transaction.abi.json`. */
Api.prototype.deserialize = function (buffer, type) {
return this.transactionTypes.get(type).deserialize(buffer);
};
/** Convert a transaction to binary */
Api.prototype.serializeTransaction = function (transaction) {
var buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
this.serialize(buffer, 'transaction', __assign({ max_net_usage_words: 0, max_cpu_usage_ms: 0, delay_sec: 0, context_free_actions: [], actions: [], transaction_extensions: [] }, transaction));
return buffer.asUint8Array();
};
/** Convert a transaction from binary. Leaves actions in hex. */
Api.prototype.deserializeTransaction = function (transaction) {
var buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
buffer.pushArray(transaction);
return this.deserialize(buffer, 'transaction');
};
/** Convert actions to hex */
Api.prototype.serializeActions = function (actions) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, Promise.all(actions.map(function (_a) {
var account = _a.account, name = _a.name, authorization = _a.authorization, data = _a.data;
return __awaiter(_this, void 0, void 0, function () {
var contract;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.getContract(account)];
case 1:
contract = _b.sent();
return [2 /*return*/, ser.serializeAction(contract, account, name, authorization, data, this.textEncoder, this.textDecoder)];
}
});
});
}))];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Convert actions from hex */
Api.prototype.deserializeActions = function (actions) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, Promise.all(actions.map(function (_a) {
var account = _a.account, name = _a.name, authorization = _a.authorization, data = _a.data;
return __awaiter(_this, void 0, void 0, function () {
var contract;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.getContract(account)];
case 1:
contract = _b.sent();
return [2 /*return*/, ser.deserializeAction(contract, account, name, authorization, data, this.textEncoder, this.textDecoder)];
}
});
});
}))];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Convert a transaction from binary. Also deserializes actions. */
Api.prototype.deserializeTransactionWithActions = function (transaction) {
return __awaiter(this, void 0, void 0, function () {
var deserializedTransaction, deserializedActions;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (typeof transaction === 'string') {
transaction = ser.hexToUint8Array(transaction);
}
deserializedTransaction = this.deserializeTransaction(transaction);
return [4 /*yield*/, this.deserializeActions(deserializedTransaction.actions)];
case 1:
deserializedActions = _a.sent();
return [2 /*return*/, __assign({}, deserializedTransaction, { actions: deserializedActions })];
}
});
});
};
/**
* Create and optionally broadcast a transaction.
*
* Named Parameters:
* * `broadcast`: broadcast this transaction?
* * `sign`: sign this transaction?
* * If both `blocksBehind` and `expireSeconds` are present,
* then fetch the block which is `blocksBehind` behind head block,
* use it as a reference for TAPoS, and expire the transaction `expireSeconds` after that block's time.
* @returns node response if `broadcast`, `{signatures, serializedTransaction}` if `!broadcast`
*/
Api.prototype.transact = function (transaction, _a) {
var _b = _a === void 0 ? {} : _a, _c = _b.broadcast, broadcast = _c === void 0 ? true : _c, _d = _b.sign, sign = _d === void 0 ? true : _d, blocksBehind = _b.blocksBehind, expireSeconds = _b.expireSeconds;
return __awaiter(this, void 0, void 0, function () {
var info, refBlock, abis, _e, _f, serializedTransaction, pushTransactionArgs, availableKeys, requiredKeys;
return __generator(this, function (_g) {
switch (_g.label) {
case 0:
if (!!this.chainId) return [3 /*break*/, 2];
return [4 /*yield*/, this.rpc.get_info()];
case 1:
info = _g.sent();
this.chainId = info.chain_id;
_g.label = 2;
case 2:
if (!(typeof blocksBehind === 'number' && expireSeconds)) return [3 /*break*/, 6];
if (!!info) return [3 /*break*/, 4];
return [4 /*yield*/, this.rpc.get_info()];
case 3:
info = _g.sent();
_g.label = 4;
case 4: return [4 /*yield*/, this.rpc.get_block(info.head_block_num - blocksBehind)];
case 5:
refBlock = _g.sent();
transaction = __assign({}, ser.transactionHeader(refBlock, expireSeconds), transaction);
_g.label = 6;
case 6:
if (!this.hasRequiredTaposFields(transaction)) {
throw new Error('Required configuration or TAPOS fields are not present');
}
return [4 /*yield*/, this.getTransactionAbis(transaction)];
case 7:
abis = _g.sent();
_e = [{}, transaction];
_f = {};
return [4 /*yield*/, this.serializeActions(transaction.actions)];
case 8:
transaction = __assign.apply(void 0, _e.concat([(_f.actions = _g.sent(), _f)]));
serializedTransaction = this.serializeTransaction(transaction);
pushTransactionArgs = { serializedTransaction: serializedTransaction, signatures: [] };
if (!sign) return [3 /*break*/, 12];
return [4 /*yield*/, this.signatureProvider.getAvailableKeys()];
case 9:
availableKeys = _g.sent();
return [4 /*yield*/, this.authorityProvider.getRequiredKeys({ transaction: transaction, availableKeys: availableKeys })];
case 10:
requiredKeys = _g.sent();
return [4 /*yield*/, this.signatureProvider.sign({
chainId: this.chainId,
requiredKeys: requiredKeys,
serializedTransaction: serializedTransaction,
abis: abis,
})];
case 11:
pushTransactionArgs = _g.sent();
_g.label = 12;
case 12:
if (broadcast) {
return [2 /*return*/, this.pushSignedTransaction(pushTransactionArgs)];
}
return [2 /*return*/, pushTransactionArgs];
}
});
});
};
/** Broadcast a signed transaction */
Api.prototype.pushSignedTransaction = function (_a) {
var signatures = _a.signatures, serializedTransaction = _a.serializedTransaction;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
return [2 /*return*/, this.rpc.push_transaction({
signatures: signatures,
serializedTransaction: serializedTransaction,
})];
});
});
};
// eventually break out into TransactionValidator class
Api.prototype.hasRequiredTaposFields = function (_a) {
var expiration = _a.expiration, ref_block_num = _a.ref_block_num, ref_block_prefix = _a.ref_block_prefix, transaction = __rest(_a, ["expiration", "ref_block_num", "ref_block_prefix"]);
return !!(expiration && ref_block_num && ref_block_prefix);
};
return Api;
}()); // Api
exports.Api = Api;
//# sourceMappingURL=eosjs-api.js.map
File diff suppressed because one or more lines are too long
+63
View File
@@ -0,0 +1,63 @@
/**
* @module JSON-RPC
*/
import { AbiProvider, AuthorityProvider, AuthorityProviderArgs, BinaryAbi } from './eosjs-api-interfaces';
import { GetAbiResult, GetBlockResult, GetCodeResult, GetInfoResult, GetRawCodeAndAbiResult, PushTransactionArgs } from "./eosjs-rpc-interfaces";
/** Make RPC calls */
export declare class JsonRpc implements AuthorityProvider, AbiProvider {
endpoint: string;
fetchBuiltin: (input?: Request | string, init?: RequestInit) => Promise<Response>;
/**
* @param args
* * `fetch`:
* * browsers: leave `null` or `undefined`
* * node: provide an implementation
*/
constructor(endpoint: string, args?: {
fetch?: (input?: string | Request, init?: RequestInit) => Promise<Response>;
});
/** Post `body` to `endpoint + path`. Throws detailed error information in `RpcError` when available. */
fetch(path: string, body: any): Promise<any>;
/** Raw call to `/v1/chain/get_abi` */
get_abi(accountName: string): Promise<GetAbiResult>;
/** Raw call to `/v1/chain/get_account` */
get_account(accountName: string): Promise<any>;
/** Raw call to `/v1/chain/get_block_header_state` */
get_block_header_state(blockNumOrId: number | string): Promise<any>;
/** Raw call to `/v1/chain/get_block` */
get_block(blockNumOrId: number | string): Promise<GetBlockResult>;
/** Raw call to `/v1/chain/get_code` */
get_code(accountName: string): Promise<GetCodeResult>;
/** Raw call to `/v1/chain/get_currency_balance` */
get_currency_balance(code: string, account: string, symbol?: string): Promise<any>;
/** Raw call to `/v1/chain/get_currency_stats` */
get_currency_stats(code: string, symbol: string): Promise<any>;
/** Raw call to `/v1/chain/get_info` */
get_info(): Promise<GetInfoResult>;
/** Raw call to `/v1/chain/get_producer_schedule` */
get_producer_schedule(): Promise<any>;
/** Raw call to `/v1/chain/get_producers` */
get_producers(json?: boolean, lowerBound?: string, limit?: number): Promise<any>;
/** Raw call to `/v1/chain/get_raw_code_and_abi` */
get_raw_code_and_abi(accountName: string): Promise<GetRawCodeAndAbiResult>;
/** calls `/v1/chain/get_raw_code_and_abi` and pulls out unneeded raw wasm code */
getRawAbi(accountName: string): Promise<BinaryAbi>;
/** Raw call to `/v1/chain/get_table_rows` */
get_table_rows({ json, code, scope, table, table_key, lower_bound, upper_bound, index_position, key_type, limit, reverse, show_payer, }: any): Promise<any>;
/** Raw call to `/v1/chain/get_table_by_scope` */
get_table_by_scope({ code, table, lower_bound, upper_bound, limit, }: any): Promise<any>;
/** Get subset of `availableKeys` needed to meet authorities in `transaction`. Implements `AuthorityProvider` */
getRequiredKeys(args: AuthorityProviderArgs): Promise<string[]>;
/** Push a serialized transaction */
push_transaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any>;
/** Raw call to `/v1/db_size/get` */
db_size_get(): Promise<any>;
/** Raw call to `/v1/history/get_actions` */
history_get_actions(accountName: string, pos?: number, offset?: number): Promise<any>;
/** Raw call to `/v1/history/get_transaction` */
history_get_transaction(id: string, blockNumHint?: number): Promise<any>;
/** Raw call to `/v1/history/get_key_accounts` */
history_get_key_accounts(publicKey: string): Promise<any>;
/** Raw call to `/v1/history/get_controlled_accounts` */
history_get_controlled_accounts(controllingAccount: string): Promise<any>;
}
+402
View File
@@ -0,0 +1,402 @@
"use strict";
/**
* @module JSON-RPC
*/
// copyright defined in eosjs/LICENSE.txt
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });
var eosjs_numeric_1 = require("./eosjs-numeric");
var eosjs_rpcerror_1 = require("./eosjs-rpcerror");
function arrayToHex(data) {
var e_1, _a;
var result = '';
try {
for (var data_1 = __values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) {
var x = data_1_1.value;
result += ('00' + x.toString(16)).slice(-2);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1);
}
finally { if (e_1) throw e_1.error; }
}
return result;
}
/** Make RPC calls */
var JsonRpc = /** @class */ (function () {
/**
* @param args
* * `fetch`:
* * browsers: leave `null` or `undefined`
* * node: provide an implementation
*/
function JsonRpc(endpoint, args) {
if (args === void 0) { args = {}; }
this.endpoint = endpoint;
if (args.fetch) {
this.fetchBuiltin = args.fetch;
}
else {
this.fetchBuiltin = global.fetch;
}
}
/** Post `body` to `endpoint + path`. Throws detailed error information in `RpcError` when available. */
JsonRpc.prototype.fetch = function (path, body) {
return __awaiter(this, void 0, void 0, function () {
var response, json, f, e_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
f = this.fetchBuiltin;
return [4 /*yield*/, f(this.endpoint + path, {
body: JSON.stringify(body),
method: 'POST',
})];
case 1:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 2:
json = _a.sent();
if (json.processed && json.processed.except) {
throw new eosjs_rpcerror_1.RpcError(json);
}
return [3 /*break*/, 4];
case 3:
e_2 = _a.sent();
e_2.isFetchError = true;
throw e_2;
case 4:
if (!response.ok) {
throw new eosjs_rpcerror_1.RpcError(json);
}
return [2 /*return*/, json];
}
});
});
};
/** Raw call to `/v1/chain/get_abi` */
JsonRpc.prototype.get_abi = function (accountName) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_abi', { account_name: accountName })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_account` */
JsonRpc.prototype.get_account = function (accountName) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_account', { account_name: accountName })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_block_header_state` */
JsonRpc.prototype.get_block_header_state = function (blockNumOrId) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_block_header_state', { block_num_or_id: blockNumOrId })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_block` */
JsonRpc.prototype.get_block = function (blockNumOrId) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_block', { block_num_or_id: blockNumOrId })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_code` */
JsonRpc.prototype.get_code = function (accountName) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_code', { account_name: accountName })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_currency_balance` */
JsonRpc.prototype.get_currency_balance = function (code, account, symbol) {
if (symbol === void 0) { symbol = null; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_currency_balance', { code: code, account: account, symbol: symbol })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_currency_stats` */
JsonRpc.prototype.get_currency_stats = function (code, symbol) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_currency_stats', { code: code, symbol: symbol })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_info` */
JsonRpc.prototype.get_info = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_info', {})];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_producer_schedule` */
JsonRpc.prototype.get_producer_schedule = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_producer_schedule', {})];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_producers` */
JsonRpc.prototype.get_producers = function (json, lowerBound, limit) {
if (json === void 0) { json = true; }
if (lowerBound === void 0) { lowerBound = ''; }
if (limit === void 0) { limit = 50; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_producers', { json: json, lower_bound: lowerBound, limit: limit })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_raw_code_and_abi` */
JsonRpc.prototype.get_raw_code_and_abi = function (accountName) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_raw_code_and_abi', { account_name: accountName })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** calls `/v1/chain/get_raw_code_and_abi` and pulls out unneeded raw wasm code */
// TODO: use `/v1/chain/get_raw_abi` directly when it becomes available
JsonRpc.prototype.getRawAbi = function (accountName) {
return __awaiter(this, void 0, void 0, function () {
var rawCodeAndAbi, abi;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.get_raw_code_and_abi(accountName)];
case 1:
rawCodeAndAbi = _a.sent();
abi = eosjs_numeric_1.base64ToBinary(rawCodeAndAbi.abi);
return [2 /*return*/, { accountName: rawCodeAndAbi.account_name, abi: abi }];
}
});
});
};
/** Raw call to `/v1/chain/get_table_rows` */
JsonRpc.prototype.get_table_rows = function (_a) {
var _b = _a.json, json = _b === void 0 ? true : _b, code = _a.code, scope = _a.scope, table = _a.table, _c = _a.table_key, table_key = _c === void 0 ? '' : _c, _d = _a.lower_bound, lower_bound = _d === void 0 ? '' : _d, _e = _a.upper_bound, upper_bound = _e === void 0 ? '' : _e, _f = _a.index_position, index_position = _f === void 0 ? 1 : _f, _g = _a.key_type, key_type = _g === void 0 ? '' : _g, _h = _a.limit, limit = _h === void 0 ? 10 : _h, _j = _a.reverse, reverse = _j === void 0 ? false : _j, _k = _a.show_payer, show_payer = _k === void 0 ? false : _k;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_l) {
switch (_l.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_table_rows', {
json: json,
code: code,
scope: scope,
table: table,
table_key: table_key,
lower_bound: lower_bound,
upper_bound: upper_bound,
index_position: index_position,
key_type: key_type,
limit: limit,
reverse: reverse,
show_payer: show_payer,
})];
case 1: return [2 /*return*/, _l.sent()];
}
});
});
};
/** Raw call to `/v1/chain/get_table_by_scope` */
JsonRpc.prototype.get_table_by_scope = function (_a) {
var code = _a.code, table = _a.table, _b = _a.lower_bound, lower_bound = _b === void 0 ? '' : _b, _c = _a.upper_bound, upper_bound = _c === void 0 ? '' : _c, _d = _a.limit, limit = _d === void 0 ? 10 : _d;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_e) {
switch (_e.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/get_table_by_scope', {
code: code,
table: table,
lower_bound: lower_bound,
upper_bound: upper_bound,
limit: limit,
})];
case 1: return [2 /*return*/, _e.sent()];
}
});
});
};
/** Get subset of `availableKeys` needed to meet authorities in `transaction`. Implements `AuthorityProvider` */
JsonRpc.prototype.getRequiredKeys = function (args) {
return __awaiter(this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = eosjs_numeric_1.convertLegacyPublicKeys;
return [4 /*yield*/, this.fetch('/v1/chain/get_required_keys', {
transaction: args.transaction,
available_keys: args.availableKeys,
})];
case 1: return [2 /*return*/, _a.apply(void 0, [(_b.sent()).required_keys])];
}
});
});
};
/** Push a serialized transaction */
JsonRpc.prototype.push_transaction = function (_a) {
var signatures = _a.signatures, serializedTransaction = _a.serializedTransaction;
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/chain/push_transaction', {
signatures: signatures,
compression: 0,
packed_context_free_data: '',
packed_trx: arrayToHex(serializedTransaction),
})];
case 1: return [2 /*return*/, _b.sent()];
}
});
});
};
/** Raw call to `/v1/db_size/get` */
JsonRpc.prototype.db_size_get = function () {
return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/db_size/get', {})];
case 1: return [2 /*return*/, _a.sent()];
}
}); });
};
/** Raw call to `/v1/history/get_actions` */
JsonRpc.prototype.history_get_actions = function (accountName, pos, offset) {
if (pos === void 0) { pos = null; }
if (offset === void 0) { offset = null; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/history/get_actions', { account_name: accountName, pos: pos, offset: offset })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/history/get_transaction` */
JsonRpc.prototype.history_get_transaction = function (id, blockNumHint) {
if (blockNumHint === void 0) { blockNumHint = null; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/history/get_transaction', { id: id, block_num_hint: blockNumHint })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/history/get_key_accounts` */
JsonRpc.prototype.history_get_key_accounts = function (publicKey) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/history/get_key_accounts', { public_key: publicKey })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/** Raw call to `/v1/history/get_controlled_accounts` */
JsonRpc.prototype.history_get_controlled_accounts = function (controllingAccount) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.fetch('/v1/history/get_controlled_accounts', { controlling_account: controllingAccount })];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
return JsonRpc;
}()); // JsonRpc
exports.JsonRpc = JsonRpc;
//# sourceMappingURL=eosjs-jsonrpc.js.map
File diff suppressed because one or more lines are too long
+20
View File
@@ -0,0 +1,20 @@
/**
* @module JS-Sig
*/
import { SignatureProvider, SignatureProviderArgs } from './eosjs-api-interfaces';
/** Signs transactions using in-process private keys */
export declare class JsSignatureProvider implements SignatureProvider {
/** map public to private keys */
keys: Map<string, string>;
/** public keys */
availableKeys: string[];
/** @param privateKeys private keys to sign with */
constructor(privateKeys: string[]);
/** Public keys associated with the private keys that the `SignatureProvider` holds */
getAvailableKeys(): Promise<string[]>;
/** Sign a transaction */
sign({ chainId, requiredKeys, serializedTransaction }: SignatureProviderArgs): Promise<{
signatures: any[];
serializedTransaction: Uint8Array;
}>;
}
+105
View File
@@ -0,0 +1,105 @@
"use strict";
/**
* @module JS-Sig
*/
// copyright defined in eosjs/LICENSE.txt
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });
var ecc = require("eosjs-ecc");
var eosjs_numeric_1 = require("./eosjs-numeric");
/** Signs transactions using in-process private keys */
var JsSignatureProvider = /** @class */ (function () {
/** @param privateKeys private keys to sign with */
function JsSignatureProvider(privateKeys) {
var e_1, _a;
/** map public to private keys */
this.keys = new Map();
/** public keys */
this.availableKeys = [];
try {
for (var privateKeys_1 = __values(privateKeys), privateKeys_1_1 = privateKeys_1.next(); !privateKeys_1_1.done; privateKeys_1_1 = privateKeys_1.next()) {
var k = privateKeys_1_1.value;
var pub = eosjs_numeric_1.convertLegacyPublicKey(ecc.PrivateKey.fromString(k).toPublic().toString());
this.keys.set(pub, k);
this.availableKeys.push(pub);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (privateKeys_1_1 && !privateKeys_1_1.done && (_a = privateKeys_1.return)) _a.call(privateKeys_1);
}
finally { if (e_1) throw e_1.error; }
}
}
/** Public keys associated with the private keys that the `SignatureProvider` holds */
JsSignatureProvider.prototype.getAvailableKeys = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.availableKeys];
});
});
};
/** Sign a transaction */
JsSignatureProvider.prototype.sign = function (_a) {
var chainId = _a.chainId, requiredKeys = _a.requiredKeys, serializedTransaction = _a.serializedTransaction;
return __awaiter(this, void 0, void 0, function () {
var signBuf, signatures;
var _this = this;
return __generator(this, function (_b) {
signBuf = Buffer.concat([
new Buffer(chainId, 'hex'), new Buffer(serializedTransaction), new Buffer(new Uint8Array(32)),
]);
signatures = requiredKeys.map(function (pub) { return ecc.Signature.sign(signBuf, _this.keys.get(eosjs_numeric_1.convertLegacyPublicKey(pub))).toString(); });
return [2 /*return*/, { signatures: signatures, serializedTransaction: serializedTransaction }];
});
});
};
return JsSignatureProvider;
}());
exports.JsSignatureProvider = JsSignatureProvider;
//# sourceMappingURL=eosjs-jssig.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"eosjs-jssig.js","sourceRoot":"","sources":["../src/eosjs-jssig.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,yCAAyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEzC,+BAAiC;AAEjC,iDAAyD;AAEzD,uDAAuD;AACvD;IAOI,mDAAmD;IACnD,6BAAY,WAAqB;;QAPjC,iCAAiC;QAC1B,SAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;QAExC,kBAAkB;QACX,kBAAa,GAAG,EAAc,CAAC;;YAIlC,KAAgB,IAAA,gBAAA,SAAA,WAAW,CAAA,wCAAA,iEAAE;gBAAxB,IAAM,CAAC,wBAAA;gBACR,IAAM,GAAG,GAAG,sCAAsB,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACvF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBACtB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;aAChC;;;;;;;;;IACL,CAAC;IAED,sFAAsF;IACzE,8CAAgB,GAA7B;;;gBACI,sBAAO,IAAI,CAAC,aAAa,EAAC;;;KAC7B;IAED,yBAAyB;IACZ,kCAAI,GAAjB,UAAkB,EAAuE;YAArE,oBAAO,EAAE,8BAAY,EAAE,gDAAqB;;;;;gBACtD,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;oBAC1B,IAAI,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,IAAI,MAAM,CAAC,qBAAqB,CAAC,EAAE,IAAI,MAAM,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;iBAChG,CAAC,CAAC;gBACG,UAAU,GAAG,YAAY,CAAC,GAAG,CAC/B,UAAC,GAAG,IAAK,OAAA,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,KAAI,CAAC,IAAI,CAAC,GAAG,CAAC,sCAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAlF,CAAkF,CAC9F,CAAC;gBACF,sBAAO,EAAE,UAAU,YAAA,EAAE,qBAAqB,uBAAA,EAAE,EAAC;;;KAChD;IACL,0BAAC;AAAD,CAAC,AA/BD,IA+BC;AA/BY,kDAAmB"}
+75
View File
@@ -0,0 +1,75 @@
/**
* @module Numeric
*/
/** Is `bignum` a negative number? */
export declare function isNegative(bignum: Uint8Array): boolean;
/** Negate `bignum` */
export declare function negate(bignum: Uint8Array): void;
/**
* Convert an unsigned decimal number in `s` to a bignum
* @param size bignum size (bytes)
*/
export declare function decimalToBinary(size: number, s: string): Uint8Array;
/**
* Convert a signed decimal number in `s` to a bignum
* @param size bignum size (bytes)
*/
export declare function signedDecimalToBinary(size: number, s: string): Uint8Array;
/**
* Convert `bignum` to an unsigned decimal number
* @param minDigits 0-pad result to this many digits
*/
export declare function binaryToDecimal(bignum: Uint8Array, minDigits?: number): string;
/**
* Convert `bignum` to a signed decimal number
* @param minDigits 0-pad result to this many digits
*/
export declare function signedBinaryToDecimal(bignum: Uint8Array, minDigits?: number): string;
/**
* Convert an unsigned base-58 number in `s` to a bignum
* @param size bignum size (bytes)
*/
export declare function base58ToBinary(size: number, s: string): Uint8Array;
/**
* Convert `bignum` to a base-58 number
* @param minDigits 0-pad result to this many digits
*/
export declare function binaryToBase58(bignum: Uint8Array, minDigits?: number): string;
/** Convert an unsigned base-64 number in `s` to a bignum */
export declare function base64ToBinary(s: string): Uint8Array;
/** Key types this library supports */
export declare enum KeyType {
k1 = 0,
r1 = 1
}
/** Public key data size, excluding type field */
export declare const publicKeyDataSize = 33;
/** Private key data size, excluding type field */
export declare const privateKeyDataSize = 32;
/** Signature data size, excluding type field */
export declare const signatureDataSize = 65;
/** Public key, private key, or signature in binary form */
export interface Key {
type: KeyType;
data: Uint8Array;
}
/** Convert key in `s` to binary form */
export declare function stringToPublicKey(s: string): Key;
/** Convert `key` to string (base-58) form */
export declare function publicKeyToString(key: Key): string;
/** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`).
* Leaves other formats untouched
*/
export declare function convertLegacyPublicKey(s: string): string;
/** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`).
* Leaves other formats untouched
*/
export declare function convertLegacyPublicKeys(keys: string[]): string[];
/** Convert key in `s` to binary form */
export declare function stringToPrivateKey(s: string): Key;
/** Convert `key` to string (base-58) form */
export declare function privateKeyToString(key: Key): string;
/** Convert key in `s` to binary form */
export declare function stringToSignature(s: string): Key;
/** Convert `signature` to string (base-58) form */
export declare function signatureToString(signature: Key): string;
+468
View File
@@ -0,0 +1,468 @@
"use strict";
/**
* @module Numeric
*/
// copyright defined in eosjs/LICENSE.txt
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
} catch (error) {
e = {error: error};
} finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
} finally {
if (e) throw e.error;
}
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return {value: o && o[i++], done: !o};
}
};
};
Object.defineProperty(exports, "__esModule", {value: true});
// const ripemd160 = require('./ripemd').RIPEMD160.hash as (a: Uint8Array) => ArrayBuffer;
var crypto = require('crypto');
function ripemd160(data) {
var hash = crypto.createHash('ripemd160');
hash.update(data);
return hash.digest('hex');
}
var base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
var base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var bs58 = require('base-x')(base58Chars);
function create_base58_map() {
var base58M = Array(256).fill(-1);
for (var i = 0; i < base58Chars.length; ++i) {
base58M[base58Chars.charCodeAt(i)] = i;
}
return base58M;
}
var base58Map = create_base58_map();
function create_base64_map() {
var base64M = Array(256).fill(-1);
for (var i = 0; i < base64Chars.length; ++i) {
base64M[base64Chars.charCodeAt(i)] = i;
}
base64M['='.charCodeAt(0)] = 0;
return base64M;
}
var base64Map = create_base64_map();
/** Is `bignum` a negative number? */
function isNegative(bignum) {
return (bignum[bignum.length - 1] & 0x80) !== 0;
}
exports.isNegative = isNegative;
/** Negate `bignum` */
function negate(bignum) {
var carry = 1;
for (var i = 0; i < bignum.length; ++i) {
var x = (~bignum[i] & 0xff) + carry;
bignum[i] = x;
carry = x >> 8;
}
}
exports.negate = negate;
/**
* Convert an unsigned decimal number in `s` to a bignum
* @param size bignum size (bytes)
*/
function decimalToBinary(size, s) {
var result = new Uint8Array(size);
for (var i = 0; i < s.length; ++i) {
var srcDigit = s.charCodeAt(i);
if (srcDigit < '0'.charCodeAt(0) || srcDigit > '9'.charCodeAt(0)) {
throw new Error('invalid number');
}
var carry = srcDigit - '0'.charCodeAt(0);
for (var j = 0; j < size; ++j) {
var x = result[j] * 10 + carry;
result[j] = x;
carry = x >> 8;
}
if (carry) {
throw new Error('number is out of range');
}
}
return result;
}
exports.decimalToBinary = decimalToBinary;
/**
* Convert a signed decimal number in `s` to a bignum
* @param size bignum size (bytes)
*/
function signedDecimalToBinary(size, s) {
var negative = s[0] === '-';
if (negative) {
s = s.substr(1);
}
var result = decimalToBinary(size, s);
if (negative) {
negate(result);
if (!isNegative(result)) {
throw new Error('number is out of range');
}
} else if (isNegative(result)) {
throw new Error('number is out of range');
}
return result;
}
exports.signedDecimalToBinary = signedDecimalToBinary;
/**
* Convert `bignum` to an unsigned decimal number
* @param minDigits 0-pad result to this many digits
*/
function binaryToDecimal(bignum, minDigits) {
if (minDigits === void 0) {
minDigits = 1;
}
var result = Array(minDigits).fill('0'.charCodeAt(0));
for (var i = bignum.length - 1; i >= 0; --i) {
var carry = bignum[i];
for (var j = 0; j < result.length; ++j) {
var x = ((result[j] - '0'.charCodeAt(0)) << 8) + carry;
result[j] = '0'.charCodeAt(0) + x % 10;
carry = (x / 10) | 0;
}
while (carry) {
result.push('0'.charCodeAt(0) + carry % 10);
carry = (carry / 10) | 0;
}
}
result.reverse();
return String.fromCharCode.apply(String, __spread(result));
}
exports.binaryToDecimal = binaryToDecimal;
/**
* Convert `bignum` to a signed decimal number
* @param minDigits 0-pad result to this many digits
*/
function signedBinaryToDecimal(bignum, minDigits) {
if (minDigits === void 0) {
minDigits = 1;
}
if (isNegative(bignum)) {
var x = bignum.slice();
negate(x);
return '-' + binaryToDecimal(x, minDigits);
}
return binaryToDecimal(bignum, minDigits);
}
exports.signedBinaryToDecimal = signedBinaryToDecimal;
/**
* Convert an unsigned base-58 number in `s` to a bignum
* @param size bignum size (bytes)
*/
function base58ToBinary(size, s) {
var result = new Uint8Array(size);
for (var i = 0; i < s.length; ++i) {
var carry = base58Map[s.charCodeAt(i)];
if (carry < 0) {
throw new Error('invalid base-58 value');
}
for (var j = 0; j < size; ++j) {
var x = result[j] * 58 + carry;
result[j] = x;
carry = x >> 8;
}
if (carry) {
throw new Error('base-58 value is out of range');
}
}
result.reverse();
return result;
}
exports.base58ToBinary = base58ToBinary;
/**
* Convert `bignum` to a base-58 number
* @param minDigits 0-pad result to this many digits
*/
function binaryToBase58(bignum, minDigits) {
return bs58.encode(Buffer.from(bignum));
// if (minDigits === void 0) {
// minDigits = 1;
// }
// var e_1, _a, e_2, _b;
// var result = [];
// try {
// for (var bignum_1 = __values(bignum), bignum_1_1 = bignum_1.next(); !bignum_1_1.done; bignum_1_1 = bignum_1.next()) {
// var byte = bignum_1_1.value;
// var carry = byte;
// for (var j = 0; j < result.length; ++j) {
// var x = (base58Map[result[j]] << 8) + carry;
// result[j] = base58Chars.charCodeAt(x % 58);
// carry = (x / 58) | 0;
// }
// while (carry) {
// result.push(base58Chars.charCodeAt(carry % 58));
// carry = (carry / 58) | 0;
// }
// }
// } catch (e_1_1) {
// e_1 = {error: e_1_1};
// } finally {
// try {
// if (bignum_1_1 && !bignum_1_1.done && (_a = bignum_1.return)) _a.call(bignum_1);
// } finally {
// if (e_1) throw e_1.error;
// }
// }
// try {
// for (var bignum_2 = __values(bignum), bignum_2_1 = bignum_2.next(); !bignum_2_1.done; bignum_2_1 = bignum_2.next()) {
// var byte = bignum_2_1.value;
// if (byte) {
// break;
// } else {
// result.push('1'.charCodeAt(0));
// }
// }
// } catch (e_2_1) {
// e_2 = {error: e_2_1};
// } finally {
// try {
// if (bignum_2_1 && !bignum_2_1.done && (_b = bignum_2.return)) _b.call(bignum_2);
// } finally {
// if (e_2) throw e_2.error;
// }
// }
// result.reverse();
// return String.fromCharCode.apply(String, __spread(result));
}
exports.binaryToBase58 = binaryToBase58;
/** Convert an unsigned base-64 number in `s` to a bignum */
function base64ToBinary(s) {
var len = s.length;
if ((len & 3) === 1 && s[len - 1] === '=') {
len -= 1;
} // fc appends an extra '='
if ((len & 3) !== 0) {
throw new Error('base-64 value is not padded correctly');
}
var groups = len >> 2;
var bytes = groups * 3;
if (len > 0 && s[len - 1] === '=') {
if (s[len - 2] === '=') {
bytes -= 2;
} else {
bytes -= 1;
}
}
var result = new Uint8Array(bytes);
for (var group = 0; group < groups; ++group) {
var digit0 = base64Map[s.charCodeAt(group * 4 + 0)];
var digit1 = base64Map[s.charCodeAt(group * 4 + 1)];
var digit2 = base64Map[s.charCodeAt(group * 4 + 2)];
var digit3 = base64Map[s.charCodeAt(group * 4 + 3)];
result[group * 3 + 0] = (digit0 << 2) | (digit1 >> 4);
if (group * 3 + 1 < bytes) {
result[group * 3 + 1] = ((digit1 & 15) << 4) | (digit2 >> 2);
}
if (group * 3 + 2 < bytes) {
result[group * 3 + 2] = ((digit2 & 3) << 6) | digit3;
}
}
return result;
}
exports.base64ToBinary = base64ToBinary;
/** Key types this library supports */
var KeyType;
(function (KeyType) {
KeyType[KeyType["k1"] = 0] = "k1";
KeyType[KeyType["r1"] = 1] = "r1";
})(KeyType = exports.KeyType || (exports.KeyType = {}));
/** Public key data size, excluding type field */
exports.publicKeyDataSize = 33;
/** Private key data size, excluding type field */
exports.privateKeyDataSize = 32;
/** Signature data size, excluding type field */
exports.signatureDataSize = 65;
function digestSuffixRipemd160(data, suffix) {
var d = new Uint8Array(data.length + suffix.length);
for (var i = 0; i < data.length; ++i) {
d[i] = data[i];
}
for (var i = 0; i < suffix.length; ++i) {
d[data.length + i] = suffix.charCodeAt(i);
}
return ripemd160(d);
}
function stringToKey(s, type, size, suffix) {
var whole = base58ToBinary(size + 4, s);
var result = {type: type, data: new Uint8Array(whole.buffer, 0, size)};
var digest = new Uint8Array(digestSuffixRipemd160(result.data, suffix));
if (digest[0] !== whole[size + 0] || digest[1] !== whole[size + 1]
|| digest[2] !== whole[size + 2] || digest[3] !== whole[size + 3]) {
throw new Error('checksum doesn\'t match');
}
return result;
}
function keyToString(key, suffix, prefix) {
var digest = new Uint8Array(digestSuffixRipemd160(key.data, suffix));
var whole = new Uint8Array(key.data.length + 4);
for (var i = 0; i < key.data.length; ++i) {
whole[i] = key.data[i];
}
for (var i = 0; i < 4; ++i) {
whole[i + key.data.length] = digest[i];
}
return prefix + binaryToBase58(whole);
}
/** Convert key in `s` to binary form */
function stringToPublicKey(s) {
if (typeof s !== 'string') {
throw new Error('expected string containing public key');
}
if (s.substr(0, 3) === 'EOS') {
var whole = base58ToBinary(exports.publicKeyDataSize + 4, s.substr(3));
var key = {type: KeyType.k1, data: new Uint8Array(exports.publicKeyDataSize)};
for (var i = 0; i < exports.publicKeyDataSize; ++i) {
key.data[i] = whole[i];
}
var digest = new Uint8Array(ripemd160(key.data));
if (digest[0] !== whole[exports.publicKeyDataSize] || digest[1] !== whole[34]
|| digest[2] !== whole[35] || digest[3] !== whole[36]) {
throw new Error('checksum doesn\'t match');
}
return key;
} else if (s.substr(0, 7) === 'PUB_K1_') {
return stringToKey(s.substr(7), KeyType.k1, exports.publicKeyDataSize, 'K1');
} else if (s.substr(0, 7) === 'PUB_R1_') {
return stringToKey(s.substr(7), KeyType.r1, exports.publicKeyDataSize, 'R1');
} else {
throw new Error('unrecognized public key format');
}
}
exports.stringToPublicKey = stringToPublicKey;
/** Convert `key` to string (base-58) form */
function publicKeyToString(key) {
if (key.type === KeyType.k1 && key.data.length === exports.publicKeyDataSize) {
return keyToString(key, 'K1', 'PUB_K1_');
} else if (key.type === KeyType.r1 && key.data.length === exports.publicKeyDataSize) {
return keyToString(key, 'R1', 'PUB_R1_');
} else {
throw new Error('unrecognized public key format');
}
}
exports.publicKeyToString = publicKeyToString;
/** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`).
* Leaves other formats untouched
*/
function convertLegacyPublicKey(s) {
if (s.substr(0, 3) === 'EOS') {
return publicKeyToString(stringToPublicKey(s));
}
return s;
}
exports.convertLegacyPublicKey = convertLegacyPublicKey;
/** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`).
* Leaves other formats untouched
*/
function convertLegacyPublicKeys(keys) {
return keys.map(convertLegacyPublicKey);
}
exports.convertLegacyPublicKeys = convertLegacyPublicKeys;
/** Convert key in `s` to binary form */
function stringToPrivateKey(s) {
if (typeof s !== 'string') {
throw new Error('expected string containing private key');
}
if (s.substr(0, 7) === 'PVT_R1_') {
return stringToKey(s.substr(7), KeyType.r1, exports.privateKeyDataSize, 'R1');
} else {
throw new Error('unrecognized private key format');
}
}
exports.stringToPrivateKey = stringToPrivateKey;
/** Convert `key` to string (base-58) form */
function privateKeyToString(key) {
if (key.type === KeyType.r1) {
return keyToString(key, 'R1', 'PVT_R1_');
} else {
throw new Error('unrecognized private key format');
}
}
exports.privateKeyToString = privateKeyToString;
/** Convert key in `s` to binary form */
function stringToSignature(s) {
if (typeof s !== 'string') {
throw new Error('expected string containing signature');
}
if (s.substr(0, 7) === 'SIG_K1_') {
return stringToKey(s.substr(7), KeyType.k1, exports.signatureDataSize, 'K1');
} else if (s.substr(0, 7) === 'SIG_R1_') {
return stringToKey(s.substr(7), KeyType.r1, exports.signatureDataSize, 'R1');
} else {
throw new Error('unrecognized signature format');
}
}
exports.stringToSignature = stringToSignature;
/** Convert `signature` to string (base-58) form */
function signatureToString(signature) {
if (signature.type === KeyType.k1) {
return keyToString(signature, 'K1', 'SIG_K1_');
} else if (signature.type === KeyType.r1) {
return keyToString(signature, 'R1', 'SIG_R1_');
} else {
throw new Error('unrecognized signature format');
}
}
exports.signatureToString = signatureToString;
//# sourceMappingURL=eosjs-numeric.js.map
File diff suppressed because one or more lines are too long
+103
View File
@@ -0,0 +1,103 @@
/** Structured format for abis */
export interface Abi {
version: string;
types: Array<{
new_type_name: string;
type: string;
}>;
structs: Array<{
name: string;
base: string;
fields: Array<{
name: string;
type: string;
}>;
}>;
actions: Array<{
name: string;
type: string;
ricardian_contract: string;
}>;
tables: Array<{
name: string;
type: string;
index_type: string;
key_names: string[];
key_types: string[];
}>;
ricardian_clauses: Array<{
id: string;
body: string;
}>;
error_messages: Array<{
error_code: string;
error_msg: string;
}>;
abi_extensions: Array<{
tag: number;
value: string;
}>;
variants?: Array<{
name: string;
types: string[];
}>;
}
/** Return value of `/v1/chain/get_abi` */
export interface GetAbiResult {
account_name: string;
abi: Abi;
}
/** Subset of `GetBlockResult` needed to calculate TAPoS fields in transactions */
export interface BlockTaposInfo {
timestamp: string;
block_num: number;
ref_block_prefix: number;
}
/** Return value of `/v1/chain/get_block` */
export interface GetBlockResult {
timestamp: string;
producer: string;
confirmed: number;
previous: string;
transaction_mroot: string;
action_mroot: string;
schedule_version: number;
producer_signature: string;
id: string;
block_num: number;
ref_block_prefix: number;
}
/** Return value of `/v1/chain/get_code` */
export interface GetCodeResult {
account_name: string;
code_hash: string;
wast: string;
wasm: string;
abi: Abi;
}
/** Return value of `/v1/chain/get_info` */
export interface GetInfoResult {
server_version: string;
chain_id: string;
head_block_num: number;
last_irreversible_block_num: number;
last_irreversible_block_id: string;
head_block_id: string;
head_block_time: string;
head_block_producer: string;
virtual_block_cpu_limit: number;
virtual_block_net_limit: number;
block_cpu_limit: number;
block_net_limit: number;
}
/** Return value of `/v1/chain/get_raw_code_and_abi` */
export interface GetRawCodeAndAbiResult {
account_name: string;
wasm: string;
abi: string;
}
/** Arguments for `push_transaction` */
export interface PushTransactionArgs {
signatures: string[];
serializedTransaction: Uint8Array;
}
@@ -0,0 +1,4 @@
"use strict";
// copyright defined in eosjs/LICENSE.txt
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=eosjs-rpc-interfaces.js.map
@@ -0,0 +1 @@
{"version":3,"file":"eosjs-rpc-interfaces.js","sourceRoot":"","sources":["../src/eosjs-rpc-interfaces.ts"],"names":[],"mappings":";AAAA,yCAAyC"}
+9
View File
@@ -0,0 +1,9 @@
/**
* @module RPC-Error
*/
/** Holds detailed error information */
export declare class RpcError extends Error {
/** Detailed error information */
json: any;
constructor(json: any);
}
+41
View File
@@ -0,0 +1,41 @@
"use strict";
/**
* @module RPC-Error
*/
// copyright defined in eosjs/LICENSE.txt
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
/** Holds detailed error information */
var RpcError = /** @class */ (function (_super) {
__extends(RpcError, _super);
function RpcError(json) {
var _this = this;
if (json.error && json.error.details && json.error.details.length && json.error.details[0].message) {
_this = _super.call(this, json.error.details[0].message) || this;
}
else if (json.processed && json.processed.except && json.processed.except.message) {
_this = _super.call(this, json.processed.except.message) || this;
}
else {
_this = _super.call(this, json.message) || this;
}
Object.setPrototypeOf(_this, RpcError.prototype);
_this.json = json;
return _this;
}
return RpcError;
}(Error));
exports.RpcError = RpcError;
//# sourceMappingURL=eosjs-rpcerror.js.map
@@ -0,0 +1 @@
{"version":3,"file":"eosjs-rpcerror.js","sourceRoot":"","sources":["../src/eosjs-rpcerror.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,yCAAyC;;;;;;;;;;;;;;;AAEzC,uCAAuC;AACvC;IAA8B,4BAAK;IAI/B,kBAAY,IAAS;QAArB,iBAUC;QATG,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE;YAChG,QAAA,kBAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAC;SACxC;aAAM,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE;YACjF,QAAA,kBAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,SAAC;SACxC;aAAM;YACH,QAAA,kBAAM,IAAI,CAAC,OAAO,CAAC,SAAC;SACvB;QACD,MAAM,CAAC,cAAc,CAAC,KAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;QAChD,KAAI,CAAC,IAAI,GAAG,IAAI,CAAC;;IACrB,CAAC;IACL,eAAC;AAAD,CAAC,AAfD,CAA8B,KAAK,GAelC;AAfY,4BAAQ"}
+241
View File
@@ -0,0 +1,241 @@
/**
* @module Serialize
*/
import { Abi, BlockTaposInfo } from './eosjs-rpc-interfaces';
/** A field in an abi */
export interface Field {
/** Field name */
name: string;
/** Type name in string form */
typeName: string;
/** Type of the field */
type: Type;
}
/** Options for serialize() and deserialize() */
export interface SerializerOptions {
bytesAsUint8Array?: boolean;
}
/** State for serialize() and deserialize() */
export declare class SerializerState {
options: SerializerOptions;
/** Have any binary extensions been skipped? */
skippedBinaryExtension: boolean;
constructor(options?: SerializerOptions);
}
/** A type in an abi */
export interface Type {
/** Type name */
name: string;
/** Type name this is an alias of, if any */
aliasOfName: string;
/** Type this is an array of, if any */
arrayOf: Type;
/** Type this is an optional of, if any */
optionalOf: Type;
/** Marks binary extension fields */
extensionOf?: Type;
/** Base name of this type, if this is a struct */
baseName: string;
/** Base of this type, if this is a struct */
base: Type;
/** Contained fields, if this is a struct */
fields: Field[];
/** Convert `data` to binary form and store in `buffer` */
serialize: (buffer: SerialBuffer, data: any, state?: SerializerState, allowExtensions?: boolean) => void;
/** Convert data in `buffer` from binary form */
deserialize: (buffer: SerialBuffer, state?: SerializerState, allowExtensions?: boolean) => any;
}
/** Structural representation of a symbol */
export interface Symbol {
/** Name of the symbol, not including precision */
name: string;
/** Number of digits after the decimal point */
precision: number;
}
export interface Contract {
actions: Map<string, Type>;
types: Map<string, Type>;
}
export interface Authorization {
actor: string;
permission: string;
}
/** Action with data in structured form */
export interface Action {
account: string;
name: string;
authorization: Authorization[];
data: any;
}
/** Action with data in serialized hex form */
export interface SerializedAction {
account: string;
name: string;
authorization: Authorization[];
data: string;
}
/** Serialize and deserialize data */
export declare class SerialBuffer {
/** Amount of valid data in `array` */
length: number;
/** Data in serialized (binary) form */
array: Uint8Array;
/** Current position while reading (deserializing) */
readPos: number;
textEncoder: TextEncoder;
textDecoder: TextDecoder;
/**
* @param __namedParameters
* * `array`: `null` if serializing, or binary data to deserialize
* * `textEncoder`: `TextEncoder` instance to use. Pass in `null` if running in a browser
* * `textDecoder`: `TextDecider` instance to use. Pass in `null` if running in a browser
*/
constructor({ textEncoder, textDecoder, array }?: {
textEncoder?: TextEncoder;
textDecoder?: TextDecoder;
array?: Uint8Array;
});
/** Resize `array` if needed to have at least `size` bytes free */
reserve(size: number): void;
/** Is there data available to read? */
haveReadData(): boolean;
/** Restart reading from the beginning */
restartRead(): void;
/** Return data with excess storage trimmed away */
asUint8Array(): Uint8Array;
/** Append bytes */
pushArray(v: number[] | Uint8Array): void;
/** Append bytes */
push(...v: number[]): void;
/** Get a single byte */
get(): number;
/** Append bytes in `v`. Throws if `len` doesn't match `v.length` */
pushUint8ArrayChecked(v: Uint8Array, len: number): void;
/** Get `len` bytes */
getUint8Array(len: number): Uint8Array;
/** Append a `uint16` */
pushUint16(v: number): void;
/** Get a `uint16` */
getUint16(): number;
/** Append a `uint32` */
pushUint32(v: number): void;
/** Get a `uint32` */
getUint32(): number;
/** Append a `uint64`. *Caution*: `number` only has 53 bits of precision */
pushNumberAsUint64(v: number): void;
/**
* Get a `uint64` as a `number`. *Caution*: `number` only has 53 bits of precision; some values will change.
* `numeric.binaryToDecimal(serialBuffer.getUint8Array(8))` recommended instead
*/
getUint64AsNumber(): number;
/** Append a `varuint32` */
pushVaruint32(v: number): void;
/** Get a `varuint32` */
getVaruint32(): number;
/** Append a `varint32` */
pushVarint32(v: number): void;
/** Get a `varint32` */
getVarint32(): number;
/** Append a `float32` */
pushFloat32(v: number): void;
/** Get a `float32` */
getFloat32(): number;
/** Append a `float64` */
pushFloat64(v: number): void;
/** Get a `float64` */
getFloat64(): number;
/** Append a `name` */
pushName(s: string): void;
/** Get a `name` */
getName(): string;
/** Append length-prefixed binary data */
pushBytes(v: number[] | Uint8Array): void;
/** Get length-prefixed binary data */
getBytes(): Uint8Array;
/** Append a string */
pushString(v: string): void;
/** Get a string */
getString(): string;
/** Append a `symbol_code`. Unlike `symbol`, `symbol_code` doesn't include a precision. */
pushSymbolCode(name: string): void;
/** Get a `symbol_code`. Unlike `symbol`, `symbol_code` doesn't include a precision. */
getSymbolCode(): string;
/** Append a `symbol` */
pushSymbol({ name, precision }: {
name: string;
precision: number;
}): void;
/** Get a `symbol` */
getSymbol(): {
name: string;
precision: number;
};
/** Append an asset */
pushAsset(s: string): void;
/** Get an asset */
getAsset(): string;
/** Append a public key */
pushPublicKey(s: string): void;
/** Get a public key */
getPublicKey(): string;
/** Append a private key */
pushPrivateKey(s: string): void;
/** Get a private key */
getPrivateKey(): string;
/** Append a signature */
pushSignature(s: string): void;
/** Get a signature */
getSignature(): string;
}
/** Is this a supported ABI version? */
export declare function supportedAbiVersion(version: string): boolean;
/** Convert date in ISO format to `time_point` (miliseconds since epoch) */
export declare function dateToTimePoint(date: string): number;
/** Convert `time_point` (miliseconds since epoch) to date in ISO format */
export declare function timePointToDate(us: number): string;
/** Convert date in ISO format to `time_point_sec` (seconds since epoch) */
export declare function dateToTimePointSec(date: string): number;
/** Convert `time_point_sec` (seconds since epoch) to to date in ISO format */
export declare function timePointSecToDate(sec: number): string;
/** Convert date in ISO format to `block_timestamp_type` (half-seconds since a different epoch) */
export declare function dateToBlockTimestamp(date: string): number;
/** Convert `block_timestamp_type` (half-seconds since a different epoch) to to date in ISO format */
export declare function blockTimestampToDate(slot: number): string;
/** Convert `string` to `Symbol`. format: `precision,NAME`. */
export declare function stringToSymbol(s: string): {
name: string;
precision: number;
};
/** Convert `Symbol` to `string`. format: `precision,NAME`. */
export declare function symbolToString({ name, precision }: {
name: string;
precision: number;
}): string;
/** Convert binary data to hex */
export declare function arrayToHex(data: Uint8Array): string;
/** Convert hex to binary data */
export declare function hexToUint8Array(hex: string): Uint8Array;
/** Create the set of types built-in to the abi format */
export declare function createInitialTypes(): Map<string, Type>;
/** Get type from `types` */
export declare function getType(types: Map<string, Type>, name: string): Type;
/**
* Get types from abi
* @param initialTypes Set of types to build on.
* In most cases, it's best to fill this from a fresh call to `getTypesFromAbi()`.
*/
export declare function getTypesFromAbi(initialTypes: Map<string, Type>, abi: Abi): Map<string, Type>;
/** TAPoS: Return transaction fields which reference `refBlock` and expire `expireSeconds` after `refBlock.timestamp` */
export declare function transactionHeader(refBlock: BlockTaposInfo, expireSeconds: number): {
expiration: string;
ref_block_num: number;
ref_block_prefix: number;
};
/** Convert action data to serialized form (hex) */
export declare function serializeActionData(contract: Contract, account: string, name: string, data: any, textEncoder: TextEncoder, textDecoder: TextDecoder): string;
/** Return action in serialized form */
export declare function serializeAction(contract: Contract, account: string, name: string, authorization: Authorization[], data: any, textEncoder: TextEncoder, textDecoder: TextDecoder): SerializedAction;
/** Deserialize action data. If `data` is a `string`, then it's assumed to be in hex. */
export declare function deserializeActionData(contract: Contract, account: string, name: string, data: string | Uint8Array | number[], textEncoder: TextEncoder, textDecoder: TextDecoder): any;
/** Deserialize action. If `data` is a `string`, then it's assumed to be in hex. */
export declare function deserializeAction(contract: Contract, account: string, name: string, authorization: Authorization[], data: string | Uint8Array | number[], textEncoder: TextEncoder, textDecoder: TextDecoder): Action;
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+8
View File
@@ -0,0 +1,8 @@
import { Api } from './eosjs-api';
import * as ApiInterfaces from './eosjs-api-interfaces';
import { JsonRpc } from './eosjs-jsonrpc';
import * as Numeric from './eosjs-numeric';
import * as RpcInterfaces from './eosjs-rpc-interfaces';
import { RpcError } from './eosjs-rpcerror';
import * as Serialize from './eosjs-serialize';
export { Api, ApiInterfaces, JsonRpc, Numeric, RpcInterfaces, RpcError, Serialize };
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var eosjs_api_1 = require("./eosjs-api");
exports.Api = eosjs_api_1.Api;
var ApiInterfaces = require("./eosjs-api-interfaces");
exports.ApiInterfaces = ApiInterfaces;
var eosjs_jsonrpc_1 = require("./eosjs-jsonrpc");
exports.JsonRpc = eosjs_jsonrpc_1.JsonRpc;
var Numeric = require("./eosjs-numeric");
exports.Numeric = Numeric;
var RpcInterfaces = require("./eosjs-rpc-interfaces");
exports.RpcInterfaces = RpcInterfaces;
var eosjs_rpcerror_1 = require("./eosjs-rpcerror");
exports.RpcError = eosjs_rpcerror_1.RpcError;
var Serialize = require("./eosjs-serialize");
exports.Serialize = Serialize;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,yCAAkC;AAQzB,cARA,eAAG,CAQA;AAPZ,sDAAwD;AAO1C,sCAAa;AAN3B,iDAA0C;AAMb,kBANpB,uBAAO,CAMoB;AALpC,yCAA2C;AAKL,0BAAO;AAJ7C,sDAAwD;AAIT,sCAAa;AAH5D,mDAA4C;AAGkB,mBAHrD,yBAAQ,CAGqD;AAFtE,6CAA+C;AAEyB,8BAAS"}
+401
View File
@@ -0,0 +1,401 @@
// https://gist.githubusercontent.com/wlzla000/bac83df6d3c51916c4dd0bc947e46947/raw/7ee3462b095ab22580ddaf191f44a590da6fe33b/RIPEMD-160.js
/*
RIPEMD-160.js
developed
by K. (https://github.com/wlzla000)
on December 27-29, 2017,
licensed under
the MIT license
Copyright (c) 2017 K.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
"use strict";
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var RIPEMD160 = function () {
function RIPEMD160() {
// https://webcache.googleusercontent.com/search?q=cache:CnLOgolTHYEJ:https://www.cosic.esat.kuleuven.be/publications/article-317.pdf
// http://shodhganga.inflibnet.ac.in/bitstream/10603/22978/13/13_appendix.pdf
_classCallCheck(this, RIPEMD160);
}
_createClass(RIPEMD160, null, [{
key: "get_n_pad_bytes",
value: function get_n_pad_bytes(message_size /* in bytes, 1 byte is 8 bits. */) {
// Obtain the number of bytes needed to pad the message.
// It does not contain the size of the message size information.
/*
https://webcache.googleusercontent.com/search?q=cache:CnLOgolTHYEJ:https://www.cosic.esat.kuleuven.be/publications/article-317.pdf
The Cryptographic Hash Function RIPEMD-160
written by
Bart Preneel,
Hans Dobbertin,
Antoon Bosselaers
in
1997.
--------------------------------------------------
§5 Description of RIPEMD-160
......
In order to guarantee that the total input size is a
multiple of 512 bits, the input is padded in the same
way as for all the members of the MD4-family: one
appends a single 1 followed by a string of 0s (the
number of 0s lies between 0 and 511); the last 64 bits
of the extended input contain the binary representation
of the input size in bits, least significant byte first.
*/
/*
https://tools.ietf.org/rfc/rfc1186.txt
RFC 1186: MD4 Message Digest Algorithm.
written by
Ronald Linn Rivest
in
October 1990.
--------------------------------------------------
§3 MD4 Algorithm Description
......
Step 1. Append padding bits
The message is "padded" (extended) so that its length
(in bits) is congruent to 448, modulo 512. That is, the
message is extended so that it is just 64 bits shy of
being a multiple of 512 bits long. Padding is always
performed, even if the length of the message is already
congruent to 448, modulo 512 (in which case 512 bits of
padding are added).
Padding is performed as follows: a single "1" bit is
appended to the message, and then enough zero bits are
appended so that the length in bits of the padded
message becomes congruent to 448, modulo 512.
Step 2. Append length
A 64-bit representation of b (the length of the message
before the padding bits were added) is appended to the
result of the previous step. In the unlikely event that
b is greater than 2^64, then only the low-order 64 bits
of b are used. (These bits are appended as two 32-bit
words and appended low-order word first in accordance
with the previous conventions.)
At this point the resulting message (after padding with
bits and with b) has a length that is an exact multiple
of 512 bits. Equivalently, this message has a length
that is an exact multiple of 16 (32-bit) words. Let
M[0 ... N-1] denote the words of the resulting message,
where N is a multiple of 16.
*/
// https://crypto.stackexchange.com/a/32407/54568
/*
Example case # 1
[0 bit: message.]
[1 bit: 1.]
[447 bits: 0.]
[64 bits: message size information.]
Example case # 2
[512-bits: message]
[1 bit: 1.]
[447 bits: 0.]
[64 bits: message size information.]
Example case # 3
[(512 - 64 = 448) bits: message.]
[1 bit: 1.]
[511 bits: 0.]
[64 bits: message size information.]
Example case # 4
[(512 - 65 = 447) bits: message.]
[1 bit: 1.]
[0 bit: 0.]
[64 bits: message size information.]
*/
// The number of padding zero bits:
// 511 - [{(message size in bits) + 64} (mod 512)]
return 64 - (message_size + 8 & 63 /* 63 */);
}
}, {
key: "pad",
value: function pad(message /* An ArrayBuffer. */) {
var message_size = message.byteLength;
var n_pad = RIPEMD160.get_n_pad_bytes(message_size);
// `Number.MAX_SAFE_INTEGER` is ((2 ** 53) - 1) and
// bitwise operation in Javascript is done on 32-bits operands.
var divmod = function divmod(dividend, divisor) {
return [Math.floor(dividend / divisor), dividend % divisor];
};
/*
To shift
00000000 000????? ???????? ???????? ???????? ???????? ???????? ????????
t o
00000000 ???????? ???????? ???????? ???????? ???????? ???????? ?????000
--------------------------------------------------------------------------------
Method #1
00000000 000????? ???????? ???????? ???????? ???????? ???????? ????????
[00000000 000AAAAA AAAAAAAA AAAAAAAA] (<A> captured)
[00000000 AAAAAAAA AAAAAAAA AAAAA000] (<A> shifted)
(<B> captured) [BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB]
(<B> shifted) [BBB][BBBBBBBB BBBBBBBB BBBBBBBB BBBBB000]
[00000000 AAAAAAAA AAAAAAAA AAAAABBB] (<A> & <B_2> merged)
[00000000 AAAAAAAA AAAAAAAA AAAAABBB][BBBBBBBB BBBBBBBB BBBBBBBB BBBBB000]
00000000 ???????? ???????? ???????? ???????? ???????? ???????? ?????000
const uint32_max_plus_1 = 0x100000000; // (2 ** 32)
const [
msg_byte_size_most, // Value range [0, (2 ** 21) - 1].
msg_byte_size_least // Value range [0, (2 ** 32) - 1].
] = divmod(message_size, uint32_max_plus_1);
const [
carry, // Value range [0, 7].
msg_bit_size_least // Value range [0, (2 ** 32) - 8].
] = divmod(message_byte_size_least * 8, uint32_max_plus_1);
const message_bit_size_most = message_byte_size_most * 8
+ carry; // Value range [0, (2 ** 24) - 1].
--------------------------------------------------------------------------------
Method #2
00000000 000????? ???????? ???????? ???????? ???????? ???????? ????????
[00000 000AAAAA AAAAAAAA AAAAAAAA AAA] (<A> captured)
(<B> captured) [000BBBBB BBBBBBBB BBBBBBBB BBBBBBBB]
(<B> shifted) [BBBBBBBB BBBBBBBB BBBBBBBB BBBBB000]
[00000000 AAAAAAAA AAAAAAAA AAAAAAAA][BBBBBBBB BBBBBBBB BBBBBBBB BBBBB000]
00000000 ???????? ???????? ???????? ???????? ???????? ???????? ?????000
*/
var _divmod$map = divmod(message_size, 536870912 /* (2 ** 29) */).map(function (x, index) {
return index ? x * 8 : x;
}),
_divmod$map2 = _slicedToArray(_divmod$map, 2),
msg_bit_size_most = _divmod$map2[0],
msg_bit_size_least = _divmod$map2[1];
// `ArrayBuffer.transfer()` is not supported.
var padded = new Uint8Array(message_size + n_pad + 8);
padded.set(new Uint8Array(message), 0);
var data_view = new DataView(padded.buffer);
data_view.setUint8(message_size, 128);
data_view.setUint32(message_size + n_pad, msg_bit_size_least, true // Little-endian
);
data_view.setUint32(message_size + n_pad + 4, msg_bit_size_most, true // Little-endian
);
return padded.buffer;
}
}, {
key: "f",
value: function f(j, x, y, z) {
if (0 <= j && j <= 15) {
// Exclusive-OR
return x ^ y ^ z;
}
if (16 <= j && j <= 31) {
// Multiplexing (muxing)
return x & y | ~x & z;
}
if (32 <= j && j <= 47) {
return (x | ~y) ^ z;
}
if (48 <= j && j <= 63) {
// Multiplexing (muxing)
return x & z | y & ~z;
}
if (64 <= j && j <= 79) {
return x ^ (y | ~z);
}
}
}, {
key: "K",
value: function K(j) {
if (0 <= j && j <= 15) {
return 0x00000000;
}
if (16 <= j && j <= 31) {
// Math.floor((2 ** 30) * Math.SQRT2)
return 0x5A827999;
}
if (32 <= j && j <= 47) {
// Math.floor((2 ** 30) * Math.sqrt(3))
return 0x6ED9EBA1;
}
if (48 <= j && j <= 63) {
// Math.floor((2 ** 30) * Math.sqrt(5))
return 0x8F1BBCDC;
}
if (64 <= j && j <= 79) {
// Math.floor((2 ** 30) * Math.sqrt(7))
return 0xA953FD4E;
}
}
}, {
key: "KP",
value: function KP(j) // K'
{
if (0 <= j && j <= 15) {
// Math.floor((2 ** 30) * Math.cbrt(2))
return 0x50A28BE6;
}
if (16 <= j && j <= 31) {
// Math.floor((2 ** 30) * Math.cbrt(3))
return 0x5C4DD124;
}
if (32 <= j && j <= 47) {
// Math.floor((2 ** 30) * Math.cbrt(5))
return 0x6D703EF3;
}
if (48 <= j && j <= 63) {
// Math.floor((2 ** 30) * Math.cbrt(7))
return 0x7A6D76E9;
}
if (64 <= j && j <= 79) {
return 0x00000000;
}
}
}, {
key: "add_modulo32",
value: function add_modulo32() /* ...... */{
// 1. Modulo addition (addition modulo) is associative.
// https://proofwiki.org/wiki/Modulo_Addition_is_Associative
// 2. Bitwise operation in Javascript
// is done on 32-bits operands
// and results in a 32-bits value.
return Array.from(arguments).reduce(function (a, b) {
return a + b;
}, 0) | 0;
}
}, {
key: "rol32",
value: function rol32(value, count) {
// Cyclic left shift (rotate) on 32-bits value.
return value << count | value >>> 32 - count;
}
}, {
key: "hash",
value: function hash(message /* An ArrayBuffer. */) {
////////// Padding //////////
// The padded message.
var padded = RIPEMD160.pad(message);
////////// Compression //////////
// Message word selectors.
var r = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13];
var rP = [// r'
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11];
// Amounts for 'rotate left' operation.
var s = [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6];
var sP = [// s'
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11];
// The size, in bytes, of a word.
var word_size = 4;
// The size, in bytes, of a 16-words block.
var block_size = 64;
// The number of the 16-words blocks.
var t = padded.byteLength / block_size;
// The message after padding consists of t 16-word blocks that
// are denoted with X_i[j], with 0≤i≤(t 1) and 0≤j≤15.
var X = new Array(t).fill(undefined).map(function (_, i) {
return function (j) {
return new DataView(padded, i * block_size, block_size).getUint32(j * word_size, true // Little-endian
);
};
});
// The result of RIPEMD-160 is contained in five 32-bit words,
// which form the internal state of the algorithm. The final
// content of these five 32-bit words is converted to a 160-bit
// string, again using the little-endian convention.
var h = [0x67452301, // h_0
0xEFCDAB89, // h_1
0x98BADCFE, // h_2
0x10325476, // h_3
0xC3D2E1F0 // h_4
];
for (var i = 0; i < t; ++i) {
var A = h[0],
B = h[1],
C = h[2],
D = h[3],
E = h[4];
var AP = A,
BP = B,
CP = C,
DP = D,
EP = E;
for (var j = 0; j < 80; ++j) {
// Left rounds
var _T = RIPEMD160.add_modulo32(RIPEMD160.rol32(RIPEMD160.add_modulo32(A, RIPEMD160.f(j, B, C, D), X[i](r[j]), RIPEMD160.K(j)), s[j]), E);
A = E;
E = D;
D = RIPEMD160.rol32(C, 10);
C = B;
B = _T;
// Right rounds
_T = RIPEMD160.add_modulo32(RIPEMD160.rol32(RIPEMD160.add_modulo32(AP, RIPEMD160.f(79 - j, BP, CP, DP), X[i](rP[j]), RIPEMD160.KP(j)), sP[j]), EP);
AP = EP;
EP = DP;
DP = RIPEMD160.rol32(CP, 10);
CP = BP;
BP = _T;
}
var T = RIPEMD160.add_modulo32(h[1], C, DP);
h[1] = RIPEMD160.add_modulo32(h[2], D, EP);
h[2] = RIPEMD160.add_modulo32(h[3], E, AP);
h[3] = RIPEMD160.add_modulo32(h[4], A, BP);
h[4] = RIPEMD160.add_modulo32(h[0], B, CP);
h[0] = T;
}
// The final output string then consists of the concatenatation
// of h_0, h_1, h_2, h_3, and h_4 after converting each h_i to a
// 4-byte string using the little-endian convention.
var result = new ArrayBuffer(20);
var data_view = new DataView(result);
h.forEach(function (h_i, i) {
return data_view.setUint32(i * 4, h_i, true);
});
return result;
}
}]);
return RIPEMD160;
}();
module.exports = {
RIPEMD160: RIPEMD160
};
+3
View File
@@ -0,0 +1,3 @@
import { JsonRpc } from './eosjs-jsonrpc';
import { RpcError } from './eosjs-rpcerror';
export { JsonRpc, RpcError };
+7
View File
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var eosjs_jsonrpc_1 = require("./eosjs-jsonrpc");
exports.JsonRpc = eosjs_jsonrpc_1.JsonRpc;
var eosjs_rpcerror_1 = require("./eosjs-rpcerror");
exports.RpcError = eosjs_rpcerror_1.RpcError;
//# sourceMappingURL=rpc-web.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"rpc-web.js","sourceRoot":"","sources":["../src/rpc-web.ts"],"names":[],"mappings":";;AAAA,iDAA0C;AAGjC,kBAHA,uBAAO,CAGA;AAFhB,mDAA4C;AAE1B,mBAFT,yBAAQ,CAES"}
+193
View File
@@ -0,0 +1,193 @@
{
"version": "eosio::abi/1.1",
"structs": [
{
"name": "extensions_entry",
"base": "",
"fields": [
{
"name": "tag",
"type": "uint16"
},
{
"name": "value",
"type": "bytes"
}
]
},
{
"name": "type_def",
"base": "",
"fields": [
{
"name": "new_type_name",
"type": "string"
},
{
"name": "type",
"type": "string"
}
]
},
{
"name": "field_def",
"base": "",
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "type",
"type": "string"
}
]
},
{
"name": "struct_def",
"base": "",
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "base",
"type": "string"
},
{
"name": "fields",
"type": "field_def[]"
}
]
},
{
"name": "action_def",
"base": "",
"fields": [
{
"name": "name",
"type": "name"
},
{
"name": "type",
"type": "string"
},
{
"name": "ricardian_contract",
"type": "string"
}
]
},
{
"name": "table_def",
"base": "",
"fields": [
{
"name": "name",
"type": "name"
},
{
"name": "index_type",
"type": "string"
},
{
"name": "key_names",
"type": "string[]"
},
{
"name": "key_types",
"type": "string[]"
},
{
"name": "type",
"type": "string"
}
]
},
{
"name": "clause_pair",
"base": "",
"fields": [
{
"name": "id",
"type": "string"
},
{
"name": "body",
"type": "string"
}
]
},
{
"name": "error_message",
"base": "",
"fields": [
{
"name": "error_code",
"type": "uint64"
},
{
"name": "error_msg",
"type": "string"
}
]
},
{
"name": "variant_def",
"base": "",
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "types",
"type": "string[]"
}
]
},
{
"name": "abi_def",
"base": "",
"fields": [
{
"name": "version",
"type": "string"
},
{
"name": "types",
"type": "type_def[]"
},
{
"name": "structs",
"type": "struct_def[]"
},
{
"name": "actions",
"type": "action_def[]"
},
{
"name": "tables",
"type": "table_def[]"
},
{
"name": "ricardian_clauses",
"type": "clause_pair[]"
},
{
"name": "error_messages",
"type": "error_message[]"
},
{
"name": "abi_extensions",
"type": "extensions_entry[]"
},
{
"name": "variants",
"type": "variant_def[]$"
}
]
}
]
}
@@ -0,0 +1,117 @@
{
"version": "eosio::abi/1.0",
"types": [
{
"new_type_name": "account_name",
"type": "name"
},
{
"new_type_name": "action_name",
"type": "name"
},
{
"new_type_name": "permission_name",
"type": "name"
}
],
"structs": [
{
"name": "permission_level",
"base": "",
"fields": [
{
"name": "actor",
"type": "account_name"
},
{
"name": "permission",
"type": "permission_name"
}
]
},
{
"name": "action",
"base": "",
"fields": [
{
"name": "account",
"type": "account_name"
},
{
"name": "name",
"type": "action_name"
},
{
"name": "authorization",
"type": "permission_level[]"
},
{
"name": "data",
"type": "bytes"
}
]
},
{
"name": "extension",
"base": "",
"fields": [
{
"name": "type",
"type": "uint16"
},
{
"name": "data",
"type": "bytes"
}
]
},
{
"name": "transaction_header",
"base": "",
"fields": [
{
"name": "expiration",
"type": "time_point_sec"
},
{
"name": "ref_block_num",
"type": "uint16"
},
{
"name": "ref_block_prefix",
"type": "uint32"
},
{
"name": "max_net_usage_words",
"type": "varuint32"
},
{
"name": "max_cpu_usage_ms",
"type": "uint8"
},
{
"name": "delay_sec",
"type": "varuint32"
}
]
},
{
"name": "transaction",
"base": "transaction_header",
"fields": [
{
"name": "context_free_actions",
"type": "action[]"
},
{
"name": "actions",
"type": "action[]"
},
{
"name": "transaction_extensions",
"type": "extension[]"
}
]
}
]
}
+1
View File
@@ -0,0 +1 @@
export {};
+259
View File
@@ -0,0 +1,259 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _this = this;
Object.defineProperty(exports, "__esModule", { value: true });
var text_encoding_1 = require("text-encoding");
var eosjs_api_1 = require("../eosjs-api");
var eosjs_jsonrpc_1 = require("../eosjs-jsonrpc");
var eosjs_jssig_1 = require("../eosjs-jssig");
var transaction = {
expiration: '2018-09-04T18:42:49',
ref_block_num: 38096,
ref_block_prefix: 505360011,
max_net_usage_words: 0,
max_cpu_usage_ms: 0,
delay_sec: 0,
context_free_actions: [],
actions: [
{
account: 'testeostoken',
name: 'transfer',
authorization: [
{
actor: 'thegazelle',
permission: 'active',
},
],
data: {
from: 'thegazelle',
to: 'remasteryoda',
quantity: '1.0000 EOS',
memo: 'For a secure future.',
},
hex_data: "00808a517dc354cb6012f557656ca4ba102700000000000004454f530000000014466f722\n 06120736563757265206675747572652e",
},
{
account: 'testeostoken',
name: 'transfer',
authorization: [
{
actor: 'thegazelle',
permission: 'active',
},
],
data: {
from: 'thegazelle',
to: 'remasteryoda',
quantity: '2.0000 EOS',
memo: 'For a second secure future (multiverse?)',
},
hex_data: "00808a517dc354cb6012f557656ca4ba204e00000000000004454f530000000028466f722061207365636f6e642073656\n 37572652066757475726520286d756c746976657273653f29",
},
],
transaction_extensions: [],
};
var serializedTx = [
41, 210, 142, 91, 208, 148, 139, 46, 31, 30, 0, 0, 0, 0, 2, 48, 21, 164,
25, 83, 149, 177, 202, 0, 0, 0, 87, 45, 60, 205, 205, 1, 0, 128, 138, 81,
125, 195, 84, 203, 0, 0, 0, 0, 168, 237, 50, 50, 0, 48, 21, 164, 25, 83,
149, 177, 202, 0, 0, 0, 87, 45, 60, 205, 205, 1, 0, 128, 138, 81, 125,
195, 84, 203, 0, 0, 0, 0, 168, 237, 50, 50, 0, 0,
];
var deserializedTx = {
actions: [
{
account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: '',
name: 'transfer',
},
{
account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: '',
name: 'transfer',
},
],
context_free_actions: [],
delay_sec: 0,
expiration: '2018-09-04T18:42:49.000',
max_cpu_usage_ms: 0,
max_net_usage_words: 0,
ref_block_num: 38096,
ref_block_prefix: 505360011,
transaction_extensions: [],
};
var serializedActions = [
{
account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: "00808A517DC354CB6012F557656CA4BA102700000000000004454F530000000014466F72206120736563757265206675747572652E",
name: 'transfer',
},
{
account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: "00808A517DC354CB6012F557656CA4BA204E00000000000004454F530000000028466F722061207365636F6E64207365637572652066757475726520286D756C746976657273653F29",
name: 'transfer',
},
];
var deserializedActions = [
{
account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: {
from: 'thegazelle',
memo: 'For a secure future.',
quantity: '1.0000 EOS',
to: 'remasteryoda',
},
name: 'transfer',
},
{
account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: {
from: 'thegazelle',
memo: 'For a second secure future (multiverse?)',
quantity: '2.0000 EOS',
to: 'remasteryoda',
},
name: 'transfer',
},
];
describe('eosjs-api', function () {
var api;
var fetch = function (input, init) { return __awaiter(_this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
return [2 /*return*/, ({
ok: true,
json: function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (input === '/v1/chain/get_raw_code_and_abi') {
return [2 /*return*/, {
account_name: 'testeostoken',
abi: "DmVvc2lvOjphYmkvMS4wAQxhY2NvdW50X25hbWUEbmFtZQUIdHJhbnNmZXIABARmcm9tDGFjY291bnRfbmFtZQJ0bwxhY2NvdW50X25hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcGY3JlYXRlAAIGaXNzdWVyDGFjY291bnRfbmFtZQ5tYXhpbXVtX3N1cHBseQVhc3NldAVpc3N1ZQADAnRvDGFjY291bnRfbmFtZQhxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwdhY2NvdW50AAEHYmFsYW5jZQVhc3NldA5jdXJyZW5jeV9zdGF0cwADBnN1cHBseQVhc3NldAptYXhfc3VwcGx5BWFzc2V0Bmlzc3VlcgxhY2NvdW50X25hbWUDAAAAVy08zc0IdHJhbnNmZXLnBSMjIFRyYW5zZmVyIFRlcm1zICYgQ29uZGl0aW9ucwoKSSwge3tmcm9tfX0sIGNlcnRpZnkgdGhlIGZvbGxvd2luZyB0byBiZSB0cnVlIHRvIHRoZSBiZXN0IG9mIG15IGtub3dsZWRnZToKCjEuIEkgY2VydGlmeSB0aGF0IHt7cXVhbnRpdHl9fSBpcyBub3QgdGhlIHByb2NlZWRzIG9mIGZyYXVkdWxlbnQgb3IgdmlvbGVudCBhY3Rpdml0aWVzLgoyLiBJIGNlcnRpZnkgdGhhdCwgdG8gdGhlIGJlc3Qgb2YgbXkga25vd2xlZGdlLCB7e3RvfX0gaXMgbm90IHN1cHBvcnRpbmcgaW5pdGlhdGlvbiBvZiB2aW9sZW5jZSBhZ2FpbnN0IG90aGVycy4KMy4gSSBoYXZlIGRpc2Nsb3NlZCBhbnkgY29udHJhY3R1YWwgdGVybXMgJiBjb25kaXRpb25zIHdpdGggcmVzcGVjdCB0byB7e3F1YW50aXR5fX0gdG8ge3t0b319LgoKSSB1bmRlcnN0YW5kIHRoYXQgZnVuZHMgdHJhbnNmZXJzIGFyZSBub3QgcmV2ZXJzaWJsZSBhZnRlciB0aGUge3t0cmFuc2FjdGlvbi5kZWxheX19IHNlY29uZHMgb3Igb3RoZXIgZGVsYXkgYXMgY29uZmlndXJlZCBieSB7e2Zyb219fSdzIHBlcm1pc3Npb25zLgoKSWYgdGhpcyBhY3Rpb24gZmFpbHMgdG8gYmUgaXJyZXZlcnNpYmx5IGNvbmZpcm1lZCBhZnRlciByZWNlaXZpbmcgZ29vZHMgb3Igc2VydmljZXMgZnJvbSAne3t0b319JywgSSBhZ3JlZSB0byBlaXRoZXIgcmV0dXJuIHRoZSBnb29kcyBvciBzZXJ2aWNlcyBvciByZXNlbmQge3txdWFudGl0eX19IGluIGEgdGltZWx5IG1hbm5lci4KAAAAAAClMXYFaXNzdWUAAAAAAKhs1EUGY3JlYXRlAAIAAAA4T00RMgNpNjQBCGN1cnJlbmN5AQZ1aW50NjQHYWNjb3VudAAAAAAAkE3GA2k2NAEIY3VycmVuY3kBBnVpbnQ2NA5jdXJyZW5jeV9zdGF0cwAAAA===",
}];
}
return [2 /*return*/, transaction];
});
}); },
})];
});
}); };
beforeEach(function () {
var rpc = new eosjs_jsonrpc_1.JsonRpc('', { fetch: fetch });
var signatureProvider = new eosjs_jssig_1.JsSignatureProvider(['5JtUScZK2XEp3g9gh7F8bwtPTRAkASmNrrftmx4AxDKD5K4zDnr']);
var chainId = '038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca';
api = new eosjs_api_1.Api({
rpc: rpc, signatureProvider: signatureProvider, chainId: chainId, textDecoder: new text_encoding_1.TextDecoder(), textEncoder: new text_encoding_1.TextEncoder(),
});
});
it('Doesnt crash', function () {
expect(api).toBeTruthy();
});
it('getAbi returns an abi', function () { return __awaiter(_this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, api.getAbi('testeostoken')];
case 1:
response = _a.sent();
expect(response).toBeTruthy();
return [2 /*return*/];
}
});
}); });
it('getTransactionAbis returns abis by transactions', function () { return __awaiter(_this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, api.getTransactionAbis(transaction)];
case 1:
response = _a.sent();
expect(response[0].abi.length).toBeGreaterThan(0);
return [2 /*return*/];
}
});
}); });
it('getContract returns a contract', function () { return __awaiter(_this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, api.getContract('testeostoken')];
case 1:
response = _a.sent();
expect(response.actions).toBeTruthy();
return [2 /*return*/];
}
});
}); });
it('deserializeTransaction converts tx from binary', function () {
var tx = api.deserializeTransaction(serializedTx);
expect(tx).toEqual(deserializedTx);
});
it('serializeActions converts actions to hex', function () { return __awaiter(_this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, api.serializeActions(transaction.actions)];
case 1:
response = _a.sent();
expect(response).toEqual(serializedActions);
return [2 /*return*/];
}
});
}); });
it('deserializeActions converts actions from hex', function () { return __awaiter(_this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, api.deserializeActions(serializedActions)];
case 1:
response = _a.sent();
expect(response).toEqual(deserializedActions);
return [2 /*return*/];
}
});
}); });
it('hasRequiredTaposFields returns true, if required fields are present', function () {
var response = api.hasRequiredTaposFields(transaction);
expect(response).toEqual(true);
});
});
//# sourceMappingURL=eosjs-api.test.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export {};
@@ -0,0 +1,880 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _this = this;
Object.defineProperty(exports, "__esModule", { value: true });
var eosjs_jsonrpc_1 = require("../eosjs-jsonrpc");
var eosjs_rpcerror_1 = require("../eosjs-rpcerror");
describe('JSON RPC', function () {
var endpoint = 'http://localhost';
var fetchMock = fetch;
var jsonRpc;
beforeEach(function () {
fetchMock.resetMocks();
jsonRpc = new eosjs_jsonrpc_1.JsonRpc(endpoint);
});
it('throws error bad status', function () { return __awaiter(_this, void 0, void 0, function () {
var actMessage, expMessage, accountName, expReturn, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
actMessage = '';
expMessage = 'Not Found';
accountName = 'myaccountaaa';
expReturn = { data: '12345', message: expMessage };
fetchMock.once(JSON.stringify(expReturn), { status: 404 });
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, jsonRpc.get_abi(accountName)];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
e_1 = _a.sent();
expect(e_1).toBeInstanceOf(eosjs_rpcerror_1.RpcError);
actMessage = e_1.message;
return [3 /*break*/, 4];
case 4:
expect(actMessage).toEqual(expMessage);
return [2 /*return*/];
}
});
}); });
it('throws error unprocessed', function () { return __awaiter(_this, void 0, void 0, function () {
var actMessage, expMessage, accountName, expReturn, e_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
actMessage = '';
expMessage = 'Not Processed';
accountName = 'myaccountaaa';
expReturn = {
data: '12345',
processed: {
except: {
message: expMessage,
},
},
};
fetchMock.once(JSON.stringify(expReturn));
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, jsonRpc.get_abi(accountName)];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
e_2 = _a.sent();
expect(e_2).toBeInstanceOf(eosjs_rpcerror_1.RpcError);
actMessage = e_2.message;
return [3 /*break*/, 4];
case 4:
expect(actMessage).toEqual(expMessage);
return [2 /*return*/];
}
});
}); });
it('calls provided fetch instead of default', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, accountName, expReturn, expParams, mockResp, myFetch;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_abi';
accountName = 'myaccountaaa';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
account_name: accountName,
}),
method: 'POST',
};
mockResp = {
json: function () {
return expReturn;
},
ok: true,
};
myFetch = jest.fn();
myFetch.mockReturnValue(mockResp);
jsonRpc = new eosjs_jsonrpc_1.JsonRpc(endpoint, { fetch: myFetch });
return [4 /*yield*/, jsonRpc.get_abi(accountName)];
case 1:
_a.sent();
expect(myFetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_abi', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, accountName, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_abi';
accountName = 'myaccountaaa';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
account_name: accountName,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_abi(accountName)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_account', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, accountName, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_account';
accountName = 'myaccountaaa';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
account_name: accountName,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_account(accountName)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_block_header_state', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, blockNumOrId, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_block_header_state';
blockNumOrId = 1234;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
block_num_or_id: blockNumOrId,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_block_header_state(blockNumOrId)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_block', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, blockNumOrId, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_block';
blockNumOrId = 1234;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
block_num_or_id: blockNumOrId,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_block(blockNumOrId)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_code', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, accountName, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_code';
accountName = 'myaccountaaa';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
account_name: accountName,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_code(accountName)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_currency_balance with all params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, code, account, symbol, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_currency_balance';
code = 'morse';
account = 'myaccountaaa';
symbol = 'EOS';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
code: code,
account: account,
symbol: symbol,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_currency_balance(code, account, symbol)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_currency_balance with default params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, code, account, symbol, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_currency_balance';
code = 'morse';
account = 'myaccountaaa';
symbol = null;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
code: code,
account: account,
symbol: symbol,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_currency_balance(code, account)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_currency_stats with all params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, code, symbol, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_currency_stats';
code = 'morse';
symbol = 'EOS';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
code: code,
symbol: symbol,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_currency_stats(code, symbol)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_info', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_info';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_info()];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_producer_schedule', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_producer_schedule';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_producer_schedule()];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_producers with all params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, json, lowerBound, limit, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_producers';
json = false;
lowerBound = 'zero';
limit = 10;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
json: json,
lower_bound: lowerBound,
limit: limit,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_producers(json, lowerBound, limit)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_producers with default params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, json, lowerBound, limit, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_producers';
json = true;
lowerBound = '';
limit = 50;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
json: json,
lower_bound: lowerBound,
limit: limit,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_producers()];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_raw_code_and_abi', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, accountName, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_raw_code_and_abi';
accountName = 'myaccountaaa';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
account_name: accountName,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_raw_code_and_abi(accountName)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_table_rows with all params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, json, code, scope, table, tableKey, lowerBound, upperBound, limit, indexPosition, keyType, expReturn, reverse, showPayer, callParams, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_table_rows';
json = false;
code = 'morse';
scope = 'minty';
table = 'coffee';
tableKey = 'front_door';
lowerBound = 'zero';
upperBound = 'five';
limit = 20;
indexPosition = 1;
keyType = 'str';
expReturn = { data: '12345' };
reverse = false;
showPayer = false;
callParams = {
json: json,
code: code,
scope: scope,
table: table,
table_key: tableKey,
lower_bound: lowerBound,
upper_bound: upperBound,
index_position: indexPosition,
key_type: keyType,
limit: limit,
reverse: reverse,
show_payer: showPayer,
};
expParams = {
body: JSON.stringify(callParams),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_table_rows(callParams)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_table_rows with default params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, json, code, scope, table, tableKey, lowerBound, upperBound, limit, indexPosition, keyType, reverse, showPayer, expReturn, callParams, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_table_rows';
json = true;
code = 'morse';
scope = 'minty';
table = 'coffee';
tableKey = '';
lowerBound = '';
upperBound = '';
limit = 10;
indexPosition = 1;
keyType = '';
reverse = false;
showPayer = false;
expReturn = { data: '12345' };
callParams = {
code: code,
scope: scope,
table: table,
};
expParams = {
body: JSON.stringify({
json: json,
code: code,
scope: scope,
table: table,
table_key: tableKey,
lower_bound: lowerBound,
upper_bound: upperBound,
index_position: indexPosition,
key_type: keyType,
limit: limit,
reverse: reverse,
show_payer: showPayer,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_table_rows(callParams)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_table_by_scope with all params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, code, table, lowerBound, upperBound, limit, expReturn, callParams, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_table_by_scope';
code = 'morse';
table = 'coffee';
lowerBound = 'minty';
upperBound = 'minty';
limit = 20;
expReturn = { data: '12345' };
callParams = {
code: code,
table: table,
lower_bound: lowerBound,
upper_bound: upperBound,
limit: limit,
};
expParams = {
body: JSON.stringify(callParams),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_table_by_scope(callParams)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls get_table_by_scope with default params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, code, table, lowerBound, upperBound, limit, expReturn, callParams, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_table_by_scope';
code = 'morse';
table = 'coffee';
lowerBound = '';
upperBound = '';
limit = 10;
expReturn = { data: '12345' };
callParams = {
code: code,
table: table,
};
expParams = {
body: JSON.stringify({
code: code,
table: table,
lower_bound: lowerBound,
upper_bound: upperBound,
limit: limit,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.get_table_by_scope(callParams)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls getRequiredKeys', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, keys, expReturn, callParams, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/get_required_keys';
keys = ['key1', 'key2', 'key3'];
expReturn = { required_keys: keys };
callParams = {
transaction: 'mytxn',
availableKeys: keys,
};
expParams = {
body: JSON.stringify({
transaction: callParams.transaction,
available_keys: callParams.availableKeys,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.getRequiredKeys(callParams)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn.required_keys);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls push_transaction', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, signatures, serializedTransaction, limit, expReturn, callParams, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/chain/push_transaction';
signatures = [
'George Washington',
'John Hancock',
'Abraham Lincoln',
];
serializedTransaction = new Uint8Array([
0, 16, 32, 128, 255,
]);
limit = 50;
expReturn = { data: '12345' };
callParams = {
signatures: signatures,
serializedTransaction: serializedTransaction,
};
expParams = {
body: JSON.stringify({
signatures: signatures,
compression: 0,
packed_context_free_data: '',
packed_trx: '00102080ff',
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.push_transaction(callParams)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls db_size_get', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/db_size/get';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.db_size_get()];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls history_get_actions with all params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, accountName, pos, offset, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/history/get_actions';
accountName = 'myaccountaaa';
pos = 5;
offset = 10;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
account_name: accountName,
pos: pos,
offset: offset,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.history_get_actions(accountName, pos, offset)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls history_get_actions with default params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, accountName, pos, offset, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/history/get_actions';
accountName = 'myaccountaaa';
pos = null;
offset = null;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
account_name: accountName,
pos: pos,
offset: offset,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.history_get_actions(accountName)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls history_get_transaction with all params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, id, blockNumHint, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/history/get_transaction';
id = 'myaccountaaa';
blockNumHint = 20;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
id: id,
block_num_hint: blockNumHint,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.history_get_transaction(id, blockNumHint)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls history_get_transaction with default params', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, id, blockNumHint, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/history/get_transaction';
id = 'myaccountaaa';
blockNumHint = null;
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
id: id,
block_num_hint: blockNumHint,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.history_get_transaction(id)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls history_get_key_accounts', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, publicKey, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/history/get_key_accounts';
publicKey = 'key12345';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
public_key: publicKey,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.history_get_key_accounts(publicKey)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
it('calls history_get_controlled_accounts', function () { return __awaiter(_this, void 0, void 0, function () {
var expPath, controllingAccount, expReturn, expParams, response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
expPath = '/v1/history/get_controlled_accounts';
controllingAccount = 'key12345';
expReturn = { data: '12345' };
expParams = {
body: JSON.stringify({
controlling_account: controllingAccount,
}),
method: 'POST',
};
fetchMock.once(JSON.stringify(expReturn));
return [4 /*yield*/, jsonRpc.history_get_controlled_accounts(controllingAccount)];
case 1:
response = _a.sent();
expect(response).toEqual(expReturn);
expect(fetch).toBeCalledWith(endpoint + expPath, expParams);
return [2 /*return*/];
}
});
}); });
});
//# sourceMappingURL=eosjs-jsonrpc.test.js.map
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
export {};
@@ -0,0 +1,92 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _this = this;
Object.defineProperty(exports, "__esModule", { value: true });
var ecc = require("eosjs-ecc");
var eosjs_jssig_1 = require("../eosjs-jssig");
describe('JsSignatureProvider', function () {
var privateKeys = ['key1', 'key2', 'key3'];
var publicKeys = [
'PUB_K1_8iD9ABKFH5b9JyFgb5PE51BdCV74qGN9UMfg9V3TwaExCQWxJm',
'PUB_K1_8f2o2LLQ3phteqyazxirQZnQzQFpnjLnXiUFEJcsSYhnjWNvSX',
'PUB_K1_5imfbmmHC83VRxLRTcvovviAc6LPpyszcDuKtkwka9e9Jg37Hp',
];
it('builds public keys from private when constructed', function () { return __awaiter(_this, void 0, void 0, function () {
var eccPkFromString, provider, actualPublicKeys;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
eccPkFromString = jest.spyOn(ecc.PrivateKey, 'fromString');
eccPkFromString.mockImplementation(function (k) { return ecc.PrivateKey.fromHex(ecc.sha256(k)); });
provider = new eosjs_jssig_1.JsSignatureProvider(privateKeys);
return [4 /*yield*/, provider.getAvailableKeys()];
case 1:
actualPublicKeys = _a.sent();
expect(eccPkFromString).toHaveBeenCalledTimes(privateKeys.length);
expect(actualPublicKeys).toEqual(publicKeys);
return [2 /*return*/];
}
});
}); });
it('signs a transaction', function () { return __awaiter(_this, void 0, void 0, function () {
var eccSignatureSign, provider, chainId, requiredKeys, serializedTransaction, abis, signOutput;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
eccSignatureSign = jest.spyOn(ecc.Signature, 'sign');
eccSignatureSign.mockImplementation(function (buffer, signKey) { return signKey; });
provider = new eosjs_jssig_1.JsSignatureProvider(privateKeys);
chainId = '12345';
requiredKeys = [
publicKeys[0],
publicKeys[2],
];
serializedTransaction = new Uint8Array([
0, 16, 32, 128, 255,
]);
abis = [];
return [4 /*yield*/, provider.sign({ chainId: chainId, requiredKeys: requiredKeys, serializedTransaction: serializedTransaction, abis: abis })];
case 1:
signOutput = _a.sent();
expect(eccSignatureSign).toHaveBeenCalledTimes(2);
expect(signOutput).toEqual({ signatures: [privateKeys[0], privateKeys[2]], serializedTransaction: serializedTransaction });
return [2 /*return*/];
}
});
}); });
});
//# sourceMappingURL=eosjs-jssig.test.js.map
@@ -0,0 +1 @@
{"version":3,"file":"eosjs-jssig.test.js","sourceRoot":"","sources":["../../src/tests/eosjs-jssig.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBA0CA;;AA1CA,+BAAiC;AACjC,8CAAqD;AAErD,QAAQ,CAAC,qBAAqB,EAAE;IAC5B,IAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,IAAM,UAAU,GAAG;QACf,2DAA2D;QAC3D,2DAA2D;QAC3D,2DAA2D;KAC9D,CAAC;IAEF,EAAE,CAAC,kDAAkD,EAAE;;;;;oBAC7C,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;oBACjE,eAAe,CAAC,kBAAkB,CAAC,UAAC,CAAC,IAAK,OAAA,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAArC,CAAqC,CAAC,CAAC;oBAC3E,QAAQ,GAAG,IAAI,iCAAmB,CAAC,WAAW,CAAC,CAAC;oBAC7B,qBAAM,QAAQ,CAAC,gBAAgB,EAAE,EAAA;;oBAApD,gBAAgB,GAAG,SAAiC;oBAE1D,MAAM,CAAC,eAAe,CAAC,CAAC,qBAAqB,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;oBAClE,MAAM,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;;;;SAChD,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE;;;;;oBAChB,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;oBAC3D,gBAAgB,CAAC,kBAAkB,CAAC,UAAC,MAAM,EAAE,OAAO,IAAK,OAAA,OAAO,EAAP,CAAO,CAAC,CAAC;oBAE5D,QAAQ,GAAG,IAAI,iCAAmB,CAAC,WAAW,CAAC,CAAC;oBAChD,OAAO,GAAG,OAAO,CAAC;oBAClB,YAAY,GAAG;wBACjB,UAAU,CAAC,CAAC,CAAC;wBACb,UAAU,CAAC,CAAC,CAAC;qBAChB,CAAC;oBACI,qBAAqB,GAAG,IAAI,UAAU,CAAC;wBACzC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG;qBACtB,CAAC,CAAC;oBACG,IAAI,GAAU,EAAE,CAAC;oBAEJ,qBAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,SAAA,EAAE,YAAY,cAAA,EAAE,qBAAqB,uBAAA,EAAE,IAAI,MAAA,EAAE,CAAC,EAAA;;oBAAxF,UAAU,GAAG,SAA2E;oBAE9F,MAAM,CAAC,gBAAgB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;oBAClD,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,qBAAqB,uBAAA,EAAE,CAAC,CAAC;;;;SACvG,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
+1
View File
@@ -0,0 +1 @@
declare const tests: any;
+140
View File
@@ -0,0 +1,140 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _this = this;
var tests = require('./node');
describe('Node JS environment', function () {
var transactionResponse;
var transactionSignatures;
var failedAsPlanned;
it('transacts with configuration object', function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tests.transactWithConfig()];
case 1:
transactionResponse = _a.sent();
expect(Object.keys(transactionResponse)).toContain('transaction_id');
return [2 /*return*/];
}
});
}); });
it('transacts with manually configured TAPOS fields', function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tests.transactWithoutConfig()];
case 1:
transactionResponse = _a.sent();
expect(Object.keys(transactionResponse)).toContain('transaction_id');
return [2 /*return*/];
}
});
}); }, 10000);
it('transacts without broadcasting, returning signatures and packed transaction', function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tests.transactWithoutBroadcast()];
case 1:
transactionSignatures = _a.sent();
expect(Object.keys(transactionSignatures)).toContain('signatures');
expect(Object.keys(transactionSignatures)).toContain('serializedTransaction');
return [2 /*return*/];
}
});
}); });
it('broadcasts packed transaction, given valid signatures', function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, tests.transactWithoutBroadcast()];
case 1:
transactionSignatures = _a.sent();
return [4 /*yield*/, tests.broadcastResult(transactionSignatures)];
case 2:
transactionResponse = _a.sent();
expect(Object.keys(transactionResponse)).toContain('transaction_id');
return [2 /*return*/];
}
});
}); });
it('throws appropriate error message without configuration object or TAPOS in place', function () { return __awaiter(_this, void 0, void 0, function () {
var e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
failedAsPlanned = true;
return [4 /*yield*/, tests.transactShouldFail()];
case 1:
_a.sent();
failedAsPlanned = false;
return [3 /*break*/, 3];
case 2:
e_1 = _a.sent();
if (e_1.message !== 'Required configuration or TAPOS fields are not present') {
failedAsPlanned = false;
}
return [3 /*break*/, 3];
case 3:
expect(failedAsPlanned).toEqual(true);
return [2 /*return*/];
}
});
}); });
it('throws an an error with RpcError structure for invalid RPC calls', function () { return __awaiter(_this, void 0, void 0, function () {
var e_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 3]);
failedAsPlanned = true;
return [4 /*yield*/, tests.rpcShouldFail()];
case 1:
_a.sent();
failedAsPlanned = false;
return [3 /*break*/, 3];
case 2:
e_2 = _a.sent();
if (!e_2.json || !e_2.json.error || !(e_2.json.error.hasOwnProperty('details'))) {
failedAsPlanned = false;
}
return [3 /*break*/, 3];
case 3:
expect(failedAsPlanned).toEqual(true);
return [2 /*return*/];
}
});
}); });
});
//# sourceMappingURL=node.test.js.map
@@ -0,0 +1 @@
{"version":3,"file":"node.test.js","sourceRoot":"","sources":["../../src/tests/node.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBAuDA;AAvDA,IAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEhC,QAAQ,CAAC,qBAAqB,EAAE;IAC5B,IAAI,mBAAwB,CAAC;IAC7B,IAAI,qBAA0B,CAAC;IAC/B,IAAI,eAAwB,CAAC;IAE7B,EAAE,CAAC,qCAAqC,EAAE;;;wBAChB,qBAAM,KAAK,CAAC,kBAAkB,EAAE,EAAA;;oBAAtD,mBAAmB,GAAG,SAAgC,CAAC;oBACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;;;;SACxE,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE;;;wBAC5B,qBAAM,KAAK,CAAC,qBAAqB,EAAE,EAAA;;oBAAzD,mBAAmB,GAAG,SAAmC,CAAC;oBAC1D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;;;;SACxE,EAAE,KAAK,CAAC,CAAC;IAEV,EAAE,CAAC,6EAA6E,EAAE;;;wBACtD,qBAAM,KAAK,CAAC,wBAAwB,EAAE,EAAA;;oBAA9D,qBAAqB,GAAG,SAAsC,CAAC;oBAC/D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;oBACnE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;;;;SACjF,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE;;;wBAChC,qBAAM,KAAK,CAAC,wBAAwB,EAAE,EAAA;;oBAA9D,qBAAqB,GAAG,SAAsC,CAAC;oBACzC,qBAAM,KAAK,CAAC,eAAe,CAAC,qBAAqB,CAAC,EAAA;;oBAAxE,mBAAmB,GAAG,SAAkD,CAAC;oBACzE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;;;;SACxE,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE;;;;;;oBAE9E,eAAe,GAAG,IAAI,CAAC;oBACvB,qBAAM,KAAK,CAAC,kBAAkB,EAAE,EAAA;;oBAAhC,SAAgC,CAAC;oBACjC,eAAe,GAAG,KAAK,CAAC;;;;oBAExB,IAAI,GAAC,CAAC,OAAO,KAAK,wDAAwD,EAAE;wBACxE,eAAe,GAAG,KAAK,CAAC;qBAC3B;;;oBAEL,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;;;SACzC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE;;;;;;oBAE/D,eAAe,GAAG,IAAI,CAAC;oBACvB,qBAAM,KAAK,CAAC,aAAa,EAAE,EAAA;;oBAA3B,SAA2B,CAAC;oBAC5B,eAAe,GAAG,KAAK,CAAC;;;;oBAExB,IAAI,CAAC,GAAC,CAAC,IAAI,IAAI,CAAC,GAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,GAAC,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,EAAE;wBACvE,eAAe,GAAG,KAAK,CAAC;qBAC3B;;;oBAEL,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;;;SACzC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -1,8 +1,7 @@
import {HyperionConfig} from "../../interfaces/hyperionConfig.js";
import {getPackageJson} from "../../helpers/common_functions.js";
import {HyperionConfig} from "../../interfaces/hyperionConfig";
export function generateOpenApiConfig(config: HyperionConfig) {
const packageData = getPackageJson();
const packageData = require('../../package');
const health_link = `https://${config.api.server_name}/v2/health`;
const explorer_link = `https://${config.api.server_name}/v2/explore`;
@@ -1,4 +1,4 @@
import {HyperionConfig} from "../../interfaces/hyperionConfig.js";
import {HyperionConfig} from "../../interfaces/hyperionConfig";
import {createHash} from "crypto";
import {FastifyRequest} from "fastify";
@@ -28,20 +28,20 @@ export class CacheManager {
setInterval(() => {
try {
// remove expired entries
let removeCount = 0;
// let removeCount = 0;
const now = Date.now();
this.v1Caches.forEach((pathCacheMap: Map<string, CachedEntry>, pathKey: string) => {
pathCacheMap.forEach((cache: CachedEntry, entryKey: string, map: Map<string, CachedEntry>) => {
if (cache.exp < now) {
map.delete(entryKey);
removeCount++;
// removeCount++;
}
});
});
if (removeCount > 0) {
console.log(`${removeCount} expired cache entries removed`);
}
} catch (e: any) {
// if (removeCount > 0) {
// console.log(`${removeCount} expired cache entries removed`);
// }
} catch (e) {
console.log(e);
}
}, 5000);
@@ -53,13 +53,10 @@ export class CacheManager {
setCachedData(hash: string, path: string, payload: any): void {
if (this.v1CacheConfigs.has(path) && this.v1Caches.has(path)) {
const ttl = this.v1CacheConfigs.get(path)?.ttl
if (ttl) {
this.v1Caches.get(path)?.set(hash, {
data: payload,
exp: ttl + Date.now()
});
}
this.v1Caches.get(path).set(hash, {
data: payload,
exp: this.v1CacheConfigs.get(path).ttl + Date.now()
});
}
}
@@ -74,15 +71,15 @@ export class CacheManager {
payload = request.url;
}
const hashedString = this.hashPayload(payload);
if (this.v1Caches.has(path as string)) {
const entry = this.v1Caches.get(path as string)?.get(hashedString);
if (this.v1Caches.has(path)) {
const entry = this.v1Caches.get(path).get(hashedString);
if (entry && entry.exp > Date.now()) {
return [entry.data, hashedString, path as string];
return [entry.data, hashedString, path];
} else {
return [null, hashedString, path as string];
return [null, hashedString, path];
}
} else {
return [null, hashedString, path as string];
return [null, hashedString, path];
}
}
+835
View File
@@ -0,0 +1,835 @@
import {createHash} from "crypto";
import * as _ from "lodash";
import {FastifyInstance, FastifyReply, FastifyRequest, FastifySchema, HTTPMethods} from "fastify";
import got from "got";
import {checkDeltaFilter, checkFilter, hLog} from "../../helpers/common_functions";
import {Socket} from "socket.io";
const deltaQueryFields = ['code', 'table', 'scope', 'payer'];
export async function streamPastDeltas(fastify: FastifyInstance, socket, data) {
const search_body = {
query: {bool: {must: []}},
sort: {block_num: 'asc'},
};
await addBlockRangeOpts(data, search_body, fastify);
deltaQueryFields.forEach(f => {
addTermMatch(data, search_body, f);
});
const onDemandDeltaFilters = [];
if (data.filters.length > 0) {
data.filters.forEach(f => {
if (f.field && f.value) {
if (f.field.startsWith('@') && !f.field.startsWith('data')) {
const _q = {};
_q[f.field] = f.value;
search_body.query.bool.must.push({'term': _q});
} else {
onDemandDeltaFilters.push(f);
}
}
});
}
const responseQueue = [];
let counter = 0;
let total = 0;
let totalFiltered = 0;
let longScroll = false;
// console.log(JSON.stringify(search_body, null, 2));
const init_response = await fastify.elastic.search({
index: fastify.manager.chain + '-delta-*',
scroll: '30s',
size: fastify.manager.config.api.stream_scroll_batch || 500,
body: search_body,
});
const scrollLimit = fastify.manager.config.api.stream_scroll_limit;
if (scrollLimit && scrollLimit !== -1 && init_response.body.hits.total.value > scrollLimit) {
const errorMsg = `Requested ${init_response.body.hits.total.value} deltas, limit is ${scrollLimit}.`;
socket.emit('message', {
reqUUID: socket.data.reqUUID,
type: 'delta_trace', mode: 'history', messages: [],
error: errorMsg
});
return {status: false, error: errorMsg};
}
if (init_response.body.hits.total.value > 10000) {
total = init_response.body.hits.total.value;
longScroll = true;
hLog(`Attention! Long scroll (deltas) is running!`);
}
// emit first block
if (init_response.body.hits.hits.length > 0) {
emitTraceInit(socket, init_response.body.hits.hits[0]._source.block_num, init_response.body.hits.total.value);
}
responseQueue.push(init_response);
let lastTransmittedBlock = 0;
let pendingScrollId = '';
while (responseQueue.length) {
let filterCount = 0;
const {body} = responseQueue.shift();
pendingScrollId = body['_scroll_id'];
const enqueuedMessages = [];
counter += body['hits']['hits'].length;
for (const doc of body['hits']['hits']) {
let allow = false;
if (onDemandDeltaFilters.length > 0) {
allow = onDemandDeltaFilters.every(filter => {
return checkDeltaFilter(filter, doc._source);
});
} else {
allow = true;
}
if (allow) {
enqueuedMessages.push(doc._source);
} else {
filterCount++;
}
// set last block
if (doc._source.block_num > lastTransmittedBlock) {
lastTransmittedBlock = doc._source.block_num;
}
}
totalFiltered += filterCount;
if (socket.connected) {
if (enqueuedMessages.length > 0) {
socket.emit('message', {
reqUUID: socket.data.reqUUID,
type: 'delta_trace',
mode: 'history',
messages: enqueuedMessages,
filtered: filterCount
});
}
} else {
hLog('LOST CLIENT');
break;
}
if (longScroll) {
hLog(`Progress: ${counter + totalFiltered}/${total}`);
}
if (body['hits'].total.value === counter) {
hLog(`${counter} past deltas streamed to ${socket.id} (${totalFiltered} filtered)`);
break;
}
const next_response = await fastify.elastic.scroll({
body: {scroll_id: body['_scroll_id'], scroll: '30s'}
});
responseQueue.push(next_response);
}
// destroy scroll context
await fastify.elastic.clearScroll({scroll_id: pendingScrollId});
return {status: true, lastTransmittedBlock};
}
export function emitTraceInit(socket: Socket, firstBlock: number, totalResults: number) {
socket.emit('message', {
reqUUID: socket.data.reqUUID,
type: 'trace_init',
mode: 'history',
first_block: firstBlock,
results: totalResults
});
}
export async function streamPastActions(fastify: FastifyInstance, socket, data) {
const search_body = {query: {bool: {must: []}}, sort: {global_sequence: 'asc'}};
await addBlockRangeOpts(data, search_body, fastify);
if (data.account !== '') {
search_body.query.bool.must.push({
bool: {
should: [
{term: {'notified': data.account}},
{term: {'act.authorization.actor': data.account}},
],
},
});
}
if (data.contract !== '*' && data.contract !== '') {
search_body.query.bool.must.push({'term': {'act.account': data.contract}});
}
if (data.action !== '*' && data.action !== '') {
search_body.query.bool.must.push({'term': {'act.name': data.action}});
}
const onDemandFilters = [];
if (data.filters.length > 0) {
data.filters.forEach(f => {
if (f.field && f.value) {
if (f.field.startsWith('@') && !f.field.startsWith('act.data')) {
const _q = {};
_q[f.field] = f.value;
search_body.query.bool.must.push({'term': _q});
} else {
onDemandFilters.push(f);
}
}
});
}
const responseQueue = [];
let counter = 0;
let total = 0;
let totalFiltered = 0;
let longScroll = false;
const init_response = await fastify.elastic.search({
index: fastify.manager.chain + '-action-*',
scroll: '30s',
size: fastify.manager.config.api.stream_scroll_batch || 500,
body: search_body,
});
const scrollLimit = fastify.manager.config.api.stream_scroll_limit;
if (scrollLimit && scrollLimit !== -1 && init_response.body.hits.total.value > scrollLimit) {
const errorMsg = `Requested ${init_response.body.hits.total.value} actions, limit is ${scrollLimit}.`;
socket.emit('message', {
reqUUID: socket.data.reqUUID,
type: 'action_trace', mode: 'history', messages: [],
error: `Requested ${init_response.body.hits.total.value} actions, limit is ${scrollLimit}.`
});
return {status: false, error: errorMsg};
}
if (init_response.body.hits.total.value > 10000) {
total = init_response.body.hits.total.value;
longScroll = true;
hLog(`Attention! Long scroll (actions) is running!`);
}
// emit first block
if (init_response.body.hits.hits.length > 0) {
emitTraceInit(socket, init_response.body.hits.hits[0]._source.block_num, init_response.body.hits.total.value);
}
responseQueue.push(init_response);
let lastTransmittedBlock = 0;
let pendingScrollId = '';
while (responseQueue.length) {
let filterCount = 0;
const {body} = responseQueue.shift();
pendingScrollId = body['_scroll_id'];
const enqueuedMessages = [];
counter += body['hits']['hits'].length;
for (const doc of body['hits']['hits']) {
let allow = false;
if (onDemandFilters.length > 0) {
allow = onDemandFilters.every(filter => {
return checkFilter(filter, doc._source);
});
} else {
allow = true;
}
if (allow) {
enqueuedMessages.push(doc._source);
} else {
filterCount++;
}
// set last block
if (doc._source.block_num > lastTransmittedBlock) {
lastTransmittedBlock = doc._source.block_num;
}
}
totalFiltered += filterCount;
if (socket.connected) {
if (enqueuedMessages.length > 0) {
socket.emit('message', {
reqUUID: socket.data.reqUUID,
type: 'action_trace',
mode: 'history',
messages: enqueuedMessages,
filtered: filterCount
});
}
} else {
hLog('LOST CLIENT');
break;
}
if (longScroll) {
hLog(`Progress: ${counter + totalFiltered}/${total}`);
}
if (body['hits'].total.value === counter) {
hLog(`${counter} past actions streamed to ${socket.id} (${totalFiltered} filtered)`);
break;
}
const next_response = await fastify.elastic.scroll({
body: {scroll_id: body['_scroll_id'], scroll: '30s'}
});
responseQueue.push(next_response);
}
// destroy scroll context
await fastify.elastic.clearScroll({scroll_id: pendingScrollId});
return {status: true, lastTransmittedBlock};
}
export function addTermMatch(data, search_body, field) {
if (data[field] && data[field] !== '*' && data[field] !== '') {
const termQuery = {};
termQuery[field] = data[field];
search_body.query.bool.must.push({'term': termQuery});
}
}
export async function addBlockRangeOpts(data, search_body, fastify: FastifyInstance) {
let timeRange;
let blockRange;
let head;
if (typeof data['start_from'] === 'string' && data['start_from'] !== '') {
if (!timeRange) {
timeRange = {"@timestamp": {}};
}
timeRange["@timestamp"]['gte'] = data['start_from'];
}
if (typeof data['read_until'] === 'string' && data['read_until'] !== '') {
if (!timeRange) {
timeRange = {"@timestamp": {}};
}
timeRange["@timestamp"]['lte'] = data['read_until'];
}
if (typeof data['start_from'] === 'number' && data['start_from'] !== 0) {
if (!blockRange) {
blockRange = {"block_num": {}};
}
if (data['start_from'] < 0) {
if (!head) {
head = (await fastify.eosjs.rpc.get_info()).head_block_num;
}
blockRange["block_num"]['gte'] = head + data['start_from'];
} else {
blockRange["block_num"]['gte'] = data['start_from'];
}
}
if (typeof data['read_until'] === 'number' && data['read_until'] !== 0) {
if (!blockRange) {
blockRange = {"block_num": {}};
}
if (data['read_until'] < 0) {
if (!head) {
head = (await fastify.eosjs.rpc.get_info()).head_block_num;
}
blockRange["block_num"]['lte'] = head + data['read_until'];
} else {
blockRange["block_num"]['lte'] = data['read_until'];
}
}
if (timeRange) {
search_body.query.bool.must.push({
range: timeRange,
});
}
if (blockRange) {
search_body.query.bool.must.push({
range: blockRange,
});
}
}
export function extendResponseSchema(responseProps: any) {
const props = {
query_time_ms: {type: "number"},
cached: {type: "boolean"},
hot_only: {type: "boolean"},
lib: {type: "number"},
last_indexed_block: {type: "number"},
last_indexed_block_time: {type: "string"},
total: {
type: "object",
properties: {
value: {type: "number"},
relation: {type: "string"}
}
}
};
for (const p in responseProps) {
if (responseProps.hasOwnProperty(p)) {
props[p] = responseProps[p];
}
}
return {
200: {
type: 'object',
properties: props
}
};
}
export function extendQueryStringSchema(queryParams: any, required?: string[]) {
const params = {
limit: {
description: 'limit of [n] results per page',
type: 'integer',
minimum: 1
},
skip: {
description: 'skip [n] results',
type: 'integer',
minimum: 0
}
};
for (const p in queryParams) {
if (queryParams.hasOwnProperty(p)) {
params[p] = queryParams[p];
}
}
const schema = {
type: 'object',
properties: params
}
if (required && required.length > 0) {
schema["required"] = required;
}
return schema;
}
export async function getCacheByHash(redis, key, chain) {
const hash = createHash('sha256');
const query_hash = hash.update(chain + "-" + key).digest('hex');
return [await redis.get(query_hash), query_hash];
}
export function mergeActionMeta(action) {
const name = action.act.name;
if (action['@' + name]) {
action['act']['data'] = _.merge(action['@' + name], action['act']['data']);
delete action['@' + name];
}
action['timestamp'] = action['@timestamp'];
// delete action['@timestamp'];
}
export function mergeDeltaMeta(delta: any) {
const name = delta.table;
if (delta["@" + name]) {
delta['data'] = _.merge(delta['@' + name], delta['data']);
delete delta['@' + name];
}
delta['timestamp'] = delta['@timestamp'];
delete delta['@timestamp'];
return delta;
}
export function setCacheByHash(fastify, hash, response, expiration?: number) {
if (fastify.manager.config.api.enable_caching) {
let exp;
if (expiration) {
exp = expiration;
} else {
exp = fastify.manager.config.api.cache_life;
}
fastify.redis.set(hash, JSON.stringify(response), 'EX', exp).catch(console.log);
}
}
export function getRouteName(filename: string) {
const arr = filename.split("/");
return arr[arr.length - 2];
}
export function addApiRoute(
fastifyInstance: FastifyInstance,
method: HTTPMethods | HTTPMethods[],
routeName: string,
routeBuilder: (fastify: FastifyInstance, route: string) => (request: FastifyRequest, reply: FastifyReply) => Promise<void>,
schema: FastifySchema
) {
fastifyInstance.route({
url: '/' + routeName,
method,
handler: routeBuilder(fastifyInstance, routeName),
schema
});
}
export async function getCachedResponse(server: FastifyInstance, route: string, key: any) {
const chain = server.manager.chain;
let resp, hash;
if (server.manager.config.api.enable_caching) {
[resp, hash] = await getCacheByHash(server.redis, route + JSON.stringify(key), chain);
if (resp) {
resp = JSON.parse(resp);
resp['cached'] = true;
return [resp, hash];
} else {
return [null, hash];
}
} else {
return [null, null];
}
}
export function getTrackTotalHits(query) {
let trackTotalHits: number | boolean = 10000;
if (query?.track) {
if (query.track === 'true') {
trackTotalHits = true;
} else if (query.track === 'false') {
trackTotalHits = false;
} else {
const parsed = parseInt(query.track, 10);
if (parsed > 0) {
trackTotalHits = parsed;
} else {
throw new Error('failed to parse track param');
}
}
}
return trackTotalHits;
}
function bigint2Milliseconds(input: bigint) {
return parseFloat((parseInt(input.toString()) / 1000000).toFixed(3));
}
const defaultRouteCacheMap = {
get_resource_usage: 3600,
get_creator: 3600 * 24,
health: 10
}
export async function timedQuery(
queryFunction: (fastify: FastifyInstance, request: FastifyRequest) => Promise<any>,
fastify: FastifyInstance, request: FastifyRequest, route: string): Promise<any> {
// get reference time in nanoseconds
const t0 = process.hrtime.bigint();
// check for cached data, return the response hash if caching is enabled
const [cachedResponse, hash] = await getCachedResponse(
fastify,
route,
request.method === 'POST' ? request.body : request.query
);
let lastIndexedBlockNumber = null;
let lastIndexedBlockTime = null;
const lastIndexedBlock = await fastify.redis.get(`${fastify.manager.chain}:last_idx_block`);
if (lastIndexedBlock) {
const arr = lastIndexedBlock.split("@");
if (arr.length === 2) {
lastIndexedBlockNumber = parseInt(arr[0], 10);
lastIndexedBlockTime = arr[1];
}
}
if (cachedResponse && !request.query["ignoreCache"]) {
// add cached query time
cachedResponse['query_time_ms'] = bigint2Milliseconds(process.hrtime.bigint() - t0);
if (lastIndexedBlock) {
cachedResponse['last_indexed_block'] = lastIndexedBlockNumber;
cachedResponse['last_indexed_block_time'] = lastIndexedBlockTime;
}
return cachedResponse;
}
// call query function
const response = await queryFunction(fastify, request);
// save response to cache
if (hash) {
let EX = null;
if (defaultRouteCacheMap[route]) {
EX = defaultRouteCacheMap[route];
}
setCacheByHash(fastify, hash, response, EX);
}
// add normal query time
if (response) {
response['query_time_ms'] = bigint2Milliseconds(process.hrtime.bigint() - t0);
if (lastIndexedBlock) {
response['last_indexed_block'] = lastIndexedBlockNumber;
response['last_indexed_block_time'] = lastIndexedBlockTime;
}
return response;
} else {
return {};
}
}
export function chainApiHandler(fastify: FastifyInstance) {
return async (request: FastifyRequest, reply: FastifyReply) => {
// check cache
const [cachedData, hash, path] = fastify.cacheManager.getCachedData(request);
if (cachedData) {
console.log('cache hit:', path, hash);
reply.headers({'hyperion-cached': true}).send(cachedData);
} else {
// call actual request
const apiResponse = await handleChainApiRedirect(request, reply, fastify);
// console.log('cache miss:', path, hash);
fastify.cacheManager.setCachedData(hash, path, apiResponse);
}
}
}
export async function handleChainApiRedirect(
request: FastifyRequest,
reply: FastifyReply,
fastify: FastifyInstance
): Promise<string> {
const urlParts = request.url.split("?");
let reqUrl = fastify.chain_api + urlParts[0];
// const pathComponents = urlParts[0].split('/');
// const path = pathComponents.at(-1);
if (urlParts[0] === '/v1/chain/push_transaction' && fastify.push_api && fastify.push_api !== "") {
reqUrl = fastify.push_api + urlParts[0];
}
const opts = {};
if (request.method === 'POST') {
if (request.body) {
if (typeof request.body === 'string') {
opts['body'] = request.body;
} else if (typeof request.body === 'object') {
opts['body'] = JSON.stringify(request.body);
}
} else {
opts['body'] = "";
}
} else if (request.method === 'GET') {
opts['json'] = request.query;
}
try {
const apiResponse = await got.post(reqUrl, opts);
reply.headers({"Content-Type": "application/json"});
if (request.method === 'HEAD') {
reply.headers({"Content-Length": apiResponse.body.length});
reply.send("");
return '';
} else {
reply.send(apiResponse.body);
return apiResponse.body;
}
} catch (error) {
if (error.response) {
reply.status(error.response.statusCode).send(error.response.body);
} else {
console.log(error);
reply.status(500).send();
}
if (fastify.manager.config.api.chain_api_error_log) {
try {
if (error.response) {
const error_msg = JSON.parse(error.response.body).error.details[0].message;
console.log(`endpoint: ${request.raw.url} | status: ${error.response.statusCode} | error: ${error_msg}`);
} else {
console.log(error);
}
// if (request.req.url === '/v1/chain/push_transaction') {
// const packedTrx = JSON.parse(opts['body']).packed_trx;
// const trxBuffer = Buffer.from(packedTrx, 'hex');
// const trxData = await fastify.eosjs.api.deserializeTransactionWithActions(trxBuffer);
// console.log(trxData);
// }
} catch (e) {
console.log(e);
}
}
return '';
}
}
export function addChainApiRoute(fastify: FastifyInstance, routeName, description, props?, required?) {
const baseSchema = {
description: description,
summary: description,
tags: ['chain']
};
addApiRoute(
fastify,
['GET', 'HEAD'],
routeName,
chainApiHandler,
{
...baseSchema,
querystring: props ? {
type: 'object',
properties: props,
required: required
} : undefined
}
);
addApiRoute(
fastify,
'POST',
routeName,
chainApiHandler,
{
...baseSchema,
body: props ? {
type: ['object', 'string'],
properties: props,
required: required
} : undefined
}
);
}
export function addSharedSchemas(fastify: FastifyInstance) {
fastify.addSchema({
$id: "WholeNumber",
title: "Integer",
description: "Integer or String",
anyOf: [
{
type: "string",
pattern: "^\\d+$"
},
{
type: "integer"
}
],
});
fastify.addSchema({
$id: "Symbol",
type: "string",
description: "A symbol composed of capital letters between 1-7.",
pattern: "^([A-Z]{1,7})$",
title: "Symbol"
});
fastify.addSchema({
$id: "Signature",
type: "string",
description: "String representation of an EOSIO compatible cryptographic signature",
pattern: "^SIG_([RK]1|WA)_[1-9A-HJ-NP-Za-km-z]+$",
title: "Signature"
})
fastify.addSchema({
$id: "AccountName",
description: "String representation of an EOSIO compatible account name",
"anyOf": [
{
"type": "string",
"description": "String representation of privileged EOSIO name type",
"pattern": "^(eosio[\\.][a-z1-5]{1,6})([a-j]{1})?$",
"title": "NamePrivileged"
},
{
"type": "string",
"description": "String representation of basic EOSIO name type, must be 12 characters and contain only a-z and 0-5",
"pattern": "^([a-z]{1}[a-z1-5]{11})([a-j]{1})?$",
"title": "NameBasic"
},
{
"type": "string",
"description": "String representation of EOSIO bid name type, 1-12 characters and only a-z and 0-5 are allowed",
"pattern": "^([a-z1-5]{1,12})([a-j]{1})?$",
"title": "NameBid"
},
{
"type": "string",
"description": "String representation of EOSIO name type",
"pattern": "^([a-z1-5]{1}[a-z1-5\\.]{0,10}[a-z1-5]{1})([a-j]{1})?$",
"title": "NameCatchAll"
}
],
"title": "Name"
});
fastify.addSchema({
$id: "Expiration",
"description": "Time that transaction must be confirmed by.",
"type": "string",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$",
"title": "DateTime"
});
fastify.addSchema({
$id: "BlockExtensions",
"type": "array",
"items": {
"anyOf": [
{"type": "integer"},
{"type": "string"}
]
},
"title": "Extension"
})
fastify.addSchema({
$id: "ActionItems",
"type": "object",
"additionalProperties": false,
"minProperties": 5,
"required": [
"account",
"name",
"authorization",
"data",
"hex_data"
],
"properties": {
"account": {$ref: 'AccountName#'},
"name": {$ref: 'AccountName#'},
"authorization": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"minProperties": 2,
"required": [
"actor",
"permission"
],
"properties": {
"actor": {$ref: 'AccountName#'},
"permission": {$ref: 'AccountName#'}
},
"title": "Authority"
}
},
"data": {
"type": "object",
"additionalProperties": true
},
"hex_data": {
"type": "string"
}
},
"title": "Action"
});
}
+33
View File
@@ -0,0 +1,33 @@
import * as Fastify from "fastify";
import {IncomingMessage, Server, ServerResponse} from "http";
// fastify plugins
import * as fastifyElasticsearch from 'fastify-elasticsearch';
import fastifySwagger from '@fastify/swagger';
import fastifyCors from '@fastify/cors';
import formBodyPlugin from '@fastify/formbody';
import fastifyRedis from '@fastify/redis';
import fastifyRateLimit from '@fastify/rate-limit';
// custom plugins
import fastify_eosjs from "./plugins/fastify-eosjs";
export function registerPlugins(server: Fastify.FastifyInstance<Server, IncomingMessage, ServerResponse>, params: any) {
server.register(fastifyElasticsearch, params.fastify_elasticsearch);
if (params.fastify_swagger) {
server.register(fastifySwagger, params.fastify_swagger);
}
server.register(fastifyCors);
server.register(formBodyPlugin);
server.register(fastifyRedis, params.fastify_redis);
if (params.fastify_rate_limit) {
server.register(fastifyRateLimit, params.fastify_rate_limit);
}
server.register(fastify_eosjs, params.fastify_eosjs);
}
+18
View File
@@ -0,0 +1,18 @@
import {FastifyInstance, FastifyPluginOptions} from "fastify";
import {Api} from "eosjs/dist";
import fp from "fastify-plugin";
export default fp(async (fastify: FastifyInstance, options: FastifyPluginOptions): Promise<void> => {
const rpc = fastify.manager.nodeosJsonRPC;
const api = new Api({
rpc,
signatureProvider: null,
chainId: options.chain_id,
textDecoder: new TextDecoder(),
textEncoder: new TextEncoder(),
});
fastify.decorate('eosjs', {api, rpc});
}, {
fastify: '>=2.0.0',
name: 'fastify-eosjs'
});
+36 -28
View File
@@ -1,10 +1,9 @@
import {join} from "path";
import {FastifyError, FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {createReadStream} from "fs";
import {addSharedSchemas, handleChainApiRedirect} from "./helpers/functions.js";
import {fastifyAutoload} from '@fastify/autoload';
import {addSharedSchemas, handleChainApiRedirect} from "./helpers/functions";
import autoLoad from '@fastify/autoload';
import got from "got";
import {resolve} from "node:path";
import {hLog} from "../helpers/common_functions.js";
function addRedirect(server: FastifyInstance, url: string, redirectTo: string) {
server.route({
@@ -20,8 +19,8 @@ function addRedirect(server: FastifyInstance, url: string, redirectTo: string) {
}
function addRoute(server: FastifyInstance, handlersPath: string, prefix: string) {
server.register(fastifyAutoload, {
dir: resolve('dist', 'api', 'routes', handlersPath),
server.register(autoLoad, {
dir: join(__dirname, 'routes', handlersPath),
ignorePattern: /.*(handler|schema).js/,
dirNameRoutePrefix: false,
options: {prefix}
@@ -33,7 +32,6 @@ export function registerRoutes(server: FastifyInstance) {
// build internal map of routes
const routeSet = new Set<string>();
server.decorate('routeSet', routeSet);
const ignoreList = [
'/v2',
'/v2/history',
@@ -41,7 +39,6 @@ export function registerRoutes(server: FastifyInstance) {
'/v1/chain/*',
'/v1/chain'
];
server.addHook('onRoute', opts => {
if (!ignoreList.includes(opts.url)) {
if (opts.url.startsWith('/v')) {
@@ -74,9 +71,6 @@ export function registerRoutes(server: FastifyInstance) {
tags: ["chain"]
},
handler: async (request: FastifyRequest, reply: FastifyReply) => {
console.log(request.url);
await handleChainApiRedirect(request, reply, server);
}
});
@@ -85,27 +79,41 @@ export function registerRoutes(server: FastifyInstance) {
server.route({
url: '/v1/node/get_supported_apis',
method: ["GET"],
schema: {summary: "Get list of supported APIs", tags: ["node"]},
schema: {
summary: "Get list of supported APIs",
tags: ["node"]
},
handler: async (request: FastifyRequest, reply: FastifyReply) => {
const response = {apis: []} as { apis: string[], error?: string };
const apiSet = new Set(server.routeSet);
try {
const data = await got.get(`${server.chain_api}/v1/node/get_supported_apis`).json() as any;
if (data.apis && data.apis.length > 0) {
data.apis.forEach((a: string) => apiSet.add(a));
response.apis = [...apiSet];
}
} catch (e: any) {
hLog(e.message);
const data = await got.get(`${server.chain_api}/v1/node/get_supported_apis`).json() as any;
if (data.apis && data.apis.length > 0) {
const apiSet = new Set(server.routeSet);
data.apis.forEach((a) => apiSet.add(a));
reply.send({apis: [...apiSet]});
} else {
reply.send({apis: [...server.routeSet], error: 'nodeos did not send any data'});
}
if (response.apis.length === 0) {
response.apis = [...server.routeSet];
response.error = 'nodeos did not send any data';
}
reply.send(response);
}
});
// global onRequest hook to collect hourly statistics for each path on redis
server.addHook('onResponse', (request: FastifyRequest, reply: FastifyReply, done) => {
const path = request.url.split('?')[0].replace(/\/$/, '');
const now = new Date();
const ts = now.getTime();
// normalized time in hours
const factor = 1000 * 60 * 60;
const ts_hour_unix = Math.floor(ts / factor) * factor;
const key = `stats:${server.manager.chain}:H:${ts_hour_unix}`;
// console.log(reply.statusCode, key, new Date(ts_hour_unix));
server.redis.multi()
.incr(`stats:${server.manager.chain}:total:${reply.statusCode}:${path}`)
.zincrby(key, 1, `[${reply.statusCode}]${path}`)
.expire(key, 60 * 60 * 24 * 7)
.exec()
.catch(console.log);
done();
});
server.addHook('onError', (request: FastifyRequest, reply: FastifyReply, error: FastifyError, done) => {
console.log(`[${request.headers['x-real-ip'] || request.ip}] ${request.method} ${request.url} failed >> ${error.message}`);
done();
@@ -117,7 +125,7 @@ export function registerRoutes(server: FastifyInstance) {
'/stream-client.js',
{schema: {tags: ['internal']}},
(request: FastifyRequest, reply: FastifyReply) => {
const stream = createReadStream('./node_modules/@eosrio/hyperion-stream-client/dist/hyperion-stream-client.js');
const stream = createReadStream('./hyperion-stream-client.js');
reply.type('application/javascript').send(stream);
});
}
@@ -1,19 +1,15 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Returns an object containing rows from the specified table.',
{
"code": {$ref: 'AccountName#'},
"action": {$ref: 'AccountName#'},
"binargs": {
"type": "string",
"pattern": "^(0x)(([0-9a-f][0-9a-f])+)?$",
"title": "Hex"
}
"binargs": {"type": "string"}
},
["code", "action", "binargs"]
);
@@ -1,19 +1,20 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Convert JSON object to binary',
{
"binargs": {
"type": "string",
"pattern": "^(0x)(([0-9a-f][0-9a-f])+)?$",
"title": "Hex"
"code": {$ref: 'AccountName#'},
"action": {$ref: 'AccountName#'},
"args": {
type: 'object',
additionalProperties: true
}
},
["binargs"]
["code", "action", "args"]
);
next();
}
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves the ABI for a contract based on its account name',
{"account_name": {$ref: 'AccountName#'}},
["account_name"]
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Returns an object containing various details about a specific account on the blockchain.',
{
"account_name": {$ref: 'AccountName#'}
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retreives the activated protocol features for producer node',
{
"lower_bound": {
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Returns an object containing various details about a specific block on the blockchain.',
{
"block_num_or_id": {
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves the block header state',
{
"block_num_or_id": {
@@ -1,14 +1,18 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves contract code',
{
"account_name": {$ref: 'AccountName#'},
code_as_wasm: {type: 'integer'}
"code_as_wasm": {
"type": "integer",
"default": 1,
"description": "This must be 1 (true)"
}
},
["account_name", "code_as_wasm"]
);
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves the current balance',
{
"code": {$ref: 'AccountName#'},
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves currency stats',
{
"code": {$ref: 'AccountName#'},
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Returns an object containing various details about the blockchain.'
);
next();
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves producers list',
{
"limit": {
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves raw ABI for a contract based on account name',
{
"account_name": {$ref: 'AccountName#'}
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves raw code and ABI for a contract based on account name',
{
"account_name": {$ref: 'AccountName#'}
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves the scheduled transaction',
{
"lower_bound": {
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Retrieves table scope',
{
"code": {
@@ -1,10 +1,10 @@
import {FastifyInstance} from "fastify";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions.js";
import {addChainApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
addChainApiRoute(
fastify,
getRouteName(import.meta.url),
getRouteName(__filename),
'Returns an object containing rows from the specified table.',
{
"code": {
@@ -0,0 +1,39 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, chainApiHandler, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next) {
addApiRoute(
fastify,
'POST',
getRouteName(__filename),
chainApiHandler,
{
description: "This method expects a transaction in JSON format and will attempt to apply it to the blockchain.",
summary: "This method expects a transaction in JSON format and will attempt to apply it to the blockchain.",
tags: ['chain'],
body: {
type: ['object', 'string'],
properties: {
signatures: {
"type": "array",
"description": "array of signatures required to authorize transaction",
"items": {$ref: 'Signature#'}
},
compression: {
"type": "boolean",
"description": "Compression used, usually false"
},
packed_context_free_data: {
"type": "string",
"description": "json to hex"
},
packed_trx: {
"type": "string",
"description": "Transaction object json to hex"
}
}
}
}
);
next();
}
@@ -0,0 +1,55 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, chainApiHandler, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next) {
addApiRoute(
fastify,
'POST',
getRouteName(__filename),
chainApiHandler,
{
description: "This method expects a transaction in JSON format and will attempt to apply it to the blockchain.",
summary: "This method expects a transaction in JSON format and will attempt to apply it to the blockchain.",
tags: ['chain'],
body: {
type: ['array', 'object', 'string'],
items: {
type: ['object', 'string'],
additionalProperties: false,
minProperties: 8,
required: [
"expiration",
"ref_block_num",
"ref_block_prefix",
"max_net_usage_words",
"max_cpu_usage_ms",
"delay_sec",
"context_free_actions",
"actions"
],
properties: {
"expiration": {$ref: 'Expiration#'},
"ref_block_num": {"type": "integer"},
"ref_block_prefix": {"type": "integer"},
"max_net_usage_words": {$ref: 'WholeNumber#'},
"max_cpu_usage_ms": {$ref: 'WholeNumber#'},
"delay_sec": {"type": "integer"},
"context_free_actions": {
"type": "array",
"items": {$ref: 'ActionItems#'}
},
"actions": {
"type": "array",
"items": {$ref: 'ActionItems#'}
},
"transaction_extensions": {
"type": "array",
"items": {$ref: 'BlockExtensions#'}
}
},
}
}
}
);
next();
}
@@ -0,0 +1,39 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, chainApiHandler, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next) {
addApiRoute(
fastify,
'POST',
getRouteName(__filename),
chainApiHandler,
{
description: "This method expects a transaction in JSON format and will attempt to apply it to the blockchain.",
summary: "This method expects a transaction in JSON format and will attempt to apply it to the blockchain.",
tags: ['chain'],
body: {
type: ['object', 'string'],
properties: {
signatures: {
"type": "array",
"description": "array of signatures required to authorize transaction",
"items": {$ref: 'Signature#'}
},
compression: {
"type": "boolean",
"description": "Compression used, usually false"
},
packed_context_free_data: {
"type": "string",
"description": "json to hex"
},
packed_trx: {
"type": "string",
"description": "Transaction object json to hex"
}
}
}
}
);
next();
}
@@ -1,16 +1,152 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {mergeActionMeta, pushBoolElement, timedQuery} from "../../../helpers/functions.js";
import {HyperionAction} from "../../../../interfaces/hyperion-action.js";
import {Serialize} from "enf-eosjs";
import {getContractAtBlock} from "../../../../helpers/common_functions.js";
import {estypes} from "@elastic/elasticsearch";
import {mergeActionMeta, timedQuery} from "../../../helpers/functions";
import {Serialize} from "eosjs";
import {hLog} from "../../../../helpers/common_functions";
import * as AbiEOS from "@eosrio/node-abieos";
import {ApiResponse} from "@elastic/elasticsearch";
import {TextDecoder, TextEncoder} from "util";
import {JsonRpc} from "eosjs/dist";
import {terms} from "../../v2-history/get_actions/definitions";
const terms = ["notified", "act.authorization.actor"];
const extendedActions = new Set(["transfer", "newaccount", "updateauth"]);
const abi_remapping = {
"_Bool": "bool"
};
const txEnc = new TextEncoder();
const txDec = new TextDecoder();
async function fetchAbiHexAtBlockElastic(client, chain, contract_name, last_block, get_json) {
try {
const _includes = ["actions", "tables", "block"];
if (get_json) {
_includes.push("abi");
} else {
_includes.push("abi_hex");
}
const query = {
bool: {
must: [
{term: {account: contract_name}},
{range: {block: {lte: last_block}}}
]
}
};
const queryResult: ApiResponse = await client.search({
index: `${chain}-abi-*`,
body: {
size: 1, query,
sort: [{block: {order: "desc"}}],
_source: {includes: _includes}
}
});
const results = queryResult.body.hits.hits;
if (results.length > 0) {
const nextRefResponse: ApiResponse = await client.search({
index: `${chain}-abi-*`,
body: {
size: 1,
query: {
bool: {
must: [
{term: {account: contract_name}},
{range: {block: {gte: last_block}}}
]
}
},
sort: [{block: {order: "asc"}}],
_source: {includes: ["block"]}
}
});
const nextRef = nextRefResponse.body.hits.hits;
if (nextRef.length > 0) {
return {
valid_until: nextRef[0]._source.block,
...results[0]._source
};
}
return results[0]._source;
} else {
return null;
}
} catch (e) {
hLog(e);
return null;
}
}
async function getAbiFromHeadBlock(rpc: JsonRpc, code) {
let _abi;
try {
_abi = (await rpc.get_abi(code)).abi;
} catch (e) {
hLog(e);
}
return {abi: _abi, valid_until: null, valid_from: null};
}
async function getContractAtBlock(esClient, rpc, chain, accountName: string, block_num: number, check_action?: string) {
let savedAbi, abi;
savedAbi = await fetchAbiHexAtBlockElastic(esClient, chain, accountName, block_num, true);
if (savedAbi === null || (savedAbi.actions && !savedAbi.actions.includes(check_action))) {
savedAbi = await getAbiFromHeadBlock(rpc, accountName);
if (!savedAbi) return [null, null];
abi = savedAbi.abi;
} else {
try {
abi = JSON.parse(savedAbi.abi);
} catch (e) {
hLog(e);
return [null, null];
}
}
if (!abi) return [null, null];
const initialTypes = Serialize.createInitialTypes();
let types;
try {
types = Serialize.getTypesFromAbi(initialTypes, abi);
} catch (e) {
let remapped = false;
for (const struct of abi.structs) {
for (const field of struct.fields) {
if (abi_remapping[field.type]) {
field.type = abi_remapping[field.type];
remapped = true;
}
}
}
if (remapped) {
try {
types = Serialize.getTypesFromAbi(initialTypes, abi);
} catch (e) {
hLog('failed after remapping abi');
hLog(accountName, block_num, check_action);
hLog(e);
}
} else {
hLog(accountName, block_num);
hLog(e);
}
}
const actions = new Map();
for (const {name, type} of abi.actions) {
actions.set(name, Serialize.getType(types, type));
}
const result = {types, actions, tables: abi.tables};
if (check_action) {
if (actions.has(check_action)) {
try {
AbiEOS['load_abi'](accountName, JSON.stringify(abi));
} catch (e) {
hLog(e);
}
}
}
return [result, abi];
}
const extendedActions = new Set(["transfer", "newaccount", "updateauth"]);
async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
if (typeof request.body === 'string') {
@@ -18,19 +154,19 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
const reqBody = request.body as any;
const should_array = [] as any[];
const should_array = [];
for (const entry of terms) {
const tObj: any = {term: {}};
const tObj = {term: {}};
tObj.term[entry] = reqBody.account_name;
should_array.push(tObj);
}
let code, method, pos, offset;
let sort_direction = 'desc';
let filterObj: any[] = [];
let filterObj = [];
if (reqBody.filter) {
const filters = reqBody.filter.split(',');
for (const filter of filters) {
const obj = {bool: {must: [] as any[]}};
const obj = {bool: {must: []}};
const parts = filter.split(':');
if (parts.length === 2) {
[code, method] = parts;
@@ -46,8 +182,8 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
pos = parseInt(reqBody.pos || 0, 10);
offset = parseInt(reqBody.offset || 20, 10);
let from, size;
from = size = 0;
let from = 0;
let size = 0;
if (pos === -1) {
if (offset < 0) {
from = 0;
@@ -73,35 +209,40 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
}
const queryStruct: estypes.QueryDslQueryContainer = {
bool: {
must: [] as any,
const queryStruct = {
"bool": {
must: [],
boost: 1.0
}
};
if (reqBody.parent !== undefined) {
const parent = parseInt(reqBody.parent, 10);
if (queryStruct.bool) {
queryStruct.bool.filter = [{term: {parent: parent}}];
}
queryStruct.bool['filter'] = [];
queryStruct.bool['filter'].push({
"term": {
"parent": parent
}
});
}
if (reqBody.account_name) {
pushBoolElement(queryStruct, 'must', {bool: {should: should_array}});
queryStruct.bool.must.push({"bool": {should: should_array}});
}
for (const prop in reqBody) {
if (Object.prototype.hasOwnProperty.call(reqBody, prop)) {
const actionName = prop.split(".")[0];
if (prop.split(".").length > 1) {
const _termQuery: Record<string, any> = {};
if (extendedActions.has(actionName)) {
const _termQuery = {};
_termQuery["@" + prop] = reqBody[prop];
queryStruct.bool.must.push({term: _termQuery});
} else {
const _termQuery = {};
_termQuery[prop] = reqBody[prop];
queryStruct.bool.must.push({term: _termQuery});
}
pushBoolElement(queryStruct, "must", {term: _termQuery});
}
}
}
@@ -111,25 +252,19 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
let _gte = 0;
if (reqBody['before']) _lte = reqBody['before'];
if (reqBody['after']) _gte = reqBody['after'];
pushBoolElement(queryStruct, 'filter', {
range: {
"@timestamp": {
gte: _gte,
lte: _lte
}
}
if (!queryStruct.bool['filter']) queryStruct.bool['filter'] = [];
queryStruct.bool['filter'].push({
range: {"@timestamp": {"gte": _gte, "lte": _lte}}
});
}
if (reqBody.filter && queryStruct.bool) {
queryStruct.bool.should = filterObj;
queryStruct.bool.minimum_should_match = 1;
if (reqBody.filter) {
queryStruct.bool['should'] = filterObj;
queryStruct.bool['minimum_should_match'] = 1;
}
const getActionsLimit = fastify.manager.config.api.limits.get_actions;
const esOpts = {
"index": fastify.manager.chain + '-action-*',
"from": from || 0,
"size": (getActionsLimit && (size > getActionsLimit) ? getActionsLimit : size),
"size": (size > fastify.manager.config.api.limits.get_actions ? fastify.manager.config.api.limits.get_actions : size),
"body": {
"query": queryStruct,
"sort": {
@@ -137,13 +272,14 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
}
};
// console.log(JSON.stringify(esOpts, null, 2));
const pResults = await Promise.all([fastify.eosjs.rpc.get_info(), fastify.elastic['search'](esOpts)]);
const results = pResults[1];
const response = {
actions: [] as any[],
actions: [],
last_irreversible_block: pResults[0].last_irreversible_block_num
};
const hits = results.hits.hits;
const hits = results['body']['hits']['hits'];
if (hits.length > 0) {
let actions = hits;
if (offset < 0) {
@@ -163,7 +299,8 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
for (let i = 0; i < actions.length; i++) {
const action = actions[i]._source as HyperionAction;
let action = actions[i];
action = action._source;
let act: any = {
"global_action_seq": action.global_sequence,
"account_action_seq": i,
@@ -205,6 +342,8 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
}
// TODO: Optionally re-encode using the original ABI, will increase query time
// act.action_trace.act.hex_data = Buffer.from(flatstr(JSON.stringify(action.act.data))).toString('hex');
if (action.act.account_ram_deltas) {
act.action_trace.account_ram_deltas = action.account_ram_deltas
}
@@ -1,64 +1,57 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, getRouteName} from "../../../helpers/functions.js";
import {getActionsHandler} from "./get_actions.js";
import {addApiRoute, getRouteName} from "../../../helpers/functions";
import {getActionsHandler} from "./get_actions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
// POST
addApiRoute(fastify, 'POST', getRouteName(import.meta.url), getActionsHandler, {
addApiRoute(fastify, 'POST', getRouteName(__filename), getActionsHandler, {
description: 'legacy get actions query',
summary: 'get actions',
tags: ['history'],
body: {
anyOf: [
{
type: ['object', 'string'],
properties: {
"account_name": {
description: 'notified account',
type: 'string',
minLength: 1,
maxLength: 12
},
"pos": {
description: 'action position (pagination)',
type: 'integer'
},
"offset": {
description: 'limit of [n] actions per page',
type: 'integer'
},
"filter": {
description: 'code:name filter',
type: 'string',
minLength: 3
},
"sort": {
description: 'sort direction',
enum: ['desc', 'asc', '1', '-1'],
type: 'string'
},
{
type: 'object',
properties: {
"account_name": {
description: 'notified account',
type: 'string',
minLength: 1,
maxLength: 12
},
"pos": {
description: 'action position (pagination)',
type: 'integer'
},
"offset": {
description: 'limit of [n] actions per page',
type: 'integer'
},
"filter": {
description: 'code:name filter',
type: 'string',
minLength: 3
},
"sort": {
description: 'sort direction',
enum: ['desc', 'asc', '1', '-1'],
type: 'string'
},
"after": {
description: 'filter after specified date (ISO8601)',
type: 'string',
format: 'date-time'
},
"before": {
description: 'filter before specified date (ISO8601)',
type: 'string',
format: 'date-time'
},
"parent": {
description: 'filter by parent global sequence',
type: 'integer',
minimum: 0
}
}
"after": {
description: 'filter after specified date (ISO8601)',
type: 'string',
format: 'date-time'
},
"before": {
description: 'filter before specified date (ISO8601)',
type: 'string',
format: 'date-time'
},
"parent": {
description: 'filter by parent global sequence',
type: 'integer',
minimum: 0
}
],
}
},
response: {
200: {
@@ -0,0 +1,72 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions";
import {ApiResponse} from "@elastic/elasticsearch";
async function getControlledAccounts(fastify: FastifyInstance, request: FastifyRequest) {
if (typeof request.body === 'string') {
request.body = JSON.parse(request.body)
}
let controlling_account = request.body["controlling_account"];
const results: ApiResponse = await fastify.elastic.search({
index: fastify.manager.chain + '-action-*',
size: 100,
body: {
query: {
bool: {
should: [
{
term: {"@updateauth.auth.accounts.permission.actor": controlling_account}
},
{
bool: {
must: [
{term: {"act.account": "eosio"}},
{term: {"act.name": "newaccount"}},
{term: {"act.authorization.actor": controlling_account}}
]
}
}
],
minimum_should_match: 1
}
},
sort: [
{"global_sequence": {"order": "desc"}}
]
}
});
const response = {
controlled_accounts: []
};
const hits = results.body.hits.hits;
if (hits.length > 0) {
response.controlled_accounts = hits.map((v) => {
if (v._source.act.name === 'newaccount') {
if (v._source['@newaccount'].newact) {
return v._source['@newaccount'].newact;
} else if (v._source.act.data.newact) {
return v._source.act.data.newact;
} else {
return null;
}
} else if (v._source.act.name === 'updateauth') {
return v._source.act.data.account;
} else {
return null;
}
});
}
if (response.controlled_accounts.length > 0) {
response.controlled_accounts = [...(new Set(response.controlled_accounts))];
}
return response;
}
export function getControlledAccountsHandler(fastify: FastifyInstance, route: string) {
return async (request: FastifyRequest, reply: FastifyReply) => {
reply.send(await timedQuery(getControlledAccounts, fastify, request, route));
}
}
@@ -1,28 +1,21 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, getRouteName} from "../../../helpers/functions.js";
import {getControlledAccountsHandler} from "./get_controlled_accounts.js";
import {addApiRoute, getRouteName} from "../../../helpers/functions";
import {getControlledAccountsHandler} from "./get_controlled_accounts";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
addApiRoute(fastify, 'POST', getRouteName(import.meta.url), getControlledAccountsHandler, {
export default function (fastify: FastifyInstance, opts: any, next) {
addApiRoute(fastify, 'POST', getRouteName(__filename), getControlledAccountsHandler, {
description: 'get controlled accounts by controlling accounts',
summary: 'get controlled accounts by controlling accounts',
tags: ['accounts'],
body: {
anyOf: [
{
type: ['object', 'string'],
properties: {
"controlling_account": {
description: 'controlling account',
type: 'string'
},
{
type: 'object',
properties: {
"controlling_account": {
description: 'controlling account',
type: 'string'
},
},
required: ["controlling_account"]
}
]
},
required: ["controlling_account"]
},
response: {
200: {
@@ -1,30 +1,18 @@
import {FastifyInstance} from "fastify";
import {getKeyAccountsHandler} from "../../v2-state/get_key_accounts/get_key_accounts.js";
import {addApiRoute, getRouteName} from "../../../helpers/functions.js";
import {getKeyAccountsHandler} from "../../v2-state/get_key_accounts/get_key_accounts";
import {addApiRoute, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
// POST
addApiRoute(fastify, 'POST', getRouteName(import.meta.url), getKeyAccountsHandler, {
addApiRoute(fastify, 'POST', getRouteName(__filename), getKeyAccountsHandler, {
description: 'get accounts by public key',
summary: 'get accounts by public key',
tags: ['accounts'],
body: {
anyOf: [
{
type: 'string'
},
{
type: 'object',
properties: {
"public_key": {
description: 'public key',
type: 'string'
}
},
required: ["public_key"]
}
]
type: ['object', 'string'],
properties: {"public_key": {description: 'public key', type: 'string'}},
required: ["public_key"]
},
response: {
200: {
@@ -0,0 +1,190 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {mergeActionMeta, timedQuery} from "../../../helpers/functions";
import {GetInfoResult} from "eosjs/dist/eosjs-rpc-interfaces";
async function getTransaction(fastify: FastifyInstance, request: FastifyRequest) {
if (request.method === 'POST' && !request.body) {
throw new Error("missing POST body");
}
if (typeof request.body === 'string') {
request.body = JSON.parse(request.body)
}
const body: any = request.body;
const redis = fastify.redis;
const trxId = body.id.toLowerCase();
const conf = fastify.manager.config;
const cachedData = await redis.hgetall('trx_' + trxId);
const response: any = {
"id": body.id,
"trx": {
"receipt": {
"status": "executed",
"cpu_usage_us": 0,
"net_usage_words": 0,
"trx": [1, {
"signatures": "",
"compression": "none",
"packed_context_free_data": "",
"packed_trx": ""
}]
},
"trx": {}
},
"block_num": 0,
"block_time": "",
"last_irreversible_block": undefined,
"traces": []
};
let hits;
// build get_info request with caching
const $getInfo = new Promise<GetInfoResult>(resolve => {
const key = `${fastify.manager.chain}_get_info`;
fastify.redis.get(key).then(value => {
if (value) {
resolve(JSON.parse(value));
} else {
fastify.eosjs.rpc.get_info().then(value1 => {
fastify.redis.set(key, JSON.stringify(value1), 'EX', 6);
resolve(value1);
}).catch((reason) => {
console.log(reason);
response.error = 'failed to get last_irreversible_block_num'
resolve(null);
});
}
});
});
// reconstruct hits from cached data
if (cachedData && Object.keys(cachedData).length > 0) {
const gsArr = [];
for (let cachedDataKey in cachedData) {
gsArr.push(cachedData[cachedDataKey]);
}
gsArr.sort((a, b) => {
return a.global_sequence - b.global_sequence;
});
hits = gsArr.map(value => {
return {
_source: JSON.parse(value)
};
});
const promiseResults = await Promise.all([
redis.ttl('trx_' + trxId),
$getInfo
]);
response.cache_expires_in = promiseResults[0];
response.last_irreversible_block = promiseResults[1].last_irreversible_block_num;
}
// search on ES if cache is not present
if (!hits) {
const _size = conf.api.limits.get_trx_actions || 100;
const blockHint = parseInt(body.block_num_hint, 10);
let indexPattern = '';
if (blockHint) {
const idxPart = Math.ceil(blockHint / conf.settings.index_partition_size).toString().padStart(6, '0');
indexPattern = fastify.manager.chain + `-action-${conf.settings.index_version}-${idxPart}`;
} else {
indexPattern = fastify.manager.chain + '-action-*';
}
let pResults;
try {
// build search request
const $search = fastify.elastic.search({
index: indexPattern,
size: _size,
body: {
query: {bool: {must: [{term: {trx_id: trxId}}]}},
sort: {global_sequence: "asc"}
}
});
// execute in parallel
pResults = await Promise.all([$getInfo, $search]);
} catch (e) {
console.log(e.message);
if (e.meta.statusCode === 404) {
return response;
}
}
hits = pResults[1]['body']['hits']['hits'];
response.last_irreversible_block = pResults[0].last_irreversible_block_num;
}
if (hits.length > 0) {
const actions = hits;
response.trx.trx = {
"expiration": "",
"ref_block_num": 0,
"ref_block_prefix": 0,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [],
"transaction_extensions": [],
"signatures": [],
"context_free_data": []
};
for (let action of actions) {
action = action._source;
mergeActionMeta(action);
response.block_num = action.block_num;
response.block_time = action['@timestamp'];
for (const receipt of action.receipts) {
if (action.act_digest) {
receipt.act_digest = action.act_digest.toLowerCase();
}
response.traces.push({
receipt: receipt,
act: action.act,
account_ram_deltas: action.account_ram_deltas || [],
context_free: false,
block_num: action.block_num,
block_time: action['@timestamp'],
console: "",
elapsed: 0,
except: null,
inline_traces: [],
producer_block_id: "",
trx_id: body.id
});
}
}
} else {
const errmsg = "Transaction " + body.id.toLowerCase() + " not found in history and no block hint was given";
return {
code: 500,
message: "Internal Service Error",
error: {
code: 3040011,
name: "tx_not_found",
what: "The transaction can not be found",
details: [
{
message: errmsg,
file: "",
line_number: 1,
method: "get_transaction"
}
]
}
}
}
return response;
}
export function getTransactionHandler(fastify: FastifyInstance, route: string) {
return async (request: FastifyRequest, reply: FastifyReply) => {
reply.send(await timedQuery(getTransaction, fastify, request, route));
}
}
@@ -0,0 +1,20 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, getRouteName} from "../../../helpers/functions";
import {getTransactionHandler} from "./get_transaction";
export default function (fastify: FastifyInstance, opts: any, next) {
addApiRoute(fastify, 'POST', getRouteName(__filename), getTransactionHandler, {
description: 'get all actions belonging to the same transaction',
summary: 'get transaction by id',
tags: ['history'],
body: {
type: ['object', 'string'],
properties: {
id: {description: 'transaction id', type: 'string'},
block_num_hint: {description: 'block number hint', type: 'integer'},
},
required: ["id"]
}
});
next();
}
@@ -1,8 +1,16 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions.js";
import {ActionIndexSource, BlockIndexSource, getBlockTraceResponse} from "../../../../interfaces/es-interfaces.js";
import {group} from "radash";
import {estypes} from "@elastic/elasticsearch";
import {timedQuery} from "../../../helpers/functions";
import * as _ from "lodash";
interface getBlockTraceResponse {
id: string;
number: number;
previous_id: string;
status: string;
timestamp: string;
producer: string;
transactions: any[];
}
async function getBlockTrace(fastify: FastifyInstance, request: FastifyRequest) {
@@ -12,7 +20,7 @@ async function getBlockTrace(fastify: FastifyInstance, request: FastifyRequest)
const reqBody: any = request.body;
const targetBlock = parseInt(reqBody.block_num);
let searchBody: estypes.SearchRequest | undefined;
let searchBody;
if (reqBody.block_id) {
searchBody = {
@@ -43,17 +51,21 @@ async function getBlockTrace(fastify: FastifyInstance, request: FastifyRequest)
}
}
const response = {transactions: [] as any[]} as getBlockTraceResponse;
const response = {transactions: []} as getBlockTraceResponse;
if (searchBody) {
const getBlockHeader = await fastify.elastic.search<BlockIndexSource>({
const getBlockHeader = await fastify.elastic.search({
index: fastify.manager.chain + "-block-*",
size: 1,
...searchBody
body: searchBody
});
if (getBlockHeader.hits.hits.length === 1) {
const block = getBlockHeader.hits.hits[0]._source as any;
if (getBlockHeader.body.hits.hits.length === 1) {
const block = getBlockHeader.body.hits.hits[0]._source;
const info = await fastify.eosjs.rpc.get_info();
response.id = block.block_id;
response.number = block.block_num;
response.previous_id = block.prev_id;
@@ -62,43 +74,41 @@ async function getBlockTrace(fastify: FastifyInstance, request: FastifyRequest)
response.producer = block.producer;
// lookup all actions on block
const getActionsResponse = await fastify.elastic.search<ActionIndexSource>({
const getActionsResponse = await fastify.elastic.search({
index: fastify.manager.chain + "-action-*",
size: fastify.manager.config.api.limits.get_actions || 1000,
query: {
bool: {
must: [
{term: {block_num: block.block_num}}
]
}
},
sort: ["global_sequence:asc"]
body: {
query: {
bool: {
must: [
{term: {block_num: block.block_num}}
]
}
},
sort: {global_sequence: "asc"}
}
});
const hits = getActionsResponse.hits.hits;
const hits = getActionsResponse.body.hits.hits;
if (hits.length > 0) {
const trxGroup = group(hits, (v) => v._source?.trx_id ?? ".");
for (let trxId in trxGroup) {
const actArray: any[] = [];
for (const act of trxGroup[trxId]) {
_.forEach(_.groupBy(hits, (v) => v['_source']['trx_id']), (value, key) => {
const actArray = [];
for (const act of value) {
const action = act['_source']
if (action) {
for (const receipt of action.receipts) {
actArray.push({
receiver: receipt.receiver,
account: action.act.account,
action: action.act.name,
authorization: action.act.authorization.map(auth => {
return {account: auth.actor, permission: auth.permission};
}),
data: action.act.data
});
}
for (const receipt of action.receipts) {
actArray.push({
receiver: receipt.receiver,
account: action.act.account,
action: action.act.name,
authorization: action.act.authorization.map(auth => {
return {account: auth.actor, permission: auth.permission};
}),
data: action.act.data
});
}
}
response.transactions.push({id: trxId, actions: actArray});
}
response.transactions.push({id: key, actions: actArray});
});
}
return response;
} else {
@@ -1,31 +1,24 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, extendResponseSchema, getRouteName} from "../../../helpers/functions.js";
import {getBlockTraceHandler} from "./get_block.js";
import {addApiRoute, extendResponseSchema, getRouteName} from "../../../helpers/functions";
import {getBlockTraceHandler} from "./get_block";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
const schema = {
description: 'get block traces',
summary: 'get block traces',
tags: ['history'],
body: {
anyOf: [
{
type: 'string'
type: ['object', 'string'],
properties: {
"block_num": {
description: 'block number',
type: 'integer'
},
{
type: 'object',
properties: {
"block_num": {
description: 'block number',
type: 'integer'
},
"block_id": {
description: 'block id',
type: 'string'
}
}
"block_id": {
description: 'block id',
type: 'string'
}
]
}
},
response: extendResponseSchema({
"id": {type: "string"},
@@ -71,7 +64,7 @@ export default function (fastify: FastifyInstance, opts: any, next: (err?: Error
addApiRoute(
fastify,
'POST',
getRouteName(import.meta.url),
getRouteName(__filename),
getBlockTraceHandler,
schema
);
@@ -1,5 +1,5 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions.js";
import {timedQuery} from "../../../helpers/functions";
async function checkTransaction(fastify: FastifyInstance, request: FastifyRequest) {
const query: any = request.query;
@@ -1,8 +1,8 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, extendResponseSchema, getRouteName} from "../../../helpers/functions.js";
import {checkTransactionHandler} from "./check_transaction.js";
import {addApiRoute, extendResponseSchema, getRouteName} from "../../../helpers/functions";
import {checkTransactionHandler} from "./check_transaction";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
const schema = {
description: 'check if a transaction was included in a block',
summary: 'check if a transaction was included in a block',
@@ -47,7 +47,7 @@ export default function (fastify: FastifyInstance, opts: any, next: (err?: Error
addApiRoute(
fastify,
'GET',
getRouteName(import.meta.url),
getRouteName(__filename),
checkTransactionHandler,
schema
);
@@ -1,5 +1,5 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions.js";
import {timedQuery} from "../../../helpers/functions";
async function exportActions(fastify: FastifyInstance, request: FastifyRequest) {
@@ -1,8 +1,8 @@
import {FastifyInstance, FastifySchema} from "fastify";
import {addApiRoute, getRouteName} from "../../../helpers/functions.js";
import {getCreatorHandler} from "../get_creator/get_creator.js";
import {addApiRoute, getRouteName} from "../../../helpers/functions";
import {getCreatorHandler} from "../get_creator/get_creator";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
const schema: FastifySchema = {
description: 'request large action data export',
summary: 'request large action data export',
@@ -11,7 +11,7 @@ export default function (fastify: FastifyInstance, opts: any, next: (err?: Error
addApiRoute(
fastify,
'GET',
getRouteName(import.meta.url),
getRouteName(__filename),
getCreatorHandler,
schema
);
@@ -0,0 +1,51 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions";
async function getAbiSnapshot(fastify: FastifyInstance, request: FastifyRequest) {
const response = {
block_num: null
};
const query: any = request.query;
const code = query.contract;
const block = query.block;
const should_fetch = query.fetch;
const mustArray = [];
mustArray.push({"term": {"account": code}});
if (block) {
mustArray.push({"range": {"block": {"lte": parseInt(block)}}});
}
const results = await fastify.elastic.search({
index: fastify.manager.chain + '-abi-*',
size: 1,
body: {
query: {bool: {must: mustArray}},
sort: [{block: {order: "desc"}}]
}
});
if (results['body']['hits']['hits'].length > 0) {
if (should_fetch) {
response['abi'] = JSON.parse(results['body']['hits']['hits'][0]['_source']['abi']);
} else {
response['present'] = true;
}
response.block_num = results['body']['hits']['hits'][0]['_source']['block'];
} else {
response['present'] = false;
response['error'] = 'abi not found for ' + code + ' until block ' + block;
}
return response;
}
export function getAbiSnapshotHandler(fastify: FastifyInstance, route: string) {
return async (request: FastifyRequest, reply: FastifyReply) => {
reply.send(await timedQuery(getAbiSnapshot, fastify, request, route));
}
}
@@ -1,8 +1,8 @@
import {FastifyInstance} from "fastify";
import {addApiRoute, getRouteName} from "../../../helpers/functions.js";
import {getAbiSnapshotHandler} from "./get_abi_snapshot.js";
import {addApiRoute, getRouteName} from "../../../helpers/functions";
import {getAbiSnapshotHandler} from "./get_abi_snapshot";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
const schema = {
description: 'fetch contract abi at specific block',
summary: 'fetch abi at specific block',
@@ -32,7 +32,7 @@ export default function (fastify: FastifyInstance, opts: any, next: (err?: Error
addApiRoute(
fastify,
'GET',
getRouteName(import.meta.url),
getRouteName(__filename),
getAbiSnapshotHandler,
schema
);
@@ -1,5 +1,6 @@
export const terms = [
"notified",
"receipts.receiver",
"act.authorization.actor"
];
@@ -11,12 +12,19 @@ export const extendedActions = new Set([
"buyrambytes",
"delegatebw",
"undelegatebw",
"voteproducer"
"voteproducer",
'statement',
'decision',
'batch',
'act',
'exec',
'votefor',
'voteagainst'
]);
export const primaryTerms = [
"notified",
"block_num",
"block_id",
"global_sequence",
"producer",
"@timestamp",
@@ -24,5 +32,10 @@ export const primaryTerms = [
"action_ordinal",
"cpu_usage_us",
"net_usage_words",
"trx_id"
"trx_id",
"receipts.receiver",
"receipts.global_sequence",
"receipts.recv_sequence",
"receipts.auth_sequence.account",
"receipts.auth_sequence.sequence"
];
@@ -1,29 +1,23 @@
import {primaryTerms, terms} from "./definitions.js";
import {estypes} from "@elastic/elasticsearch";
import {pushBoolElement} from "../../../helpers/functions.js";
import {primaryTerms, terms} from "./definitions";
export function addSortedBy(query: any, queryBody: estypes.SearchRequest, sort_direction: estypes.SortOrder) {
export function addSortedBy(query, queryBody, sort_direction) {
if (query['sortedBy']) {
const opts = query['sortedBy'].split(":");
const sortedByObj: Record<string, any> = {};
const sortedByObj = {};
sortedByObj[opts[0]] = opts[1];
queryBody.sort = sortedByObj;
queryBody['sort'] = sortedByObj;
} else {
queryBody.sort = {
queryBody['sort'] = {
"global_sequence": sort_direction
};
}
}
export function processMultiVars(
queryStruct: estypes.QueryDslQueryContainer,
parts: string[],
field: string
) {
const must: any[] = [];
const mustNot: any[] = [];
export function processMultiVars(queryStruct, parts, field) {
const must = [];
const mustNot = [];
parts.forEach((part: string) => {
parts.forEach(part => {
if (part.startsWith("!")) {
mustNot.push(part.replace("!", ""));
} else {
@@ -32,85 +26,116 @@ export function processMultiVars(
});
if (must.length > 1) {
pushBoolElement(queryStruct, 'must', {
queryStruct.bool.must.push({
bool: {
should: must.map(elem => {
const _q: Record<string, any> = {};
const _q = {};
_q[field] = elem;
return {term: _q}
})
}
});
} else if (must.length === 1) {
const mustQuery: Record<string, any> = {};
const mustQuery = {};
mustQuery[field] = must[0];
pushBoolElement(queryStruct, 'must', {term: mustQuery});
queryStruct.bool.must.push({term: mustQuery});
}
if (mustNot.length > 1) {
pushBoolElement(queryStruct, 'must_not', {
queryStruct.bool.must_not.push({
bool: {
should: mustNot.map(elem => {
const _q: Record<string, any> = {};
const _q = {};
_q[field] = elem;
return {term: _q}
})
}
});
} else if (mustNot.length === 1) {
const mustNotQuery: Record<string, any> = {};
const mustNotQuery = {};
mustNotQuery[field] = mustNot[0].replace("!", "");
pushBoolElement(queryStruct, 'must_not', {term: mustNotQuery});
queryStruct.bool.must_not.push({term: mustNotQuery});
}
}
function addRangeQuery(
queryStruct: estypes.QueryDslQueryContainer,
prop: string,
pkey: string,
query: Record<string, any>
) {
const _termQuery: Record<string, any> = {};
function addRangeQuery(queryStruct, prop, pkey, query) {
const _termQuery = {};
const parts = query[prop].split("-");
_termQuery[pkey] = {
"gte": parts[0],
"lte": parts[1]
};
pushBoolElement(queryStruct, "must", {range: _termQuery});
queryStruct.bool.must.push({range: _termQuery});
}
export function applyTimeFilter(query: Record<string, any>, queryStruct: estypes.QueryDslQueryContainer) {
export function applyTimeFilter(query, queryStruct) {
if (query['after'] || query['before']) {
let _lte = "now";
let _gte = "0";
if (query['before']) {
try {
_lte = new Date(query['before']).toISOString();
} catch (e: any) {
throw new Error(e.message + ' [before]');
if (query['after']?.includes(' ')) {
query['after'] = query['after'].replace(' ', 'T');
}
if (query['before']?.includes(' ')) {
query['before'] = query['before'].replace(' ', 'T');
}
if (query['after']?.includes('T') || query['before']?.includes('T')) {
let _lte = "now";
let _gte = "0";
if (query['before']) {
try {
_lte = new Date(query['before']).toISOString();
} catch (e) {
throw new Error(e.message + ' [before]');
}
}
if (query['after']) {
try {
_gte = new Date(query['after']).toISOString();
} catch (e) {
throw new Error(e.message + ' [after]');
}
}
if (!queryStruct.bool['filter']) {
queryStruct.bool['filter'] = [];
}
queryStruct.bool['filter'].push({
range: {
"@timestamp": {
"gte": _gte,
"lte": _lte
}
}
});
} else {
// search by block number
const rangeObj = {
range: {
block_num: {}
}
};
if (parseInt(query['after']) > 0) {
rangeObj.range.block_num['gte'] = query['after'];
}
if (parseInt(query['before']) > 0) {
rangeObj.range.block_num['lte'] = query['before'];
}
if (Object.keys(rangeObj.range.block_num).length > 0) {
if (!queryStruct.bool['filter']) {
queryStruct.bool['filter'] = [];
}
queryStruct.bool['filter'].push(rangeObj);
}
}
if (query['after']) {
try {
_gte = new Date(query['after']).toISOString();
} catch (e: any) {
throw new Error(e.message + ' [after]');
}
}
pushBoolElement(queryStruct, "filter", {range: {"@timestamp": {gte: _gte, lte: _lte}}});
}
}
export function applyGenericFilters(
query: Record<string, any>,
queryStruct: estypes.QueryDslQueryContainer,
allowedExtraParams: Set<string>
) {
export function applyGenericFilters(query, queryStruct, allowedExtraParams: Set<string>) {
for (const prop in query) {
if (Object.prototype.hasOwnProperty.call(query, prop)) {
const pair = prop.split(".");
if (pair.length > 1 || primaryTerms.includes(pair[0])) {
let pkey: string;
let pkey;
if (pair.length > 1 && allowedExtraParams) {
pkey = allowedExtraParams.has(pair[0]) ? "@" + prop : prop;
} else {
@@ -119,7 +144,7 @@ export function applyGenericFilters(
if (query[prop].indexOf("-") !== -1) {
addRangeQuery(queryStruct, prop, pkey, query);
} else {
const _qObj: Record<string, any> = {};
const _qObj = {};
const parts = query[prop].split(",");
if (parts.length > 1) {
processMultiVars(queryStruct, parts, prop);
@@ -130,28 +155,33 @@ export function applyGenericFilters(
_qObj[pkey] = {
query: parts[0]
};
if (query.match_fuzziness) {
_qObj[pkey].fuzziness = query.match_fuzziness;
}
if (query.match_operator) {
_qObj[pkey].operator = query.match_operator;
}
pushBoolElement(queryStruct, "must", {match: _qObj});
queryStruct.bool.must.push({
match: _qObj
});
} else {
const andParts = parts[0].split(" ");
if (andParts.length > 1) {
andParts.forEach((value: string) => {
const _q: Record<string, any> = {};
andParts.forEach(value => {
const _q = {};
_q[pkey] = value;
pushBoolElement(queryStruct, "must", {term: _q});
queryStruct.bool.must.push({term: _q});
});
} else {
if (parts[0].startsWith("!")) {
_qObj[pkey] = parts[0].replace("!", "");
pushBoolElement(queryStruct, "must_not", {term: _qObj});
queryStruct.bool.must_not.push({term: _qObj});
} else {
_qObj[pkey] = parts[0];
pushBoolElement(queryStruct, "must", {term: _qObj});
queryStruct.bool.must.push({term: _qObj});
}
}
}
@@ -162,22 +192,22 @@ export function applyGenericFilters(
}
}
export function makeShouldArray(query: Record<string, any>) {
const should_array: any[] = [];
export function makeShouldArray(query) {
const should_array = [];
for (const entry of terms) {
const tObj: { term: Record<string, any> } = {term: {}};
const tObj = {term: {}};
tObj.term[entry] = query.account;
should_array.push(tObj);
}
return should_array;
}
export function applyCodeActionFilters(query: Record<string, any>, queryStruct: estypes.QueryDslQueryContainer) {
let filterObj: any[] = [];
export function applyCodeActionFilters(query, queryStruct) {
let filterObj = [];
if (query.filter) {
for (const filter of query.filter.split(',')) {
if (filter !== '*:*') {
const _arr: any[] = [];
const _arr = [];
const parts = filter.split(':');
if (parts.length === 2) {
const [code, method] = parts;
@@ -193,14 +223,14 @@ export function applyCodeActionFilters(query: Record<string, any>, queryStruct:
}
}
}
if (queryStruct.bool && filterObj.length > 0) {
if (filterObj.length > 0) {
queryStruct.bool['should'] = filterObj;
queryStruct.bool['minimum_should_match'] = 1;
}
}
}
export function getSkipLimit(query: Record<string, any>, max?: number) {
export function getSkipLimit(query, max?: number) {
let skip, limit;
skip = parseInt(query.skip, 10);
if (skip < 0) {
@@ -209,14 +239,14 @@ export function getSkipLimit(query: Record<string, any>, max?: number) {
limit = parseInt(query.limit, 10);
if (limit < 1) {
throw new Error('invalid limit parameter');
} else if (max && limit > max) {
} else if (limit > max) {
throw new Error(`limit too big, maximum: ${max}`);
}
return {skip, limit};
}
export function getSortDir(query: Record<string, any>): estypes.SortOrder {
let sort_direction: estypes.SortOrder = 'desc';
export function getSortDir(query) {
let sort_direction = 'desc';
if (query.sort) {
if (query.sort === 'asc' || query.sort === '1') {
sort_direction = 'asc';
@@ -229,6 +259,8 @@ export function getSortDir(query: Record<string, any>): estypes.SortOrder {
return sort_direction;
}
export function applyAccountFilters(query: Record<string, any>, queryStruct: estypes.QueryDslQueryContainer) {
pushBoolElement(queryStruct, "must", {"bool": {should: makeShouldArray(query)}})
export function applyAccountFilters(query, queryStruct) {
if (query.account) {
queryStruct.bool.must.push({"bool": {should: makeShouldArray(query)}});
}
}
@@ -1,5 +1,5 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {getTrackTotalHits, mergeActionMeta, timedQuery} from "../../../helpers/functions.js";
import {getTrackTotalHits, mergeActionMeta, timedQuery} from "../../../helpers/functions";
import {
addSortedBy,
applyAccountFilters,
@@ -8,15 +8,12 @@ import {
applyTimeFilter,
getSkipLimit,
getSortDir
} from "./functions.js";
import {estypes} from "@elastic/elasticsearch";
import {HyperionAction} from "../../../../interfaces/hyperion-action.js";
import {Serialize} from "enf-eosjs";
} from "./functions";
async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
const query: any = request.query;
const maxActions = fastify.manager.config.api.limits.get_actions;
const queryStruct: estypes.QueryDslQueryContainer = {
const queryStruct = {
"bool": {
must: [],
must_not: [],
@@ -25,11 +22,17 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
};
const {skip, limit} = getSkipLimit(query, maxActions);
const sort_direction = getSortDir(query);
applyAccountFilters(query, queryStruct);
applyGenericFilters(query, queryStruct, fastify.allowedActionQueryParamSet);
applyTimeFilter(query, queryStruct);
applyCodeActionFilters(query, queryStruct);
// allow precise counting of total hits
const trackTotalHits = getTrackTotalHits(query);
@@ -49,20 +52,21 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
indexPattern = fastify.manager.chain + '-action';
}
const esResults = await fastify.elastic.search<HyperionAction>({
const esOpts = {
"index": indexPattern,
"from": skip || 0,
"size": (maxActions && (limit > maxActions) ? maxActions : limit) || 10,
...query_body
});
"size": (limit > maxActions ? maxActions : limit) || 10,
"body": query_body
};
console.log(esResults);
// console.log(JSON.stringify(esOpts, null, 2));
const esResults = await fastify.elastic.search(esOpts);
const results = esResults.hits;
const results = esResults['body']['hits'];
const response: any = {
cached: false,
lib: 0,
total: results.total
total: results['total']
};
if (query.hot_only) {
@@ -74,17 +78,14 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
if (query.simple) {
response.simple_actions = [];
response['simple_actions'] = [];
} else {
response.actions = [];
response['actions'] = [];
}
if (results.hits.length > 0) {
const actions = results.hits.map(a => a._source);
for (let action of actions) {
if (!action) {
continue;
}
if (results['hits'].length > 0) {
const actions = results['hits'];
for (let action of actions.map(a => a._source)) {
try {
if (action.act.data) {
@@ -97,29 +98,31 @@ async function getActions(fastify: FastifyInstance, request: FastifyRequest) {
}
mergeActionMeta(action);
if (query.noBinary === true) {
for (const key in action.act.data) {
if (action.act.data.hasOwnProperty(key)) {
if (typeof action.act.data[key] === 'string' && action.act.data[key].length > 256) {
action.act.data[key] = action.act.data[key].slice(0, 32) + "...";
for (const key in action['act']['data']) {
if (action['act']['data'].hasOwnProperty(key)) {
if (typeof action['act']['data'][key] === 'string' && action['act']['data'][key].length > 256) {
action['act']['data'][key] = action['act']['data'][key].slice(0, 32) + "...";
}
}
}
}
if (query.simple) {
let notified = new Set(action.receipts.map(r => r.receiver));
response.simple_actions.push({
block: action.block_num,
irreversible: response.lib !== 0 ? action.block_num < response.lib : undefined,
timestamp: action["@timestamp"],
transaction_id: action.trx_id,
actors: action.act.authorization.map((a: Serialize.Authorization) => {
return `${a.actor}@${a.permission}`;
}).join(","),
notified: action.notified.join(','),
contract: action.act.account,
action: action.act.name,
data: action.act.data
block: action['block_num'],
irreversible: response.lib !== 0 ? action['block_num'] < response.lib : undefined,
timestamp: action['@timestamp'],
transaction_id: action['trx_id'],
actors: action['act']['authorization'].map(a => `${a.actor}@${a.permission}`).join(","),
notified: [...notified].join(','),
contract: action['act']['account'],
action: action['act']['name'],
data: action['act']['data']
});
} else {
response.actions.push(action);
}
+160
View File
@@ -0,0 +1,160 @@
import {FastifyInstance, FastifySchema} from "fastify";
import {getActionsHandler} from "./get_actions";
import {addApiRoute, extendQueryStringSchema, extendResponseSchema, getRouteName} from "../../../helpers/functions";
export const getActionResponseSchema = {
"@timestamp": {type: "string"},
"timestamp": {type: "string"},
"block_num": {type: "number"},
"block_id": {type: "string"},
"trx_id": {type: "string"},
"act": {
type: 'object',
properties: {
"account": {type: "string"},
"name": {type: "string"},
"authorization": {
type: "array",
items: {
type: "object",
properties: {
"actor": {type: "string"},
"permission": {type: "string"},
}
}
}
},
additionalProperties: true
},
"receipts": {
type: "array",
items: {
type: "object",
properties: {
"receiver": {type: "string"},
"global_sequence": {type: "number"},
"recv_sequence": {type: "number"},
"auth_sequence": {
type: "array",
items: {
type: "object",
properties: {
"account": {type: "string"},
"sequence": {type: "number"},
}
}
}
}
}
},
"cpu_usage_us": {type: "number"},
"net_usage_words": {type: "number"},
"account_ram_deltas": {
type: "array",
items: {
type: "object",
properties: {
"account": {type: "string"},
"delta": {type: "number"}
},
additionalProperties: true
}
},
"global_sequence": {type: "number"},
"producer": {type: "string"},
"parent": {type: "number"},
"action_ordinal": {type: 'number'},
"creator_action_ordinal": {type: 'number'},
"signatures": {type: "array", items: {type: 'string'}}
};
export default function (fastify: FastifyInstance, opts: any, next) {
const schema: FastifySchema = {
description: 'get actions based on notified account. this endpoint also accepts generic filters based on indexed fields' +
' (e.g. act.authorization.actor=eosio or act.name=delegatebw), if included they will be combined with a AND operator',
summary: 'get root actions',
tags: ['history'],
querystring: extendQueryStringSchema({
"account": {
description: 'notified account',
type: 'string',
minLength: 1,
maxLength: 12
},
"track": {
description: 'total results to track (count) [number or true]',
type: 'string'
},
"filter": {
description: 'code:name filter',
type: 'string',
minLength: 3
},
"sort": {
description: 'sort direction',
enum: ['desc', 'asc', '1', '-1'],
type: 'string'
},
"after": {
description: 'filter after specified date (ISO8601)',
type: 'string'
},
"before": {
description: 'filter before specified date (ISO8601)',
type: 'string'
},
"simple": {
description: 'simplified output mode',
type: 'boolean'
},
"hot_only": {
description: 'search only the latest hot index',
type: 'boolean'
},
"noBinary": {
description: "exclude large binary data",
type: 'boolean'
},
"checkLib": {
description: "perform reversibility check",
type: 'boolean'
},
}),
response: extendResponseSchema({
"simple_actions": {
type: "array",
items: {
type: "object",
properties: {
"block": {type: "number"},
"timestamp": {type: "string"},
"irreversible": {type: "boolean"},
"contract": {type: "string"},
"action": {type: "string"},
"actors": {type: "string"},
"notified": {type: "string"},
"transaction_id": {type: "string"},
"data": {
additionalProperties: true
}
}
}
},
"actions": {
type: "array",
items: {
type: 'object',
properties: getActionResponseSchema
}
}
})
};
addApiRoute(
fastify,
'GET',
getRouteName(__filename),
getActionsHandler,
schema
);
next();
}
@@ -0,0 +1,58 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions";
import {getSkipLimit} from "../get_actions/functions";
async function getCreatedAccounts(fastify: FastifyInstance, request: FastifyRequest) {
const query: any = request.query;
const {skip, limit} = getSkipLimit(query);
const maxActions = fastify.manager.config.api.limits.get_created_accounts;
const results = await fastify.elastic.search({
"index": fastify.manager.chain + '-action-*',
"from": skip || 0,
"size": (limit > maxActions ? maxActions : limit) || 100,
"body": {
"query": {
"bool": {
must: [
{term: {"act.authorization.actor": query.account.toLowerCase()}},
{term: {"act.name": "newaccount"}},
{term: {"act.account": "eosio"}}
]
}
},
sort: {
"global_sequence": "desc"
}
}
});
const response = {accounts: []};
if (results['body']['hits']['hits'].length > 0) {
const actions = results['body']['hits']['hits'];
for (let action of actions) {
action = action._source;
const _tmp = {};
if (action['act']['data']['newact']) {
_tmp['name'] = action['act']['data']['newact'];
} else if (action['@newaccount']['newact']) {
_tmp['name'] = action['@newaccount']['newact'];
} else {
console.log(action);
}
_tmp['trx_id'] = action['trx_id'];
_tmp['timestamp'] = action['@timestamp'];
response.accounts.push(_tmp);
}
}
return response;
}
export function getCreatedAccountsHandler(fastify: FastifyInstance, route: string) {
return async (request: FastifyRequest, reply: FastifyReply) => {
reply.send(await timedQuery(getCreatedAccounts, fastify, request, route));
}
}
@@ -1,8 +1,8 @@
import {FastifyInstance, FastifySchema} from "fastify";
import {getCreatedAccountsHandler} from "./get_created_accounts.js";
import {addApiRoute, extendQueryStringSchema, extendResponseSchema, getRouteName} from "../../../helpers/functions.js";
import {getCreatedAccountsHandler} from "./get_created_accounts";
import {addApiRoute, extendQueryStringSchema, extendResponseSchema, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
const schema: FastifySchema = {
description: 'get all accounts created by one creator',
summary: 'get created accounts',
@@ -39,6 +39,6 @@ export default function (fastify: FastifyInstance, opts: any, next: (err?: Error
}
})
};
addApiRoute(fastify, 'GET', getRouteName(import.meta.url), getCreatedAccountsHandler, schema);
addApiRoute(fastify, 'GET', getRouteName(__filename), getCreatedAccountsHandler, schema);
next();
}
@@ -1,10 +1,5 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions.js";
import {RpcInterfaces} from "enf-eosjs";
interface GetBlockResultsWithTransactions extends RpcInterfaces.GetBlockResult {
transactions: any[];
}
import {timedQuery} from "../../../helpers/functions";
async function getCreator(fastify: FastifyInstance, request: FastifyRequest) {
@@ -19,26 +14,34 @@ async function getCreator(fastify: FastifyInstance, request: FastifyRequest) {
};
if (query.account === fastify.manager.config.settings.eosio_alias) {
const genesisBlock = await fastify.eosjs.rpc.get_block(1);
if (genesisBlock) {
response.creator = '__self__';
response.timestamp = genesisBlock.timestamp;
response.block_num = 1;
response.trx_id = "";
return response;
} else {
throw new Error("genesis block not found");
try {
const genesisBlock = await fastify.eosjs.rpc.get_block(1);
if (genesisBlock) {
response.timestamp = genesisBlock.timestamp;
}
} catch (e) {
console.log(e.message);
}
response.creator = '__self__';
response.block_num = 1;
response.trx_id = "";
return response;
}
const results = await fastify.elastic.search<any>({
index: fastify.manager.chain + '-action-*',
size: 1,
query: {bool: {must: [{term: {"@newaccount.newact": query.account}}]}}
const results = await fastify.elastic.search({
"index": fastify.manager.chain + '-action-*',
"body": {
size: 1,
query: {
bool: {
must: [{term: {"@newaccount.newact": query.account}}]
}
}
}
});
if (results.hits.hits.length === 1) {
const result = results.hits.hits[0]._source;
if (results['body']['hits']['hits'].length === 1) {
const result = results['body']['hits']['hits'][0]._source;
response.trx_id = result.trx_id;
response.block_num = result.block_num;
response.creator = result.act.data.creator;
@@ -48,22 +51,27 @@ async function getCreator(fastify: FastifyInstance, request: FastifyRequest) {
let accountInfo;
try {
accountInfo = await fastify.eosjs.rpc.get_account(query.account);
} catch (e: any) {
} catch (e) {
throw new Error("account not found");
}
if (accountInfo) {
try {
response.timestamp = accountInfo.created;
const blockHeader = await fastify.elastic.search<any>({
const blockHeader = await fastify.elastic.search({
"index": fastify.manager.chain + '-block-*',
size: 1,
query: {
bool: {must: [{term: {"@timestamp": response.timestamp}}]}
"body": {
size: 1,
query: {
bool: {
must: [{term: {"@timestamp": response.timestamp}}]
}
}
}
});
if (blockHeader.hits.hits && blockHeader.hits.hits.length > 0 && blockHeader.hits.hits[0]._source) {
const blockId = blockHeader.hits.hits[0]._source.block_id;
const blockData = await fastify.eosjs.rpc.get_block(blockId) as GetBlockResultsWithTransactions;
const hits = blockHeader['body']['hits']['hits'];
if (hits.length > 0 && hits[0]._source) {
const blockId = blockHeader['body']['hits']['hits'][0]._source.block_id;
const blockData = await fastify.eosjs.rpc.get_block(blockId);
response.block_num = blockData.block_num;
for (const transaction of blockData["transactions"]) {
if (typeof transaction.trx !== 'string') {
@@ -81,11 +89,12 @@ async function getCreator(fastify: FastifyInstance, request: FastifyRequest) {
}
}
return response;
} catch (e: any) {
} catch (e) {
console.log(e.message);
throw new Error("account creation not found");
}
} else {
throw new Error("account creation not found");
throw new Error("account not found");
}
}
}
@@ -1,8 +1,8 @@
import {FastifyInstance, FastifySchema} from "fastify";
import {getCreatorHandler} from "./get_creator.js";
import {addApiRoute, extendResponseSchema, getRouteName} from "../../../helpers/functions.js";
import {getCreatorHandler} from "./get_creator";
import {addApiRoute, extendResponseSchema, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
const schema: FastifySchema = {
description: 'get account creator',
summary: 'get account creator',
@@ -40,6 +40,6 @@ export default function (fastify: FastifyInstance, opts: any, next: (err?: Error
}
})
};
addApiRoute(fastify, 'GET', getRouteName(import.meta.url), getCreatorHandler, schema);
addApiRoute(fastify, 'GET', getRouteName(__filename), getCreatorHandler, schema);
next();
}
@@ -1,12 +1,11 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {mergeDeltaMeta, timedQuery} from "../../../helpers/functions.js";
import {applyTimeFilter} from "../get_actions/functions.js";
import {mergeDeltaMeta, timedQuery} from "../../../helpers/functions";
import {applyTimeFilter} from "../get_actions/functions";
async function getDeltas(fastify: FastifyInstance, request: FastifyRequest) {
let skip;
let limit = 10;
let skip, limit;
let sort_direction = 'desc';
const mustArray: any[] = [];
const mustArray = [];
const query: any = request.query;
for (const param in query) {
if (Object.prototype.hasOwnProperty.call(query, param)) {
@@ -43,15 +42,23 @@ async function getDeltas(fastify: FastifyInstance, request: FastifyRequest) {
break;
}
default: {
const values = query[param].split(",");
if (values.length > 1) {
const terms: Record<string, any> = {};
terms[param] = values;
mustArray.push({terms: terms});
if (typeof value === 'string') {
const values = query[param].split(",");
if (values.length > 1) {
const terms = {};
terms[param] = values;
mustArray.push({terms: terms});
} else {
const term = {};
term[param] = values[0];
mustArray.push({term: term});
}
} else {
const term: Record<string, any> = {};
term[param] = values[0];
mustArray.push({term: term});
if (typeof value === 'number') {
const term = {};
term[param] = value;
mustArray.push({term: term});
}
}
break;
}
@@ -64,20 +71,23 @@ async function getDeltas(fastify: FastifyInstance, request: FastifyRequest) {
applyTimeFilter(query, queryStruct);
const results = await fastify.elastic.search<any>({
index: fastify.manager.chain + '-delta-*',
from: skip || 0,
size: (limit > maxDeltas ? maxDeltas : limit) || 10,
query: queryStruct,
sort: "block_num:" + sort_direction
const results = await fastify.elastic.search({
"index": fastify.manager.chain + '-delta-*',
"from": skip || 0,
"size": (limit > maxDeltas ? maxDeltas : limit) || 10,
"body": {
query: queryStruct,
sort: {
"block_num": sort_direction
}
}
});
const deltas = results.hits.hits.map((d) => {
const deltas = results['body']['hits']['hits'].map((d) => {
return mergeDeltaMeta(d._source);
});
return {
query_time: null,
total: results.hits.total,
total: results['body']['hits']['total'],
deltas
};
}
@@ -1,8 +1,8 @@
import {FastifyInstance, FastifySchema} from "fastify";
import {getDeltasHandler} from "./get_deltas.js";
import {addApiRoute, extendQueryStringSchema, extendResponseSchema, getRouteName} from "../../../helpers/functions.js";
import {getDeltasHandler} from "./get_deltas";
import {addApiRoute, extendQueryStringSchema, extendResponseSchema, getRouteName} from "../../../helpers/functions";
export default function (fastify: FastifyInstance, opts: any, next: (err?: Error) => void) {
export default function (fastify: FastifyInstance, opts: any, next) {
const schema: FastifySchema = {
description: 'get state deltas',
summary: 'get state deltas',
@@ -65,7 +65,7 @@ export default function (fastify: FastifyInstance, opts: any, next: (err?: Error
addApiRoute(
fastify,
'GET',
getRouteName(import.meta.url),
getRouteName(__filename),
getDeltasHandler,
schema
);
@@ -0,0 +1,105 @@
import {FastifyInstance, FastifyReply, FastifyRequest} from "fastify";
import {timedQuery} from "../../../helpers/functions";
import {createHash} from "crypto";
import {base58ToBinary, binaryToBase58} from "eosjs/dist/eosjs-numeric";
import {Search} from "@elastic/elasticsearch/api/requestParams";
function convertToLegacyKey(block_signing_key: string) {
if (block_signing_key.startsWith("PUB_K1_")) {
const buf = base58ToBinary(37, block_signing_key.substr(7));
const data = buf.slice(0, buf.length - 4);
const merged = Buffer.concat([
data,
createHash('ripemd160')
.update(data)
.digest()
.slice(0, 4)
]);
return "EOS" + binaryToBase58(merged);
} else {
return block_signing_key;
}
}
async function getSchedule(fastify: FastifyInstance, request: FastifyRequest) {
const query: any = request.query;
const response: any = {
producers: []
};
if (query.mode === 'activated') {
const searchParams: Search<any> = {
track_total_hits: true,
index: fastify.manager.chain + "-block-*",
size: 1,
body: {
query: {bool: {must: []}},
sort: {block_num: query.sort || "desc"}
}
};
if (query.version) {
searchParams.body.query.bool.must.push({"term": {"new_producers.version": {"value": query.version}}});
} else {
searchParams.body.query.bool.must.push({"exists": {"field": "new_producers.version"}});
}
const apiResponse = await fastify.elastic.search(searchParams);
const results = apiResponse.body.hits.hits;
if (results && results.length > 0) {
response.timestamp = results[0]._source["@timestamp"];
response.block_num = results[0]._source.block_num;
response.version = results[0]._source.new_producers.version;
response.producers = results[0]._source.new_producers.producers.map(prod => {
return {
...prod,
legacy_key: convertToLegacyKey(prod.block_signing_key)
}
});
}
} else {
// default "proposed" mode
const searchParams: Search<any> = {
track_total_hits: true,
index: fastify.manager.chain + "-schedule-*",
size: 1,
body: {
query: {bool: {must: []}},
sort: {version: query.sort || "desc"}
}
};
if (query.version) {
searchParams.body.query.bool.must.push({"term": {"version": {"value": query.version}}});
} else {
searchParams.body.query.bool.must.push({"exists": {"field": "version"}});
}
if (query.producer) {
searchParams.body.query.bool.must.push({"term": {"producers.name": {"value": query.producer}}});
}
if (query.key) {
searchParams.body.query.bool.must.push({"term": {"producers.keys": {"value": query.key}}});
}
const apiResponse = await fastify.elastic.search(searchParams);
const results = apiResponse.body.hits.hits;
if (results && results.length > 0) {
response.timestamp = results[0]._source["@timestamp"];
response.proposal_block_num = results[0]._source.block_num;
response.version = results[0]._source.version;
response.producers = results[0]._source.producers;
// sort producers by name
// response.producers.sort((a, b) => {
// if (a.name < b.name) {
// return -1;
// }
// if (a.name > b.name) {
// return 1;
// }
// return 0;
// });
}
}
return response;
}
export function getScheduleHandler(fastify: FastifyInstance, route: string) {
return async (request: FastifyRequest, reply: FastifyReply) => {
reply.send(await timedQuery(getSchedule, fastify, request, route));
}
}

Some files were not shown because too many files have changed in this diff Show More