osbc 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. checksums.yaml +7 -0
  2. data/.env +5 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +273 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +84 -0
  8. data/Dockerfile +17 -0
  9. data/Gemfile +109 -0
  10. data/Gemfile.lock +343 -0
  11. data/LICENSE.md +21 -0
  12. data/LICENSE.txt +21 -0
  13. data/Procfile +3 -0
  14. data/Procfile.dev +2 -0
  15. data/README.md +185 -0
  16. data/Rakefile +6 -0
  17. data/app/assets/builds/.keep +0 -0
  18. data/app/assets/config/manifest.js +5 -0
  19. data/app/assets/images/.keep +0 -0
  20. data/app/assets/images/bg.png +0 -0
  21. data/app/assets/images/gimage.png +0 -0
  22. data/app/assets/images/image.png +0 -0
  23. data/app/assets/images/logo.png +0 -0
  24. data/app/assets/images/outerspc.jpg +0 -0
  25. data/app/assets/images/proxy.jpg +0 -0
  26. data/app/assets/images/space.jpg +0 -0
  27. data/app/assets/images/space_four.jpg +0 -0
  28. data/app/assets/images/space_t.jpg +0 -0
  29. data/app/assets/images/space_th.jpg +0 -0
  30. data/app/assets/images/space_two.jpg +0 -0
  31. data/app/assets/images/th.jpg +0 -0
  32. data/app/assets/stylesheets/application.css +344 -0
  33. data/app/assets/stylesheets/application.tailwind.css +13 -0
  34. data/app/assets/stylesheets/home.css +0 -0
  35. data/app/channels/application_cable/channel.rb +6 -0
  36. data/app/channels/application_cable/connection.rb +6 -0
  37. data/app/controllers/api/v1/block_confirmations_controller.rb +65 -0
  38. data/app/controllers/application_controller.rb +72 -0
  39. data/app/controllers/blocks_controller.rb +20 -0
  40. data/app/controllers/chains_controller.rb +72 -0
  41. data/app/controllers/concerns/.keep +0 -0
  42. data/app/controllers/contracts_controller.rb +25 -0
  43. data/app/controllers/pools_controller.rb +73 -0
  44. data/app/controllers/signatures_controller.rb +25 -0
  45. data/app/controllers/tickets_controller.rb +76 -0
  46. data/app/controllers/transactions_controller.rb +48 -0
  47. data/app/controllers/users/confirmations_controller.rb +30 -0
  48. data/app/controllers/users/omniauth_callbacks_controller.rb +30 -0
  49. data/app/controllers/users/passwords_controller.rb +34 -0
  50. data/app/controllers/users/registrations_controller.rb +61 -0
  51. data/app/controllers/users/sessions_controller.rb +27 -0
  52. data/app/controllers/users/unlocks_controller.rb +30 -0
  53. data/app/controllers/wallets_controller.rb +18 -0
  54. data/app/helpers/application_helper.rb +4 -0
  55. data/app/helpers/blocks_helper.rb +4 -0
  56. data/app/helpers/chains_helper.rb +4 -0
  57. data/app/helpers/contracts_helper.rb +4 -0
  58. data/app/helpers/pools_helper.rb +4 -0
  59. data/app/helpers/signatures_helper.rb +4 -0
  60. data/app/helpers/tickets_helper.rb +4 -0
  61. data/app/helpers/transactions_helper.rb +4 -0
  62. data/app/helpers/wallets_helper.rb +4 -0
  63. data/app/javascript/application.js +3 -0
  64. data/app/javascript/controllers/application.js +9 -0
  65. data/app/javascript/controllers/hello_controller.js +7 -0
  66. data/app/javascript/controllers/index.js +11 -0
  67. data/app/jobs/application_job.rb +9 -0
  68. data/app/mailers/application_mailer.rb +6 -0
  69. data/app/models/acceptable_number_sequence.rb +4 -0
  70. data/app/models/acceptable_symbol_sequence.rb +4 -0
  71. data/app/models/acceptable_word.rb +4 -0
  72. data/app/models/application_record.rb +5 -0
  73. data/app/models/block.rb +17 -0
  74. data/app/models/chain.rb +10 -0
  75. data/app/models/concerns/.keep +0 -0
  76. data/app/models/concerns/sequences_validator.rb +30 -0
  77. data/app/models/concerns/wallet_exists_validator.rb +13 -0
  78. data/app/models/contract.rb +7 -0
  79. data/app/models/pool.rb +5 -0
  80. data/app/models/signature.rb +12 -0
  81. data/app/models/ticket.rb +11 -0
  82. data/app/models/transaction.rb +25 -0
  83. data/app/models/user.rb +44 -0
  84. data/app/models/wallet.rb +33 -0
  85. data/app/services/application_service.rb +23 -0
  86. data/app/services/assign_contracts_service.rb +162 -0
  87. data/app/services/create_ticket_service.rb +87 -0
  88. data/app/services/create_wallet_service.rb +20 -0
  89. data/app/services/transaction_to_block_service.rb +62 -0
  90. data/app/views/application/_featured_board.html.erb +77 -0
  91. data/app/views/application/home.html.slim +1 -0
  92. data/app/views/application/mining_profile.html.slim +59 -0
  93. data/app/views/application/privacy_policy.html.erb +0 -0
  94. data/app/views/application/terms.html.erb +0 -0
  95. data/app/views/blocks/_block.html.slim +13 -0
  96. data/app/views/blocks/_block.json.jbuilder +4 -0
  97. data/app/views/blocks/_form.html.slim +26 -0
  98. data/app/views/blocks/edit.html.slim +10 -0
  99. data/app/views/blocks/index.html.slim +12 -0
  100. data/app/views/blocks/index.json.jbuilder +3 -0
  101. data/app/views/blocks/new.html.slim +8 -0
  102. data/app/views/blocks/show.html.slim +8 -0
  103. data/app/views/blocks/show.json.jbuilder +3 -0
  104. data/app/views/chains/_chain.html.slim +16 -0
  105. data/app/views/chains/_chain.json.jbuilder +4 -0
  106. data/app/views/chains/_form.html.slim +30 -0
  107. data/app/views/chains/edit.html.slim +10 -0
  108. data/app/views/chains/index.html.slim +11 -0
  109. data/app/views/chains/index.json.jbuilder +3 -0
  110. data/app/views/chains/new.html.slim +8 -0
  111. data/app/views/chains/show.html.slim +10 -0
  112. data/app/views/chains/show.json.jbuilder +3 -0
  113. data/app/views/contracts/_contract.html.slim +8 -0
  114. data/app/views/contracts/_contract.json.jbuilder +4 -0
  115. data/app/views/contracts/_form.html.slim +34 -0
  116. data/app/views/contracts/edit.html.slim +10 -0
  117. data/app/views/contracts/index.html.slim +12 -0
  118. data/app/views/contracts/index.json.jbuilder +3 -0
  119. data/app/views/contracts/new.html.slim +8 -0
  120. data/app/views/contracts/show.html.slim +8 -0
  121. data/app/views/contracts/show.json.jbuilder +3 -0
  122. data/app/views/layouts/_alert.html.slim +6 -0
  123. data/app/views/layouts/_navbar.html.slim +27 -0
  124. data/app/views/layouts/_notice.html.slim +6 -0
  125. data/app/views/layouts/application.html.erb +32 -0
  126. data/app/views/layouts/mailer.html.erb +13 -0
  127. data/app/views/layouts/mailer.text.erb +1 -0
  128. data/app/views/pools/_form.html.slim +30 -0
  129. data/app/views/pools/_pool.html.slim +16 -0
  130. data/app/views/pools/_pool.json.jbuilder +4 -0
  131. data/app/views/pools/edit.html.slim +10 -0
  132. data/app/views/pools/index.html.slim +12 -0
  133. data/app/views/pools/index.json.jbuilder +3 -0
  134. data/app/views/pools/new.html.slim +8 -0
  135. data/app/views/pools/show.html.slim +8 -0
  136. data/app/views/pools/show.json.jbuilder +3 -0
  137. data/app/views/signatures/_form.html.slim +46 -0
  138. data/app/views/signatures/_signature.html.slim +28 -0
  139. data/app/views/signatures/_signature.json.jbuilder +4 -0
  140. data/app/views/signatures/edit.html.slim +10 -0
  141. data/app/views/signatures/index.html.slim +10 -0
  142. data/app/views/signatures/index.json.jbuilder +3 -0
  143. data/app/views/signatures/new.html.slim +8 -0
  144. data/app/views/signatures/show.html.slim +10 -0
  145. data/app/views/signatures/show.json.jbuilder +3 -0
  146. data/app/views/tickets/_form.html.slim +26 -0
  147. data/app/views/tickets/_ticket.html.slim +10 -0
  148. data/app/views/tickets/_ticket.json.jbuilder +4 -0
  149. data/app/views/tickets/edit.html.slim +10 -0
  150. data/app/views/tickets/index.html.slim +16 -0
  151. data/app/views/tickets/index.json.jbuilder +3 -0
  152. data/app/views/tickets/new.html.slim +10 -0
  153. data/app/views/tickets/show.html.slim +8 -0
  154. data/app/views/tickets/show.json.jbuilder +3 -0
  155. data/app/views/transactions/_form.html.slim +16 -0
  156. data/app/views/transactions/_transaction.html.slim +24 -0
  157. data/app/views/transactions/_transaction.json.jbuilder +4 -0
  158. data/app/views/transactions/edit.html.slim +10 -0
  159. data/app/views/transactions/index.html.slim +19 -0
  160. data/app/views/transactions/index.json.jbuilder +3 -0
  161. data/app/views/transactions/new.html.slim +9 -0
  162. data/app/views/transactions/show.html.slim +8 -0
  163. data/app/views/transactions/show.json.jbuilder +3 -0
  164. data/app/views/users/confirmations/new.html.erb +16 -0
  165. data/app/views/users/mailer/confirmation_instructions.html.erb +5 -0
  166. data/app/views/users/mailer/email_changed.html.erb +7 -0
  167. data/app/views/users/mailer/password_change.html.erb +3 -0
  168. data/app/views/users/mailer/reset_password_instructions.html.erb +8 -0
  169. data/app/views/users/mailer/unlock_instructions.html.erb +7 -0
  170. data/app/views/users/passwords/edit.html.erb +25 -0
  171. data/app/views/users/passwords/new.html.erb +16 -0
  172. data/app/views/users/registrations/edit.html.erb +43 -0
  173. data/app/views/users/registrations/new.html.erb +37 -0
  174. data/app/views/users/sessions/new.html.erb +30 -0
  175. data/app/views/users/shared/_error_messages.html.erb +15 -0
  176. data/app/views/users/shared/_links.html.erb +25 -0
  177. data/app/views/users/unlocks/new.html.erb +16 -0
  178. data/app/views/wallets/_form.html.slim +30 -0
  179. data/app/views/wallets/_wallet.html.slim +13 -0
  180. data/app/views/wallets/_wallet.json.jbuilder +4 -0
  181. data/app/views/wallets/edit.html.slim +10 -0
  182. data/app/views/wallets/index.html.slim +18 -0
  183. data/app/views/wallets/index.json.jbuilder +3 -0
  184. data/app/views/wallets/new.html.slim +8 -0
  185. data/app/views/wallets/show.html.slim +11 -0
  186. data/app/views/wallets/show.json.jbuilder +3 -0
  187. data/app/workers/application_worker.rb +82 -0
  188. data/app/workers/assign_contract_worker.rb +27 -0
  189. data/app/workers/create_ticket_worker.rb +23 -0
  190. data/app/workers/create_wallet_worker.rb +21 -0
  191. data/app/workers/transaction_to_block_worker.rb +48 -0
  192. data/bin/bundle +114 -0
  193. data/bin/console +15 -0
  194. data/bin/dev +9 -0
  195. data/bin/importmap +5 -0
  196. data/bin/osbc +77 -0
  197. data/bin/rails +6 -0
  198. data/bin/rake +6 -0
  199. data/bin/setup +35 -0
  200. data/config/application.rb +25 -0
  201. data/config/boot.rb +6 -0
  202. data/config/cable.yml +10 -0
  203. data/config/credentials.yml.enc +1 -0
  204. data/config/database.yml +21 -0
  205. data/config/environment.rb +7 -0
  206. data/config/environments/development.rb +73 -0
  207. data/config/environments/production.rb +95 -0
  208. data/config/environments/test.rb +62 -0
  209. data/config/importmap.rb +9 -0
  210. data/config/initializers/assets.rb +14 -0
  211. data/config/initializers/content_security_policy.rb +26 -0
  212. data/config/initializers/devise.rb +311 -0
  213. data/config/initializers/filter_parameter_logging.rb +10 -0
  214. data/config/initializers/inflections.rb +17 -0
  215. data/config/initializers/permissions_policy.rb +12 -0
  216. data/config/locales/devise.en.yml +65 -0
  217. data/config/locales/en.yml +33 -0
  218. data/config/puma.rb +45 -0
  219. data/config/routes/api.rb +9 -0
  220. data/config/routes.rb +30 -0
  221. data/config/sidekiq.yml +10 -0
  222. data/config/storage.yml +34 -0
  223. data/config/tailwind.config.js +23 -0
  224. data/config.ru +8 -0
  225. data/coverage/.last_run.json +5 -0
  226. data/coverage/.resultset.json +1853 -0
  227. data/coverage/.resultset.json.lock +0 -0
  228. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc.png +0 -0
  229. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  230. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_both.png +0 -0
  231. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc.png +0 -0
  232. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  233. data/coverage/assets/0.12.3/application.css +1 -0
  234. data/coverage/assets/0.12.3/application.js +7 -0
  235. data/coverage/assets/0.12.3/colorbox/border.png +0 -0
  236. data/coverage/assets/0.12.3/colorbox/controls.png +0 -0
  237. data/coverage/assets/0.12.3/colorbox/loading.gif +0 -0
  238. data/coverage/assets/0.12.3/colorbox/loading_background.png +0 -0
  239. data/coverage/assets/0.12.3/favicon_green.png +0 -0
  240. data/coverage/assets/0.12.3/favicon_red.png +0 -0
  241. data/coverage/assets/0.12.3/favicon_yellow.png +0 -0
  242. data/coverage/assets/0.12.3/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  243. data/coverage/assets/0.12.3/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  244. data/coverage/assets/0.12.3/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  245. data/coverage/assets/0.12.3/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  246. data/coverage/assets/0.12.3/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  247. data/coverage/assets/0.12.3/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  248. data/coverage/assets/0.12.3/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  249. data/coverage/assets/0.12.3/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  250. data/coverage/assets/0.12.3/images/ui-icons_222222_256x240.png +0 -0
  251. data/coverage/assets/0.12.3/images/ui-icons_2e83ff_256x240.png +0 -0
  252. data/coverage/assets/0.12.3/images/ui-icons_454545_256x240.png +0 -0
  253. data/coverage/assets/0.12.3/images/ui-icons_888888_256x240.png +0 -0
  254. data/coverage/assets/0.12.3/images/ui-icons_cd0a0a_256x240.png +0 -0
  255. data/coverage/assets/0.12.3/loading.gif +0 -0
  256. data/coverage/assets/0.12.3/magnify.png +0 -0
  257. data/coverage/index.html +20731 -0
  258. data/db/migrate/20221018053949_devise_create_users.rb +45 -0
  259. data/db/migrate/20221019002956_create_chains.rb +13 -0
  260. data/db/migrate/20221020112137_create_blocks.rb +12 -0
  261. data/db/migrate/20221020123102_add_chain_to_blocks.rb +5 -0
  262. data/db/migrate/20221020150504_create_wallets.rb +13 -0
  263. data/db/migrate/20221022221059_create_transactions.rb +20 -0
  264. data/db/migrate/20221023011005_add_block_to_transactions.rb +5 -0
  265. data/db/migrate/20221023014707_create_contracts.rb +11 -0
  266. data/db/migrate/20221023040749_create_pools.rb +13 -0
  267. data/db/migrate/20221023041015_create_tickets.rb +11 -0
  268. data/db/migrate/20221023103509_add_contracts_count_to_block.rb +6 -0
  269. data/db/migrate/20221023110613_add_acceptable_word_list_to_users.rb +7 -0
  270. data/db/migrate/20221023113539_create_signatures.rb +19 -0
  271. data/db/migrate/20221023113750_create_acceptable_words.rb +9 -0
  272. data/db/migrate/20221023114152_create_acceptable_number_sequences.rb +9 -0
  273. data/db/migrate/20221023114203_create_acceptable_symbol_sequences.rb +9 -0
  274. data/db/migrate/20221023114324_add_user_acceptable_hash_to_tickets.rb +7 -0
  275. data/db/migrate/20221023114408_add_time_ref_to_tickets.rb +5 -0
  276. data/db/migrate/20221024125047_add_master_hash_to_blocks.rb +5 -0
  277. data/db/migrate/20221109161845_add_transactions_count_to_blocks.rb +5 -0
  278. data/db/migrate/20221117135003_add_balance_to_chains.rb +5 -0
  279. data/db/migrate/20221117203417_add_transaction_id_list_to_tickets.rb +5 -0
  280. data/db/migrate/20221118080357_add_api_keys_to_users.rb +6 -0
  281. data/db/schema.rb +179 -0
  282. data/db/seeds.rb +134 -0
  283. data/docker-compose.yml +53 -0
  284. data/entrypoint.sh +8 -0
  285. data/lib/assets/.keep +0 -0
  286. data/lib/osbc/osbc.rb +9 -0
  287. data/lib/outerspace/blockchain/version.rb +7 -0
  288. data/lib/outerspace/blockchain.rb +10 -0
  289. data/lib/tasks/.keep +0 -0
  290. data/lib/tasks/compose.rake +92 -0
  291. data/lib/tasks/compose_db.rake +71 -0
  292. data/lib/tasks/compose_logs.rake +95 -0
  293. data/lib/tasks/compose_test.rake +62 -0
  294. data/log/.keep +0 -0
  295. data/mining_concept.ipynb +284 -0
  296. data/outerspace-blockchain.gemspec +50 -0
  297. data/public/404.html +67 -0
  298. data/public/422.html +67 -0
  299. data/public/500.html +66 -0
  300. data/public/apple-touch-icon-precomposed.png +0 -0
  301. data/public/apple-touch-icon.png +0 -0
  302. data/public/favicon.ico +0 -0
  303. data/public/robots.txt +1 -0
  304. data/storage/.keep +0 -0
  305. data/tmp/.keep +0 -0
  306. data/tmp/pids/.keep +0 -0
  307. data/tmp/storage/.keep +0 -0
  308. data/vendor/.keep +0 -0
  309. data/vendor/javascript/.keep +0 -0
  310. metadata +643 -0
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class User < ApplicationRecord
4
+ # Include default devise modules. Others available are:
5
+ # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
6
+ after_create :create_wallet
7
+ devise :database_authenticatable, :registerable,
8
+ :recoverable, :rememberable, :validatable
9
+
10
+ has_one :wallet
11
+ has_many :tickets
12
+ validates :email, presence: true, uniqueness: true
13
+ validates :password, presence: true, length: { minimum: 6 }
14
+ validates :username, presence: true, uniqueness: true
15
+ before_create :save_acceptable_assets
16
+ before_create :save_api_keys
17
+ has_many :signatures
18
+
19
+ private
20
+ def create_wallet
21
+ CreateWalletWorker.perform_async(self.id)
22
+ end
23
+
24
+ def save_acceptable_assets
25
+ words = AcceptableWord.all.sample(4)
26
+ number_sequences = AcceptableNumberSequence.all.sample(4)
27
+ symbol_sequences = AcceptableSymbolSequence.all.sample(4)
28
+
29
+ words_to_save = words.map { |word| word.word }
30
+
31
+ number_sequences_to_save = number_sequences.map { |number_sequence| number_sequence.seq }
32
+
33
+ symbol_sequences_to_save = symbol_sequences.map { |symbol_sequence| symbol_sequence.seq }
34
+
35
+ self.acceptable_words = words_to_save
36
+ self.acceptable_number_sequences = number_sequences_to_save
37
+ self.acceptable_symbol_sequences = symbol_sequences_to_save
38
+ end
39
+
40
+ def save_api_keys
41
+ self.api_key = SecureRandom.hex(32)
42
+ self.api_secret = SecureRandom.hex(32)
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Wallet < ApplicationRecord
4
+ belongs_to :user
5
+
6
+ validates :user_id, presence: true
7
+ validates :pr_key, presence: false
8
+ validates :pv_key, presence: false
9
+ # validates :balance, presence: true, numericality: { equal_to: 0.0 }, on: :create
10
+ validates :status, presence: true, inclusion: %w(active inactive)
11
+
12
+ before_create :create_keys
13
+
14
+
15
+ enum status: { active: 0, inactive: 1 }
16
+
17
+ def create_keys(pv_random = nil, pr_random = nil)
18
+ if pv_random.nil? && pr_random.nil?
19
+ pv_random = SecureRandom.hex(64)
20
+ pr_random = SecureRandom.hex(64)
21
+ end
22
+
23
+ dig_pv = Digest::SHA256.hexdigest(pv_random)
24
+ dig_pr = Digest::SHA256.hexdigest(pr_random)
25
+
26
+ if Wallet.exists?(pr_key: dig_pr) || Wallet.exists?(pv_key: dig_pv)
27
+ raise "Key already exists"
28
+ else
29
+ self.pr_key = dig_pr
30
+ self.pv_key = dig_pv
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationService
4
+ private
5
+ def dev_error(e)
6
+ if env_acceptable?
7
+ puts "#{e.class}: #{e.message}"
8
+ puts e.backtrace
9
+ end
10
+ end
11
+
12
+ def user_exists?
13
+ User.find_by(id: user_id).present?
14
+ end
15
+
16
+ def wallet_exists?(method, key)
17
+ Wallet.find_by(method => key).present?
18
+ end
19
+
20
+ def env_acceptable?
21
+ Rails.env.development? || Rails.env.test?
22
+ end
23
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AssignContractsService < ApplicationService
4
+ def initialize(contract_ids, ticket_id)
5
+ @contract_ids = contract_ids
6
+ @ticket_id = ticket_id
7
+ end
8
+
9
+ def call
10
+ assign_contract
11
+ end
12
+
13
+ private
14
+ attr_reader :contract_ids, :ticket_id
15
+
16
+ def ticket
17
+ @ticket ||= Ticket.find_by(id: ticket_id)
18
+ end
19
+
20
+ def contracts
21
+ @contracts ||= Contract.where(id: contract_ids)
22
+ end
23
+
24
+ def block
25
+ @block ||= Block.where(master_hash: nil).last
26
+ end
27
+
28
+ def block_confirmed?
29
+ block.nonce >= ENV["CONTRACTS_LIMIT"].to_i
30
+ end
31
+
32
+ def update_nonce
33
+ block.update(nonce: block.nonce + 1)
34
+ end
35
+
36
+ def signatures_limit_reached?(contract)
37
+ contract.signatures.count == ENV["SIGNATURES_LIMIT"].to_i
38
+ end
39
+
40
+ def create_block
41
+ Block.create!(chain: Chain.first, previous_hash: block.master_hash,
42
+ master_hash: nil, nonce: 0, connections: 0, contracts_count: 0,
43
+ contracts_limit: ENV["CONTRACTS_LIMIT"].to_i, block_data: "block #{block.id + 1}")
44
+ end
45
+
46
+ def confirm_block
47
+ return if confirmed_now == true
48
+ @confirmed_now = true
49
+ block.update(master_hash: generate_master_hash)
50
+ block.reload
51
+ @new_block = create_block
52
+ pay_receivers
53
+ pay_miners
54
+ end
55
+
56
+ def complete_contracts
57
+ @complete_contracts ||= []
58
+ end
59
+
60
+ def uncomplete_contracts
61
+ @uncomplete_contracts ||= []
62
+ end
63
+
64
+ def signatures
65
+ @signatures ||= []
66
+ end
67
+
68
+ def generate_master_hash
69
+ Digest::SHA256.hexdigest(complete_contracts.map(&:signatures).flatten.map(&:signature).join)
70
+ end
71
+
72
+ def complete_contracts_limit_reached?
73
+ complete_contracts.count == ENV["CONTRACTS_LIMIT"].to_i
74
+ end
75
+
76
+ def confirmed_now
77
+ @confirmed_now ||= false
78
+ end
79
+
80
+ def pay_receivers
81
+ block_transactions = block.transactions
82
+ conts = block_transactions.map(&:contract)
83
+ conts_to_destroy = []
84
+ conts.each do |contract|
85
+ if contract.signatures.count < ENV["SIGNATURES_LIMIT"].to_i
86
+ transact = block_transactions.find_by(contract: contract)
87
+ conts_to_destroy << contract.id
88
+ transact.update(block: @new_block)
89
+ Contract.create(blk_transaction: transact)
90
+ end
91
+ amount = contract.blk_transaction.amount.to_f - contract.blk_transaction.fee.to_f
92
+ wallet = Wallet.find_by(pr_key: contract.blk_transaction.receiver_key)
93
+ wallet.update(balance: wallet.balance + amount)
94
+ end
95
+
96
+ Contract.where(id: conts_to_destroy).destroy_all
97
+ end
98
+
99
+ def payed_miners
100
+ @payed_miners ||= []
101
+ end
102
+
103
+ def pay_miners
104
+ tickets = Ticket.where(pool_id: block.pool.id)
105
+ total_signatures = tickets.map(&:signatures).map(&:count).sum
106
+ counted_users = []
107
+ amount_to_pay = []
108
+ tickets.each do |ticket|
109
+ signatures = ticket.signatures
110
+ user = ticket.user
111
+ unless counted_users.include?(user)
112
+ counted_users << user
113
+ amount_to_pay << signatures.count
114
+ else
115
+ amount_to_pay[counted_users.index(user)] += signatures.count
116
+ end
117
+ end
118
+ amount_to_pay.each_with_index do |amount, index|
119
+ next if payed_miners.include?(counted_users[index])
120
+ wallet = counted_users[index].wallet
121
+ wallet.update(balance: wallet.balance + (amount.to_f / total_signatures.to_f) * block.pool.amount)
122
+ payed_miners << counted_users[index]
123
+ end
124
+ end
125
+
126
+ def new_signature(contract)
127
+ contract.update(signatures_count: contract.signatures_count + 1)
128
+ Signature.new(contract_id: contract.id, signature: ticket.user_acceptable_hash, ticket_id: ticket.id, user_id: ticket.user_id)
129
+ end
130
+
131
+ def parse_in_arrays(contract)
132
+ uncomplete_contracts << contract unless signatures_limit_reached?(contract)
133
+ complete_contracts << contract if signatures_limit_reached?(contract)
134
+ end
135
+
136
+ def add_signature(contract)
137
+ return if signatures_limit_reached?(contract) || confirmed_now == true || block_confirmed?
138
+ signatures << new_signature(contract)
139
+ contract.update(status: (contract.status + 1))
140
+ end
141
+
142
+ def block_actions(contract)
143
+ update_nonce if signatures_limit_reached?(contract)
144
+ confirm_block if complete_contracts_limit_reached? || block_confirmed?
145
+ end
146
+
147
+ def signatures_import(signatures)
148
+ Signature.import signatures if signatures.present?
149
+ ticket.update(status: :inactive)
150
+ end
151
+
152
+ def assign_contract
153
+ contracts.each do |contract|
154
+ parse_in_arrays(contract)
155
+ add_signature(contract)
156
+ end
157
+ signatures_import(signatures)
158
+ contracts.each do |contract|
159
+ block_actions(contract)
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateTicketService < ApplicationService
4
+ def initialize(user_id, pool_id, time_ref)
5
+ @user_id = user_id
6
+ @pool_id = pool_id
7
+ @time_ref = time_ref
8
+ end
9
+
10
+ def call
11
+ return false if ticket_exists?
12
+ return false unless user_exists?
13
+ if ticket_created?
14
+ update_block_connections
15
+ true
16
+ else
17
+ false
18
+ end
19
+ end
20
+
21
+ private
22
+ attr_reader :user_id, :pool_id, :time_ref
23
+
24
+ def block
25
+ @block ||= Block.where(master_hash: nil).last
26
+ end
27
+
28
+ def transactions
29
+ @transactions ||= block.transactions.where(created_at: time_ref..Time.now)
30
+ end
31
+
32
+ def user
33
+ @user ||= User.find(user_id)
34
+ end
35
+
36
+ def word
37
+ @word ||= user.acceptable_words.sample
38
+ end
39
+
40
+ def number_sequence
41
+ @number_sequence ||= user.acceptable_number_sequences.sample
42
+ end
43
+
44
+ def symbol_sequence
45
+ @symbol_sequence ||= user.acceptable_symbol_sequences.sample
46
+ end
47
+
48
+ def generate_transaction_id_list
49
+ transactions.map(&:id)
50
+ end
51
+
52
+ def shuffled_string
53
+ puts "Word: #{word}"
54
+ puts "Number sequence: #{number_sequence}"
55
+ puts "Symbol sequence: #{symbol_sequence}"
56
+ string_sum = (word + number_sequence + symbol_sequence).split("").shuffle.join
57
+ puts "Shuffled string: #{string_sum}"
58
+ string_sum
59
+ end
60
+
61
+ def generate_user_acceptable_hash
62
+ hash = Digest::SHA256.hexdigest(shuffled_string)
63
+ puts "Hash: #{hash}"
64
+ block_hash = Digest::SHA256.hexdigest(@transactions.to_json)
65
+ puts "Block hash: #{block_hash}"
66
+ master_hash = Digest::SHA256.hexdigest(hash + block_hash)
67
+ puts "Master hash: #{master_hash}"
68
+ [hash, block_hash, master_hash]
69
+ end
70
+
71
+ def update_block_connections
72
+ block.update(connections: (block.connections + 1))
73
+ end
74
+
75
+ def ticket_created?
76
+ hash, block_hash, master_hash = generate_user_acceptable_hash
77
+ @ticket = Ticket.new(user_id: user_id, status: :active, pool_id: pool_id,
78
+ time_ref: time_ref, user_acceptable_hash: hash,
79
+ confirmation_hash: master_hash, block_hash: block_hash,
80
+ transaction_id_list: generate_transaction_id_list)
81
+ @ticket.save ? true : false
82
+ end
83
+
84
+ def ticket_exists?
85
+ Ticket.find_by(user_id: user_id, pool_id: pool_id, status: :active).present?
86
+ end
87
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateWalletService < ApplicationService
4
+ def initialize(user_id)
5
+ @user_id = user_id
6
+ end
7
+
8
+
9
+ def call
10
+ return if wallet_exists?("user_id", user_id)
11
+ create_wallet
12
+ end
13
+
14
+ private
15
+ attr_reader :user_id
16
+
17
+ def create_wallet
18
+ Wallet.create(user_id: user_id) ? true : false
19
+ end
20
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TransactionToBlockService < ApplicationService
4
+ def initialize(receiver_key, sender_key, amount, block_id)
5
+ @receiver_key = receiver_key
6
+ @sender_key = sender_key
7
+ @amount = amount
8
+ @block_id = block_id
9
+ end
10
+
11
+ def call
12
+ create_transaction_to_block
13
+ end
14
+
15
+ private
16
+ attr_reader :receiver_key, :sender_key, :amount, :block_id
17
+
18
+ def create_transaction_to_block
19
+ return false unless wallets_present?
20
+ unless block_confirmed?
21
+ transaction.block_id = block.id
22
+ pool.amount += transaction.fee
23
+ pool.save
24
+ transaction_saved?
25
+ else
26
+ refresh_block
27
+ create_transaction_to_block
28
+ end
29
+ end
30
+
31
+ def block
32
+ @block ||= Block.find(block_id)
33
+ end
34
+
35
+ def pool
36
+ block.pool
37
+ end
38
+
39
+ def fee
40
+ (amount.to_f * 0.10).round(2)
41
+ end
42
+
43
+ def transaction
44
+ @transaction ||= Transaction.new(receiver_key: receiver_key, sender_key: sender_key, amount: amount, block_id: block.id, fee: fee)
45
+ end
46
+
47
+ def block_confirmed?
48
+ block.master_hash.present?
49
+ end
50
+
51
+ def transaction_saved?
52
+ transaction.save ? true : false
53
+ end
54
+
55
+ def wallets_present?
56
+ wallet_exists?("pr_key", receiver_key) && wallet_exists?("pv_key", sender_key)
57
+ end
58
+
59
+ def refresh_block
60
+ @block = Block.where(master_hash: nil).last
61
+ end
62
+ end
@@ -0,0 +1,77 @@
1
+ <div class=" h-full w-full px-5 pt-6 pb-20 overflow-y-auto">
2
+ <div class="mb-3">
3
+ <h1 class="text-3xl text-white font-bold">Blocks</h1>
4
+ <p class="text-sm text-purple-500 uppercase font-bold">Last Blocks</p>
5
+ </div>
6
+
7
+ <% @blocks.each do |block| %>
8
+ <% if block %>
9
+ <div class="mb-5">
10
+ <a href="<%= url_for(block) %>" class="block rounded-lg relative p-5 transform transition-all duration-300 scale-100 hover_scale-95" style="background: url(<%= asset_path "gimage.png" %>) center; background-size: cover;">
11
+ <div class="absolute top-0 right-0 -mt-3 mr-3">
12
+ <div class="rounded-full bg-indigo-500 text-white text-xs py-1 pl-2 pr-3 leading-none"><i class="mdi mdi-fire text-base align-middle"></i> <span class="align-middle">FRESH</span></div>
13
+ </div>
14
+ <div class="h-48"></div>
15
+ <h2 class="text-white text-2xl font-bold leading-tight mb-3 pr-5">Block <%= block.id %></h2>
16
+ <div class="flex w-full items-center text-sm text-gray-300 font-medium">
17
+ <div class="flex-1 flex items-center">
18
+ <div class="rounded-full w-8 h-8 mr-3" style="background: url(<%= asset_path "logo.png" %>) center; background-size: cover;"></div>
19
+ <% if block.master_hash.present? %>
20
+ <div class="text-white" style="font-weight: 550;" >confirmed</div>
21
+ <% else %>
22
+ <div class="text-white" style="font-weight: 600; font-size: 25px;" >unconfirmed</div>
23
+ <% end %>
24
+ </div>
25
+
26
+ <div><i class="mdi mdi-thumb-up text-black"></i><%= block.transactions.count %> transactions</div>
27
+ </div>
28
+ </a>
29
+ </div>
30
+ <% end %>
31
+ <% end %>
32
+
33
+ <div class="mb-3">
34
+ <h1 class="text-3xl text-white font-bold">HUB</h1>
35
+ <p class="text-sm text-purple-500 uppercase font-bold">explore</p>
36
+ </div>
37
+
38
+ <div class="flex -mx-1 mb-5">
39
+
40
+ <div class="w-1/2 px-1 text-center">
41
+ <a href="blocks" class="block mb-2 p-5 rounded overflow-hidden transform transition-all duration-300 scale-100 hover_scale-95" style="background: url(<%= asset_path "space.jpg" %>) center; background-size: cover;">
42
+ <div class="h-24"></div>
43
+ <div class="text-lg font-bold text-black leading-tight glitch" data-glitch="Blockchain">Blockchain</div>
44
+ </a>
45
+ <a href="transactions" class="block mb-2 p-5 rounded overflow-hidden transform transition-all duration-300 scale-100 hover_scale-95" style="background: url(<%= asset_path "space_two.jpg" %>) center; background-size: cover;">
46
+ <div class="h-32"></div>
47
+ <div class="text-lg font-bold text-white leading-tight glitch" data-glitch="Transactions">Transactions</div>
48
+ </a>
49
+ </div>
50
+
51
+ <% if user_signed_in? %>
52
+ <div class="w-1/2 px-1 text-center">
53
+ <a href="wallets" class="block mb-2 p-5 rounded overflow-hidden transform transition-all duration-300 scale-100 hover_scale-95" style="background: url(<%= asset_path "space_th.jpg" %>) center; background-size: cover;">
54
+ <div class="h-32"></div>
55
+ <h3 class="text-lg font-bold text-white leading-tight glitch" data-glitch="Wallet">Wallet</h3>
56
+ </a>
57
+ <a href="mining_profile" class="block mb-2 p-5 rounded overflow-hidden text-center transform transition-all duration-300 scale-100 hover_scale-95" style="background: url(<%= asset_path "space_four.jpg" %>) center; background-size: cover;">
58
+ <div class="h-24"></div>
59
+ <div class="text-lg font-bold text-white leading-tight glitch" data-glitch="Mining Profile">Mining Profile</div>
60
+ </a>
61
+ </div>
62
+ <% else %>
63
+ <div class="w-1/2 px-1 text-center">
64
+ <a href="/users/sign_in" class="block mb-2 p-5 rounded overflow-hidden transform transition-all duration-300 scale-100 hover_scale-95" style="background: url(<%= asset_path "space_th.jpg" %>) center; background-size: cover;">
65
+ <div class="h-32"></div>
66
+ <h3 class="text-lg font-bold text-white leading-tight glitch" data-glitch="Login">Login</h3>
67
+ </a>
68
+ <a href="/users/sign_up" class="block mb-2 p-5 rounded overflow-hidden transform transition-all duration-300 scale-100 hover_scale-95" style="background: url(<%= asset_path "space_four.jpg" %>) center; background-size: cover;">
69
+ <div class="h-24"></div>
70
+ <h3 class="text-lg font-bold text-white leading-tight glitch" data-glitch="Sign Up">Sign Up</h3>
71
+ </a>
72
+ </div>
73
+ <% end %>
74
+ </div>
75
+
76
+
77
+ </div>
@@ -0,0 +1 @@
1
+ = render 'featured_board'
@@ -0,0 +1,59 @@
1
+ .text-white.text-center
2
+ p[style="font-size: 20px;font-weight: 550;"]
3
+ / outersapce logo rounded image
4
+ = image_tag("logo.png", class: "rounded-full h-20 w-20", style: "margin: 0 auto;")
5
+ strong
6
+ = "#{current_user.username}'s"
7
+ h1 Mining profile
8
+ br
9
+ .flex
10
+ .w-1/2.text-center.mr-4.mt-4.border-2.border-purple-500.rounded.p-4.bg-purple-500
11
+ p[style="font-size: 20px; font-weight: 550;"]
12
+ strong Wallet
13
+ p[style="font-size: 16px;"]
14
+ strong
15
+ = "Balance: #{current_user.wallet.balance}"
16
+ p[style="font-size: 16px;"]
17
+ strong
18
+ = "Address: #{current_user.wallet.pr_key}"
19
+ .w-1/2.text-center.mr-4.mt-4.border-2.border-purple-500.rounded.p-4.bg-purple-500
20
+ p[style="font-size: 20px;font-weight: 550;"]
21
+ strong API
22
+ p[style="font-size: 16px;"]
23
+ strong Key:
24
+ = current_user.api_key
25
+ p[style="font-size: 16px;"]
26
+ strong Secret:
27
+ = current_user.api_secret
28
+ p[style="font-size: 16px;"]
29
+ strong
30
+ = "Has a ticket? #{@ticket.present?}"
31
+ - unless @ticket.present?
32
+ br
33
+ = link_to "Get a ticket", new_ticket_path, class: "px-4 py-2 rounded bg-gray-800 hover_bg-black text-white"
34
+ br
35
+ br
36
+ .flex
37
+ .w-1/3.text-center.mr-4.mt-4.border-2.border-purple-500.rounded.p-4.bg-purple-500
38
+ p[style="font-size: 20px;font-weight: 550;"]
39
+ strong Acceptable Words
40
+ - @words.each do |word|
41
+ p[style="font-size: 16px;"]
42
+ strong
43
+ = word
44
+ .w-1/3.text-center.mr-4.mt-4.border-2.border-purple-500.rounded.p-4.bg-purple-500
45
+ p[style="font-size: 20px;font-weight: 550;"]
46
+ strong Acceptable Number Sequences
47
+ - @numbers.each do |sequence|
48
+ p[style="font-size: 16px;"]
49
+ strong
50
+ = sequence
51
+ .w-1/3.text-center.mr-4.mt-4.border-2.border-purple-500.rounded.p-4.bg-purple-500
52
+ p[style="font-size: 20px;font-weight: 550;"]
53
+ strong Acceptable Symbol Sequences
54
+ - @symbols.each do |sequence|
55
+ p[style="font-size: 16px;"]
56
+ strong
57
+ = sequence
58
+ br
59
+ br
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ div id="#{dom_id block}"
2
+ p
3
+ strong Previous hash:
4
+ =< block.previous_hash
5
+ p
6
+ strong Block data:
7
+ =< block.block_data
8
+ p
9
+ strong Connections:
10
+ =< block.connections
11
+ p
12
+ strong Transactions:
13
+ =< block.transactions.count
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.extract! block, :id, :nonce, :previous_hash, :block_data, :connections, :created_at, :updated_at
4
+ json.url block_url(block, format: :json)
@@ -0,0 +1,26 @@
1
+ = form_with(model: @block) do |form|
2
+ - if @block.errors.any?
3
+ div style="color: red"
4
+ h2 = "#{pluralize(@block.errors.count, "error")} prohibited this block from being saved:"
5
+ ul
6
+ - @block.errors.each do |error|
7
+ li = error.full_message
8
+
9
+ div
10
+ = form.label :nonce, style: "display: block"
11
+ = form.number_field :nonce
12
+
13
+ div
14
+ = form.label :previous_hash, style: "display: block"
15
+ = form.text_field :previous_hash
16
+
17
+ div
18
+ = form.label :block_data, style: "display: block"
19
+ = form.text_area :block_data
20
+
21
+ div
22
+ = form.label :connections, style: "display: block"
23
+ = form.text_field :connections
24
+
25
+ div
26
+ = form.submit
@@ -0,0 +1,10 @@
1
+ h1 Editing block
2
+
3
+ == render "form", block: @block
4
+
5
+ br
6
+
7
+ div
8
+ => link_to "Show this block", @block
9
+ '|
10
+ =< link_to "Back to blocks", blocks_path
@@ -0,0 +1,12 @@
1
+ .text-center.text-white
2
+
3
+
4
+ h1[style="font-size: 25px; font-weight: 600;"] Blockchain
5
+
6
+ #blocks
7
+ - @blocks.each do |block|
8
+ == render block
9
+ br
10
+ p
11
+ = link_to "Show this block", block, class: "px-4 py-2 rounded bg-purple-500 hover_bg-purple-700 text-white"
12
+ br
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.array! @blocks, partial: "blocks/block", as: :block
@@ -0,0 +1,8 @@
1
+ h1 New block
2
+
3
+ == render "form", block: @block
4
+
5
+ br
6
+
7
+ div
8
+ = link_to "Back to blocks", blocks_path
@@ -0,0 +1,8 @@
1
+ .text-center.text-white
2
+
3
+
4
+ == render @block
5
+ br
6
+ div
7
+ = link_to "Back to blocks", blocks_path, class: "px-4 py-2 rounded bg-purple-500 hover_bg-purple-700 text-white"
8
+ br
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ json.partial! "blocks/block", block: @block