eost 0.1.5 → 0.1.11

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.
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('bigdecimal/util')
4
+
5
+ # @author Hernani Rodrigues Vaz
6
+ module Eost
7
+ # classe para processar carteiras & transacoes
8
+ class Carteiras
9
+ # @return [Eosscan] API eosscan
10
+ attr_reader :api
11
+ # @return [Array<Hash>] todos os dados bigquery
12
+ attr_reader :dbq
13
+ # @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
14
+ attr_reader :ops
15
+ # @return [Array<Integer>] lista blocknumbers transacoes no bigquery - condicionados por opcoes iniciais
16
+ attr_reader :abn
17
+
18
+ # @param [Hash] dad todos os dados bigquery
19
+ # @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
20
+ # @option pop [Hash] :h ({}) configuracao dias ajuste reposicionamento temporal
21
+ # @option pop [Boolean] :v (false) mostra dados transacoes?
22
+ # @option pop [Boolean] :t (false) mostra transacoes todas ou somente novas?
23
+ # @return [Carteiras] API eosscan - processar transacoes
24
+ def initialize(dad, pop)
25
+ @api = Eosscan.new
26
+ @dbq = dad
27
+ @ops = pop
28
+ @abn = (ops[:t] ? [] : dbq[:nt].map { |t| t[:blocknumber] })
29
+ end
30
+
31
+ # @return [Array<Hash>] todos os dados eosscan - saldos & transacoes
32
+ def des
33
+ @des ||= dbq[:wb].map { |e| base_eosscan(e) }
34
+ end
35
+
36
+ # @return [Array<Hash>] todos os dados juntos bigquery & eosscan
37
+ def djn
38
+ @djn ||= dbq[:wb].map { |b| bigquery_eosscan(b, des.select { |s| b[:ax] == s[:ax] }.first) }
39
+ end
40
+
41
+ # @return [Array<Integer>] lista blocknumbers de transacoes novas
42
+ def bnn
43
+ @bnn ||= (des.map { |e| e[:tx].map { |n| Integer(n['block_num']) } }.flatten - abn)
44
+ end
45
+
46
+ # @return [Array<Hash>] lista transacoes novas
47
+ def novas
48
+ @novas ||= des.map { |e| e[:tx].select { |s| bnn.include?(Integer(s['block_num'])) } }.flatten.uniq
49
+ end
50
+
51
+ # @return [Array<Hash>] lista ordenada transacoes novas
52
+ def novas_sort
53
+ novas.sort { |a, b| Integer(a['block_num']) <=> Integer(b['block_num']) }
54
+ end
55
+
56
+ # @param [Hash] hwb wallet bigquery eos
57
+ # @return [Hash] dados eosscan - address, saldo & transacoes
58
+ def base_eosscan(hwb)
59
+ {
60
+ ax: hwb[:ax],
61
+ sl: eosscan_sl(hwb[:ax]).inject(:+),
62
+ tx: eosscan_tx(hwb[:ax])
63
+ }
64
+ end
65
+
66
+ # @param (see bigquery_eosscan)
67
+ # @return [Hash<Array, Boolean>] lista blocknumbers novos & carteira ok?
68
+ def novas_ok(hwb, hes)
69
+ # quando todas as transacoes obtidas da api vao ser inseridas,
70
+ # entao podem ficar transacoes por inserir - api consegue apenas um maximo de 100 transacoes
71
+ n = hes[:tx].map { |v| Integer(v['block_num']) } - abn
72
+ { nn: n, ok: hwb[:sl] == hes[:sl] && n.count < hes[:tx].count }
73
+ end
74
+
75
+ # @param hwb (see base_eosscan)
76
+ # @param [Hash] hes dados eosscan
77
+ # @return [Hash] dados juntos bigquery & eosscan
78
+ def bigquery_eosscan(hwb, hes)
79
+ {
80
+ id: hwb[:id],
81
+ ax: hwb[:ax],
82
+ bs: hwb[:sl],
83
+ bt: dbq[:nt].select { |t| t[:iax] == hwb[:ax] },
84
+ es: hes[:sl],
85
+ et: hes[:tx]
86
+ }.merge(novas_ok(hwb, hes))
87
+ end
88
+
89
+ # @param [String] add endereco carteira EOS
90
+ # @return [Array<BigDecimal>] lista recursos - liquido, net, spu
91
+ def eosscan_sl(add)
92
+ v = api.chain_get_account(account_name: add)
93
+ [
94
+ v['core_liquid_balance'].to_d,
95
+ v['total_resources']['net_weight'].to_d,
96
+ v['total_resources']['cpu_weight'].to_d
97
+ ]
98
+ end
99
+
100
+ # @param (see eosscan_sl)
101
+ # @return [Array<Hash>] lista ultimas 100 transacoes ligadas a uma carteira - sem elementos irrelevantes
102
+ def eosscan_tx(add)
103
+ api.history_get_actions(account_name: add, offset: -100)['actions'].map do |e|
104
+ e.delete('global_action_seq')
105
+ e
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('faraday')
4
+ require('json')
5
+
6
+ module Eost
7
+ # classe para acesso dados blockchain EOS
8
+ class Eosscan
9
+ # @return [String] endereco da API blockchain EOS
10
+ attr_reader :url
11
+
12
+ # attr_reader :spec, :api, :edp
13
+
14
+ # @return [Eosscan] acesso dados blockchain EOS
15
+ def initialize(www: 'https://eos.greymass.com')
16
+ @url = www
17
+ # load_specs
18
+ end
19
+
20
+ # @return [<Symbol>] adapter for the connection - default :net_http
21
+ def adapter
22
+ @adapter ||= Faraday.default_adapter
23
+ end
24
+
25
+ # manage the default properties and the middleware stack for fulfilling an HTTP request
26
+ #
27
+ # @return [<Faraday::Connection>] connection object with an URL & adapter
28
+ def conn
29
+ @conn ||=
30
+ Faraday.new(url: url) do |c|
31
+ c.request(:url_encoded)
32
+ c.adapter(adapter)
33
+ end
34
+ end
35
+
36
+ # @example chain_get_account
37
+ # {
38
+ # 'account_name': '...',
39
+ # 'head_block_num': 138_586_631,
40
+ # 'head_block_time': '2020-08-26T10:16:05.500',
41
+ # 'privileged': false,
42
+ # 'last_code_update': '1970-01-01T00:00:00.000',
43
+ # 'created': '2018-06-09T13:14:37.000',
44
+ # # DEVOLVIDO 'core_liquid_balance': '1232.0226 EOS',
45
+ # 'ram_quota': 9548,
46
+ # 'net_weight': 10_001_142,
47
+ # 'cpu_weight': 10_001_144,
48
+ # 'total_resources': {
49
+ # 'owner': '...',
50
+ # # DEVOLVIDO 'net_weight': '1000.1142 EOS',
51
+ # # DEVOLVIDO 'cpu_weight': '1000.1144 EOS',
52
+ # 'ram_bytes': 8148
53
+ # },
54
+ # 'net_limit': { 'used': 0, 'available': 1_068_152_841, 'max': 1_068_152_841 },
55
+ # 'cpu_limit': { 'used': 338, 'available': 90_856, 'max': 91_194 },
56
+ # 'ram_usage': 3574,
57
+ # 'permissions': [
58
+ # {
59
+ # 'perm_name': 'active',
60
+ # 'parent': 'owner',
61
+ # 'required_auth': {
62
+ # 'threshold': 1,
63
+ # 'keys': [{ 'key': '...', 'weight': 1 }],
64
+ # 'accounts': [],
65
+ # 'waits': []
66
+ # }
67
+ # },
68
+ # {
69
+ # 'perm_name': 'owner',
70
+ # 'parent': '',
71
+ # 'required_auth': {
72
+ # 'threshold': 1,
73
+ # 'keys': [{ 'key': '...', 'weight': 1 }],
74
+ # 'accounts': [],
75
+ # 'waits': []
76
+ # }
77
+ # }
78
+ # ],
79
+ # 'self_delegated_bandwidth': {
80
+ # 'from': '...', 'to': '...', 'net_weight': '1000.1142 EOS', 'cpu_weight': '1000.1144 EOS'
81
+ # },
82
+ # 'refund_request': nil,
83
+ # 'voter_info': {
84
+ # 'owner': '...',
85
+ # 'proxy': '...',
86
+ # 'producers': [],
87
+ # 'staked': 20_002_286,
88
+ # 'last_vote_weight': '17172913021904.12109375000000000',
89
+ # 'proxied_vote_weight': '0.00000000000000000',
90
+ # 'is_proxy': 0,
91
+ # 'flags1': 0,
92
+ # 'reserved2': 0,
93
+ # 'reserved3': '0.0000 EOS'
94
+ # },
95
+ # 'rex_info': nil
96
+ # }
97
+ # @return [Hash] dados numa carteira EOS
98
+ def chain_get_account(**args)
99
+ JSON.parse(conn.post('/v1/chain/get_account', args.to_json, content_type: 'application/json').body)
100
+ end
101
+
102
+ # @example history_get_actions
103
+ # {
104
+ # 'actions' => [
105
+ # {
106
+ # 'account_action_seq': 937,
107
+ # 'action_trace': {
108
+ # 'account_ram_deltas': [],
109
+ # 'act': {
110
+ # 'account': 'newsblockone',
111
+ # 'authorization': [
112
+ # { 'actor': 'blockonenews', 'permission': 'active' },
113
+ # { 'actor': 'newsblockone', 'permission': 'active' }
114
+ # ],
115
+ # 'data': {
116
+ # 'from': 'newsblockone',
117
+ # 'memo': '100 million EOS tokens released on the network - EOS Reallocation Program @ get-eos.io',
118
+ # 'quantity': '1.0000 NEWS',
119
+ # 'to': '...'
120
+ # },
121
+ # 'hex_data': 'a02685',
122
+ # 'name': 'transfer'
123
+ # },
124
+ # 'action_ordinal': 20,
125
+ # 'block_num': 135_581_543,
126
+ # 'block_time': '2020-08-09T00:45:41.000',
127
+ # 'closest_unnotified_ancestor_action_ordinal': 10,
128
+ # 'context_free': false,
129
+ # 'creator_action_ordinal': 10,
130
+ # 'elapsed': 17,
131
+ # 'producer_block_id': '0814cf67c5dfe81e8647be1ddec70a8c84c45e1d65779132ace3561be044a12c',
132
+ # 'receipt': {
133
+ # 'abi_sequence': 2,
134
+ # 'act_digest': '8b2a534341229734f1532430ffcd40c30c7b82da30c3f23446f248c2e1209a68',
135
+ # 'auth_sequence': [['blockonenews', 485_788], ['newsblockone', 368_458]],
136
+ # 'code_sequence': 2,
137
+ # 'global_sequence': 204_352_530_651,
138
+ # 'receiver': '...',
139
+ # 'recv_sequence': 900
140
+ # },
141
+ # 'receiver': '...',
142
+ # 'trx_id': 'de327b9ba02f2fbca9eb2ee3a4e26f8ead6198248b52d184e1f480c578705ba9'
143
+ # },
144
+ # 'block_num': 135_581_543,
145
+ # 'block_time': '2020-08-09T00:45:41.000',
146
+ # # DELETED 'global_action_seq': 204_352_530_651,
147
+ # 'irreversible': true
148
+ # }
149
+ # ],
150
+ # 'head_block_num' => 138_936_528,
151
+ # 'last_irreversible_block' => 138_936_194
152
+ # }
153
+ # @return [Hash] dados das transacoes ligadas a uma carteira EOS
154
+ def history_get_actions(**args)
155
+ JSON.parse(conn.post('/v1/history/get_actions', args.to_json, content_type: 'application/json').body)
156
+ end
157
+
158
+ # private
159
+ # Load API specification from spec files
160
+ # def load_specs
161
+ # @spec = {}
162
+ # Dir["#{spec_path}*"].map { |f| File.basename(f, '.json') }.compact.each { |n| @spec[n] = read_spec(n) }
163
+ # end
164
+ #
165
+ # def spec_path
166
+ # "#{File.dirname(__dir__)}/../specs/"
167
+ # end
168
+ #
169
+ # def read_spec(name)
170
+ # JSON.parse(File.read("#{spec_path}#{name}.json"))
171
+ # end
172
+ #
173
+ # Add API methods to class for seamless usage - this used for undefined methods
174
+ # def method_missing(method_name, *args)
175
+ # return super(method_name, *args) unless respond_to_missing?(method_name)
176
+ #
177
+ # api_call(args.first)
178
+ # end
179
+ #
180
+ # def respond_to_missing?(method_name)
181
+ # @api, @edp = extract_endpoint(method_name)
182
+ # return super(endpoint, *args) unless rtm?
183
+ #
184
+ # rtm?
185
+ # end
186
+ #
187
+ # def rtm?
188
+ # spec.key?(api) && spec[api].key?(edp)
189
+ # end
190
+ #
191
+ # def extract_endpoint(name)
192
+ # name.to_s.split('_', 2)
193
+ # end
194
+ #
195
+ # def known_params
196
+ # # api, endpoint = extract_endpoint(method_name)
197
+ # return {} unless rtm?
198
+ #
199
+ # spec[api][edp]['params'] || {}
200
+ # end
201
+ #
202
+ # # The actual http call
203
+ # def api_call(args)
204
+ # args ||= {}
205
+ # known = known_params
206
+ # r = conn.post(
207
+ # "/v1/#{api}/#{edp}",
208
+ # args.select { |k, _| known.include?(k.to_s) }.to_json,
209
+ # content_type: 'application/json'
210
+ # )
211
+ # JSON.parse(r.body)
212
+ # end
213
+ end
214
+ end
@@ -1,83 +1,79 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Eost
4
- HT = %w[block_num block_time contract action
5
- from to amount symbol memo data].freeze
6
- R1 = '%<v3>-12.12s %<v4>s %<v5>-12.12s %<v6>-12.12s'
7
- R2 = '%<v7>10.5f %<v8>-10.10s'
4
+ HT = %w[block_num block_time contract action from to amount symbol memo data].freeze
5
+ R1 = '%<v5>-12.12s %<v6>-12.12s'
6
+ R2 = '%<v7>10.5f %<v8>-8.8s'
8
7
 
9
- # folhas calculo comuns no bigquery
8
+ # trabalhar com folhas calculo bloks.io & dados no bigquery
10
9
  class Bigquery
11
- # @return [String] linha folha calculo formatada
12
- def row_str
13
- "#{row[0]} #{DateTime.parse(row[1]).strftime(DF)} " + row_r1 + row_r2
14
- end
15
-
16
- # @return [String] linha folha calculo formatada
17
- def row_r1
18
- format(R1, v3: row[2], v4: row[3], v5: row[4], v6: row[5])
19
- end
20
-
21
- # @return [String] linha folha calculo formatada
22
- def row_r2
23
- format(R2, v7: row[6], v8: row[7])
24
- end
25
-
26
- # processa linhas folha calculo
27
- def processa
10
+ # processa folha calculo
11
+ def processa_csv
28
12
  n = 0
29
- # usada somente a primeira sheet
30
- book.sheet(0).parse(header_search: HT) do |r|
13
+ folha.sheet(0).parse(header_search: HT) do |r|
31
14
  n += 1
32
- puts n == 1 ? "\n" + book.info : processa_row(r)
33
- end
34
- end
35
-
36
- # mostra linhas folha calculo
37
- def show
38
- n = 0
39
- # usada somente a primeira sheet
40
- book.sheet(0).parse(header_search: HT) do |r|
41
- n += 1
42
- puts n == 1 ? "\n" + book.info : show_row(r)
15
+ puts n == 1 ? "\n#{folha.info}" : processa_row(r)
43
16
  end
44
17
  end
45
18
 
46
19
  # processa linha folha calculo para arquivo
47
20
  #
48
- # @param (see show_row)
49
- # @return [String] linha folha calculo processada
21
+ # @param [Hash] has da linha em processamento
22
+ # @return [String] texto informativo do processamento
50
23
  def processa_row(has)
51
24
  @row = has.values
52
- sql_select
53
- if rnaoexiste? then row_str + (sql_insert == 1 ? ' NOVA' : ' ERRO')
54
- elsif rexiste? then row_existente
25
+
26
+ # array.count = 0 ==> pode carregar esta linha
27
+ # array.count >= 1 ==> nao carregar esta linha
28
+ sql("select #{eos_fields} #{sql_where}", [{}, {}])
29
+
30
+ if row_naoexiste? then row_str + (eos_insert_csv == 1 ? ' NOVA' : ' ERRO')
31
+ elsif row_existe? then row_existente
32
+ else row_multiplas
55
33
  end
56
34
  end
57
35
 
58
- # obtem linha folha calculo para apresentacao
59
- #
60
- # @param [Hash] has da linha em processamento
61
- # @return (see row_str)
62
- def show_row(has)
63
- @row = has.values
64
- row_str
36
+ # @return [String] linha folha calculo formatada
37
+ def row_str
38
+ "#{row[0]} #{Time.parse(row[1]).strftime(DF)} " + row_r1 + row_r2
39
+ end
40
+
41
+ # @return [String] linha folha calculo formatada
42
+ def row_r1
43
+ format(R1, v5: row[4], v6: row[5])
44
+ end
45
+
46
+ # @return [String] linha folha calculo formatada
47
+ def row_r2
48
+ format(R2, v7: Float(row[6]), v8: row[7])
65
49
  end
66
50
 
67
51
  # @return [String] linha folha calculo existente
68
52
  def row_existente
69
- d = apaga ? sql_delete : 0
70
- row_str + " EXISTENTE#{d.zero? ? '' : ' APAGADA'}"
53
+ d = linha[:e] ? dml("delete #{sql_where}") : 0
54
+ "#{row_str} EXISTENTE#{str_apagadas(d)}"
55
+ end
56
+
57
+ # @return [String] linha folha calculo existencia multipla
58
+ def row_multiplas
59
+ d = linha[:m] ? dml("delete #{sql_where}") : 0
60
+ "#{row_str} MULTIPLAS #{sql.count}#{str_apagadas(d)}"
61
+ end
62
+
63
+ # @param [Integer] num numero linhas apagadas
64
+ # @return [String] texto formatado linhas apagadas
65
+ def str_apagadas(num)
66
+ num.positive? ? " & #{num} APAGADA(S) " : ' '
71
67
  end
72
68
 
73
69
  # @return [Boolean] linha folha calculo nao existe no bigquery?
74
- def rnaoexiste?
75
- sql.count.zero?
70
+ def row_naoexiste?
71
+ sqr.count.zero?
76
72
  end
77
73
 
78
74
  # @return [Boolean] linha folha calculo existe no bigquery?
79
- def rexiste?
80
- sql.count == 1
75
+ def row_existe?
76
+ sqr.count == 1
81
77
  end
82
78
  end
83
79
  end