xgt-ruby 0.1.0

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 (123) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/Gemfile.lock +56 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +45 -0
  10. data/Rakefile +6 -0
  11. data/bin/.wallet.swp +0 -0
  12. data/bin/setup +8 -0
  13. data/bin/wallet +438 -0
  14. data/examples/api/account_by_key_api/get_key_references.rb +18 -0
  15. data/examples/api/account_history_api/deprecated/enum_virtual_ops.rb +15 -0
  16. data/examples/api/account_history_api/deprecated/get_transaction.rb +12 -0
  17. data/examples/api/account_history_api/get_account_history.rb +16 -0
  18. data/examples/api/account_history_api/get_ops_in_block.rb +17 -0
  19. data/examples/api/chain_api/deprecated/dummy_code.rb +65 -0
  20. data/examples/api/chain_api/deprecated/push_block.rb +20 -0
  21. data/examples/api/database_api/accounts/find_accounts.rb +16 -0
  22. data/examples/api/database_api/accounts/list_accounts.rb +18 -0
  23. data/examples/api/database_api/accounts/not_supported/find_account_recovery_requests.rb +16 -0
  24. data/examples/api/database_api/accounts/not_supported/find_change_recovery_account_requests.rb +0 -0
  25. data/examples/api/database_api/accounts/not_supported/find_decline_voting_rights_requests.rb +0 -0
  26. data/examples/api/database_api/accounts/not_supported/find_escrows.rb +0 -0
  27. data/examples/api/database_api/accounts/not_supported/find_sbd_conversion_requests.rb +0 -0
  28. data/examples/api/database_api/accounts/not_supported/find_vesting_delegation_expirations.rb +0 -0
  29. data/examples/api/database_api/accounts/not_supported/find_vesting_delegations.rb +0 -0
  30. data/examples/api/database_api/accounts/not_supported/find_withdraw_vesting_routes.rb +18 -0
  31. data/examples/api/database_api/accounts/not_supported/list_account_recovery_requests.rb +18 -0
  32. data/examples/api/database_api/accounts/not_supported/list_change_recovery_account_requests.rb +0 -0
  33. data/examples/api/database_api/accounts/not_supported/list_decline_voting_rights_requests.rb +0 -0
  34. data/examples/api/database_api/accounts/not_supported/list_escrows.rb +18 -0
  35. data/examples/api/database_api/accounts/not_supported/list_recovery_histories.rb +17 -0
  36. data/examples/api/database_api/accounts/not_supported/list_sbd_conversion_requests.rb +0 -0
  37. data/examples/api/database_api/accounts/not_supported/list_vesting_delegation_expirations.rb +0 -0
  38. data/examples/api/database_api/accounts/not_supported/list_vesting_delegations.rb +18 -0
  39. data/examples/api/database_api/accounts/not_supported/list_withdraw_vesting_routes.rb +18 -0
  40. data/examples/api/database_api/authority/not_supported/find_smt_contributions.rb +0 -0
  41. data/examples/api/database_api/authority/not_supported/find_smt_token_balances.rb +0 -0
  42. data/examples/api/database_api/authority/not_supported/find_smt_token_emissions.rb +0 -0
  43. data/examples/api/database_api/authority/not_supported/find_smt_tokens.rb +0 -0
  44. data/examples/api/database_api/authority/not_supported/get_nai_pool.rb +0 -0
  45. data/examples/api/database_api/authority/not_supported/get_potential_signatures.rb +0 -0
  46. data/examples/api/database_api/authority/not_supported/get_required_signatures.rb +0 -0
  47. data/examples/api/database_api/authority/not_supported/get_smt_balances.rb +0 -0
  48. data/examples/api/database_api/authority/not_supported/get_transaction_hex.rb +0 -0
  49. data/examples/api/database_api/authority/not_supported/list_smt_contributions.rb +0 -0
  50. data/examples/api/database_api/authority/not_supported/list_smt_token_balances.rb +0 -0
  51. data/examples/api/database_api/authority/not_supported/list_smt_token_emissions.rb +0 -0
  52. data/examples/api/database_api/authority/not_supported/list_smt_tokens.rb +0 -0
  53. data/examples/api/database_api/authority/not_supported/verify_account_authority.rb +0 -0
  54. data/examples/api/database_api/authority/not_supported/verify_authority.rb +0 -0
  55. data/examples/api/database_api/authority/not_supported/verify_signatures.rb +0 -0
  56. data/examples/api/database_api/comments/not_supported/find_comments.rb +0 -0
  57. data/examples/api/database_api/comments/not_supported/find_votes.rb +0 -0
  58. data/examples/api/database_api/comments/not_supported/list_comments.rb +0 -0
  59. data/examples/api/database_api/comments/not_supported/list_votes.rb +0 -0
  60. data/examples/api/database_api/globals/get_config.rb +14 -0
  61. data/examples/api/database_api/globals/get_dynamic_global_properties.rb +14 -0
  62. data/examples/api/database_api/globals/get_hardfork_properties.rb +14 -0
  63. data/examples/api/database_api/globals/get_reward_funds.rb +14 -0
  64. data/examples/api/database_api/globals/get_version.rb +15 -0
  65. data/examples/api/database_api/globals/get_witness_schedule.rb +14 -0
  66. data/examples/api/database_api/market/not_supported/find_limit_orders.rb +0 -0
  67. data/examples/api/database_api/market/not_supported/get_order_book.rb +0 -0
  68. data/examples/api/database_api/market/not_supported/list_limit_orders.rb +0 -0
  69. data/examples/api/database_api/sps/not_supported/find_proposals.rb +0 -0
  70. data/examples/api/database_api/sps/not_supported/list_proposal_votes.rb +0 -0
  71. data/examples/api/database_api/sps/not_supported/list_proposals.rb +0 -0
  72. data/examples/api/database_api/witnesses/deprecated/get_round.rb +14 -0
  73. data/examples/api/database_api/witnesses/find_witnesses.rb +16 -0
  74. data/examples/api/database_api/witnesses/get_active_witnesses.rb +14 -0
  75. data/examples/api/database_api/witnesses/list_witnesses.rb +17 -0
  76. data/examples/api/database_api/witnesses/not_supported/list_witness_votes.rb +16 -0
  77. data/examples/api/extras/get_balance.rb +27 -0
  78. data/examples/api/network_broadcast_api/broadcast_transaction.rb +16 -0
  79. data/examples/api/network_broadcast_api/broadcast_transaction_synchronous.rb +15 -0
  80. data/examples/api/network_broadcast_api/create_wallet.rb +79 -0
  81. data/examples/api/network_broadcast_api/dummy_code.rb +68 -0
  82. data/examples/api/network_broadcast_api/get_transaction_hex.rb +17 -0
  83. data/examples/api/network_broadcast_api/not_supported/broadcast_block.rb +17 -0
  84. data/examples/api/network_broadcast_api/transfer.rb +45 -0
  85. data/examples/api/payloads.txt +3580 -0
  86. data/examples/api/transaction_status_api/find_transaction.rb +16 -0
  87. data/examples/operations/broadcast_transaction_synchronous.rb +16 -0
  88. data/examples/operations/completed/account_create.rb +79 -0
  89. data/examples/operations/completed/account_witness_proxy.rb +29 -0
  90. data/examples/operations/completed/account_witness_vote.rb +31 -0
  91. data/examples/operations/completed/claim_account.rb +33 -0
  92. data/examples/operations/completed/create_claimed_account.rb +62 -0
  93. data/examples/operations/completed/custom.rb +31 -0
  94. data/examples/operations/completed/custom_json.rb +32 -0
  95. data/examples/operations/completed/decline_voting_rights.rb +30 -0
  96. data/examples/operations/completed/delegate_some_vesting_shares.rb +32 -0
  97. data/examples/operations/completed/set_withdraw_vesting_route.rb +32 -0
  98. data/examples/operations/completed/transfer.rb +44 -0
  99. data/examples/operations/completed/transfer_to_vesting.rb +32 -0
  100. data/examples/operations/completed/update_proposal_votes.rb +31 -0
  101. data/examples/operations/completed/withdraw_vesting.rb +30 -0
  102. data/examples/operations/completed/witness_update.rb +64 -0
  103. data/examples/operations/deprecated/account_update.rb +44 -0
  104. data/examples/operations/deprecated/cancel_transfer_from_savings.rb +30 -0
  105. data/examples/operations/deprecated/challenge_authority.rb +28 -0
  106. data/examples/operations/deprecated/claim_reward_balance.rb +35 -0
  107. data/examples/operations/deprecated/convert.rb +38 -0
  108. data/examples/operations/deprecated/custom_binary.rb +31 -0
  109. data/examples/operations/deprecated/feed_publish.rb +33 -0
  110. data/examples/operations/do_later/change_recovery_account.rb +31 -0
  111. data/examples/operations/do_later/claim_reward_balance2.rb +37 -0
  112. data/examples/operations/do_later/remove_proposal_votes.rb +0 -0
  113. data/examples/operations/in_progress/create_proposal.rb +40 -0
  114. data/examples/operations/in_progress/escrow_approve.rb +36 -0
  115. data/examples/operations/in_progress/witness_set_properties.rb +62 -0
  116. data/lib/xgt/.ruby.rb.swp +0 -0
  117. data/lib/xgt/ruby.rb +200 -0
  118. data/lib/xgt/ruby/version.rb +5 -0
  119. data/payloads.txt +461 -0
  120. data/sample.rb +41 -0
  121. data/sample2.rb +104 -0
  122. data/xgt-ruby.gemspec +31 -0
  123. metadata +262 -0
@@ -0,0 +1,37 @@
1
+ require 'xgt/ruby'
2
+
3
+ def claim_reward_balance2
4
+ rpc = Xgt::Ruby::Rpc.new('http://localhost:8751')
5
+ wif = '5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n'
6
+ config = rpc.call('database_api.get_config', {})
7
+ address_prefix = config['XGT_ADDRESS_PREFIX']
8
+ chain_id = config["XGT_CHAIN_ID"]
9
+
10
+ txn = {
11
+ "extensions": [],
12
+ "operations": [
13
+ [
14
+ "claim_reward_balance2",
15
+ {
16
+ "account": "XGT0000000000000",
17
+ "reward_tokens": [
18
+ {
19
+ "amount": "1",
20
+ "precision": 0,
21
+ "nai": "@@904705667"
22
+ }
23
+ ],
24
+ "extensions": []
25
+ }
26
+ ]
27
+ ]
28
+ }
29
+
30
+ signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [wif], chain_id)
31
+ puts JSON.pretty_generate(signed)
32
+ puts "\n\n"
33
+ response = rpc.call('network_broadcast_api.broadcast_transaction_synchronous', [signed])
34
+ puts JSON.pretty_generate(response)
35
+ end
36
+
37
+ claim_reward_balance2
@@ -0,0 +1,40 @@
1
+ require 'xgt/ruby'
2
+
3
+ def create_proposal
4
+ rpc = Xgt::Ruby::Rpc.new('http://localhost:8751')
5
+ wif = ENV["WIF"] || '5JNHfZYKGaomSFvd4NUdQ9qMcEAC43kujbfjueTHpVapX1Kzq2n'
6
+ receiver = ENV["RECEIVER"] || 'XGT0000000000001'
7
+ config = rpc.call('database_api.get_config', {})
8
+ address_prefix = config['XGT_ADDRESS_PREFIX']
9
+ chain_id = config["XGT_CHAIN_ID"]
10
+ current_time = Time.now
11
+
12
+ txn = {
13
+ "extensions": [],
14
+ "operations": [
15
+ [
16
+ "create_proposal",
17
+ {
18
+ "creator": "XGT0000000000000",
19
+ "receiver": receiver,
20
+ "start_date": "2020-05-24T09:00:00",
21
+ "end_date": "2020-05-25T09:00:00",
22
+ "daily_pay": "3000.000 SBD",
23
+ "amount": 8000,
24
+ "precision": 3,
25
+ "nai": "@@000000013",
26
+ "subject": "subject",
27
+ "permlink": "http://test.host"
28
+ }
29
+ ]
30
+ ]
31
+ }
32
+
33
+ signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [wif], chain_id)
34
+ puts JSON.pretty_generate(signed)
35
+ puts "\n\n"
36
+ response = rpc.call('network_broadcast_api.broadcast_transaction_synchronous', [signed])
37
+ puts JSON.pretty_generate(response)
38
+ end
39
+
40
+ create_proposal
@@ -0,0 +1,36 @@
1
+ require 'xgt/ruby'
2
+
3
+ def escrow_approve
4
+ rpc = Xgt::Ruby::Rpc.new('http://localhost:8751')
5
+ wif = '5JANXuPvF1DuhEpf2AKCDhMgaY7ZhYj6qM6HtKUfvnLkuZ6JwGZ'
6
+ wif2 = '5JdgpjVNcAQQhTjhvZgypEQsZqS7nLfPTyURWUgJXze8k65SKiJ'
7
+ wif3 = '5JWufsfFUfKQKwhsYy26oiVifMpyTy3bCkzuL7bcgYpNrCW731s'
8
+ config = rpc.call('database_api.get_config', {})
9
+ address_prefix = config['XGT_ADDRESS_PREFIX']
10
+ chain_id = config["XGT_CHAIN_ID"]
11
+
12
+ txn = {
13
+ "extensions": [],
14
+ "operations": [
15
+ [
16
+ "escrow_approve",
17
+ {
18
+ "from": "XGT0000000000000",
19
+ "to": "XGT32apWJQf7pVbm",
20
+ "agent": "XGT25svCHdyiRN1C",
21
+ "who": "XGT32apWJQf7pVbm",
22
+ "escrow_id": 59102208,
23
+ "approve": true
24
+ }
25
+ ]
26
+ ]
27
+ }
28
+
29
+ signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [wif3], chain_id)
30
+ puts JSON.pretty_generate(signed)
31
+ puts "\n\n"
32
+ response = rpc.call('network_broadcast_api.broadcast_transaction_synchronous', [signed])
33
+ puts JSON.pretty_generate(response)
34
+ end
35
+
36
+ escrow_approve
@@ -0,0 +1,62 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+ require 'pp'
4
+ require 'benchmark'
5
+ require 'yaml'
6
+ require 'bigdecimal'
7
+ require 'uri'
8
+ require 'openssl'
9
+ $LOAD_PATH.unshift(%(#{File.dirname(__FILE__)}/../xgt-ruby/lib))
10
+ require'xgt/ruby'
11
+
12
+ def msg(message)
13
+ puts "\e[36m#{message}\e[0m"
14
+ end
15
+
16
+ def witness_set_properties
17
+ rpc = Xgt::Ruby::Rpc.new("http://localhost:8751")
18
+ recovery_wif = '5JkEZbn8i8BDRpzTAt38Cj9jhAytkcsPuxbFB6R8kd2L7sGWcbE'
19
+ config = rpc.call('database_api.get_config', {})
20
+ witness_schedule = rpc.call('database_api.get_witness_schedule', {}) || {}
21
+ chain_properties = witness_schedule['median_props']
22
+ address_prefix = config['XGT_ADDRESS_PREFIX']
23
+ chain_id = config['XGT_CHAIN_ID']
24
+ signing_private = Xgt::Ruby::Auth.random_wif
25
+ signing_public = Xgt::Ruby::Auth.wif_to_public_key(signing_private, address_prefix)
26
+ amount = (chain_properties['account_creation_fee'] || {})['amount'].to_f * 0.001
27
+ currency_symbol = config['XGT_SYMBOL_STR']
28
+ fee = "#{'%0.3f' % amount} #{currency_symbol}"
29
+ components = fee.split(' ')
30
+ decimal = BigDecimal(components.first) * 1
31
+ final_fee = decimal.truncate.to_s + '.' + sprintf('%03d', (decimal.frac * 1000).truncate) + ' ' + components.last
32
+
33
+ txn = {
34
+ "operations": [[
35
+ "witness_set_properties",
36
+ {
37
+ "owner": "XGT0000000000000",
38
+ "maximum_block_size": 65536,
39
+ "props": [
40
+ "new_signing_key": "5JANXuPvF1DuhEpf2AKCDhMgaY7ZhYj6qM6HtKUfvnLkuZ6JwGZ",
41
+ ]
42
+ }
43
+ ]]
44
+ }
45
+
46
+ signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [recovery_wif], chain_id)
47
+ puts JSON.pretty_generate(signed)
48
+ puts "\n\n"
49
+
50
+ msg %(Registering witness "XGT272up7iTGKArE" with recovery private WIF "#{recovery_wif}"...)
51
+ msg %(Signing keypair is #{signing_private} (private) and #{signing_public} (public)...)
52
+ response = rpc.call('network_broadcast_api.broadcast_transaction_synchronous', [signed])
53
+ puts "\n\n"
54
+ puts JSON.pretty_generate(response)
55
+
56
+ {
57
+ signing_private: signing_private,
58
+ signing_public: signing_public
59
+ }
60
+ end
61
+
62
+ witness_set_properties
Binary file
data/lib/xgt/ruby.rb ADDED
@@ -0,0 +1,200 @@
1
+ require 'securerandom'
2
+ require 'faraday'
3
+ require 'faraday_middleware'
4
+ require 'bitcoin'
5
+ require 'base58'
6
+ require 'time'
7
+ require 'xgt/ruby/version'
8
+
9
+ module Xgt
10
+ module Ruby
11
+ class Error < StandardError; end
12
+ class RpcError < Error
13
+ attr_reader :response
14
+ def initialize(msg, response)
15
+ super(msg)
16
+ @response = response
17
+ end
18
+ end
19
+
20
+ class Rpc
21
+ def initialize(url, client: nil)
22
+ @url = url
23
+ @client = client || Faraday::Connection.new(url: @url) do |faraday|
24
+ faraday.request(:json)
25
+ faraday.request :retry,
26
+ max: 10,
27
+ interval: 0.05,
28
+ interval_randomness: 0.5,
29
+ backoff_factor: 2,
30
+ # TODO: Make this more specific
31
+ exceptions: ['Error']
32
+ faraday.response(:json)
33
+ faraday.response(:logger) if ENV['LOGGING_ENABLED']
34
+ faraday.adapter(Faraday.default_adapter)
35
+ end
36
+ end
37
+
38
+ def call(mthd, params)
39
+ id = SecureRandom.hex(6).to_i(16)
40
+ payload = {
41
+ 'jsonrpc' => '2.0',
42
+ 'method' => mthd,
43
+ 'id' => id
44
+ }
45
+ payload['params'] = params unless params.nil?
46
+
47
+ response = @client.post('/', payload)
48
+
49
+ # TODO: Verify status code
50
+ unless response.body
51
+ raise RpcError.new(%(No response body!\n#{response.inspect}), response)
52
+ end
53
+
54
+ if response.body['error']
55
+ raise RpcError.new(%(Endpoint returned an error response!\n#{JSON.pretty_generate(response.body['error'])}), response)
56
+ end
57
+
58
+ unless response.body['result']
59
+ raise RpcError.new(%(No result in response body!\n#{response.inspect}), response)
60
+ end
61
+
62
+ # TODO: XXX: Breaking change!
63
+ response.body['result']
64
+ end
65
+
66
+ def broadcast_transaction(txn, wifs, chain_id)
67
+ signed = Xgt::Ruby::Auth.sign_transaction(self, txn, wifs, chain_id)
68
+ response = self.call('transaction_api.broadcast_transaction', [signed])
69
+ response['id']
70
+ end
71
+
72
+ def transaction_ready?(id)
73
+ begin
74
+ self.call('wallet_history_api.get_transaction', { 'id' => id })
75
+ true
76
+ rescue Xgt::Ruby::RpcError => e
77
+ message = e&.response
78
+ &.body
79
+ &.fetch('error', nil)
80
+ &.fetch('message', nil)
81
+ wait_regexps = Regexp.union(%r(transaction.*?>.*?trx_in_block))
82
+ raise e unless message.match(wait_regexps)
83
+ false
84
+ end
85
+ end
86
+ end
87
+
88
+ class Auth
89
+ def self.sign_transaction(rpc, txn, wifs, chain_id)
90
+ # Get the last irreversible block number
91
+ response = rpc.call('database_api.get_dynamic_global_properties', {})
92
+ chain_date = response['time'] + 'Z'
93
+ last_irreversible_block_num = response['last_irreversible_block_num']
94
+ ref_block_num = (last_irreversible_block_num - 1) & 0xffff
95
+ # Get ref block info to append to the transaction
96
+ response = rpc.call('block_api.get_block_header', { 'block_num' => last_irreversible_block_num })
97
+ header = response['header']
98
+ head_block_id = (header && header['previous']) ? header['previous'] : '0000000000000000000000000000000000000000'
99
+ ref_block_prefix = [head_block_id].pack('H*')[4...8].unpack('V').first
100
+ expiration = (Time.parse(chain_date) + 600).iso8601.gsub(/Z$/, '')
101
+ # Append ref block info to the transaction
102
+ txn['ref_block_num'] = ref_block_num
103
+ txn['ref_block_prefix'] = ref_block_prefix
104
+ txn['expiration'] = expiration
105
+ # Get a hex digest of the transactioon
106
+ response = rpc.call('transaction_api.get_transaction_hex', [txn])
107
+ transaction_hex = response[0..-3]
108
+ unhexed = unhexlify(chain_id + transaction_hex)
109
+ digest_hex = Digest::SHA256.hexdigest(unhexed)
110
+ private_keys = wifs.map { |wif| Bitcoin::Key.from_base58(wif) }
111
+ ec = Bitcoin::OpenSSL_EC
112
+ count = 0
113
+ sig = nil
114
+
115
+ # Calculate signatures and add them to the transaction
116
+ txn['signatures'] ||= []
117
+ private_keys.each do |private_key|
118
+ loop do
119
+ count += 1
120
+ # TODO: Periodically check that count doesn't spin out of control
121
+ public_key_hex = private_key.pub
122
+ digest = unhexlify(digest_hex)
123
+ sig = ec.sign_compact(digest, private_key.priv, public_key_hex, false)
124
+ next if public_key_hex != ec.recover_compact(digest, sig)
125
+ break if canonical?(sig)
126
+ end
127
+ txn['signatures'] << hexlify(sig)
128
+ end
129
+ txn
130
+ end
131
+
132
+ def self.random_wif()
133
+ private_key = unhexlify('80' + SecureRandom.hex(32))
134
+ checksum = Digest::SHA256.digest( Digest::SHA256.digest(private_key) ).byteslice(0, 4)
135
+ to_base_58(private_key + checksum)
136
+ end
137
+
138
+ def self.generate_wif(name, password, role)
139
+ brain_key = (name + role + password).strip.split(/[\t\n\v\f\r ]+/).join(' ')
140
+ key = "\x80".b + Digest::SHA256.digest(brain_key)
141
+ checksum = Digest::SHA256.digest(Digest::SHA256.digest(key))[0...4]
142
+ to_base_58(key + checksum)
143
+ end
144
+
145
+ def self.wif_to_public_key(wif, address_prefix)
146
+ private_wif = unhexlify(Bitcoin.decode_base58(wif))
147
+ version = private_wif[0]
148
+ checksum = private_wif[-4..-1]
149
+ # TODO: Verify version and checksum
150
+ private_key = private_wif[1...-4]
151
+ big_num = OpenSSL::BN.new(hexlify(private_key).to_i(16))
152
+ group = OpenSSL::PKey::EC::Group.new('secp256k1')
153
+ product = group.generator.mul(big_num).to_bn
154
+ public_key_buffer = OpenSSL::PKey::EC::Point.new(group, product).to_octet_string(:compressed)
155
+ checksum = Digest::RMD160.digest(public_key_buffer)
156
+ address_prefix + to_base_58(public_key_buffer + checksum[0...4])
157
+ end
158
+
159
+ def self.generate_wallet_name(*public_keys)
160
+ hashed = Digest::SHA256.hexdigest(public_keys.join(''))
161
+ base58 = Base58.binary_to_base58([hashed].pack('H*'), :bitcoin, true)
162
+ address_prefix = 'XGT'
163
+ "#{address_prefix}#{base58[0...40]}"
164
+ end
165
+
166
+ def self.to_base_58(bytes)
167
+ Bitcoin.encode_base58(hexlify(bytes))
168
+ end
169
+
170
+ def self.from_base_58(string)
171
+ unhexlify(Bitcoin.decode_base58(string))
172
+ end
173
+
174
+ def self.hexlify(s)
175
+ a = []
176
+ if s.respond_to?(:each_byte)
177
+ s.each_byte { |b| a << sprintf('%02X', b) }
178
+ else
179
+ s.each { |b| a << sprintf('%02X', b) }
180
+ end
181
+ a.join.downcase
182
+ end
183
+
184
+ def self.unhexlify(s)
185
+ s.split.pack('H*')
186
+ end
187
+
188
+ def self.canonical?(sig)
189
+ sig = sig.unpack('C*')
190
+
191
+ !(
192
+ ((sig[0] & 0x80 ) != 0) || ( sig[0] == 0 ) ||
193
+ ((sig[1] & 0x80 ) != 0) ||
194
+ ((sig[32] & 0x80 ) != 0) || ( sig[32] == 0 ) ||
195
+ ((sig[33] & 0x80 ) != 0)
196
+ )
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,5 @@
1
+ module Xgt
2
+ module Ruby
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
data/payloads.txt ADDED
@@ -0,0 +1,461 @@
1
+ {
2
+ "jsonrpc": "2.0",
3
+ "method": "database_api.find_accounts",
4
+ "params": {
5
+ "accounts": [
6
+ "foo45fb448c"
7
+ ]
8
+ },
9
+ "id": 18466466518669
10
+ }
11
+ {
12
+ "jsonrpc": "2.0",
13
+ "result": {
14
+ "accounts": [
15
+ {
16
+ "id": 13,
17
+ "name": "foo45fb448c",
18
+ "owner": {
19
+ "weight_threshold": 1,
20
+ "account_auths": [
21
+
22
+ ],
23
+ "key_auths": [
24
+ [
25
+ "TST7xue5ESY1xHhDZj6dw2igXCwoHobA3cnxffacvp4XMzwfzLZu4",
26
+ 1
27
+ ]
28
+ ]
29
+ },
30
+ "active": {
31
+ "weight_threshold": 1,
32
+ "account_auths": [
33
+
34
+ ],
35
+ "key_auths": [
36
+ [
37
+ "TST6Yp3zeaYNU7XJF2MxoHhDcWT4vGgVkzTLEvhMY6g5tvmwzn3tN",
38
+ 1
39
+ ]
40
+ ]
41
+ },
42
+ "posting": {
43
+ "weight_threshold": 1,
44
+ "account_auths": [
45
+
46
+ ],
47
+ "key_auths": [
48
+ [
49
+ "TST5Q7ZdopjQWZMwiyZk11W5Yhvsfu1PG3f4qsQN58A7XfHP34Hig",
50
+ 1
51
+ ]
52
+ ]
53
+ },
54
+ "memo_key": "TST5u69JnHZ3oznnwn71J6VA4r5oVJX6Xu3dpbFVoHpJoZXnbDfaW",
55
+ "json_metadata": "",
56
+ "proxy": "",
57
+ "last_owner_update": "1970-01-01T00:00:00",
58
+ "last_account_update": "1970-01-01T00:00:00",
59
+ "created": "2019-04-24T06:44:48",
60
+ "mined": false,
61
+ "recovery_account": "initminer",
62
+ "last_account_recovery": "1970-01-01T00:00:00",
63
+ "reset_account": "null",
64
+ "comment_count": 0,
65
+ "lifetime_vote_count": 0,
66
+ "post_count": 0,
67
+ "can_vote": true,
68
+ "voting_manabar": {
69
+ "current_mana": 0,
70
+ "last_update_time": 1556088288
71
+ },
72
+ "balance": {
73
+ "amount": "0",
74
+ "precision": 3,
75
+ "nai": "@@000000021"
76
+ },
77
+ "savings_balance": {
78
+ "amount": "0",
79
+ "precision": 3,
80
+ "nai": "@@000000021"
81
+ },
82
+ "sbd_balance": {
83
+ "amount": "0",
84
+ "precision": 3,
85
+ "nai": "@@000000013"
86
+ },
87
+ "sbd_seconds": "0",
88
+ "sbd_seconds_last_update": "1970-01-01T00:00:00",
89
+ "sbd_last_interest_payment": "1970-01-01T00:00:00",
90
+ "savings_sbd_balance": {
91
+ "amount": "0",
92
+ "precision": 3,
93
+ "nai": "@@000000013"
94
+ },
95
+ "savings_sbd_seconds": "0",
96
+ "savings_sbd_seconds_last_update": "1970-01-01T00:00:00",
97
+ "savings_sbd_last_interest_payment": "1970-01-01T00:00:00",
98
+ "savings_withdraw_requests": 0,
99
+ "reward_sbd_balance": {
100
+ "amount": "0",
101
+ "precision": 3,
102
+ "nai": "@@000000013"
103
+ },
104
+ "reward_steem_balance": {
105
+ "amount": "0",
106
+ "precision": 3,
107
+ "nai": "@@000000021"
108
+ },
109
+ "reward_vesting_balance": {
110
+ "amount": "0",
111
+ "precision": 6,
112
+ "nai": "@@000000037"
113
+ },
114
+ "reward_vesting_steem": {
115
+ "amount": "0",
116
+ "precision": 3,
117
+ "nai": "@@000000021"
118
+ },
119
+ "vesting_shares": {
120
+ "amount": "0",
121
+ "precision": 6,
122
+ "nai": "@@000000037"
123
+ },
124
+ "delegated_vesting_shares": {
125
+ "amount": "0",
126
+ "precision": 6,
127
+ "nai": "@@000000037"
128
+ },
129
+ "received_vesting_shares": {
130
+ "amount": "0",
131
+ "precision": 6,
132
+ "nai": "@@000000037"
133
+ },
134
+ "vesting_withdraw_rate": {
135
+ "amount": "0",
136
+ "precision": 6,
137
+ "nai": "@@000000037"
138
+ },
139
+ "next_vesting_withdrawal": "1969-12-31T23:59:59",
140
+ "withdrawn": 0,
141
+ "to_withdraw": 0,
142
+ "withdraw_routes": 0,
143
+ "curation_rewards": 0,
144
+ "posting_rewards": 0,
145
+ "proxied_vsf_votes": [
146
+ 0,
147
+ 0,
148
+ 0,
149
+ 0
150
+ ],
151
+ "witnesses_voted_for": 0,
152
+ "last_post": "1970-01-01T00:00:00",
153
+ "last_root_post": "1970-01-01T00:00:00",
154
+ "last_vote_time": "1970-01-01T00:00:00",
155
+ "post_bandwidth": 0,
156
+ "pending_claimed_accounts": 0,
157
+ "is_smt": false
158
+ }
159
+ ]
160
+ },
161
+ "id": "7133625920894"
162
+ }
163
+ {
164
+ "jsonrpc": "2.0",
165
+ "method": "database_api.get_dynamic_global_properties",
166
+ "params": {
167
+ },
168
+ "id": 275146661212172
169
+ }
170
+ {
171
+ "jsonrpc": "2.0",
172
+ "id": 275146661212172,
173
+ "result": {
174
+ "time": "2019-04-30T00:34:12",
175
+ "last_irreversible_block_num": 32482872
176
+ }
177
+ }
178
+ {
179
+ "jsonrpc": "2.0",
180
+ "method": "block_api.get_block_header",
181
+ "params": {
182
+ "block_num": 32482872
183
+ },
184
+ "id": 249008441062077
185
+ }
186
+ {
187
+ "jsonrpc": "2.0",
188
+ "id": 249008441062077,
189
+ "result": {
190
+ "header": {
191
+ "previous": "01efa63783c4180b05e39fa94dde4febca9cc91d"
192
+ }
193
+ }
194
+ }
195
+ {
196
+ "jsonrpc": "2.0",
197
+ "method": "network_broadcast_api.get_transaction_hex",
198
+ "params": [
199
+ {
200
+ "extensions": [
201
+
202
+ ],
203
+ "operations": [
204
+ [
205
+ "account_create",
206
+ {
207
+ "fee": "0.000 TESTS",
208
+ "creator": "initminer",
209
+ "new_account_name": "foo41700a44",
210
+ "owner": {
211
+ "weight_threshold": 1,
212
+ "account_auths": [
213
+
214
+ ],
215
+ "key_auths": [
216
+ [
217
+ "TST7xue5ESY1xHhDZj6dw2igXCwoHobA3cnxffacvp4XMzwfzLZu4",
218
+ 1
219
+ ]
220
+ ]
221
+ },
222
+ "active": {
223
+ "weight_threshold": 1,
224
+ "account_auths": [
225
+
226
+ ],
227
+ "key_auths": [
228
+ [
229
+ "TST6Yp3zeaYNU7XJF2MxoHhDcWT4vGgVkzTLEvhMY6g5tvmwzn3tN",
230
+ 1
231
+ ]
232
+ ]
233
+ },
234
+ "posting": {
235
+ "weight_threshold": 1,
236
+ "account_auths": [
237
+
238
+ ],
239
+ "key_auths": [
240
+ [
241
+ "TST5Q7ZdopjQWZMwiyZk11W5Yhvsfu1PG3f4qsQN58A7XfHP34Hig",
242
+ 1
243
+ ]
244
+ ]
245
+ },
246
+ "memo_key": "TST5u69JnHZ3oznnwn71J6VA4r5oVJX6Xu3dpbFVoHpJoZXnbDfaW",
247
+ "json_metadata": "",
248
+ "extensions": [
249
+
250
+ ]
251
+ }
252
+ ]
253
+ ],
254
+ "ref_block_num": 42551,
255
+ "ref_block_prefix": 186172547,
256
+ "expiration": "2019-04-30T00:44:12"
257
+ }
258
+ ],
259
+ "id": 116156454840173
260
+ }
261
+ {
262
+ "jsonrpc": "2.0",
263
+ "id": 116156454840173,
264
+ "result": "37a683c4180b5c9ac75c01090000000000000000035445535453000009696e69746d696e65720b666f6f343137303061343401000000000103951f1e294b4f9e535708bcfa85d8d21240bda7585424b2e6fa0d0f1e9a756e8c010001000000000102dab63701259352fa01048a97ac76d44def848552518c7991e4bb2feb893e6eef0100010000000001024343ff4fcd3a2ddfbb53fbd178b09ed02c457dbd88d1ff2f49ce967d7c3f5637010002850edf288f0e9fdc4bf83839d352d3b9e65bdefb309147ad3642b4a63e0a6c660000ff"
265
+ }
266
+ {
267
+ "jsonrpc": "2.0",
268
+ "method": "condenser_api.get_chain_properties",
269
+ "params": [
270
+
271
+ ],
272
+ "id": 113281388192823
273
+ }
274
+ {
275
+ "jsonrpc": "2.0",
276
+ "error": {
277
+ "code": -32002,
278
+ "message": "Assert Exception:method_itr != api_itr->second.end(): Could not find method get_chain_properties",
279
+ "data": {
280
+ "code": 10,
281
+ "name": "assert_exception",
282
+ "message": "Assert Exception",
283
+ "stack": [
284
+ {
285
+ "context": {
286
+ "level": "error",
287
+ "file": "json_rpc_plugin.cpp",
288
+ "line": 209,
289
+ "method": "find_api_method",
290
+ "hostname": "",
291
+ "timestamp": "2020-04-01T19:44:15"
292
+ },
293
+ "format": "method_itr != api_itr->second.end(): Could not find method ${method}",
294
+ "data": {
295
+ "method": "get_chain_properties"
296
+ }
297
+ }
298
+ ]
299
+ }
300
+ },
301
+ "id": "113281388192823"
302
+ }
303
+ {
304
+ "jsonrpc": "2.0",
305
+ "method": "condenser_api.get_chain_properties",
306
+ "params": [
307
+
308
+ ],
309
+ "id": 197736107532241
310
+ }
311
+ {
312
+ "jsonrpc": "2.0",
313
+ "method": "condenser_api.get_chain_properties",
314
+ "params": [
315
+
316
+ ],
317
+ "id": 168893335992264
318
+ }
319
+ {
320
+ "jsonrpc": "2.0",
321
+ "method": "condenser_api.get_chain_properties",
322
+ "params": [
323
+
324
+ ],
325
+ "id": 159203180196081
326
+ }
327
+ {
328
+ "jsonrpc": "2.0",
329
+ "method": "condenser_api.get_chain_properties",
330
+ "params": [
331
+
332
+ ],
333
+ "id": 162443573580019
334
+ }
335
+ {
336
+ "jsonrpc": "2.0",
337
+ "method": "condenser_api.get_chain_properties",
338
+ "params": [
339
+
340
+ ],
341
+ "id": 265628521302471
342
+ }
343
+ {
344
+ "jsonrpc": "2.0",
345
+ "method": "condenser_api.get_chain_properties",
346
+ "params": [
347
+
348
+ ],
349
+ "id": 23335772442202
350
+ }
351
+ {
352
+ "jsonrpc": "2.0",
353
+ "method": "condenser_api.get_chain_properties",
354
+ "params": [
355
+
356
+ ],
357
+ "id": 189541321007961
358
+ }
359
+ {
360
+ "jsonrpc": "2.0",
361
+ "error": {
362
+ "code": -32002,
363
+ "message": "Assert Exception:method_itr != api_itr->second.end(): Could not find method get_chain_properties",
364
+ "data": {
365
+ "code": 10,
366
+ "name": "assert_exception",
367
+ "message": "Assert Exception",
368
+ "stack": [
369
+ {
370
+ "context": {
371
+ "level": "error",
372
+ "file": "json_rpc_plugin.cpp",
373
+ "line": 209,
374
+ "method": "find_api_method",
375
+ "hostname": "",
376
+ "timestamp": "2020-04-03T22:18:41"
377
+ },
378
+ "format": "method_itr != api_itr->second.end(): Could not find method ${method}",
379
+ "data": {
380
+ "method": "get_chain_properties"
381
+ }
382
+ }
383
+ ]
384
+ }
385
+ },
386
+ "id": "189541321007961"
387
+ }
388
+ {
389
+ "jsonrpc": "2.0",
390
+ "method": "condenser_api.get_chain_properties",
391
+ "params": [
392
+
393
+ ],
394
+ "id": 251458499472850
395
+ }
396
+ {
397
+ "jsonrpc": "2.0",
398
+ "error": {
399
+ "code": -32002,
400
+ "message": "Assert Exception:method_itr != api_itr->second.end(): Could not find method get_chain_properties",
401
+ "data": {
402
+ "code": 10,
403
+ "name": "assert_exception",
404
+ "message": "Assert Exception",
405
+ "stack": [
406
+ {
407
+ "context": {
408
+ "level": "error",
409
+ "file": "json_rpc_plugin.cpp",
410
+ "line": 209,
411
+ "method": "find_api_method",
412
+ "hostname": "",
413
+ "timestamp": "2020-04-03T22:50:20"
414
+ },
415
+ "format": "method_itr != api_itr->second.end(): Could not find method ${method}",
416
+ "data": {
417
+ "method": "get_chain_properties"
418
+ }
419
+ }
420
+ ]
421
+ }
422
+ },
423
+ "id": "251458499472850"
424
+ }
425
+ {
426
+ "jsonrpc": "2.0",
427
+ "method": "condenser_api.get_chain_properties",
428
+ "params": [
429
+
430
+ ],
431
+ "id": 66742030768951
432
+ }
433
+ {
434
+ "jsonrpc": "2.0",
435
+ "error": {
436
+ "code": -32002,
437
+ "message": "Assert Exception:method_itr != api_itr->second.end(): Could not find method get_chain_properties",
438
+ "data": {
439
+ "code": 10,
440
+ "name": "assert_exception",
441
+ "message": "Assert Exception",
442
+ "stack": [
443
+ {
444
+ "context": {
445
+ "level": "error",
446
+ "file": "json_rpc_plugin.cpp",
447
+ "line": 209,
448
+ "method": "find_api_method",
449
+ "hostname": "",
450
+ "timestamp": "2020-04-03T23:02:56"
451
+ },
452
+ "format": "method_itr != api_itr->second.end(): Could not find method ${method}",
453
+ "data": {
454
+ "method": "get_chain_properties"
455
+ }
456
+ }
457
+ ]
458
+ }
459
+ },
460
+ "id": "66742030768951"
461
+ }