line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::Ethereum; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
55881
|
use 5.020000; |
|
1
|
|
|
|
|
3
|
|
4
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
26
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
20
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
372
|
use HTTP::Request; |
|
1
|
|
|
|
|
17952
|
|
|
1
|
|
|
|
|
27
|
|
8
|
1
|
|
|
1
|
|
583
|
use LWP::UserAgent; |
|
1
|
|
|
|
|
20477
|
|
|
1
|
|
|
|
|
30
|
|
9
|
1
|
|
|
1
|
|
550
|
use JSON; |
|
1
|
|
|
|
|
7931
|
|
|
1
|
|
|
|
|
4
|
|
10
|
1
|
|
|
1
|
|
994
|
use Math::BigInt; |
|
1
|
|
|
|
|
19559
|
|
|
1
|
|
|
|
|
6
|
|
11
|
1
|
|
|
1
|
|
18882
|
use Math::BigFloat; |
|
1
|
|
|
|
|
21091
|
|
|
1
|
|
|
|
|
18
|
|
12
|
1
|
|
|
1
|
|
941
|
use File::Slurper 'read_text'; |
|
1
|
|
|
|
|
10555
|
|
|
1
|
|
|
|
|
3931
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = '0.30'; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=pod |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=encoding utf8 |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 NAME |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Net::Ethereum - Perl Framework for Ethereum JSON RPC API. |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 SYNOPSIS |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# Deploy contract |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
use Net::Ethereum; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $contract_name = $ARGV[0]; |
32
|
|
|
|
|
|
|
my $password = $ARGV[1]; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $node = Net::Ethereum->new('http://localhost:8545/'); |
35
|
|
|
|
|
|
|
$node->set_debug_mode(0); |
36
|
|
|
|
|
|
|
$node->set_show_progress(1); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# my $src_account = "0x0f687ab2be314d311a714adde92fd9055df18b48"; |
39
|
|
|
|
|
|
|
my $src_account = $node->eth_accounts()->[0]; |
40
|
|
|
|
|
|
|
print 'My account: '.$src_account, "\n"; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my $constructor_params={}; |
43
|
|
|
|
|
|
|
$constructor_params->{ initString } = '+ Init string for constructor +'; |
44
|
|
|
|
|
|
|
$constructor_params->{ initValue } = 102; # init value for constructor |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
my $contract_status = $node->compile_and_deploy_contract($contract_name, $constructor_params, $src_account, $password); |
47
|
|
|
|
|
|
|
my $new_contract_id = $contract_status->{contractAddress}; |
48
|
|
|
|
|
|
|
my $transactionHash = $contract_status->{transactionHash}; |
49
|
|
|
|
|
|
|
my $gas_used = hex($contract_status->{gasUsed}); |
50
|
|
|
|
|
|
|
print "\n", 'Contract mined.', "\n", 'Address: '.$new_contract_id, "\n", 'Transaction Hash: '.$transactionHash, "\n"; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
my $gas_price=$node->eth_gasPrice(); |
53
|
|
|
|
|
|
|
my $contract_deploy_price = $gas_used * $gas_price; |
54
|
|
|
|
|
|
|
my $price_in_eth = $node->wei2ether($contract_deploy_price); |
55
|
|
|
|
|
|
|
print 'Gas used: '.$gas_used.' ('.sprintf('0x%x', $gas_used).') wei, '.$price_in_eth.' ether', "\n\n"; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# Contract sample |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
pragma solidity ^0.4.10; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
contract HelloSol { |
63
|
|
|
|
|
|
|
string savedString; |
64
|
|
|
|
|
|
|
uint savedValue; |
65
|
|
|
|
|
|
|
address contractOwner; |
66
|
|
|
|
|
|
|
function HelloSol(uint initValue, string initString) public { |
67
|
|
|
|
|
|
|
contractOwner = msg.sender; |
68
|
|
|
|
|
|
|
savedString = initString; |
69
|
|
|
|
|
|
|
savedValue = initValue; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
function setString( string newString ) public { |
72
|
|
|
|
|
|
|
savedString = newString; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
function getString() public constant returns( string curString) { |
75
|
|
|
|
|
|
|
return savedString; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
function setValue( uint newValue ) public { |
78
|
|
|
|
|
|
|
savedValue = newValue; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
function getValue() public constant returns( uint curValue) { |
81
|
|
|
|
|
|
|
return savedValue; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
function setAll(uint newValue, string newString) public { |
84
|
|
|
|
|
|
|
savedValue = newValue; |
85
|
|
|
|
|
|
|
savedString = newString; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
function getAll() public constant returns( uint curValue, string curString) { |
88
|
|
|
|
|
|
|
return (savedValue, savedString); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
function getAllEx() public constant returns( bool isOk, address msgSender, uint curValue, string curString, uint val1, string str1, uint val2, uint val3) { |
91
|
|
|
|
|
|
|
string memory sss="++ ==================================== ++"; |
92
|
|
|
|
|
|
|
return (true, msg.sender, 33333, sss, 9999, "Line 9999", 7777, 8888); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
function repiter(bool pBool, address pAddress, uint pVal1, string pStr1, uint pVal2, string pStr2, uint pVal3, int pVal4) public pure |
96
|
|
|
|
|
|
|
returns( bool rbBool, address rpAddress, uint rpVal1, string rpStr1, uint rpVal2, string rpStr2, uint rpVal3, int rpVal4) { |
97
|
|
|
|
|
|
|
return (pBool, pAddress, pVal1, pStr1, pVal2, pStr2, pVal3, pVal4); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Call contract contract_methods |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
use Net::Ethereum; |
105
|
|
|
|
|
|
|
use Data::Dumper; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
my $contract_name = $ARGV[0]; |
108
|
|
|
|
|
|
|
my $password = $ARGV[1]; |
109
|
|
|
|
|
|
|
# my $src_account = "0x0f687ab2be314d311a714adde92fd9055df18b48"; |
110
|
|
|
|
|
|
|
my $contract_id = $ARGV[2];; |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
my $node = Net::Ethereum->new('http://localhost:8545/'); |
113
|
|
|
|
|
|
|
$node->set_debug_mode(0); |
114
|
|
|
|
|
|
|
$node->set_show_progress(1); |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
my $src_account = $node->eth_accounts()->[0]; |
117
|
|
|
|
|
|
|
print 'My account: '.$src_account, "\n"; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
my $abi = $node->_read_file('build/'.$contract_name.'.abi'); |
120
|
|
|
|
|
|
|
$node->set_contract_abi($abi); |
121
|
|
|
|
|
|
|
$node->set_contract_id($contract_id); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Call contract methods without transactions |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
my $function_params={}; |
127
|
|
|
|
|
|
|
my $test1 = $node->contract_method_call('getValue', $function_params); |
128
|
|
|
|
|
|
|
print Dumper($test1); |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
my $test = $node->contract_method_call('getString'); |
131
|
|
|
|
|
|
|
print Dumper($test); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
my $testAll = $node->contract_method_call('getAll'); |
134
|
|
|
|
|
|
|
print Dumper($testAll); |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
my $testAllEx = $node->contract_method_call('getAllEx'); |
137
|
|
|
|
|
|
|
print Dumper($testAllEx); |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
$function_params={}; |
140
|
|
|
|
|
|
|
$function_params->{ pBool } = 1; |
141
|
|
|
|
|
|
|
$function_params->{ pAddress } = "0xa3a514070f3768e657e2e574910d8b58708cdb82"; |
142
|
|
|
|
|
|
|
$function_params->{ pVal1 } = 1111; |
143
|
|
|
|
|
|
|
$function_params->{ pStr1 } = "This is string 1"; |
144
|
|
|
|
|
|
|
$function_params->{ pVal2 } = 222; |
145
|
|
|
|
|
|
|
$function_params->{ pStr2 } = "And this is String 2, very long string +++++++++++++++++========="; |
146
|
|
|
|
|
|
|
$function_params->{ pVal3 } = 333; |
147
|
|
|
|
|
|
|
$function_params->{ pVal4 } = '-999999999999999999999999999999999999999999999999999999999999999977777777'; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
my $rc = $node->contract_method_call('repiter', $function_params); |
150
|
|
|
|
|
|
|
print Dumper($rc); |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Send Transaction 1 |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
my $rc = $node->personal_unlockAccount($src_account, $password, 600); |
156
|
|
|
|
|
|
|
print 'Unlock account '.$src_account.'. Result: '.$rc, "\n"; |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
my $function_params={}; |
159
|
|
|
|
|
|
|
$function_params->{ newString } = '+++ New string for save +++'; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
my $used_gas = $node->contract_method_call_estimate_gas('setString', $function_params); |
162
|
|
|
|
|
|
|
my $gas_price=$node->eth_gasPrice(); |
163
|
|
|
|
|
|
|
my $transaction_price = $used_gas * $gas_price; |
164
|
|
|
|
|
|
|
my $call_price_in_eth = $node->wei2ether($transaction_price); |
165
|
|
|
|
|
|
|
print 'Estimate Transaction Gas: '.$used_gas.' ('.sprintf('0x%x', $used_gas).') wei, '.$call_price_in_eth.' ether', "\n"; |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
my $tr = $node->sendTransaction($src_account, $node->get_contract_id(), 'setString', $function_params, $used_gas); |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
print 'Waiting for transaction: ', "\n"; |
170
|
|
|
|
|
|
|
my $tr_status = $node->wait_for_transaction($tr, 25, $node->get_show_progress()); |
171
|
|
|
|
|
|
|
print Dumper($tr_status); |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Send Transaction 2 |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
$rc = $node->personal_unlockAccount($src_account, $password, 600); |
177
|
|
|
|
|
|
|
print 'Unlock account '.$src_account.'. Result: '.$rc, "\n"; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
$function_params={}; |
180
|
|
|
|
|
|
|
$function_params->{ newValue } = 77777; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
$used_gas = $node->contract_method_call_estimate_gas('setValue', $function_params); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
$transaction_price = $used_gas * $gas_price; |
185
|
|
|
|
|
|
|
$call_price_in_eth = $node->wei2ether($transaction_price); |
186
|
|
|
|
|
|
|
print 'Estimate Transaction Gas: '.$used_gas.' ('.sprintf('0x%x', $used_gas).') wei, '.$call_price_in_eth.' ether', "\n"; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$tr = $node->sendTransaction($src_account, $node->get_contract_id(), 'setValue', $function_params, $used_gas); |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
print 'Waiting for transaction: ', "\n"; |
191
|
|
|
|
|
|
|
$tr_status = $node->wait_for_transaction($tr, 25, $node->get_show_progress()); |
192
|
|
|
|
|
|
|
print Dumper($tr_status); |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
$testAllEx = $node->contract_method_call('getAllEx'); |
196
|
|
|
|
|
|
|
print Dumper($testAllEx); |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# Some other methods |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
my $res = $node->eth_accounts(); |
202
|
|
|
|
|
|
|
print Dumper($res); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
my $web3_version = $node->web3_clientVersion(); |
205
|
|
|
|
|
|
|
print Dumper($web3_version); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
my $web3_sha3 = $node->web3_sha3("0x68656c6c6f20776f726c64"); |
208
|
|
|
|
|
|
|
print Dumper($web3_sha3); |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my $net_version = $node->net_version(); |
211
|
|
|
|
|
|
|
print Dumper($net_version); |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
my $net_listening = $node->net_listening(); |
214
|
|
|
|
|
|
|
print Dumper($net_listening); |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
my $net_peerCount = $node->net_peerCount(); |
217
|
|
|
|
|
|
|
print Dumper($net_peerCount); |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
my $eth_protocolVersion = $node->eth_protocolVersion(); |
220
|
|
|
|
|
|
|
print Dumper($eth_protocolVersion); |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
my $eth_syncing = $node->eth_syncing(); |
223
|
|
|
|
|
|
|
print Dumper($eth_syncing); |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
my $eth_coinbase = $node->eth_coinbase(); |
226
|
|
|
|
|
|
|
print Dumper($eth_coinbase); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
my $eth_mining = $node->eth_mining(); |
229
|
|
|
|
|
|
|
print Dumper($eth_mining); |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
my $eth_hashrate = $node->eth_hashrate(); |
232
|
|
|
|
|
|
|
print Dumper($eth_hashrate); |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
my $eth_gasPrice = $node->eth_gasPrice(); |
235
|
|
|
|
|
|
|
print Dumper($eth_gasPrice); |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
my $eth_blockNumber = $node->eth_blockNumber(); |
238
|
|
|
|
|
|
|
print Dumper($eth_blockNumber); |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
my $eth_getBalance = $node->eth_getBalance('0xa15862b34abfc4b423fe52f153c95d83f606cc97', "latest"); |
241
|
|
|
|
|
|
|
print Dumper($eth_getBalance); |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
my $eth_getTransactionCount = $node->eth_getTransactionCount('0xa15862b34abfc4b423fe52f153c95d83f606cc97', "latest"); |
244
|
|
|
|
|
|
|
print Dumper($eth_getTransactionCount); |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
my $eth_getBlockTransactionCountByHash = $node->eth_getBlockTransactionCountByHash('0xe79342277d7e95cedf0409e0887c2cddb3ebc5f0d952b9f7c1c1c5cef845cb97', "latest"); |
247
|
|
|
|
|
|
|
print Dumper($eth_getBlockTransactionCountByHash); |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
my $eth_getCode = $node->eth_getCode('0x11c63c5ebc2c6851111d881cb58c213c609c92d4', "latest"); |
250
|
|
|
|
|
|
|
print Dumper($eth_getCode); |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head1 DESCRIPTION |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Net::Ethereum - Perl Framework for Ethereum JSON RPC API. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
This is alpha debugging version. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
Currently support marshaling only uint, int, bool, string types. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Start node cmd: |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
geth --datadir node1 --nodiscover --mine --minerthreads 1 --maxpeers 0 --verbosity 3 --networkid 98765 --rpc --rpcapi="db,eth,net,web3,personal,web3" console |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
Attach node: |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
geth --datadir node1 --networkid 98765 attach ipc://home/frolov/node1/geth.ipc |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head1 FUNCTIONS |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head2 new() |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
my $node = Net::Ethereum->new('http://localhost:8545/'); |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=cut |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
sub new |
281
|
|
|
|
|
|
|
{ |
282
|
0
|
|
|
0
|
1
|
|
my ($this, $api_url) = @_; |
283
|
0
|
|
|
|
|
|
my $self = {}; |
284
|
0
|
|
|
|
|
|
bless( $self, $this ); |
285
|
|
|
|
|
|
|
|
286
|
0
|
|
|
|
|
|
$self->{api_url} = $api_url; |
287
|
0
|
|
|
|
|
|
$self->{abi} = {}; |
288
|
0
|
|
|
|
|
|
$self->{debug} = 0; |
289
|
0
|
|
|
|
|
|
$self->{return_raw_data} = 0; |
290
|
0
|
|
|
|
|
|
$self->{show_progress} = 0; |
291
|
|
|
|
|
|
|
|
292
|
0
|
|
|
|
|
|
return $self; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=pod |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=head2 web3_clientVersion |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
Returns the current client version. |
301
|
|
|
|
|
|
|
my $web3_version = $node->web3_clientVersion(); |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=cut |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub web3_clientVersion() |
306
|
|
|
|
|
|
|
{ |
307
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
308
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "web3_clientVersion", params => [], id => 67}; |
309
|
0
|
|
|
|
|
|
return $this->_node_request($rq)-> { result }; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=pod |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=head2 web3_sha3 |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
Returns Keccak-256 (not the standardized SHA3-256) of the given data. |
317
|
|
|
|
|
|
|
my $web3_sha3 = $node->web3_sha3("0x68656c6c6f20776f726c64"); |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=cut |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub web3_sha3() |
322
|
|
|
|
|
|
|
{ |
323
|
0
|
|
|
0
|
1
|
|
my ($this, $val) = @_; |
324
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "web3_sha3", params => [ $val ], id => 64}; |
325
|
0
|
|
|
|
|
|
return $this->_node_request($rq)-> { result }; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
=pod |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head2 net_version |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Returns the current network id: |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=over |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=item "1": Ethereum Mainnet |
336
|
|
|
|
|
|
|
=item "2": Morden Testnet (deprecated) |
337
|
|
|
|
|
|
|
=item "3": Ropsten Testnet |
338
|
|
|
|
|
|
|
=item "4": Rinkeby Testnet |
339
|
|
|
|
|
|
|
=item "42": Kovan Testnet |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=back |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
my $net_version = $node->net_version(); |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=cut |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub net_version() |
348
|
|
|
|
|
|
|
{ |
349
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
350
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "net_version", params => [], id => 67}; |
351
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
352
|
0
|
|
|
|
|
|
my $dec = sprintf("%d", hex($num)) + 0; |
353
|
0
|
|
|
|
|
|
return $dec; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=pod |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=head2 net_listening |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
Returns 1 (true) if client is actively listening for network connections. |
361
|
|
|
|
|
|
|
my $net_listening = $node->net_listening(); |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=cut |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub net_listening() |
366
|
|
|
|
|
|
|
{ |
367
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
368
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "net_listening", params => [], id => 67}; |
369
|
0
|
|
|
|
|
|
my $rc = $this->_node_request($rq)-> { result }; |
370
|
0
|
0
|
|
|
|
|
$rc ? return 1 : return 0; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=pod |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head2 net_peerCount |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Returns number of peers currently connected to the client. |
378
|
|
|
|
|
|
|
my $net_peerCount = $node->net_peerCount(); |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=cut |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub net_peerCount() |
383
|
|
|
|
|
|
|
{ |
384
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
385
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "net_peerCount", params => [], id => 74}; |
386
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
387
|
0
|
|
|
|
|
|
my $dec = sprintf("%d", hex($num)) + 0; |
388
|
0
|
|
|
|
|
|
return $dec; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=pod |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head2 personal_unlockAccount |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
Decrypts the key with the given address from the key store. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
my $rc = $node->personal_unlockAccount($account, 'PASSWORD', 600); |
398
|
|
|
|
|
|
|
print 'Unlock account '.$src_account.'. Result: '.$rc, "\n"; |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
$account - account to unlock; |
401
|
|
|
|
|
|
|
$password - passphrase; |
402
|
|
|
|
|
|
|
$timeout - the unlock duration |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
The unencrypted key will be held in memory until the unlock duration expires. |
405
|
|
|
|
|
|
|
The account can be used with eth_sign and eth_sendTransaction while it is unlocked. |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=cut |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub personal_unlockAccount() |
410
|
|
|
|
|
|
|
{ |
411
|
0
|
|
|
0
|
1
|
|
my ($this, $account, $password, $timeout) = @_; |
412
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0",method => "personal_unlockAccount", params => [ $account, $password, $timeout ], id => 1 }; |
413
|
0
|
|
|
|
|
|
my $rc = $this->_node_request($rq); |
414
|
0
|
|
|
|
|
|
return $rc-> { result }; |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=pod |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=head2 set_contract_abi |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
Store contract ABI in this object |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
my $node = Net::Ethereum->new('http://localhost:8545/'); |
425
|
|
|
|
|
|
|
$node->set_contract_abi($src_abi); |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
=cut |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
sub set_contract_abi() |
430
|
|
|
|
|
|
|
{ |
431
|
0
|
|
|
0
|
1
|
|
my ($this, $abi_json) = @_; |
432
|
0
|
|
|
|
|
|
$this->{abi} = decode_json($abi_json); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
=pod |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=head2 get_contract_abi |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Returns ABI for contract, stored in this object |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
my $contract_abi = node->get_contract_abi(); |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=cut |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub get_contract_abi() |
446
|
|
|
|
|
|
|
{ |
447
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
448
|
0
|
|
|
|
|
|
return $this->{abi}; |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=pod |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=head2 set_debug_mode |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
Set dubug mode. Debug info printed to console. |
456
|
|
|
|
|
|
|
$node->set_debug_mode($mode); |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
$mode: 1 - debug on, 0 - debug off. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=cut |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
sub set_debug_mode() |
463
|
|
|
|
|
|
|
{ |
464
|
0
|
|
|
0
|
1
|
|
my ($this, $debug_mode) = @_; |
465
|
0
|
|
|
|
|
|
$this->{debug} = $debug_mode; |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=pod |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=head2 set_show_progress |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
Set show progress mode to waiting contract deploying. |
474
|
|
|
|
|
|
|
$node->set_show_progress($mode); |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
$mode: 1 - show progress mode on, 0 - show progress mode off. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=cut |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
sub set_show_progress() |
481
|
|
|
|
|
|
|
{ |
482
|
0
|
|
|
0
|
1
|
|
my ($this, $show_progress) = @_; |
483
|
0
|
|
|
|
|
|
$this->{show_progress} = $show_progress; |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=pod |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=head2 get_show_progress |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
Get show progress mode to waiting contract deploying. |
491
|
|
|
|
|
|
|
$node->get_show_progress(); |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
Returns: 1 - show progress mode on, 0 - show progress mode off. |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=cut |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
sub get_show_progress() |
498
|
|
|
|
|
|
|
{ |
499
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
500
|
0
|
|
|
|
|
|
return $this->{show_progress}; |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
=pod |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=head2 set_contract_id |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
Store contract Id in this object |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
my $contract_id = "0x432e816769a2657029db98303e4946d7dedbcd8f"; |
511
|
|
|
|
|
|
|
my $node = Net::Ethereum->new('http://localhost:8545/'); |
512
|
|
|
|
|
|
|
$node->set_contract_id($contract_id); |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
$contract_id - contract address |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=cut |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub set_contract_id() |
519
|
|
|
|
|
|
|
{ |
520
|
0
|
|
|
0
|
1
|
|
my ($this, $contract_id) = @_; |
521
|
0
|
|
|
|
|
|
$this->{contract_id} = $contract_id; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=pod |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=head2 get_contract_id |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
Get contract id from this object |
529
|
|
|
|
|
|
|
Returns Contract id |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
print 'New Contract id: '.$node->get_contract_id(), "\n"; |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=cut |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
sub get_contract_id() |
537
|
|
|
|
|
|
|
{ |
538
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
539
|
0
|
|
|
|
|
|
return $this->{contract_id}; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=pod |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
=head2 eth_protocolVersion |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
Returns the current ethereum protocol version. |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
my $eth_protocolVersion = $node->eth_protocolVersion(); |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=cut |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
sub eth_protocolVersion() |
554
|
|
|
|
|
|
|
{ |
555
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
556
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_protocolVersion", params => [], id => 67}; |
557
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
558
|
0
|
|
|
|
|
|
my $dec = sprintf("%d", hex($num)) + 0; |
559
|
0
|
|
|
|
|
|
return $dec; |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=pod |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
=head2 eth_syncing |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
Returns an object with data about the sync status or false. |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
Object|Boolean, An object with sync status data or 0 (FALSE), when not syncing: |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
startingBlock: QUANTITY - The block at which the import started (will only be reset, after the sync reached his head) |
571
|
|
|
|
|
|
|
currentBlock: QUANTITY - The current block, same as eth_blockNumber |
572
|
|
|
|
|
|
|
highestBlock: QUANTITY - The estimated highest block |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
my $eth_syncing = $node->eth_syncing(); |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
=cut |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
sub eth_syncing() |
580
|
|
|
|
|
|
|
{ |
581
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
582
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_syncing", params => [], id => 1}; |
583
|
0
|
|
|
|
|
|
my $rc = $this->_node_request($rq)-> { result }; |
584
|
0
|
0
|
|
|
|
|
if(!$rc) |
585
|
|
|
|
|
|
|
{ |
586
|
0
|
|
|
|
|
|
return 0; |
587
|
|
|
|
|
|
|
} |
588
|
0
|
|
|
|
|
|
return $rc; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=pod |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=head2 eth_coinbase |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
Returns the client coinbase address (20 bytes - the current coinbase address). |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
my $eth_coinbase = $node->eth_coinbase(); |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
=cut |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
sub eth_coinbase() |
602
|
|
|
|
|
|
|
{ |
603
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
604
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_coinbase", params => [], id => 64}; |
605
|
0
|
|
|
|
|
|
return $this->_node_request($rq)-> { result }; |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=pod |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
=head2 eth_mining |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
Returns true if client is actively mining new blocks. |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
my $eth_mining = $node->eth_mining(); |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=cut |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
sub eth_mining() |
619
|
|
|
|
|
|
|
{ |
620
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
621
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_mining", params => [], id => 71}; |
622
|
0
|
|
|
|
|
|
my $rc = $this->_node_request($rq)-> { result }; |
623
|
0
|
0
|
|
|
|
|
$rc ? return 1 : return 0; |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=pod |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=head2 eth_hashrate |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
Returns the number of hashes per second that the node is mining with. |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
my $eth_hashrate = $node->eth_hashrate(); |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
=cut |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
sub eth_hashrate() |
637
|
|
|
|
|
|
|
{ |
638
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
639
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_hashrate", params => [], id => 71}; |
640
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
641
|
0
|
|
|
|
|
|
my $dec = sprintf("%d", hex($num)) + 0; |
642
|
0
|
|
|
|
|
|
return $dec; |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=pod |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=head2 eth_gasPrice |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
Returns the current price per gas in wei. |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
my $eth_gasPrice = $node->eth_gasPrice(); |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=cut |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
sub eth_gasPrice() |
656
|
|
|
|
|
|
|
{ |
657
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
658
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_gasPrice", params => [], id => 73}; |
659
|
0
|
|
|
|
|
|
my $hex_string = $this->_node_request($rq)-> { result }; |
660
|
0
|
|
|
|
|
|
my $dec = Math::BigInt->new($hex_string); |
661
|
0
|
|
|
|
|
|
return $dec; |
662
|
|
|
|
|
|
|
} |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=pod |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=head2 eth_accounts |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
Returns a list of addresses owned by client. |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
my $res = $node->eth_accounts(); |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=cut |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
sub eth_accounts() |
675
|
|
|
|
|
|
|
{ |
676
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
677
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0",method => "eth_accounts", params => [], id => 1 }; |
678
|
0
|
|
|
|
|
|
return $this->_node_request($rq)-> { result }; |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=pod |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=head2 eth_blockNumber |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
Returns the number of most recent block. |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
my $eth_blockNumber = $node->eth_blockNumber(); |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
=cut |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
sub eth_blockNumber() |
692
|
|
|
|
|
|
|
{ |
693
|
0
|
|
|
0
|
1
|
|
my ($this) = @_; |
694
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_blockNumber", params => [], id => 83}; |
695
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
696
|
0
|
|
|
|
|
|
my $dec = sprintf("%d", hex($num)) + 0; |
697
|
0
|
|
|
|
|
|
return $dec; |
698
|
|
|
|
|
|
|
} |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=pod |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=head2 eth_getBalance |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
Returns the balance of the account of given address as Math::BigInt object. |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
$addr - address to check for balance; |
707
|
|
|
|
|
|
|
$block_number - integer block number, or the string "latest", "earliest" or "pending" |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
my $eth_getBalance = $node->eth_getBalance('0xa15862b34abfc4b423fe52f153c95d83f606cc97', "latest"); |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
=cut |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
sub eth_getBalance() |
714
|
|
|
|
|
|
|
{ |
715
|
0
|
|
|
0
|
1
|
|
my ($this, $addr, $block_number) = @_; |
716
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_getBalance", params => [ $addr, $block_number ], id => 1}; |
717
|
0
|
|
|
|
|
|
my $hex_string = $this->_node_request($rq)-> { result }; |
718
|
0
|
|
|
|
|
|
my $dec = Math::BigInt->new($hex_string); |
719
|
0
|
|
|
|
|
|
return $dec; |
720
|
|
|
|
|
|
|
#return $hex_string; |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
=pod |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=head2 eth_getStorageAt |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
## TODO |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=cut |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=pod |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
=head2 eth_getTransactionCount |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
Returns the number of transactions sent from an address. |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
$addr - address; |
741
|
|
|
|
|
|
|
$block_number - integer block number, or the string "latest", "earliest" or "pending" |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
my $eth_getTransactionCount = $node->eth_getTransactionCount('0xa15862b34abfc4b423fe52f153c95d83f606cc97', "latest"); |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
=cut |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
sub eth_getTransactionCount() |
748
|
|
|
|
|
|
|
{ |
749
|
0
|
|
|
0
|
1
|
|
my ($this, $addr, $block_number) = @_; |
750
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_getTransactionCount", params => [ $addr, $block_number ], id => 1}; |
751
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
752
|
0
|
|
|
|
|
|
my $dec = sprintf("%d", hex($num)) + 0; |
753
|
0
|
|
|
|
|
|
return $dec; |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
=pod |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
=head2 eth_getTransactionByHash |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
Returns the information about a transaction requested by transaction hash. |
762
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
$hash - hash of a block; |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
my $eth_getTransactionByHash = $node->eth_getBlockTransactionCountByHash('0xe79342277d7e95cedf0409e0887c2cddb3ebc5f0d952b9f7c1c1c5cef845cb97', "latest"); |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
=cut |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
sub eth_getTransactionByHash() |
770
|
|
|
|
|
|
|
{ |
771
|
0
|
|
|
0
|
1
|
|
my ($this, $hash) = @_; |
772
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_getTransactionByHash", params => [ $hash ], id => 1}; |
773
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
774
|
|
|
|
|
|
|
##my $dec = sprintf("%d", hex($num)) + 0; |
775
|
0
|
|
|
|
|
|
return $num; |
776
|
|
|
|
|
|
|
} |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=pod |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
=head2 eth_getBlockTransactionCountByHash |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
Returns the number of transactions in a block from a block matching the given block hash. |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
$hash - hash of a block; |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
my $eth_getBlockTransactionCountByHash = $node->eth_getBlockTransactionCountByHash('0xe79342277d7e95cedf0409e0887c2cddb3ebc5f0d952b9f7c1c1c5cef845cb97', "latest"); |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
=cut |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
sub eth_getBlockTransactionCountByHash() |
794
|
|
|
|
|
|
|
{ |
795
|
0
|
|
|
0
|
1
|
|
my ($this, $hash) = @_; |
796
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_getBlockTransactionCountByHash", params => [ $hash ], id => 1}; |
797
|
0
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
798
|
|
|
|
|
|
|
##my $dec = sprintf("%d", hex($num)) + 0; |
799
|
0
|
|
|
|
|
|
return $num; |
800
|
|
|
|
|
|
|
} |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
=pod |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
=head2 eth_getBlockTransactionCountByNumber |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
## TODO |
808
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
=cut |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=pod |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
=head2 eth_getUncleCountByBlockHash |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
## TODO |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=cut |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
=pod |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
=head2 eth_getUncleCountByBlockNumber |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
## TODO |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
=cut |
827
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
=pod |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
=head2 eth_getCode |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
Returns code at a given address. |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
my $contract_code=$node->eth_getCode($contract_status->{contractAddress}, "latest"); |
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
$addr - address; |
840
|
|
|
|
|
|
|
$block_number - integer block number, or the string "latest", "earliest" or "pending" |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
The following options are possible for the defaultBlock parameter: |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
HEX String - an integer block number |
845
|
|
|
|
|
|
|
String "earliest" for the earliest/genesis block |
846
|
|
|
|
|
|
|
String "latest" - for the latest mined block |
847
|
|
|
|
|
|
|
String "pending" - for the pending state/transactions |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=cut |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
sub eth_getCode() |
852
|
|
|
|
|
|
|
{ |
853
|
0
|
|
|
0
|
1
|
|
my ($this, $addr, $block_number) = @_; |
854
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_getCode", params => [ $addr, $block_number ], id => 1}; |
855
|
0
|
|
|
|
|
|
return $this->_node_request($rq)-> { result }; |
856
|
|
|
|
|
|
|
} |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
=pod |
860
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
=head2 eth_sign |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
## TODO |
864
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
=cut |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
=pod |
870
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
=head2 eth_sendTransaction |
872
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
Send message to contract. |
874
|
|
|
|
|
|
|
Returns result |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
my $rc = $this->eth_sendTransaction($params); |
877
|
|
|
|
|
|
|
return $rc; |
878
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
$from - account; |
880
|
|
|
|
|
|
|
$to - contract id to send message; |
881
|
|
|
|
|
|
|
$data - marshalled data |
882
|
|
|
|
|
|
|
$gas - gas used |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
=cut |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
sub eth_sendTransaction() |
887
|
|
|
|
|
|
|
{ |
888
|
0
|
|
|
0
|
1
|
|
my ($this, $params) = @_; |
889
|
0
|
|
|
|
|
|
my $from = $params->{ from }; |
890
|
0
|
|
|
|
|
|
my $to = $params->{ to }; |
891
|
0
|
|
|
|
|
|
my $gas = $params->{ gas }; |
892
|
0
|
|
|
|
|
|
my $data = $params->{ data }; |
893
|
|
|
|
|
|
|
|
894
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_sendTransaction", params => [ { from => $from, to => $to, gas => $gas, data => $data } ], id => 1 }; |
895
|
0
|
|
|
|
|
|
my $rc = $this->_node_request($rq); |
896
|
0
|
|
|
|
|
|
return $rc-> { result }; |
897
|
|
|
|
|
|
|
} |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
=pod |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=head2 eth_sendRawTransaction |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
## TODO |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
=cut |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
=pod |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=head2 eth_call |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
Call contract method without transaction |
915
|
|
|
|
|
|
|
Returns result |
916
|
|
|
|
|
|
|
|
917
|
|
|
|
|
|
|
my $raw_params=$this->_marshal($function_name, $function_params); |
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
my $params = {}; |
920
|
|
|
|
|
|
|
$params-> {to} = $this->{contract_id}; |
921
|
|
|
|
|
|
|
$params-> {data} = $raw_params; |
922
|
|
|
|
|
|
|
my $rc = $this->eth_call($params); |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
=cut |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
sub eth_call() |
927
|
|
|
|
|
|
|
{ |
928
|
0
|
|
|
0
|
1
|
|
my ($this, $params) = @_; |
929
|
0
|
|
|
|
|
|
my $to = $params->{ to }; |
930
|
0
|
|
|
|
|
|
my $data = $params->{ data }; |
931
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_call", params => [ { to => $to, data => $data},"latest" ], id => 1 }; |
932
|
0
|
|
|
|
|
|
return $this->_node_request($rq)-> { result }; |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
=pod |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=head2 eth_estimateGas |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
Makes a call or transaction, which won't be added to the blockchain and returns the used gas, which can be used for estimating the used gas. |
940
|
|
|
|
|
|
|
Returns the amount of gas used. |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
my $contract_used_gas = $node->deploy_contract_estimate_gas($src_account, $contract_binary); |
943
|
|
|
|
|
|
|
print 'Estimate GAS: ', Dumper($contract_used_gas); |
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
$params - See eth_call parameters, expect that all properties are optional. |
946
|
|
|
|
|
|
|
If no gas limit is specified geth uses the block gas limit from the pending block as an upper bound. |
947
|
|
|
|
|
|
|
As a result the returned estimate might not be enough to executed the call/transaction when the amount of gas is higher than the pending block gas limit. |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
Returns the amount of gas used. |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
=cut |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
sub eth_estimateGas() |
954
|
|
|
|
|
|
|
{ |
955
|
0
|
|
|
0
|
1
|
|
my ($this, $params) = @_; |
956
|
0
|
|
|
|
|
|
my $to = $params->{ to }; |
957
|
0
|
|
|
|
|
|
my $data = $params->{ data }; |
958
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_estimateGas", params => [ { to => $to, data => $data} ], id => 1 }; |
959
|
0
|
|
|
|
|
|
return $this->_node_request($rq)-> { result }; |
960
|
|
|
|
|
|
|
} |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
=pod |
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
=head2 eth_getTransactionReceipt |
966
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
Returns the receipt of a transaction by transaction hash. |
968
|
|
|
|
|
|
|
That the receipt is not available for pending transactions. |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
$tr_status = $this->eth_getTransactionReceipt($contrarc_deploy_tr); |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
=cut |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
sub eth_getTransactionReceipt() |
975
|
|
|
|
|
|
|
{ |
976
|
0
|
|
|
0
|
1
|
|
my ($this, $transaction_hash) = @_; |
977
|
0
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "eth_getTransactionReceipt", params => [ $transaction_hash ], id => 1 }; |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
#print "eth_getTransactionReceipt: ", Dumper($rq); |
980
|
|
|
|
|
|
|
|
981
|
0
|
|
|
|
|
|
my $rc = $this->_node_request($rq); |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
#print "eth_getTransactionReceipt rc: ", Dumper($rc); |
984
|
|
|
|
|
|
|
|
985
|
0
|
|
|
|
|
|
return $rc; |
986
|
|
|
|
|
|
|
# return $this->_node_request($rq); |
987
|
|
|
|
|
|
|
} |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
=pod |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
=head2 wei2ether |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
Convert wei to Ether, returns Ether |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
my $price_in_eth = $node->wei2ether($contract_deploy_price); |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
=cut |
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
sub wei2ether() |
1000
|
|
|
|
|
|
|
{ |
1001
|
0
|
|
|
0
|
1
|
|
my ($this, $wei) = @_; |
1002
|
0
|
|
|
|
|
|
my $eth_in_wei = Math::BigFloat->new(1000000000000000000); |
1003
|
0
|
|
|
|
|
|
my $wei_bigfloat = Math::BigFloat->new($wei); |
1004
|
0
|
|
|
|
|
|
my $ether = $wei_bigfloat / $eth_in_wei; |
1005
|
0
|
|
|
|
|
|
return $ether; |
1006
|
|
|
|
|
|
|
} |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
=pod |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
=head2 sendTransaction |
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
Send message to contract. |
1014
|
|
|
|
|
|
|
Returns transaction id |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
my $function_params={}; |
1017
|
|
|
|
|
|
|
$function_params->{ newString } = "+= test =+"; |
1018
|
|
|
|
|
|
|
my $tr = $node->sendTransaction($src_account, $node->get_contract_id(), 'setString', $function_params); |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
$src_account - account; |
1021
|
|
|
|
|
|
|
$contract_id - contract id to send message; |
1022
|
|
|
|
|
|
|
$function_name - function name; |
1023
|
|
|
|
|
|
|
$function_params - function params |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
=cut |
1026
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
sub sendTransaction() |
1028
|
|
|
|
|
|
|
{ |
1029
|
0
|
|
|
0
|
1
|
|
my ($this, $src_account, $contract_id, $function_name, $function_params, $gas) = @_; |
1030
|
0
|
|
|
|
|
|
my $raw_params=$this->_marshal($function_name, $function_params); |
1031
|
|
|
|
|
|
|
|
1032
|
0
|
|
|
|
|
|
my $params = {}; |
1033
|
0
|
|
|
|
|
|
$params-> {from} = $src_account; |
1034
|
0
|
|
|
|
|
|
$params-> {to} = $contract_id; |
1035
|
0
|
|
|
|
|
|
$params-> {data} = $raw_params; |
1036
|
|
|
|
|
|
|
# $params-> {gas} = "0xd312"; |
1037
|
0
|
|
|
|
|
|
$params-> {gas} = sprintf('0x%x', $gas); |
1038
|
|
|
|
|
|
|
|
1039
|
0
|
|
|
|
|
|
my $rc = $this->eth_sendTransaction($params); |
1040
|
0
|
|
|
|
|
|
return $rc; |
1041
|
|
|
|
|
|
|
} |
1042
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
=pod |
1045
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
=head2 deploy_contract_estimate_gas |
1047
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
Estimate used gas for deployed contract. |
1049
|
|
|
|
|
|
|
Makes a call or transaction, which won't be added to the blockchain and returns the used gas, which can be used for estimating the used gas. |
1050
|
|
|
|
|
|
|
Returns the amount of gas used. |
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
my $contract_used_gas = $node->deploy_contract_estimate_gas($src_account, $contract_binary); |
1053
|
|
|
|
|
|
|
print 'Estimate GAS: ', Dumper($contract_used_gas); |
1054
|
|
|
|
|
|
|
|
1055
|
|
|
|
|
|
|
$src_account - account |
1056
|
|
|
|
|
|
|
$contract_binary - contract binary code |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
=cut |
1059
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
sub deploy_contract_estimate_gas() |
1061
|
|
|
|
|
|
|
{ |
1062
|
0
|
|
|
0
|
1
|
|
my ($this, $src_account, $contract_binary, $constructor_params) = @_; |
1063
|
|
|
|
|
|
|
|
1064
|
0
|
|
|
|
|
|
my $params = {}; |
1065
|
0
|
|
|
|
|
|
$params-> {from} = $src_account; |
1066
|
|
|
|
|
|
|
|
1067
|
0
|
0
|
|
|
|
|
if($constructor_params) |
1068
|
|
|
|
|
|
|
{ |
1069
|
0
|
|
|
|
|
|
my $raw_params=$this->_marshal('constructor', $constructor_params); |
1070
|
0
|
|
|
|
|
|
$params-> {data} = $contract_binary.$raw_params; |
1071
|
|
|
|
|
|
|
} |
1072
|
|
|
|
|
|
|
else |
1073
|
|
|
|
|
|
|
{ |
1074
|
0
|
|
|
|
|
|
$params-> {data} = $contract_binary; |
1075
|
|
|
|
|
|
|
} |
1076
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
#$params-> {data} = $contract_binary; |
1078
|
0
|
|
|
|
|
|
return hex($this->eth_estimateGas($params)); |
1079
|
|
|
|
|
|
|
} |
1080
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
|
1082
|
|
|
|
|
|
|
=pod |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
=head2 deploy_contract |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
Deploy contract |
1087
|
|
|
|
|
|
|
Returns transaction id |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
my $rc = $node->personal_unlockAccount($src_account, 'ptktysq', 600); |
1090
|
|
|
|
|
|
|
print 'Unlock account '.$src_account.'. Result: '.$rc, "\n"; |
1091
|
|
|
|
|
|
|
my $contrarc_deploy_tr = $node->deploy_contract($src_account, $contract_binary); |
1092
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
$src_account - account |
1094
|
|
|
|
|
|
|
$contract_binary - contract binary code |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
=cut |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
sub deploy_contract() |
1099
|
|
|
|
|
|
|
{ |
1100
|
0
|
|
|
0
|
1
|
|
my ($this, $src_account, $contract_binary, $constructor_params, $gas) = @_; |
1101
|
|
|
|
|
|
|
|
1102
|
0
|
|
|
|
|
|
my $params = {}; |
1103
|
0
|
|
|
|
|
|
$params-> {from} = $src_account; |
1104
|
0
|
0
|
|
|
|
|
if($constructor_params) |
1105
|
|
|
|
|
|
|
{ |
1106
|
0
|
|
|
|
|
|
my $raw_params=$this->_marshal('constructor', $constructor_params); |
1107
|
0
|
|
|
|
|
|
$params-> {data} = $contract_binary.$raw_params; |
1108
|
|
|
|
|
|
|
} |
1109
|
|
|
|
|
|
|
else |
1110
|
|
|
|
|
|
|
{ |
1111
|
0
|
|
|
|
|
|
$params-> {data} = $contract_binary; |
1112
|
|
|
|
|
|
|
} |
1113
|
|
|
|
|
|
|
|
1114
|
0
|
|
|
|
|
|
$params-> {gas} = sprintf('0x%x', $gas); |
1115
|
0
|
|
|
|
|
|
my $rc = $this->eth_sendTransaction($params); |
1116
|
0
|
|
|
|
|
|
return $rc; |
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
=pod |
1120
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
=head2 wait_for_contract |
1122
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
Wait for contract deployment/ |
1124
|
|
|
|
|
|
|
Store contract address into this object. |
1125
|
|
|
|
|
|
|
Returns the transction status: |
1126
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
$VAR1 = { |
1128
|
|
|
|
|
|
|
'transactionIndex' => '0x0', |
1129
|
|
|
|
|
|
|
'logs' => [], |
1130
|
|
|
|
|
|
|
'contractAddress' => '0xa5e4b4aa28b79891f12ffa985b660ff222157659', |
1131
|
|
|
|
|
|
|
'cumulativeGasUsed' => '0xb64b3', |
1132
|
|
|
|
|
|
|
'to' => undef, |
1133
|
|
|
|
|
|
|
'blockNumber' => '0x36a6', |
1134
|
|
|
|
|
|
|
'blockHash' => '0x71b75f5eae70c532f94aeee91df0fef0df6208c451f6c007fe9a2a462fb23fc0', |
1135
|
|
|
|
|
|
|
'transactionHash' => '0xfa71027cb3ae4ed05ec7a71d1c0cdad7d0dc501679e976caa0bf665b7309b97b', |
1136
|
|
|
|
|
|
|
'from' => '0x0f687ab2be314d311a714adde92fd9055df18b48', |
1137
|
|
|
|
|
|
|
'logsBloom' => '0x0000000...00', |
1138
|
|
|
|
|
|
|
'gasUsed' => '0xb64b3', |
1139
|
|
|
|
|
|
|
'root' => '0x9a32416741eb3192eae9197fc20acf7e5436fce7e6d92153aca91f92d373d41b' |
1140
|
|
|
|
|
|
|
}; |
1141
|
|
|
|
|
|
|
|
1142
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
my $contract_status = $node->wait_for_contract($contrarc_deploy_tr); |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
$contrarc_deploy_tr - waiting contract transaction; |
1146
|
|
|
|
|
|
|
$iterations - number of wait iterations; |
1147
|
|
|
|
|
|
|
$show_progress - show progress on console (1 or 0) |
1148
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
=cut |
1150
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
sub wait_for_contract() |
1152
|
|
|
|
|
|
|
{ |
1153
|
0
|
|
|
0
|
1
|
|
my ($this, $contrarc_deploy_tr, $iterations, $show_progress) = @_; |
1154
|
0
|
|
|
|
|
|
my $new_contract_id; |
1155
|
|
|
|
|
|
|
my $tr_status; |
1156
|
|
|
|
|
|
|
|
1157
|
0
|
0
|
|
|
|
|
if($show_progress) { $| = 1; } |
|
0
|
|
|
|
|
|
|
1158
|
0
|
|
|
|
|
|
for(my $i=0; $i<$iterations;$i++) |
1159
|
|
|
|
|
|
|
{ |
1160
|
0
|
|
|
|
|
|
my $rc = $this->eth_getTransactionByHash($contrarc_deploy_tr); |
1161
|
0
|
0
|
|
|
|
|
if($rc->{blockNumber}) # do not pending |
1162
|
|
|
|
|
|
|
{ |
1163
|
0
|
|
|
|
|
|
$tr_status = $this->eth_getTransactionReceipt($contrarc_deploy_tr); |
1164
|
0
|
0
|
|
|
|
|
if($tr_status->{result}) |
1165
|
|
|
|
|
|
|
{ |
1166
|
0
|
|
|
|
|
|
$new_contract_id = $tr_status->{result}->{contractAddress}; |
1167
|
0
|
|
|
|
|
|
$this->set_contract_id($new_contract_id); |
1168
|
0
|
0
|
|
|
|
|
if($show_progress) { print "\n"; } |
|
0
|
|
|
|
|
|
|
1169
|
0
|
|
|
|
|
|
last; |
1170
|
|
|
|
|
|
|
} |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
else |
1173
|
|
|
|
|
|
|
{ |
1174
|
0
|
|
|
|
|
|
sleep(5); |
1175
|
0
|
0
|
|
|
|
|
if($show_progress) { print '.'.$i; } |
|
0
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
} |
1177
|
|
|
|
|
|
|
} |
1178
|
0
|
|
|
|
|
|
return $tr_status->{result}; |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
|
1181
|
|
|
|
|
|
|
=pod |
1182
|
|
|
|
|
|
|
|
1183
|
|
|
|
|
|
|
=head2 wait_for_transaction |
1184
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
Wait for wait_for_transaction |
1186
|
|
|
|
|
|
|
Returns the transction status: |
1187
|
|
|
|
|
|
|
|
1188
|
|
|
|
|
|
|
$VAR1 = { |
1189
|
|
|
|
|
|
|
'cumulativeGasUsed' => '0xabcd', |
1190
|
|
|
|
|
|
|
'transactionHash' => '0x237569eeae8f8f3da05d7bbd68066c18921406441dac8de13092c850addcb15b', |
1191
|
|
|
|
|
|
|
'logs' => [], |
1192
|
|
|
|
|
|
|
'gasUsed' => '0xabcd', |
1193
|
|
|
|
|
|
|
'transactionIndex' => '0x0', |
1194
|
|
|
|
|
|
|
'blockHash' => '0xdb7f3748658abdb60859e1097823630d7eb140448b40c8e1ac89170a76fc797e', |
1195
|
|
|
|
|
|
|
'from' => '0x0f687ab2be314d311a714adde92fd9055df18b48', |
1196
|
|
|
|
|
|
|
'logsBloom' => '0x000000000000000000...0000', |
1197
|
|
|
|
|
|
|
'to' => '0x6f059b63aee6af50920d2a0fbd287cec94117826', |
1198
|
|
|
|
|
|
|
'root' => '0x3fe46002e1c71876474a8b460222adb2309ab8f36b5750a6408a1f921f54ab4c', |
1199
|
|
|
|
|
|
|
'blockNumber' => '0x36e2', |
1200
|
|
|
|
|
|
|
'contractAddress' => undef |
1201
|
|
|
|
|
|
|
}; |
1202
|
|
|
|
|
|
|
|
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
my $tr_status = $node->wait_for_transaction($tr); |
1205
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
$contrarc_deploy_tr - waiting transaction; |
1207
|
|
|
|
|
|
|
$iterations - number of wait iterations; |
1208
|
|
|
|
|
|
|
$show_progress - show progress on console (1 or 0) |
1209
|
|
|
|
|
|
|
|
1210
|
|
|
|
|
|
|
=cut |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
sub wait_for_transaction() |
1213
|
|
|
|
|
|
|
{ |
1214
|
0
|
|
|
0
|
1
|
|
my ($this, $contrarc_deploy_tr, $iterations, $show_progress) = @_; |
1215
|
0
|
|
|
|
|
|
my $new_contract_id; |
1216
|
|
|
|
|
|
|
my $tr_status; |
1217
|
|
|
|
|
|
|
|
1218
|
0
|
0
|
|
|
|
|
if($show_progress) { $| = 1; } |
|
0
|
|
|
|
|
|
|
1219
|
0
|
|
|
|
|
|
for(my $i=0; $i<$iterations;$i++) |
1220
|
|
|
|
|
|
|
{ |
1221
|
0
|
|
|
|
|
|
my $rc = $this->eth_getTransactionByHash($contrarc_deploy_tr); |
1222
|
0
|
0
|
|
|
|
|
if($rc->{blockNumber}) # do not pending |
1223
|
|
|
|
|
|
|
{ |
1224
|
0
|
|
|
|
|
|
$tr_status = $this->eth_getTransactionReceipt($contrarc_deploy_tr); |
1225
|
0
|
0
|
|
|
|
|
if($tr_status->{result}) |
1226
|
|
|
|
|
|
|
{ |
1227
|
0
|
0
|
|
|
|
|
if($show_progress) { print "\n"; } |
|
0
|
|
|
|
|
|
|
1228
|
0
|
|
|
|
|
|
last; |
1229
|
|
|
|
|
|
|
} |
1230
|
|
|
|
|
|
|
} |
1231
|
|
|
|
|
|
|
else |
1232
|
|
|
|
|
|
|
{ |
1233
|
0
|
|
|
|
|
|
sleep(5); |
1234
|
0
|
0
|
|
|
|
|
if($show_progress) { print '.'.$i; } |
|
0
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
} |
1236
|
|
|
|
|
|
|
} |
1237
|
0
|
|
|
|
|
|
return $tr_status->{result}; |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
=pod |
1242
|
|
|
|
|
|
|
|
1243
|
|
|
|
|
|
|
=head2 contract_method_call_estimate_gas |
1244
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
Estimate used gas for contract method call. |
1246
|
|
|
|
|
|
|
Makes a call or transaction, which won't be added to the blockchain and returns the used gas, which can be used for estimating the used gas. |
1247
|
|
|
|
|
|
|
Returns the amount of gas used. |
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
my $function_params={}; |
1250
|
|
|
|
|
|
|
$function_params->{ newString } = '+= test GAS ok =+'; |
1251
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
my $used_gas = $node->contract_method_call_estimate_gas('setString', $function_params); |
1253
|
|
|
|
|
|
|
print 'Estimate GAS: ', Dumper($used_gas); |
1254
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
=cut |
1256
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
sub contract_method_call_estimate_gas() |
1258
|
|
|
|
|
|
|
{ |
1259
|
0
|
|
|
0
|
1
|
|
my ($this, $function_name, $function_params) = @_; |
1260
|
|
|
|
|
|
|
|
1261
|
0
|
|
|
|
|
|
my $raw_params=$this->_marshal($function_name, $function_params); |
1262
|
0
|
|
|
|
|
|
my $params = {}; |
1263
|
0
|
|
|
|
|
|
$params-> {to} = $this->{contract_id}; |
1264
|
0
|
|
|
|
|
|
$params-> {data} = $raw_params; |
1265
|
0
|
|
|
|
|
|
return hex($this->eth_estimateGas($params)); |
1266
|
|
|
|
|
|
|
} |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
=pod |
1270
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
=head2 contract_method_call |
1272
|
|
|
|
|
|
|
|
1273
|
|
|
|
|
|
|
Call contract method without transaction |
1274
|
|
|
|
|
|
|
Returns unmarshalled data |
1275
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
$function_params={}; |
1277
|
|
|
|
|
|
|
$function_params->{ pBool } = 1; |
1278
|
|
|
|
|
|
|
$function_params->{ pAddress } = "0xa3a514070f3768e657e2e574910d8b58708cdb82"; |
1279
|
|
|
|
|
|
|
$function_params->{ pVal1 } = 11; |
1280
|
|
|
|
|
|
|
$function_params->{ pStr1 } = "str1 This is string 1"; |
1281
|
|
|
|
|
|
|
$function_params->{ pVal2 } = 22; |
1282
|
|
|
|
|
|
|
$function_params->{ pStr2 } = "str2 And this is String 2, very long string +++++++++++++++++== smart!"; |
1283
|
|
|
|
|
|
|
$function_params->{ pVal3 } = 33; |
1284
|
|
|
|
|
|
|
$function_params->{ pVal4 } = 44; |
1285
|
|
|
|
|
|
|
|
1286
|
|
|
|
|
|
|
my $rc = $node->contract_method_call('repiter', $function_params); |
1287
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
=cut |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
sub contract_method_call() |
1291
|
|
|
|
|
|
|
{ |
1292
|
0
|
|
|
0
|
1
|
|
my ($this, $function_name, $function_params) = @_; |
1293
|
0
|
|
|
|
|
|
my $raw_params=$this->_marshal($function_name, $function_params); |
1294
|
|
|
|
|
|
|
|
1295
|
0
|
|
|
|
|
|
my $params = {}; |
1296
|
0
|
|
|
|
|
|
$params-> {to} = $this->{contract_id}; |
1297
|
0
|
|
|
|
|
|
$params-> {data} = $raw_params; |
1298
|
|
|
|
|
|
|
|
1299
|
0
|
0
|
|
|
|
|
if($this->{debug}) |
1300
|
|
|
|
|
|
|
{ |
1301
|
0
|
|
|
|
|
|
print 'Function name: '.$function_name. "\n"; |
1302
|
0
|
|
|
|
|
|
print 'Function params: ', Dumper($function_params); |
1303
|
0
|
|
|
|
|
|
print 'Function raw params: ', Dumper($params); |
1304
|
|
|
|
|
|
|
} |
1305
|
|
|
|
|
|
|
|
1306
|
0
|
|
|
|
|
|
my $rc = $this->eth_call($params); |
1307
|
|
|
|
|
|
|
|
1308
|
0
|
0
|
|
|
|
|
if($this->{debug}) |
1309
|
|
|
|
|
|
|
{ |
1310
|
0
|
|
|
|
|
|
print 'eth_call return data: '.$rc. "\n"; |
1311
|
|
|
|
|
|
|
} |
1312
|
0
|
|
|
|
|
|
my $raw_data = substr($rc, 2); |
1313
|
0
|
|
|
|
|
|
return $this->_unmarshal($function_name, $raw_data); |
1314
|
|
|
|
|
|
|
} |
1315
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
|
1317
|
|
|
|
|
|
|
=pod |
1318
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
=head2 compile_and_deploy_contract |
1320
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
Compile and deploy contract |
1322
|
|
|
|
|
|
|
Returns contract id |
1323
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
my $constructor_params={}; |
1325
|
|
|
|
|
|
|
$constructor_params->{ initString } = '+ from constructor +'; |
1326
|
|
|
|
|
|
|
$constructor_params->{ initValue } = 101; |
1327
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
my $contract_status = $node->compile_and_deploy_contract($contract_name, $constructor_params, $src_account, $password); |
1329
|
|
|
|
|
|
|
my $new_contract_id = $contract_status->{contractAddress}; |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
=cut |
1332
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
sub compile_and_deploy_contract() |
1334
|
|
|
|
|
|
|
{ |
1335
|
0
|
|
|
0
|
1
|
|
my ($this, $contract_name, $constructor_params, $src_account, $password) = @_; |
1336
|
|
|
|
|
|
|
|
1337
|
0
|
|
|
|
|
|
my $contract_src_path = $contract_name.'.sol'; |
1338
|
0
|
|
|
|
|
|
my $bin_solc = '/usr/bin/solc'; |
1339
|
0
|
|
|
|
|
|
my $cmd = "$bin_solc --bin --abi $contract_src_path -o build --overwrite"; |
1340
|
0
|
0
|
|
|
|
|
if(system($cmd)) |
1341
|
|
|
|
|
|
|
{ |
1342
|
0
|
|
|
|
|
|
die sprintf("Failed to compile $contract_name with value %d\n", $? >> 8); |
1343
|
|
|
|
|
|
|
} |
1344
|
|
|
|
|
|
|
|
1345
|
0
|
|
|
|
|
|
my $abi = $this->_read_file('build/'.$contract_name.'.abi'); |
1346
|
0
|
|
|
|
|
|
$this->set_contract_abi($abi); |
1347
|
0
|
|
|
|
|
|
my $bin = $this->_read_file('build/'.$contract_name.'.bin'); |
1348
|
0
|
|
|
|
|
|
$bin = '0x'.$bin; |
1349
|
|
|
|
|
|
|
|
1350
|
0
|
|
|
|
|
|
$this->personal_unlockAccount($src_account, $password, 600); |
1351
|
|
|
|
|
|
|
|
1352
|
0
|
|
|
|
|
|
my $contract_used_gas = $this->deploy_contract_estimate_gas($src_account, $bin, $constructor_params); |
1353
|
0
|
|
|
|
|
|
my $gas_price=$this->eth_gasPrice(); |
1354
|
0
|
|
|
|
|
|
my $contract_deploy_price = $contract_used_gas * $gas_price; |
1355
|
0
|
|
|
|
|
|
my $price_in_eth = $this->wei2ether($contract_deploy_price); |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
# print 'Estimate Contract GAS: '.$contract_used_gas.' wei ('.sprintf('0x%x', $contract_used_gas).' wei), $price_in_eth: '.$price_in_eth.' ether', "\n"; |
1358
|
|
|
|
|
|
|
|
1359
|
0
|
|
|
|
|
|
my $contrarc_deploy_tr = $this->deploy_contract($src_account, $bin, $constructor_params, $contract_used_gas); |
1360
|
0
|
|
|
|
|
|
my $contract_status = $this->wait_for_contract($contrarc_deploy_tr, 25, $this->{show_progress}); |
1361
|
|
|
|
|
|
|
|
1362
|
0
|
|
|
|
|
|
my $contract_code=$this->eth_getCode($contract_status->{contractAddress}, "latest"); |
1363
|
0
|
0
|
|
|
|
|
if($contract_code eq '0x') |
1364
|
|
|
|
|
|
|
{ |
1365
|
0
|
|
|
|
|
|
die 'Error: no contract code from network'.$contract_code; |
1366
|
|
|
|
|
|
|
} |
1367
|
0
|
|
|
|
|
|
return $contract_status; |
1368
|
|
|
|
|
|
|
} |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
# ========================== |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
|
1375
|
|
|
|
|
|
|
=pod |
1376
|
|
|
|
|
|
|
|
1377
|
|
|
|
|
|
|
=head2 _read_file |
1378
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
Read file into variable. |
1380
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
$file_path - path to file. |
1382
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
my $abi = $this->_read_file('build/'.$contract_name.'.abi'); |
1384
|
|
|
|
|
|
|
$this->set_contract_abi($abi); |
1385
|
|
|
|
|
|
|
my $bin = $this->_read_file('build/'.$contract_name.'.bin'); |
1386
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
=cut |
1388
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
sub _read_file() |
1390
|
|
|
|
|
|
|
{ |
1391
|
0
|
|
|
0
|
|
|
my ($this, $file_path) = @_; |
1392
|
0
|
|
|
|
|
|
my $content = read_text($file_path); |
1393
|
|
|
|
|
|
|
|
1394
|
|
|
|
|
|
|
# open my $FILE, "<", $file_path or die "Can't open file: $!\n"; |
1395
|
|
|
|
|
|
|
# local $/ = undef; |
1396
|
|
|
|
|
|
|
# my $content = <$FILE>; |
1397
|
|
|
|
|
|
|
# close $FILE; |
1398
|
0
|
|
|
|
|
|
return $content; |
1399
|
|
|
|
|
|
|
} |
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
=pod |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
=head2 _marshal |
1404
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
nternal method. |
1406
|
|
|
|
|
|
|
Marshaling data from from function params/ |
1407
|
|
|
|
|
|
|
Returns raw marshalled data |
1408
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
my $raw_params=$this->_marshal($function_name, $function_params); |
1410
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
$function_name - method name to get ABI |
1412
|
|
|
|
|
|
|
$function_params - function params |
1413
|
|
|
|
|
|
|
|
1414
|
|
|
|
|
|
|
=cut |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
sub _marshal() |
1417
|
|
|
|
|
|
|
{ |
1418
|
0
|
|
|
0
|
|
|
my ($this, $function_name, $function_params) = @_; |
1419
|
|
|
|
|
|
|
|
1420
|
0
|
|
|
|
|
|
my $function_abi; |
1421
|
|
|
|
|
|
|
|
1422
|
0
|
0
|
|
|
|
|
if($function_name eq 'constructor') |
1423
|
|
|
|
|
|
|
{ |
1424
|
0
|
|
|
|
|
|
$function_abi = $this->_get_constructor_abi($function_name); |
1425
|
|
|
|
|
|
|
} |
1426
|
|
|
|
|
|
|
else |
1427
|
|
|
|
|
|
|
{ |
1428
|
0
|
|
|
|
|
|
$function_abi = $this->_get_function_abi($function_name); |
1429
|
|
|
|
|
|
|
} |
1430
|
|
|
|
|
|
|
|
1431
|
0
|
|
|
|
|
|
my $function_inputs = $function_abi-> { inputs }; |
1432
|
|
|
|
|
|
|
|
1433
|
0
|
|
|
|
|
|
my $current_out_param_position=0; |
1434
|
0
|
|
|
|
|
|
my $param_types_list=""; |
1435
|
0
|
|
|
|
|
|
my $encoded_arguments=""; |
1436
|
|
|
|
|
|
|
|
1437
|
0
|
|
|
|
|
|
my $out_param_array=[]; |
1438
|
0
|
|
|
|
|
|
my $out_param_array_counter=0; |
1439
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
# First pass |
1441
|
|
|
|
|
|
|
|
1442
|
0
|
|
|
|
|
|
foreach my $out_param (@$function_inputs) |
1443
|
|
|
|
|
|
|
{ |
1444
|
0
|
|
|
|
|
|
my $cur_param_name = $out_param->{name}; |
1445
|
0
|
|
|
|
|
|
my $cur_param_type = $out_param->{type}; |
1446
|
0
|
|
|
|
|
|
$param_types_list .= $cur_param_type.','; |
1447
|
|
|
|
|
|
|
|
1448
|
0
|
0
|
0
|
|
|
|
if($cur_param_type eq 'bool' || $cur_param_type =~ m/^uint/i) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
{ |
1450
|
0
|
|
|
|
|
|
my $add_hunk=$function_params->{ $cur_param_name }; |
1451
|
0
|
|
|
|
|
|
$add_hunk=$this->_marshal_int($add_hunk); |
1452
|
0
|
|
|
|
|
|
$out_param_array->[$out_param_array_counter] = $add_hunk; |
1453
|
0
|
|
|
|
|
|
$out_param_array_counter++; |
1454
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1455
|
|
|
|
|
|
|
} |
1456
|
|
|
|
|
|
|
elsif($cur_param_type =~ m/^int/i) |
1457
|
|
|
|
|
|
|
{ |
1458
|
0
|
|
|
|
|
|
my $add_hunk=$function_params->{ $cur_param_name }; |
1459
|
0
|
|
|
|
|
|
$add_hunk=$this->_marshal_int($add_hunk); |
1460
|
0
|
|
|
|
|
|
$out_param_array->[$out_param_array_counter] = $add_hunk; |
1461
|
0
|
|
|
|
|
|
$out_param_array_counter++; |
1462
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1463
|
|
|
|
|
|
|
} |
1464
|
|
|
|
|
|
|
elsif($cur_param_type eq 'address') |
1465
|
|
|
|
|
|
|
{ |
1466
|
0
|
|
|
|
|
|
my $add_hunk=$function_params->{ $cur_param_name }; |
1467
|
0
|
|
|
|
|
|
$add_hunk=substr($add_hunk, 2); |
1468
|
0
|
|
|
|
|
|
$add_hunk = sprintf('%064s', $add_hunk); |
1469
|
0
|
|
|
|
|
|
$out_param_array->[$out_param_array_counter] = $add_hunk; |
1470
|
0
|
|
|
|
|
|
$out_param_array_counter++; |
1471
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1472
|
|
|
|
|
|
|
} |
1473
|
|
|
|
|
|
|
elsif($cur_param_type eq 'string') |
1474
|
|
|
|
|
|
|
{ |
1475
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1476
|
0
|
|
|
|
|
|
my $str=$function_params->{ $cur_param_name }; |
1477
|
0
|
|
|
|
|
|
my $str_length = length($str); |
1478
|
0
|
|
|
|
|
|
$out_param_array->[$out_param_array_counter] = $str_length; # replace with data hunk offset into second pass |
1479
|
0
|
|
|
|
|
|
$out_param_array_counter++; |
1480
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1481
|
|
|
|
|
|
|
} |
1482
|
|
|
|
|
|
|
else |
1483
|
|
|
|
|
|
|
{ |
1484
|
0
|
|
|
|
|
|
die 'Net::Ethereum _marshal does not support type: '.$cur_param_type; |
1485
|
|
|
|
|
|
|
} |
1486
|
|
|
|
|
|
|
} |
1487
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
# Second pass |
1489
|
|
|
|
|
|
|
|
1490
|
0
|
|
|
|
|
|
my $var_data_offset_index = $out_param_array_counter; |
1491
|
0
|
|
|
|
|
|
my $var_data_offset = $var_data_offset_index * 32; |
1492
|
0
|
|
|
|
|
|
my $array_index=0; |
1493
|
0
|
|
|
|
|
|
my $second_pass_counter=0; |
1494
|
|
|
|
|
|
|
|
1495
|
0
|
|
|
|
|
|
foreach my $out_param (@$function_inputs) |
1496
|
|
|
|
|
|
|
{ |
1497
|
0
|
|
|
|
|
|
my $cur_param_name = $out_param->{name}; |
1498
|
0
|
|
|
|
|
|
my $cur_param_type = $out_param->{type}; |
1499
|
|
|
|
|
|
|
|
1500
|
0
|
0
|
0
|
|
|
|
if($cur_param_type eq 'bool' || $cur_param_type =~ m/^uint/i) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
{ |
1502
|
0
|
|
|
|
|
|
$array_index++; |
1503
|
|
|
|
|
|
|
} |
1504
|
|
|
|
|
|
|
elsif($cur_param_type =~ m/^int/i) |
1505
|
|
|
|
|
|
|
{ |
1506
|
0
|
|
|
|
|
|
$array_index++; |
1507
|
|
|
|
|
|
|
} |
1508
|
|
|
|
|
|
|
elsif($cur_param_type eq 'address') |
1509
|
|
|
|
|
|
|
{ |
1510
|
0
|
|
|
|
|
|
$array_index++; |
1511
|
|
|
|
|
|
|
} |
1512
|
|
|
|
|
|
|
elsif($cur_param_type eq 'string') |
1513
|
|
|
|
|
|
|
{ |
1514
|
0
|
|
|
|
|
|
my $str=$function_params->{ $cur_param_name }; |
1515
|
0
|
|
|
|
|
|
my $hunk=$this->_string2hex($str); |
1516
|
0
|
|
|
|
|
|
my $hunk_size = length($hunk); |
1517
|
0
|
|
|
|
|
|
my $number_of_32b_blocks = int($hunk_size / 64); |
1518
|
0
|
|
|
|
|
|
my $part = $hunk_size % 64; |
1519
|
0
|
|
|
|
|
|
my $repeater = '0'x(64-$part + 2); |
1520
|
0
|
|
|
|
|
|
my $hunk_appended = substr($hunk.$repeater, 2); |
1521
|
0
|
|
|
|
|
|
my $str_length = length($str); |
1522
|
|
|
|
|
|
|
|
1523
|
0
|
|
|
|
|
|
$out_param_array->[$array_index] = sprintf('%064x', $var_data_offset); |
1524
|
0
|
|
|
|
|
|
$var_data_offset += (($number_of_32b_blocks+1) * 32) + 32; |
1525
|
0
|
|
|
|
|
|
$array_index++; |
1526
|
0
|
|
|
|
|
|
$out_param_array->[$var_data_offset_index + $second_pass_counter] = sprintf('%064x', $str_length); |
1527
|
0
|
|
|
|
|
|
$second_pass_counter++; |
1528
|
|
|
|
|
|
|
|
1529
|
0
|
|
|
|
|
|
my $hunk_position=0; |
1530
|
0
|
|
|
|
|
|
while(1) |
1531
|
|
|
|
|
|
|
{ |
1532
|
0
|
|
|
|
|
|
my $cur_str=substr($hunk_appended, $hunk_position, 64); |
1533
|
0
|
0
|
|
|
|
|
if($cur_str eq "") |
1534
|
|
|
|
|
|
|
{ |
1535
|
0
|
|
|
|
|
|
last; |
1536
|
|
|
|
|
|
|
} |
1537
|
0
|
|
|
|
|
|
$out_param_array->[$var_data_offset_index + $second_pass_counter] = $cur_str; |
1538
|
0
|
|
|
|
|
|
$second_pass_counter++; |
1539
|
0
|
|
|
|
|
|
$hunk_position += 64; |
1540
|
|
|
|
|
|
|
} |
1541
|
|
|
|
|
|
|
} |
1542
|
|
|
|
|
|
|
} |
1543
|
|
|
|
|
|
|
|
1544
|
0
|
|
|
|
|
|
my $raw; |
1545
|
0
|
0
|
|
|
|
|
if($function_name eq 'constructor') |
1546
|
|
|
|
|
|
|
{ |
1547
|
0
|
|
|
|
|
|
$raw=join('', @$out_param_array); |
1548
|
|
|
|
|
|
|
} |
1549
|
|
|
|
|
|
|
else |
1550
|
|
|
|
|
|
|
{ |
1551
|
|
|
|
|
|
|
# Get Contract Method Id |
1552
|
0
|
|
|
|
|
|
my $function_selector = $function_name; |
1553
|
0
|
|
|
|
|
|
chop($param_types_list); |
1554
|
0
|
|
|
|
|
|
$function_selector = $function_selector.'('.$param_types_list.')'; |
1555
|
0
|
|
|
|
|
|
my $contract_method_id = $this->_getContractMethodId($function_selector); |
1556
|
0
|
|
|
|
|
|
$raw=$contract_method_id.join('', @$out_param_array); |
1557
|
|
|
|
|
|
|
} |
1558
|
0
|
|
|
|
|
|
return $raw; |
1559
|
|
|
|
|
|
|
} |
1560
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
=pod |
1563
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
=head2 _unmarshal |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
Internal method. |
1567
|
|
|
|
|
|
|
Unmarshal data from JSON RPC call |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
return $this->_unmarshal($function_name, $raw_data); |
1570
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
$function_name - method name to get ABI |
1572
|
|
|
|
|
|
|
$raw_data - data, returned from method |
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
=cut |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
sub _unmarshal() |
1577
|
|
|
|
|
|
|
{ |
1578
|
0
|
|
|
0
|
|
|
my ($this, $function_name, $raw_data) = @_; |
1579
|
|
|
|
|
|
|
|
1580
|
0
|
|
|
|
|
|
my $function_abi = $this->_get_function_abi($function_name); |
1581
|
0
|
|
|
|
|
|
my $function_outputs = $function_abi-> { outputs }; |
1582
|
|
|
|
|
|
|
|
1583
|
0
|
|
|
|
|
|
my $return_value={}; |
1584
|
0
|
0
|
|
|
|
|
if($this->{return_raw_data}) |
1585
|
|
|
|
|
|
|
{ |
1586
|
0
|
|
|
|
|
|
$return_value-> { raw_data } = $raw_data; |
1587
|
|
|
|
|
|
|
} |
1588
|
|
|
|
|
|
|
|
1589
|
0
|
|
|
|
|
|
my $current_out_param_position=0; |
1590
|
|
|
|
|
|
|
|
1591
|
0
|
|
|
|
|
|
foreach my $out_param (@$function_outputs) |
1592
|
|
|
|
|
|
|
{ |
1593
|
0
|
|
|
|
|
|
my $cur_param_name = $out_param->{name}; |
1594
|
0
|
|
|
|
|
|
my $cur_param_type = $out_param->{type}; |
1595
|
|
|
|
|
|
|
|
1596
|
0
|
0
|
0
|
|
|
|
if($cur_param_type eq 'bool' || $cur_param_type =~ m/^uint/i) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
{ |
1598
|
0
|
|
|
|
|
|
my $hunk='0x'.substr($raw_data, $current_out_param_position, 64); |
1599
|
0
|
|
|
|
|
|
my $uint256 = $this->_unmarshal_int($hunk); |
1600
|
0
|
|
|
|
|
|
$return_value->{ $cur_param_name } = $uint256; |
1601
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1602
|
|
|
|
|
|
|
} |
1603
|
|
|
|
|
|
|
elsif($cur_param_type =~ m/^int/i) |
1604
|
|
|
|
|
|
|
{ |
1605
|
0
|
|
|
|
|
|
my $hunk='0x'.substr($raw_data, $current_out_param_position, 64); |
1606
|
0
|
|
|
|
|
|
my $uint256 = $this->_unmarshal_int($hunk); |
1607
|
0
|
|
|
|
|
|
$return_value->{ $cur_param_name } = $uint256; |
1608
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1609
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
} |
1611
|
|
|
|
|
|
|
elsif($cur_param_type eq 'address') |
1612
|
|
|
|
|
|
|
{ |
1613
|
0
|
|
|
|
|
|
my $hunk='0x'.substr($raw_data, $current_out_param_position, 64); |
1614
|
0
|
|
|
|
|
|
$hunk =~ s/00//g; |
1615
|
0
|
|
|
|
|
|
$return_value->{ $cur_param_name } = $hunk; |
1616
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1617
|
|
|
|
|
|
|
} |
1618
|
|
|
|
|
|
|
elsif($cur_param_type eq 'string') |
1619
|
|
|
|
|
|
|
{ |
1620
|
0
|
|
|
|
|
|
my $size_offset = hex('0x'.substr($raw_data, $current_out_param_position, 64)); |
1621
|
0
|
|
|
|
|
|
my $data_size = hex(substr($raw_data, $size_offset * 2, 64)); |
1622
|
0
|
|
|
|
|
|
my $data_chunk = substr($raw_data, 64 + $size_offset*2, $data_size * 2); |
1623
|
0
|
|
|
|
|
|
my $str = $this->_hex2string('0x'.$data_chunk); |
1624
|
0
|
|
|
|
|
|
$return_value->{ $cur_param_name } = $str; |
1625
|
0
|
|
|
|
|
|
$current_out_param_position += 64; |
1626
|
|
|
|
|
|
|
} |
1627
|
|
|
|
|
|
|
else |
1628
|
|
|
|
|
|
|
{ |
1629
|
0
|
|
|
|
|
|
die 'Net::Ethereum _marshal does not support type: '.$cur_param_type; |
1630
|
|
|
|
|
|
|
} |
1631
|
|
|
|
|
|
|
} |
1632
|
0
|
|
|
|
|
|
return $return_value; |
1633
|
|
|
|
|
|
|
} |
1634
|
|
|
|
|
|
|
|
1635
|
|
|
|
|
|
|
=pod |
1636
|
|
|
|
|
|
|
|
1637
|
|
|
|
|
|
|
=head2 _marshal_int |
1638
|
|
|
|
|
|
|
|
1639
|
|
|
|
|
|
|
Internal method. |
1640
|
|
|
|
|
|
|
Marshal integer value |
1641
|
|
|
|
|
|
|
Returns marshales string |
1642
|
|
|
|
|
|
|
|
1643
|
|
|
|
|
|
|
$add_hunk=$this->_marshal_int($add_hunk); |
1644
|
|
|
|
|
|
|
|
1645
|
|
|
|
|
|
|
int_to_marshal - int value to marshal |
1646
|
|
|
|
|
|
|
|
1647
|
|
|
|
|
|
|
=cut |
1648
|
|
|
|
|
|
|
|
1649
|
|
|
|
|
|
|
sub _marshal_int($$) |
1650
|
|
|
|
|
|
|
{ |
1651
|
0
|
|
|
0
|
|
|
my ($this, $int_to_marshal) = @_; |
1652
|
0
|
|
|
|
|
|
my $bint_hex; |
1653
|
|
|
|
|
|
|
my $filler_size; |
1654
|
0
|
|
|
|
|
|
my $filler_char; |
1655
|
|
|
|
|
|
|
|
1656
|
0
|
|
|
|
|
|
my $bint = Math::BigInt->new($int_to_marshal); |
1657
|
0
|
0
|
|
|
|
|
if($bint->is_negative()) |
1658
|
|
|
|
|
|
|
{ |
1659
|
0
|
|
|
|
|
|
$bint->bneg(); |
1660
|
0
|
|
|
|
|
|
$bint->bxor('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'); |
1661
|
0
|
|
|
|
|
|
$bint->binc(); |
1662
|
0
|
|
|
|
|
|
$filler_char = 'f'; |
1663
|
|
|
|
|
|
|
} |
1664
|
|
|
|
|
|
|
else |
1665
|
|
|
|
|
|
|
{ |
1666
|
0
|
|
|
|
|
|
$filler_char = '0'; |
1667
|
|
|
|
|
|
|
} |
1668
|
0
|
|
|
|
|
|
$bint_hex = $bint->to_hex(); |
1669
|
0
|
|
|
|
|
|
$filler_size = 64 - length($bint_hex); |
1670
|
0
|
|
|
|
|
|
for(1..$filler_size) |
1671
|
|
|
|
|
|
|
{ |
1672
|
0
|
|
|
|
|
|
$bint_hex = $filler_char.$bint_hex; |
1673
|
|
|
|
|
|
|
} |
1674
|
0
|
|
|
|
|
|
return($bint_hex); |
1675
|
|
|
|
|
|
|
} |
1676
|
|
|
|
|
|
|
|
1677
|
|
|
|
|
|
|
=pod |
1678
|
|
|
|
|
|
|
|
1679
|
|
|
|
|
|
|
=head2 _unmarshal_int |
1680
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
Internal method. |
1682
|
|
|
|
|
|
|
Unmarshal integer value |
1683
|
|
|
|
|
|
|
Returns unmarshaled value |
1684
|
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
my $uint256 = $this->_unmarshal_int($hunk); |
1686
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
int_to_marshal - int value to marshal |
1688
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
=cut |
1690
|
|
|
|
|
|
|
|
1691
|
|
|
|
|
|
|
sub _unmarshal_int($$) |
1692
|
|
|
|
|
|
|
{ |
1693
|
0
|
|
|
0
|
|
|
my ($this, $str_to_unmarshal) = @_; |
1694
|
0
|
|
|
|
|
|
my $unmarshalled_int = Math::BigInt->new($str_to_unmarshal); |
1695
|
0
|
|
|
|
|
|
my $neg_test = Math::BigInt->new($str_to_unmarshal); |
1696
|
0
|
0
|
|
|
|
|
if($neg_test->band('0x8000000000000000000000000000000000000000000000000000000000000000')) |
1697
|
|
|
|
|
|
|
{ |
1698
|
0
|
|
|
|
|
|
$unmarshalled_int->bxor('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'); |
1699
|
0
|
|
|
|
|
|
$unmarshalled_int->binc(); |
1700
|
0
|
|
|
|
|
|
$unmarshalled_int->bneg(); |
1701
|
|
|
|
|
|
|
} |
1702
|
0
|
|
|
|
|
|
return $unmarshalled_int; |
1703
|
|
|
|
|
|
|
} |
1704
|
|
|
|
|
|
|
|
1705
|
|
|
|
|
|
|
=pod |
1706
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
=head2 _get_function_abi |
1708
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
Internal method. |
1710
|
|
|
|
|
|
|
Returns ABI for given method |
1711
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
my $function_abi = $this->_get_function_abi($function_name); |
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
$function_name - method name to get ABI |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
=cut |
1717
|
|
|
|
|
|
|
|
1718
|
|
|
|
|
|
|
sub _get_function_abi() |
1719
|
|
|
|
|
|
|
{ |
1720
|
0
|
|
|
0
|
|
|
my ($this, $function_name) = @_; |
1721
|
0
|
|
|
|
|
|
my $rec; |
1722
|
0
|
|
|
|
|
|
my $abi = $this->{abi}; |
1723
|
0
|
|
|
|
|
|
foreach $rec (@$abi) |
1724
|
|
|
|
|
|
|
{ |
1725
|
0
|
0
|
0
|
|
|
|
if($rec->{ type } eq 'function' and $rec->{ name } eq $function_name) |
1726
|
|
|
|
|
|
|
{ |
1727
|
0
|
|
|
|
|
|
return $rec; |
1728
|
|
|
|
|
|
|
} |
1729
|
|
|
|
|
|
|
} |
1730
|
0
|
|
|
|
|
|
return {}; |
1731
|
|
|
|
|
|
|
} |
1732
|
|
|
|
|
|
|
|
1733
|
|
|
|
|
|
|
|
1734
|
|
|
|
|
|
|
=pod |
1735
|
|
|
|
|
|
|
|
1736
|
|
|
|
|
|
|
=head2 _get_constructor_abi |
1737
|
|
|
|
|
|
|
|
1738
|
|
|
|
|
|
|
Internal method. |
1739
|
|
|
|
|
|
|
Returns ABI for contract constructor |
1740
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
if($function_name eq 'constructor') |
1742
|
|
|
|
|
|
|
{ |
1743
|
|
|
|
|
|
|
$function_abi = $this->_get_constructor_abi($function_name); |
1744
|
|
|
|
|
|
|
} |
1745
|
|
|
|
|
|
|
|
1746
|
|
|
|
|
|
|
$function_name - method name to get ABI |
1747
|
|
|
|
|
|
|
|
1748
|
|
|
|
|
|
|
=cut |
1749
|
|
|
|
|
|
|
|
1750
|
|
|
|
|
|
|
sub _get_constructor_abi() |
1751
|
|
|
|
|
|
|
{ |
1752
|
0
|
|
|
0
|
|
|
my ($this, $function_name) = @_; |
1753
|
0
|
|
|
|
|
|
my $rec; |
1754
|
0
|
|
|
|
|
|
my $abi = $this->{abi}; |
1755
|
|
|
|
|
|
|
|
1756
|
0
|
|
|
|
|
|
foreach $rec (@$abi) |
1757
|
|
|
|
|
|
|
{ |
1758
|
0
|
0
|
|
|
|
|
if($rec->{ type } eq 'constructor') |
1759
|
|
|
|
|
|
|
{ |
1760
|
0
|
|
|
|
|
|
return $rec; |
1761
|
|
|
|
|
|
|
} |
1762
|
|
|
|
|
|
|
} |
1763
|
0
|
|
|
|
|
|
return {}; |
1764
|
|
|
|
|
|
|
} |
1765
|
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
|
1767
|
|
|
|
|
|
|
=pod |
1768
|
|
|
|
|
|
|
|
1769
|
|
|
|
|
|
|
=head2 _getContractMethodId |
1770
|
|
|
|
|
|
|
|
1771
|
|
|
|
|
|
|
Internal method. |
1772
|
|
|
|
|
|
|
Convert a method name into function selector (contract methos id). |
1773
|
|
|
|
|
|
|
Returns the contract methos id. |
1774
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
The first four bytes of the call data for a function call specifies the function to be called. |
1776
|
|
|
|
|
|
|
It is the first (left, high-order in big-endian) four bytes of the Keccak (SHA-3) hash of the signature of the function. |
1777
|
|
|
|
|
|
|
The signature is defined as the canonical expression of the basic prototype, i.e. the function name with the parenthesised list of parameter types. |
1778
|
|
|
|
|
|
|
Parameter types are split by a single comma - no spaces are used. |
1779
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
my $function_selector = $function_name; |
1781
|
|
|
|
|
|
|
chop($param_types_list); |
1782
|
|
|
|
|
|
|
$method_name = $function_selector.'('.$param_types_list.')'; |
1783
|
|
|
|
|
|
|
my $contract_method_id = $this->_getContractMethodId($method_name); |
1784
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
$method_name - function name, include parameters |
1786
|
|
|
|
|
|
|
|
1787
|
|
|
|
|
|
|
=cut |
1788
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
sub _getContractMethodId() |
1790
|
|
|
|
|
|
|
{ |
1791
|
0
|
|
|
0
|
|
|
my ($this, $method_name) = @_; |
1792
|
0
|
|
|
|
|
|
my $method_name_hex = $this->_string2hex($method_name); |
1793
|
0
|
|
|
|
|
|
my $hash = $this->web3_sha3($method_name_hex); |
1794
|
0
|
|
|
|
|
|
return substr($hash, 0, 10); |
1795
|
|
|
|
|
|
|
} |
1796
|
|
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
=pod |
1798
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
=head2 _hex2string |
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
Internal method. |
1802
|
|
|
|
|
|
|
Convert a hexadecimal value into string. Returns the string. |
1803
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
my $str = $this->_hex2string('0x'.$data_chunk); |
1805
|
|
|
|
|
|
|
|
1806
|
|
|
|
|
|
|
$data_chunk - hexadecimal data to conv |
1807
|
|
|
|
|
|
|
|
1808
|
|
|
|
|
|
|
=cut |
1809
|
|
|
|
|
|
|
|
1810
|
|
|
|
|
|
|
sub _hex2string() |
1811
|
|
|
|
|
|
|
{ |
1812
|
0
|
|
|
0
|
|
|
my ($this, $hex) = @_; |
1813
|
|
|
|
|
|
|
|
1814
|
0
|
|
|
|
|
|
my $n = 2; # $n is group size. |
1815
|
0
|
|
|
|
|
|
my @groups = unpack "a$n" x (length( $hex ) /$n ), $hex; |
1816
|
0
|
|
|
|
|
|
my $string = join ('', map { chr(hex($_)) } @groups ); |
|
0
|
|
|
|
|
|
|
1817
|
0
|
|
|
|
|
|
return($string); |
1818
|
|
|
|
|
|
|
} |
1819
|
|
|
|
|
|
|
|
1820
|
|
|
|
|
|
|
|
1821
|
|
|
|
|
|
|
=pod |
1822
|
|
|
|
|
|
|
|
1823
|
|
|
|
|
|
|
=head2 _string2hex |
1824
|
|
|
|
|
|
|
|
1825
|
|
|
|
|
|
|
Internal method. |
1826
|
|
|
|
|
|
|
Convert a string to hexadecimal. Returns the converted string. |
1827
|
|
|
|
|
|
|
|
1828
|
|
|
|
|
|
|
my $hunk=$this->_string2hex($str); |
1829
|
|
|
|
|
|
|
|
1830
|
|
|
|
|
|
|
$string - source string to conv |
1831
|
|
|
|
|
|
|
|
1832
|
|
|
|
|
|
|
=cut |
1833
|
|
|
|
|
|
|
|
1834
|
|
|
|
|
|
|
sub _string2hex() |
1835
|
|
|
|
|
|
|
{ |
1836
|
0
|
|
|
0
|
|
|
my ($this, $string) = @_; |
1837
|
0
|
|
|
|
|
|
my @array = split('', $string); |
1838
|
0
|
|
|
|
|
|
my @array_ascii = map { sprintf("%x", ord($_)) } @array; |
|
0
|
|
|
|
|
|
|
1839
|
0
|
|
|
|
|
|
my $string_ascii = join('', @array_ascii); |
1840
|
0
|
|
|
|
|
|
return '0x'.$string_ascii; |
1841
|
|
|
|
|
|
|
} |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
|
1844
|
|
|
|
|
|
|
=pod |
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
=head2 _node_request |
1847
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
Internal method. |
1849
|
|
|
|
|
|
|
Send request to JSON RPC API |
1850
|
|
|
|
|
|
|
|
1851
|
|
|
|
|
|
|
my $rq = { jsonrpc => "2.0", method => "net_version", params => [], id => 67}; |
1852
|
|
|
|
|
|
|
my $num = $this->_node_request($rq)-> { result }; |
1853
|
|
|
|
|
|
|
|
1854
|
|
|
|
|
|
|
=cut |
1855
|
|
|
|
|
|
|
|
1856
|
|
|
|
|
|
|
sub _node_request() |
1857
|
|
|
|
|
|
|
{ |
1858
|
0
|
|
|
0
|
|
|
my ($this, $json_data) = @_; |
1859
|
|
|
|
|
|
|
|
1860
|
0
|
|
|
|
|
|
my $req = HTTP::Request->new(POST => $this->{api_url}); |
1861
|
0
|
|
|
|
|
|
$req->header('Content-Type' => 'application/json'); |
1862
|
0
|
|
|
|
|
|
my $ua = LWP::UserAgent->new; |
1863
|
0
|
|
|
|
|
|
my $data = encode_json($json_data); |
1864
|
0
|
|
|
|
|
|
$req->add_content_utf8($data); |
1865
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
#print '_node_request req: ', Dumper($req); |
1867
|
|
|
|
|
|
|
|
1868
|
0
|
|
|
|
|
|
my $ua_rc = $ua->request($req)->{ _content }; |
1869
|
|
|
|
|
|
|
|
1870
|
|
|
|
|
|
|
#print '_node_request ua_rc: ', Dumper($ua_rc); |
1871
|
|
|
|
|
|
|
|
1872
|
0
|
|
|
|
|
|
my $rc; |
1873
|
0
|
0
|
|
|
|
|
if($ua_rc=~/"result":/) |
1874
|
|
|
|
|
|
|
{ |
1875
|
0
|
|
|
|
|
|
$rc = JSON::decode_json($ua_rc); |
1876
|
|
|
|
|
|
|
} |
1877
|
|
|
|
|
|
|
else |
1878
|
|
|
|
|
|
|
{ |
1879
|
0
|
|
|
|
|
|
die 'Died at Net::Ethereum _node_request() - '.$ua_rc; |
1880
|
|
|
|
|
|
|
} |
1881
|
0
|
0
|
|
|
|
|
if($rc->{error}) { die $rc; } |
|
0
|
|
|
|
|
|
|
1882
|
0
|
|
|
|
|
|
else { return $rc; } |
1883
|
|
|
|
|
|
|
} |
1884
|
|
|
|
|
|
|
|
1885
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
|
1887
|
|
|
|
|
|
|
1; |
1888
|
|
|
|
|
|
|
__END__ |