tezos_client 0.3.9 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -4
- data/Gemfile.lock +1 -1
- data/lib/tezos_client.rb +19 -10
- data/lib/tezos_client/exceptions.rb +92 -0
- data/lib/tezos_client/liquidity_interface.rb +4 -2
- data/lib/tezos_client/logger.rb +22 -0
- data/lib/tezos_client/operation_mgr.rb +178 -0
- data/lib/tezos_client/operations/activate_account_operation.rb +9 -27
- data/lib/tezos_client/operations/operation.rb +33 -0
- data/lib/tezos_client/operations/operation_array.rb +35 -0
- data/lib/tezos_client/operations/origination_operation.rb +13 -44
- data/lib/tezos_client/operations/reveal_operation.rb +3 -22
- data/lib/tezos_client/operations/transaction_operation.rb +21 -24
- data/lib/tezos_client/operations/transactions_operation.rb +24 -22
- data/lib/tezos_client/rpc_interface.rb +2 -0
- data/lib/tezos_client/rpc_interface/helper.rb +29 -85
- data/lib/tezos_client/rpc_interface/operations.rb +44 -0
- data/lib/tezos_client/rpc_interface/request_manager.rb +23 -5
- data/lib/tezos_client/version.rb +1 -1
- data/travis-scripts/install-liquidity.sh +2 -10
- data/travis-scripts/install-opam.sh +11 -3
- data/travis-scripts/prepare-ubuntu.sh +14 -0
- metadata +8 -4
- data/lib/tezos_client/operation.rb +0 -159
- data/travis-scripts/prepare-trusty.sh +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 725a3f4be32e4f23f291c0abb15ad9671bff432a3b00f4f149fbad9c8cadf007
|
4
|
+
data.tar.gz: 21864905eeb5b701357551ee410c88f2e24832b31f53a1d811b0025f6410248d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 810cdd1ea762452c662bac91752c53b60756ad780989c58fa488fcb056d9907b4ac76e37907bbdb0fe7e40398badf686aa8f229033b5c53ec7a27bf07c389b9e
|
7
|
+
data.tar.gz: 39b1a9bfefda07893cab407b5abdd9835603473098e6db4828847c9265358b11833e3ed160c91db6f50d0f6d52a659f38242d243a1cbc2ea112f0fccab71683e
|
data/.travis.yml
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
---
|
2
|
-
dist:
|
2
|
+
dist: xenial
|
3
|
+
language: ruby
|
3
4
|
sudo: required
|
4
|
-
#language: ruby
|
5
|
-
language: ocaml
|
6
5
|
cache:
|
7
6
|
bundler: true
|
8
7
|
directories:
|
@@ -13,9 +12,11 @@ rvm:
|
|
13
12
|
env:
|
14
13
|
- OPAMYES=1
|
15
14
|
before_install:
|
16
|
-
- sh travis-scripts/prepare-
|
15
|
+
- sh travis-scripts/prepare-ubuntu.sh
|
17
16
|
- sh travis-scripts/install-opam.sh
|
18
17
|
- sh travis-scripts/install-liquidity.sh
|
19
18
|
- gem install bundler -v 1.16.3
|
20
19
|
script:
|
20
|
+
- eval `opam config env`
|
21
|
+
- bundle install
|
21
22
|
- bundle exec rake
|
data/Gemfile.lock
CHANGED
data/lib/tezos_client.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "pp"
|
4
4
|
require "active_support/core_ext/hash/indifferent_access"
|
5
5
|
require "active_support/core_ext/string/inflections"
|
6
|
+
require "active_support/core_ext/module/delegation"
|
6
7
|
require "timeout"
|
7
8
|
|
8
9
|
require "tezos_client/version"
|
@@ -11,13 +12,16 @@ require "tezos_client/currency_utils"
|
|
11
12
|
require "tezos_client/crypto"
|
12
13
|
require "tezos_client/commands"
|
13
14
|
require "tezos_client/logger"
|
15
|
+
require "tezos_client/exceptions"
|
14
16
|
require "tezos_client/encode_utils"
|
15
|
-
require "tezos_client/
|
17
|
+
require "tezos_client/operation_mgr"
|
18
|
+
require "tezos_client/operations/operation"
|
16
19
|
require "tezos_client/operations/origination_operation"
|
17
20
|
require "tezos_client/operations/transaction_operation"
|
18
21
|
require "tezos_client/operations/transactions_operation"
|
19
22
|
require "tezos_client/operations/activate_account_operation"
|
20
23
|
require "tezos_client/operations/reveal_operation"
|
24
|
+
require "tezos_client/operations/operation_array"
|
21
25
|
|
22
26
|
require "tezos_client/client_interface"
|
23
27
|
require "tezos_client/rpc_interface"
|
@@ -72,17 +76,26 @@ class TezosClient
|
|
72
76
|
#
|
73
77
|
# @return [Hash] result of the origination containing :operation_id, :operation_result and :originated_contract
|
74
78
|
#
|
75
|
-
def originate_contract(from:, amount:, secret_key:, **args)
|
76
|
-
|
77
|
-
liquidity_interface: liquidity_interface,
|
79
|
+
def originate_contract(from:, amount:, secret_key:, script: nil, init_params: nil, **args)
|
80
|
+
origination_args = {
|
78
81
|
rpc_interface: rpc_interface,
|
79
82
|
from: from,
|
80
83
|
secret_key: secret_key,
|
81
84
|
amount: amount,
|
82
85
|
**args
|
83
|
-
|
86
|
+
}
|
87
|
+
|
88
|
+
if script != nil
|
89
|
+
origination_args[:script] = liquidity_interface.origination_script(
|
90
|
+
from: from,
|
91
|
+
script: script,
|
92
|
+
init_params: init_params
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
res = OriginationOperation.new(origination_args).test_and_broadcast
|
84
97
|
|
85
|
-
res.merge(originated_contract: res[:
|
98
|
+
res.merge(originated_contract: res[:operations_result][0][:originated_contracts][0])
|
86
99
|
end
|
87
100
|
|
88
101
|
# Transfer funds to an account
|
@@ -97,7 +110,6 @@ class TezosClient
|
|
97
110
|
#
|
98
111
|
def transfer(from:, amount:, to:, secret_key:, **args)
|
99
112
|
TransactionOperation.new(
|
100
|
-
liquidity_interface: liquidity_interface,
|
101
113
|
rpc_interface: rpc_interface,
|
102
114
|
from: from,
|
103
115
|
to: to,
|
@@ -109,7 +121,6 @@ class TezosClient
|
|
109
121
|
|
110
122
|
def activate_account(pkh:, secret:, **args)
|
111
123
|
ActivateAccountOperation.new(
|
112
|
-
liquidity_interface: liquidity_interface,
|
113
124
|
rpc_interface: rpc_interface,
|
114
125
|
pkh: pkh,
|
115
126
|
secret: secret,
|
@@ -119,7 +130,6 @@ class TezosClient
|
|
119
130
|
|
120
131
|
def transfer_to_many(from:, amounts:, secret_key:, **args)
|
121
132
|
TransactionsOperation.new(
|
122
|
-
liquidity_interface: liquidity_interface,
|
123
133
|
rpc_interface: rpc_interface,
|
124
134
|
from: from,
|
125
135
|
amounts: amounts,
|
@@ -129,7 +139,6 @@ class TezosClient
|
|
129
139
|
end
|
130
140
|
|
131
141
|
def reveal_pubkey(secret_key:, **args)
|
132
|
-
|
133
142
|
public_key = secret_key_to_public_key(secret_key)
|
134
143
|
from = public_key_to_address(public_key)
|
135
144
|
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TezosClient
|
4
|
+
class RpcRequestFailure < Exception
|
5
|
+
include Logger
|
6
|
+
|
7
|
+
attr_reader :status_code
|
8
|
+
attr_reader :error
|
9
|
+
attr_reader :formatted_response
|
10
|
+
|
11
|
+
def initialize(error:, url:, status_code:)
|
12
|
+
@status_code = status_code
|
13
|
+
@error = error
|
14
|
+
@formatted_response = formatted_response
|
15
|
+
|
16
|
+
if @message.nil?
|
17
|
+
@message = "#{url} failed with status #{status_code}:\n #{tezos_contents_log(formatted_response)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
super @message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class InvalidActivation < RpcRequestFailure
|
25
|
+
attr_reader :pkh
|
26
|
+
|
27
|
+
def initialize(error:, **_args)
|
28
|
+
@pkh = error[:pkh]
|
29
|
+
@message = "Invalid activation (pkh: #{pkh})"
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class OperationFailure < Exception
|
35
|
+
include Logger
|
36
|
+
|
37
|
+
attr_reader :metadata
|
38
|
+
attr_reader :errors
|
39
|
+
attr_reader :status
|
40
|
+
attr_reader :message
|
41
|
+
|
42
|
+
def initialize(metadata:, errors:, status:)
|
43
|
+
@metadata = metadata
|
44
|
+
@errors = errors
|
45
|
+
@status = status
|
46
|
+
|
47
|
+
error = errors[0]
|
48
|
+
|
49
|
+
if @message.nil?
|
50
|
+
@message = "failure #{status}: #{tezos_contents_log(error).pretty_inspect}"
|
51
|
+
end
|
52
|
+
|
53
|
+
super(message)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class TezBalanceTooLow < OperationFailure
|
58
|
+
attr_reader :contract
|
59
|
+
attr_reader :balance
|
60
|
+
attr_reader :amount
|
61
|
+
|
62
|
+
def initialize(metadata:, errors:, status:)
|
63
|
+
error = errors[0]
|
64
|
+
@contract = error[:contract]
|
65
|
+
@balance = error[:balance]
|
66
|
+
@amount = error[:amount]
|
67
|
+
|
68
|
+
@message = "Tezos balance too low for address #{contract} (balance: #{balance}, amount #{amount})"
|
69
|
+
|
70
|
+
super
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class ScriptRuntimeError < OperationFailure
|
75
|
+
attr_reader :location
|
76
|
+
attr_reader :with
|
77
|
+
attr_reader :contract
|
78
|
+
|
79
|
+
def initialize(metadata:, errors:, status:)
|
80
|
+
error = errors[0]
|
81
|
+
rejection_error = errors.detect { |error| error[:id] == "proto.003-PsddFKi3.scriptRejectedRuntimeError" }
|
82
|
+
|
83
|
+
@location = rejection_error[:location]
|
84
|
+
@contract = error[:contractHandle]
|
85
|
+
@with = rejection_error[:with]
|
86
|
+
@message = "Script runtime Error when executing #{contract}: #{with} (location: #{location})"
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
@@ -57,8 +57,10 @@ class TezosClient
|
|
57
57
|
|
58
58
|
def json_scripts(args)
|
59
59
|
with_file_copy(args[:script]) do |script_copy_path|
|
60
|
-
|
61
|
-
|
60
|
+
script_basename = script_copy_path.sub(/.liq$/, "")
|
61
|
+
|
62
|
+
json_init_script_path = "#{script_basename}.initializer.tz.json"
|
63
|
+
json_contract_script_path = "#{script_basename}.tz.json"
|
62
64
|
|
63
65
|
call_liquidity "--json #{script_copy_path}"
|
64
66
|
|
data/lib/tezos_client/logger.rb
CHANGED
@@ -12,6 +12,28 @@ class TezosClient
|
|
12
12
|
self.class.logger << out + "\n"
|
13
13
|
end
|
14
14
|
|
15
|
+
FILTERED_KEYS = [:code, :contractCode]
|
16
|
+
def tezos_contents_log_filter(content)
|
17
|
+
if content.is_a? Array
|
18
|
+
content.map { |el| tezos_contents_log_filter(el) }
|
19
|
+
elsif content.is_a? Hash
|
20
|
+
content.reduce({}) do |h, (k, v)|
|
21
|
+
value = if FILTERED_KEYS.include? k.to_sym
|
22
|
+
"#{v.to_s[0..30]}..."
|
23
|
+
else
|
24
|
+
tezos_contents_log_filter(v)
|
25
|
+
end
|
26
|
+
h.merge(k => value)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
content
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def tezos_contents_log(content)
|
34
|
+
tezos_contents_log_filter(content).pretty_inspect
|
35
|
+
end
|
36
|
+
|
15
37
|
class_methods do
|
16
38
|
# Setup the log for TezosClient calls.
|
17
39
|
# Value should be a logger but can can be stdout, stderr, or a filename.
|
@@ -0,0 +1,178 @@
|
|
1
|
+
|
2
|
+
class TezosClient
|
3
|
+
|
4
|
+
class OperationMgr
|
5
|
+
include Crypto
|
6
|
+
using CurrencyUtils
|
7
|
+
|
8
|
+
attr_accessor :rpc_interface,
|
9
|
+
:rpc_operation_args
|
10
|
+
|
11
|
+
def initialize(rpc_interface:, rpc_operation_args:, **args)
|
12
|
+
@rpc_interface = rpc_interface
|
13
|
+
@secret_key = args.fetch(:secret_key)
|
14
|
+
@multiple_operations = rpc_operation_args.is_a?(Array)
|
15
|
+
@rpc_operation_args = @multiple_operations ? rpc_operation_args : [rpc_operation_args]
|
16
|
+
@signed_operation_args_h = nil
|
17
|
+
@branch = args[:branch]
|
18
|
+
@protocol = args[:protocol]
|
19
|
+
end
|
20
|
+
|
21
|
+
def multiple_operations?
|
22
|
+
@multiple_operations
|
23
|
+
end
|
24
|
+
|
25
|
+
def single_operation?
|
26
|
+
!multiple_operations?
|
27
|
+
end
|
28
|
+
|
29
|
+
def branch
|
30
|
+
@branch ||= rpc_interface.head_hash
|
31
|
+
end
|
32
|
+
|
33
|
+
def protocol
|
34
|
+
@protocol ||= rpc_interface.protocol
|
35
|
+
end
|
36
|
+
|
37
|
+
def simulate_and_update_limits
|
38
|
+
run_result = run
|
39
|
+
|
40
|
+
run_result[:operations_result].zip(rpc_operation_args) do |operation_result, rpc_operation_args|
|
41
|
+
if rpc_operation_args.key?(:gas_limit)
|
42
|
+
rpc_operation_args[:gas_limit] = (operation_result[:consumed_gas].to_i + 0.001.to_satoshi).to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
run_result
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_hex
|
50
|
+
rpc_interface.forge_operations(operations: rpc_operation_args, branch: branch)
|
51
|
+
end
|
52
|
+
|
53
|
+
def sign
|
54
|
+
sign_operation(
|
55
|
+
secret_key: @secret_key,
|
56
|
+
operation_hex: to_hex
|
57
|
+
) do |base_58_signature, signed_hex, _op_id|
|
58
|
+
@signed_operation_args_h = rpc_operation_args.hash
|
59
|
+
@base_58_signature = base_58_signature
|
60
|
+
@signed_hex = signed_hex
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def signed?
|
65
|
+
@signed_operation_args_h == rpc_operation_args.hash
|
66
|
+
end
|
67
|
+
|
68
|
+
def base_58_signature
|
69
|
+
sign unless signed?
|
70
|
+
@base_58_signature
|
71
|
+
end
|
72
|
+
|
73
|
+
def signed_hex
|
74
|
+
sign unless signed?
|
75
|
+
@signed_hex
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_and_broadcast
|
79
|
+
# simulate operations and adjust gas limits
|
80
|
+
simulate_and_update_limits
|
81
|
+
operations_result = preapply
|
82
|
+
|
83
|
+
op_id = broadcast
|
84
|
+
{
|
85
|
+
operation_id: op_id,
|
86
|
+
operations_result: operations_result,
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def run
|
91
|
+
rpc_responses = rpc_interface.run_operations(
|
92
|
+
operations: rpc_operation_args,
|
93
|
+
signature: base_58_signature,
|
94
|
+
branch: branch)
|
95
|
+
|
96
|
+
consumed_storage = 0
|
97
|
+
consumed_gas = 0
|
98
|
+
|
99
|
+
operations_result = rpc_responses.map do |rpc_response|
|
100
|
+
metadata = rpc_response[:metadata]
|
101
|
+
ensure_applied!(metadata)
|
102
|
+
consumed_storage += compute_consumed_storage(metadata)
|
103
|
+
consumed_gas += compute_consumed_gas(metadata)
|
104
|
+
metadata[:operation_result]
|
105
|
+
end
|
106
|
+
|
107
|
+
{
|
108
|
+
status: :applied,
|
109
|
+
consumed_gas: consumed_gas,
|
110
|
+
consumed_storage: consumed_storage,
|
111
|
+
operations_result: operations_result
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def compute_consumed_gas(metadata)
|
116
|
+
consumed_gas = (metadata.dig(:operation_result, :consumed_gas) || "0").to_i.from_satoshi
|
117
|
+
|
118
|
+
if metadata.key?(:internal_operation_results)
|
119
|
+
metadata[:internal_operation_results].each do |internal_operation_result|
|
120
|
+
consumed_gas += (internal_operation_result[:result][:consumed_gas] || "0").to_i.from_satoshi
|
121
|
+
end
|
122
|
+
end
|
123
|
+
consumed_gas
|
124
|
+
end
|
125
|
+
|
126
|
+
def compute_consumed_storage(metadata)
|
127
|
+
(metadata.dig(:operation_result, :paid_storage_size_diff) || "0").to_i.from_satoshi
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def preapply
|
132
|
+
rpc_responses = rpc_interface.preapply_operations(
|
133
|
+
operations: rpc_operation_args,
|
134
|
+
signature: base_58_signature,
|
135
|
+
protocol: protocol,
|
136
|
+
branch: branch)
|
137
|
+
|
138
|
+
rpc_responses.map do |rpc_response|
|
139
|
+
ensure_applied!(rpc_response[:metadata])
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def broadcast
|
144
|
+
rpc_interface.broadcast_operation(signed_hex)
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def ensure_applied!(metadata)
|
150
|
+
operation_result = metadata[:operation_result]
|
151
|
+
|
152
|
+
unless operation_result.nil?
|
153
|
+
status = operation_result[:status]
|
154
|
+
if status != "applied"
|
155
|
+
failed!(status, operation_result[:errors], metadata)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
operation_result
|
160
|
+
end
|
161
|
+
|
162
|
+
def exception_klass(errors)
|
163
|
+
error = errors[0]
|
164
|
+
case error[:id]
|
165
|
+
when "proto.003-PsddFKi3.contract.balance_too_low"
|
166
|
+
TezBalanceTooLow
|
167
|
+
when "proto.003-PsddFKi3.scriptRuntimeError"
|
168
|
+
ScriptRuntimeError
|
169
|
+
else
|
170
|
+
OperationFailure
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def failed!(status, errors, metadata)
|
175
|
+
raise exception_klass(errors).new(metadata: metadata, errors: errors, status: status)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|