eost 0.1.5 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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