tezos_client 0.3.9 → 0.4.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.
- 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
|