teth 0.1.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7635b781f5fd78703f5bbddb1dcea9fd0804eb0c
4
- data.tar.gz: 47c054a1f298a4e8ff2645af025a1cc347a40945
3
+ metadata.gz: 043f398e22fcc354d5eb00e278f4b68b652abc28
4
+ data.tar.gz: c29c699f115c04c957b430857568da8f61aaa911
5
5
  SHA512:
6
- metadata.gz: c8582ab1a8eb8152f4d61e7d6203cdacf6eac0d0182fe2b02db75af672f518de50a86fab6b4b96ab09908506ca9d3a984de40c5665e5772c688e3eabaf0f0a62
7
- data.tar.gz: 411a9aee288dfb9c0d84f247afee074d02026277eec33dea92187fd8096b6d1c6262a9eab93490c988d40fe76d97629569468376d216cb9472a9cf77e68d1615
6
+ metadata.gz: d87429ea3b59ddaea5b3d7e56b05ae6ebe232ea3ade8cc507b71b05d8c6ee6307ba2f64c08d3c6ad413a48ee760fb0be1f66314f78f28fc1ac20e69b6f9b547b
7
+ data.tar.gz: dc5fc847cc0d7a5dccf21086770f6ad90656aef27a47cc13f46c473ecec6dfbc042fba83ff3078e96e7e582931a612614608d686ac9b2580693c5be4e4eec9d2
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  Teth is a Ethereum smart contract test framework in ruby.It provides two testing environments: testing in ruby EVM and testing in geth.You don't need to understand ruby grammar, just enjoy syntactic sugar.
3
3
 
4
4
  ## Dependencies
5
- - Solidity ~> 0.3.6
5
+ - Solidity ~> 0.4.1
6
6
  - Ruby ~> 2.2.2
7
7
  - Go-ethereum ~> 1.4.11
8
8
 
@@ -13,53 +13,182 @@ bundle install teth
13
13
 
14
14
  ## How to use
15
15
 
16
- Help command:
16
+ #### Help command
17
17
  ```
18
18
  $ teth
19
+ Usage: teth COMMAND [ARGS]
20
+ The most common teth commands are:
21
+ new Create a new Smart Contract application. "teth new my_app" creates a
22
+ new application called my_app in "./my_app" (short-cut alias: "n")
23
+ generate Generate new solidity smart contract and test files. "teth generate token"
24
+ creates Token contract and corresponding test files. (short-cut alias: "g")
25
+ test Run your ruby tests in ruby evm. (short-cut alias: "t")
26
+ init Bootstraps and initialises a new genesis block. "teth init" creates data directory
27
+ for private chain.(short-cut alias: "i")
28
+ import_keys Import keys to private chain (short-cut alias: "ik")
29
+ build Build contract (short-cut alias: "b")
30
+ migrate Deploy contract on private chain (short-cut alias: "m")
31
+ server Start geth server (short-cut alias: "s")
32
+ console Start geth attach (short-cut alias: "c")
33
+ gtest Run your javascript tests on geth (short-cut alias: "gt")
34
+
35
+ All commands can be run with -h (or --help) for more information.
36
+
19
37
  ```
38
+ #### Creeat project
20
39
  Create a new Smart Contract application
40
+ ```shell
41
+ $ teth n examples
42
+ Creating project examples...
43
+ Resolving dependencies...
44
+ Using ffi 1.9.14
45
+ Using little-plugger 1.1.4
46
+ Using multi_json 1.12.1
47
+ Using digest-sha3 1.1.0
48
+ Using ethash 0.2.0
49
+ Using fiddler-rb 0.1.2
50
+ Using lru_redux 1.1.0
51
+ Using minitest 5.9.0
52
+ Using rlp 0.7.3
53
+ Using bundler 1.12.5
54
+ Using bitcoin-secp256k1 0.4.0
55
+ Using logging 2.1.0
56
+ Using leveldb 0.1.9
57
+ Using block_logger 0.1.2
58
+ Using ruby-ethereum 0.9.5
59
+ Using teth 0.1.1
60
+ Bundle complete! 1 Gemfile dependency, 16 gems now installed.
61
+ Use `bundle show [gemname]` to see where a bundled gem is installed.
62
+ Done.
63
+
64
+ $ cd examples
21
65
  ```
22
- $ teth n project
23
- $ cd project
24
- ```
25
- Generate new Smart Contract and test file
66
+ #### Generate new Smart Contract and test files
67
+ ```shell
68
+ $ teth g token
69
+ Creating Token contract file...
70
+ Creating token test files...
71
+ Done.
26
72
  ```
27
- $ teth g game
73
+ This generates contract file `contracts/Token.sol`, and test files `tests/token_test.rb`, `gtests/Token_test.js`.
74
+
75
+ Edit token contract and test file.
76
+
77
+ `contracts/Token.sol`
78
+ ```javascript
79
+ pragma solidity ^0.4.0;
80
+
81
+ contract Token {
82
+ address issuer;
83
+ mapping (address => uint) balances;
84
+
85
+ event Issue(address account, uint amount);
86
+ event Transfer(address from, address to, uint amount);
87
+
88
+ function Token() {
89
+ issuer = msg.sender;
90
+ }
91
+
92
+ function issue(address account, uint amount) {
93
+ if (msg.sender != issuer) throw;
94
+ balances[account] += amount;
95
+ Issue(account, amount);
96
+ }
97
+
98
+ function transfer(address to, uint amount) {
99
+ if (balances[msg.sender] < amount) throw;
100
+
101
+ balances[msg.sender] -= amount;
102
+ balances[to] += amount;
103
+
104
+ Transfer(msg.sender, to, amount);
105
+ }
106
+
107
+ function getBalance(address account) constant returns (uint) {
108
+ return balances[account];
109
+ }
110
+ }
111
+
28
112
  ```
29
- Run tests
113
+
114
+ `tests/token_test.rb`
115
+ ```ruby
116
+ require 'teth/minitest'
117
+
118
+ class TokenTest < Teth::Minitest
119
+ def test_contract_deployed
120
+ assert_equal false, contract.address.nil?
121
+ end
122
+
123
+ def test_issue_balance
124
+ assert_equal 0, contract.getBalance(bob)
125
+ contract.issue bob, 100
126
+ assert_equal 100, contract.getBalance(bob)
127
+ end
128
+
129
+ def test_issue_exception
130
+ assert_raises(TransactionFailed) do
131
+ contract.issue bob, 100, sender: eve_privkey
132
+ end
133
+ assert_equal 0, contract.getBalance(bob)
134
+ end
135
+
136
+ def test_token_transfer
137
+ contract.issue bob, 100
138
+ contract.transfer carol, 90, sender: bob_privkey
139
+ assert_equal 90, contract.getBalance(carol)
140
+
141
+ assert_raises(TransactionFailed) { contract.transfer carol, 90, sender: bob_privkey }
142
+ end
143
+ end
144
+
30
145
  ```
31
- $ teth t game
146
+
147
+ #### Run tests in ruby evm
148
+ ```shell
149
+ $ teth t token
150
+ Test Token contract...
151
+ Run options: --seed 2192
152
+
153
+ # Running:
154
+
155
+ ....
156
+
157
+ Finished in 1.935546s, 2.0666 runs/s, 3.6166 assertions/s.
158
+
159
+ 4 runs, 7 assertions, 0 failures, 0 errors, 0 skips
160
+ Done.
32
161
  ```
33
162
 
34
- ## Unit tests
163
+ #### Unit tests
35
164
  You can wirte fast, simple tests.
36
165
  ```ruby
37
- class TokenTest < Minitest::Test
38
- include Ethereum
166
+ require 'teth/minitest'
39
167
 
40
- def setup
41
- @state = Tester::State.new
42
- @solidity_code = File.read('./contracts/Token.sol')
43
- @c = @state.abi_contract @solidity_code, language: :solidity
168
+ class TokenTest < Teth::Minitest
169
+ def test_contract_deployed
170
+ assert_equal false, contract.address.nil?
44
171
  end
45
172
 
46
173
  def test_issue_balance
47
- assert_equal 0, @c.getBalance(Tester::Fixture.accounts[2])
48
- @c.issue Tester::Fixture.accounts[2], 100
49
- assert_equal 100, @c.getBalance(Tester::Fixture.accounts[2])
174
+ assert_equal 0, contract.getBalance(bob)
175
+ contract.issue bob, 100
176
+ assert_equal 100, contract.getBalance(bob)
50
177
  end
51
178
 
52
179
  def test_issue_exception
53
- assert_raises(TransactionFailed) { @c.issue Tester::Fixture.accounts[3], 100, sender: Tester::Fixture.keys[4] }
54
- assert_equal 0, @c.getBalance(Tester::Fixture.accounts[3])
180
+ assert_raises(TransactionFailed) do
181
+ contract.issue bob, 100, sender: eve_privkey
182
+ end
183
+ assert_equal 0, contract.getBalance(bob)
55
184
  end
56
185
 
57
186
  def test_token_transfer
58
- @c.issue Tester::Fixture.accounts[2], 100
59
- @c.transfer Tester::Fixture.accounts[3], 90, sender: Tester::Fixture.keys[2]
60
- assert_equal 90, @c.getBalance(Tester::Fixture.accounts[3])
187
+ contract.issue bob, 100
188
+ contract.transfer carol, 90, sender: bob_privkey
189
+ assert_equal 90, contract.getBalance(carol)
61
190
 
62
- assert_raises(TransactionFailed) { @c.transfer Tester::Fixture.accounts[3], 90, sender: Tester::Fixture.keys[2] }
191
+ assert_raises(TransactionFailed) { contract.transfer carol, 90, sender: bob_privkey }
63
192
  end
64
193
  end
65
194
 
@@ -67,11 +196,298 @@ end
67
196
  More details:
68
197
  https://github.com/seattlerb/minitest
69
198
 
70
- ## TODO
71
- - Extract test file require and others
72
- - Save migrate address
73
- - Migrate ARGV
74
- - Script for preload
75
- - Easy way to load contract on chain
76
- - Easy way to test on chain
77
- - ES6
199
+ #### Init geth block
200
+ ```shell
201
+ $ teth init
202
+ Initialising a new genesis block...
203
+ ***** Using geth at: geth
204
+ I0917 16:01:17.338908 ethdb/database.go:82] Alloted 16MB cache and 16 file handles to /Users/u2/cryptape/teth/examples/data/chaindata
205
+ I0917 16:01:17.347151 cmd/geth/main.go:299] successfully wrote genesis block and/or chain rule set: 611596e7979cd4e7ca1531260fa706093a5492ecbdf58f20a39545397e424d04
206
+ ```
207
+ #### Import keys to geth
208
+ ```shell
209
+ $ teth ik
210
+ Importing keys, this will take a while, please be patient......
211
+ ***** Using geth at: geth
212
+ ***** Import all pre-funded private keys
213
+ Notice: No need to input your password. The default password is 123456
214
+ spawn geth --datadir data account import ./private_keys/3ae88fe370c39384fc16da2c9e768cf5d2495b48.key
215
+ Your new account is locked with a password. Please give a password. Do not forget this password.
216
+ Passphrase:
217
+ Repeat passphrase:
218
+ Address: {3ae88fe370c39384fc16da2c9e768cf5d2495b48}
219
+ Notice: No need to input your password. The default password is 123456
220
+ spawn geth --datadir data account import ./private_keys/81063419f13cab5ac090cd8329d8fff9feead4a0.key
221
+ Your new account is locked with a password. Please give a password. Do not forget this password.
222
+ Passphrase:
223
+ Repeat passphrase:
224
+ Address: {81063419f13cab5ac090cd8329d8fff9feead4a0}
225
+ Notice: No need to input your password. The default password is 123456
226
+ spawn geth --datadir data account import ./private_keys/9da26fc2e1d6ad9fdd46138906b0104ae68a65d8.key
227
+ Your new account is locked with a password. Please give a password. Do not forget this password.
228
+ Passphrase:
229
+ Repeat passphrase:
230
+ Address: {9da26fc2e1d6ad9fdd46138906b0104ae68a65d8}
231
+ ***** Done.
232
+
233
+ ```
234
+ Notice: *This will take a while, please be patient. No need to input your password.*
235
+
236
+ #### Build contract
237
+ ```shell
238
+ $ teth build token
239
+ Building contract Token
240
+
241
+ ======= Token =======
242
+ Gas estimation:
243
+ construction:
244
+ 20201 + 73400 = 93601
245
+ external:
246
+
247
+
248
+ -------------------------------------
249
+ Enter Gas:
250
+ 400000
251
+ Enter Value To Be Transferred:
252
+
253
+ Enter Input:
254
+
255
+ Done.
256
+ ```
257
+ Build all contracts if no contract name provided.
258
+
259
+ #### Start geth server
260
+ ```shell
261
+ $ teth server
262
+ ***** Using geth at: geth
263
+ Start geth server...
264
+ I0917 16:17:16.882572 ethdb/database.go:82] Alloted 128MB cache and 1024 file handles to data/chaindata
265
+ I0917 16:17:16.894415 ethdb/database.go:169] closed db:data/chaindata
266
+ I0917 16:17:16.895446 ethdb/database.go:82] Alloted 128MB cache and 1024 file handles to data/chaindata
267
+ I0917 16:17:16.946341 eth/backend.go:621] upgrading db log bloom bins
268
+ I0917 16:17:16.946478 eth/backend.go:629] upgrade completed in 142.276µs
269
+ I0917 16:17:16.946513 ethdb/database.go:82] Alloted 16MB cache and 16 file handles to data/dapp
270
+ I0917 16:17:16.951072 eth/backend.go:172] Protocol Versions: [63 62], Network Id: 31415926
271
+ I0917 16:17:16.951142 eth/backend.go:201] Blockchain DB Version: 3
272
+ I0917 16:17:16.953641 core/blockchain.go:206] Last header: #0 [611596e7…] TD=131072
273
+ I0917 16:17:16.953667 core/blockchain.go:207] Last block: #0 [611596e7…] TD=131072
274
+ I0917 16:17:16.953678 core/blockchain.go:208] Fast block: #0 [611596e7…] TD=131072
275
+ I0917 16:17:16.954420 p2p/server.go:313] Starting Server
276
+ I0917 16:17:16.955324 p2p/server.go:556] Listening on [::]:30303
277
+ I0917 16:17:16.957427 node/node.go:296] IPC endpoint opened: data/geth.ipc
278
+ I0917 16:17:16.959797 node/node.go:366] HTTP endpoint opened: http://localhost:8545
279
+ I0917 16:17:17.945231 cmd/geth/accountcmd.go:189] Unlocked account 3ae88fe370c39384fc16da2c9e768cf5d2495b48
280
+ I0917 16:17:19.158064 p2p/nat/nat.go:111] mapped network port tcp:30303 -> 30303 (ethereum p2p) using UPNP IGDv1-IP1
281
+ ```
282
+ #### Migrate
283
+ Deploy your contract on geth, must keep teth sever started.
284
+ ```shell
285
+ $ teth m
286
+ Migrating contract token
287
+ ***** Using geth at: geth
288
+ null
289
+ Contract transaction send: TransactionHash: 0x3a9ca7a774a4bc5b3ba23b57f3c65a5debbfcbba422f902009909604ee668a63 waiting to be mined...
290
+ Compiled Object : TokenCompiled
291
+ Contract : TokenContract
292
+ Contract Instance : Token
293
+ true
294
+ Contract mined! Address: 0x3a020580345e79e223580d8d6a50e063667f19b5
295
+ Done.
296
+
297
+ ```
298
+ This deploys contract on geth, and creates two files.One is `temp/db/Token.json` which keeps abi and address.
299
+ ```json
300
+ {
301
+ "Token": {
302
+ "abi": [
303
+ {
304
+ "constant": false,
305
+ "inputs": [
306
+ {
307
+ "name": "account",
308
+ "type": "address"
309
+ },
310
+ {
311
+ "name": "amount",
312
+ "type": "uint256"
313
+ }
314
+ ],
315
+ "name": "issue",
316
+ "outputs": [
317
+
318
+ ],
319
+ "payable": false,
320
+ "type": "function"
321
+ },
322
+ {
323
+ "constant": false,
324
+ "inputs": [
325
+ {
326
+ "name": "to",
327
+ "type": "address"
328
+ },
329
+ {
330
+ "name": "amount",
331
+ "type": "uint256"
332
+ }
333
+ ],
334
+ "name": "transfer",
335
+ "outputs": [
336
+
337
+ ],
338
+ "payable": false,
339
+ "type": "function"
340
+ },
341
+ {
342
+ "constant": true,
343
+ "inputs": [
344
+ {
345
+ "name": "account",
346
+ "type": "address"
347
+ }
348
+ ],
349
+ "name": "getBalance",
350
+ "outputs": [
351
+ {
352
+ "name": "",
353
+ "type": "uint256"
354
+ }
355
+ ],
356
+ "payable": false,
357
+ "type": "function"
358
+ },
359
+ {
360
+ "inputs": [
361
+
362
+ ],
363
+ "type": "constructor"
364
+ },
365
+ {
366
+ "anonymous": false,
367
+ "inputs": [
368
+ {
369
+ "indexed": false,
370
+ "name": "account",
371
+ "type": "address"
372
+ },
373
+ {
374
+ "indexed": false,
375
+ "name": "amount",
376
+ "type": "uint256"
377
+ }
378
+ ],
379
+ "name": "Issue",
380
+ "type": "event"
381
+ },
382
+ {
383
+ "anonymous": false,
384
+ "inputs": [
385
+ {
386
+ "indexed": false,
387
+ "name": "from",
388
+ "type": "address"
389
+ },
390
+ {
391
+ "indexed": false,
392
+ "name": "to",
393
+ "type": "address"
394
+ },
395
+ {
396
+ "indexed": false,
397
+ "name": "amount",
398
+ "type": "uint256"
399
+ }
400
+ ],
401
+ "name": "Transfer",
402
+ "type": "event"
403
+ }
404
+ ],
405
+ "bin": "0x606060405260008054600160a060020a0319163317905561016f806100246000396000f3606060405260e060020a6000350463867904b48114610034578063a9059cbb1461005e578063f8b2cb4f14610092575b610002565b34610002576100bc600435602435600054600160a060020a0390811633909116146100be57610002565b34610002576100bc60043560243533600160a060020a03166000908152600160205260409020548190101561010f57610002565b3461000257600160a060020a03600435166000908152600160205260409020546060908152602090f35b005b600160a060020a03821660008181526001602052604090819020805484019055606091825260808390527fc65a3f767206d2fdcede0b094a4840e01c0dd0be1888b5ba800346eaa0123c1691a15050565b6040600081812080548490039055600160a060020a03808516808352929091208054840190553316606090815260809190915260a08290527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9080a1505056",
406
+ "devdoc": {
407
+ "methods": {
408
+ }
409
+ },
410
+ "userdoc": {
411
+ "methods": {
412
+ }
413
+ }
414
+ },
415
+ "address": "0x3a020580345e79e223580d8d6a50e063667f19b5"
416
+ }
417
+ ```
418
+ Another is `temp/migrations/Token.js`
419
+ ```javascript
420
+ var TokenContract = web3.eth.contract([{"constant":false, "inputs":[{"name":"account", "type":"address"}, {"name":"amount", "type":"uint256"}], "name":"issue", "outputs":[], "payable":false, "type":"function"}, {"constant":false, "inputs":[{"name":"to", "type":"address"}, {"name":"amount", "type":"uint256"}], "name":"transfer", "outputs":[], "payable":false, "type":"function"}, {"constant":true, "inputs":[{"name":"account", "type":"address"}], "name":"getBalance", "outputs":[{"name":"", "type":"uint256"}], "payable":false, "type":"function"}, {"inputs":[], "type":"constructor"}, {"anonymous":false, "inputs":[{"indexed":false, "name":"account", "type":"address"}, {"indexed":false, "name":"amount", "type":"uint256"}], "name":"Issue", "type":"event"}, {"anonymous":false, "inputs":[{"indexed":false, "name":"from", "type":"address"}, {"indexed":false, "name":"to", "type":"address"}, {"indexed":false, "name":"amount", "type":"uint256"}], "name":"Transfer", "type":"event"}]);
421
+
422
+ var Token = TokenContract.at('0x80d29fb7f81d2ccd77c708b6135389c9c08653dc');
423
+
424
+ ```
425
+ Deploy all contracts if no contract name provided.
426
+
427
+ #### Write your own javascript test
428
+ `gtests/Token_test.js`
429
+ ```javascript
430
+ loadScript('temp/migrations/Token.js');
431
+
432
+ var balance = Token.getBalance.call(web3.eth.accounts[0], { from: web3.eth.accounts[0] })
433
+
434
+ console.log("balance is: ", balance);
435
+
436
+ Token.issue.sendTransaction(web3.eth.accounts[0], 10000, { from: web3.eth.accounts[0] }, function(err, tx){
437
+ if(err){
438
+ console.log("issue error!");
439
+ } else {
440
+ console.log("issue success. tx: ", tx);
441
+ }
442
+ })
443
+
444
+ miner.start();admin.sleepBlocks(2);miner.stop();
445
+
446
+ balance = Token.getBalance.call(web3.eth.accounts[0], { from: web3.eth.accounts[0] })
447
+
448
+ console.log("balance is: ", balance);
449
+
450
+ ```
451
+
452
+ #### Run gtest
453
+ ```
454
+ $ teth gt token
455
+ ***** Using geth at: geth
456
+ Testing contract Token...
457
+ balance is: 0
458
+ issue success. tx: 0x7fd24d1903345d4f70208c41fc3a1bd71be63f8dd7db7c654f2d3a7c176b4031
459
+ balance is: 10000
460
+ true
461
+ Done.
462
+ ```
463
+
464
+ :beers:
465
+
466
+ ## Frequently Asked Questions
467
+
468
+ #### Error: Account does not exist or account balance too low while `teth migrate token`
469
+ This is just low balance for your accoutns. Just mining for a while will be ok.
470
+ ```shell
471
+ $ teth c
472
+ ***** Using geth at: geth
473
+ Starting geth attach...
474
+ Welcome to the Geth JavaScript console!
475
+
476
+ instance: Geth/v1.4.11-stable-fed692f6/darwin/go1.7
477
+ coinbase: 0x3ae88fe370c39384fc16da2c9e768cf5d2495b48
478
+ at block: 3 (Sat, 17 Sep 2016 17:42:50 CST)
479
+ datadir: data
480
+ modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
481
+
482
+ > miner.start()
483
+ true
484
+ > web3.eth.getBalance(web3.eth.accounts[0])
485
+ 506406250000000000000
486
+ >
487
+
488
+ ```
489
+
490
+
491
+ ## TODO:
492
+
493
+ - Add chai for js test
data/bin/teth CHANGED
@@ -3,6 +3,7 @@
3
3
  require 'erb'
4
4
  require 'json'
5
5
  require 'fileutils'
6
+ require 'ethereum'
6
7
 
7
8
  ARGV << "--help" if ARGV.empty?
8
9
 
@@ -16,7 +17,7 @@ ALIASES = {
16
17
  "m" => "migrate",
17
18
  "s" => "server",
18
19
  "c" => "console",
19
- "gt" => "geth_test"
20
+ "gt" => "gtest"
20
21
  }
21
22
 
22
23
  command = ARGV.shift
@@ -26,25 +27,27 @@ HELP_MESSAGE = <<-EOF
26
27
  Usage: teth COMMAND [ARGS]
27
28
  The most common teth commands are:
28
29
  new Create a new Smart Contract application. "teth new my_app" creates a
29
- new application called MyApp in "./my_app" (short-cut alias: "n")
30
- generate Generate new Smart Contract and test file (short-cut alias: "g")
31
- test Run tests (short-cut alias: "t")
32
- init Init private geth chain (short-cut alias: "i")
33
- import_keys Import keys to chain (short-cut alias: "ik")
30
+ new application called my_app in "./my_app" (short-cut alias: "n")
31
+ generate Generate new solidity smart contract and test files. "teth generate token"
32
+ creates Token contract and corresponding test files. (short-cut alias: "g")
33
+ test Run your ruby tests in ruby evm. (short-cut alias: "t")
34
+ init Bootstraps and initialises a new genesis block. "teth init" creates data directory
35
+ for private chain.(short-cut alias: "i")
36
+ import_keys Import keys to private chain (short-cut alias: "ik")
34
37
  build Build contract (short-cut alias: "b")
35
- migrate Deploy contract on chain (short-cut alias: "m")
36
- server Start chain server (short-cut alias: "s")
37
- console Open Chain console (short-cut alias: "c")
38
- geth_test Test on chain (short-cut alias: "gt")
38
+ migrate Deploy contract on private chain (short-cut alias: "m")
39
+ server Start geth server (short-cut alias: "s")
40
+ console Start geth attach (short-cut alias: "c")
41
+ gtest Run your javascript tests on geth (short-cut alias: "gt")
39
42
 
40
43
  All commands can be run with -h (or --help) for more information.
41
44
  EOF
42
45
 
43
- KEYS_TEMPLATE = {
44
- "3ae88fe370c39384fc16da2c9e768cf5d2495b48" => "095e53c9c20e23fd01eaad953c01da9e9d3ed9bebcfed8e5b2c2fce94037d963",
45
- "81063419f13cab5ac090cd8329d8fff9feead4a0" => "5bc505a123a695176a9688ffe22798cfd40424c5b91c818e985574ea8ebda167",
46
- "9da26fc2e1d6ad9fdd46138906b0104ae68a65d8" => "b6a03207128827eaae0d31d97a7a6243de31f2baf99eabd764e33389ecf436fc"
47
- }
46
+ KEYS_TEMPLATE = [
47
+ ["3ae88fe370c39384fc16da2c9e768cf5d2495b48", "095e53c9c20e23fd01eaad953c01da9e9d3ed9bebcfed8e5b2c2fce94037d963"],
48
+ ["81063419f13cab5ac090cd8329d8fff9feead4a0", "5bc505a123a695176a9688ffe22798cfd40424c5b91c818e985574ea8ebda167"],
49
+ ["9da26fc2e1d6ad9fdd46138906b0104ae68a65d8", "b6a03207128827eaae0d31d97a7a6243de31f2baf99eabd764e33389ecf436fc"]
50
+ ]
48
51
 
49
52
  def gem_dir
50
53
  spec = Gem::Specification.find_by_name("teth")
@@ -55,22 +58,25 @@ def new
55
58
  name = ARGV.shift
56
59
  if name
57
60
  puts "Creating project #{name}..."
58
- system("mkdir #{name} && cd #{name} && mkdir private_keys && mkdir builds && mkdir db && mkdir contracts && mkdir tests")
59
-
61
+ dirs_commands = %w{ private_keys builds temp contracts tests gtests}.map{ |d| "mkdir #{d}" }.join(" && ")
62
+ system("mkdir #{name} && cd #{name} && #{dirs_commands}")
63
+ system("cd #{name} && cd temp && mkdir db && mkdir migrations")
60
64
  gemfile = File.read("#{gem_dir}/lib/teth/erbs/Gemfile")
61
65
 
62
66
  File.open("#{name}/Gemfile", "w+") {|f| f.write(gemfile) }
63
67
  system("cd #{name} && bundle install")
64
68
 
65
- KEYS_TEMPLATE.each do |k, v|
66
- File.open("#{name}/private_keys/#{k}.key", "w+") { |f| f.write(v) }
69
+ KEYS_TEMPLATE.each do |k|
70
+ File.open("#{name}/private_keys/#{k[0]}.key", "w+") { |f| f.write(k[1]) }
67
71
  end
68
72
 
69
73
  FileUtils.cp("#{gem_dir}/lib/teth/templates/private_keys/import.sh", "#{name}/private_keys/import.sh")
70
74
  FileUtils.chmod 0700, "#{name}/private_keys/import.sh"
71
75
 
72
- FileUtils.cp("#{gem_dir}/lib/teth/templates/genesis.json", "#{name}/genesis.json")
73
- FileUtils.cp("#{gem_dir}/lib/teth/templates/rakefile", "#{name}/rakefile")
76
+ %w{genesis.json rakefile gitignore}.each do |f|
77
+ FileUtils.cp("#{gem_dir}/lib/teth/templates/#{f}", "#{name}/#{f}")
78
+ end
79
+ FileUtils.mv("#{name}/gitignore", "#{name}/.gitignore")
74
80
 
75
81
  FileUtils.cp_r("#{gem_dir}/lib/teth/templates/bin/", "#{name}")
76
82
  FileUtils.chmod_R 0700, "#{name}/bin/"
@@ -83,15 +89,28 @@ end
83
89
  def generate
84
90
  name = ARGV.shift
85
91
  if name
92
+ puts "Creating #{name.capitalize} contract file..."
86
93
  contract_template = ERB.new File.read("#{gem_dir}/lib/teth/erbs/contract.sol")
87
94
  contract = contract_template.result(binding)
95
+
96
+ version = Ethereum::Tester::Language.get(:solidity).compiler_version
97
+ semver = version.split('-').first
98
+ major, minor, patch = semver.split('.')
99
+ unless major.to_i < 1 && minor.to_i < 4
100
+ pragma = "pragma solidity ^#{major}.#{minor}.0;" # always set patch to 0
101
+ contract = "#{pragma}\n\n#{contract}"
102
+ end
103
+
88
104
  puts "Create #{name.capitalize}.sol contract file..."
89
105
  File.open("contracts/#{name.capitalize}.sol", "w+") { |f| f.write(contract) }
90
106
 
107
+ puts "Creating #{name} test files..."
91
108
  test_template = ERB.new File.read("#{gem_dir}/lib/teth/erbs/contract_test.rb")
92
109
  test = test_template.result(binding)
93
- puts "Create #{name}_test.rb test file..."
94
- File.open("tests/#{name.capitalize}_test.rb", "w+") {|f| f.write(test) }
110
+ File.open("tests/#{name}_test.rb", "w+") {|f| f.write(test) }
111
+ File.open("gtests/#{name.capitalize}_test.js", "w") do |f|
112
+ f.write("loadScript('temp/migrations/#{name.capitalize}.js');")
113
+ end
95
114
  puts "Done."
96
115
  else
97
116
  puts "Need contract name"
@@ -111,10 +130,12 @@ def test
111
130
  end
112
131
 
113
132
  def init
133
+ puts "Initialising a new genesis block..."
114
134
  system("./bin/init.sh")
115
135
  end
116
136
 
117
137
  def import_keys
138
+ puts "Importing keys, this will take a while, please be patient..."
118
139
  system("./bin/import_keys.sh")
119
140
  end
120
141
 
@@ -129,15 +150,43 @@ end
129
150
 
130
151
  def migrate
131
152
  name = ARGV.shift
132
- system("./bin/migrate.sh #{name}")
153
+ if name
154
+ puts "Migrating contract #{name}"
155
+ else
156
+ puts "Migrating all contracts"
157
+ end
158
+ output = `./bin/migrate.sh #{name}`
159
+ puts output
160
+ contract = ""
161
+ output.split("\n").each do |o|
162
+ if o.match("Contract Instance")
163
+ contract = o.split("Contract Instance : ")[1]
164
+ end
165
+ if o.match("Contract mined!")
166
+ address = o.split("Address: ")[1]
167
+ data = File.read("temp/db/#{contract}.json")
168
+ data = JSON.parse data
169
+ data["address"] = address
170
+ File.open("temp/db/#{contract}.json", "w") do |f|
171
+ f.write(JSON.pretty_generate data)
172
+ end
173
+ File.open("temp/migrations/#{contract}.js", "w") do |f|
174
+ abi = data[contract]["abi"]
175
+ template = ERB.new File.read("#{gem_dir}/lib/teth/erbs/migration")
176
+ migration = template.result(binding)
177
+ f.write(migration.gsub("=>", ":"))
178
+ end
179
+ end
180
+ end
133
181
  end
134
182
 
135
183
  def console
136
184
  system("./bin/attach.sh")
137
185
  end
138
186
 
139
- def geth_test
140
- system("./bin/test.sh")
187
+ def gtest
188
+ name = ARGV.shift
189
+ system("./bin/test.sh #{name}")
141
190
  end
142
191
 
143
192
  def help
@@ -1 +1 @@
1
- gem 'teth', '>= 0.1.0'
1
+ gem 'teth', '>= 0.2.0'
@@ -1,6 +1,9 @@
1
1
  require 'teth/minitest'
2
2
 
3
3
  class <%=name.capitalize%>Test < Teth::Minitest
4
- print_logs false
5
- print_events false
4
+
5
+ def test_something
6
+ assert !contract.address.nil?
7
+ end
8
+
6
9
  end
@@ -0,0 +1,3 @@
1
+ var <%= contract %>Contract = web3.eth.contract(<%= abi %>);
2
+
3
+ var <%= contract %> = <%=contract%>Contract.at('<%= address %>');
@@ -30,7 +30,7 @@ module Teth
30
30
  when /\.sol\z/
31
31
  type = :solidity
32
32
  when /\.se\z/
33
- raise NotImplemented, "Serpent not supported yet"
33
+ type = :serpent
34
34
  else
35
35
  raise "Unknown contract source type: #{path}"
36
36
  end
@@ -41,7 +41,7 @@ module Teth
41
41
  if self.class.print_logs
42
42
  topics = log.topics.map {|t| heuristic_prettify Utils.int_to_big_endian(t) }
43
43
  data = heuristic_prettify(log.data)
44
- puts "[Log] #{Utils.encode_hex(log.address)} >>> topics=#{topics} data=#{data}"
44
+ puts "[Log] #{Utils.encode_hex(log.address)} >>> topics=#{topics} data=#{data.inspect}"
45
45
  end
46
46
  else # user defined event
47
47
  if self.class.print_logs && self.class.print_events
@@ -108,22 +108,15 @@ module Teth
108
108
  end
109
109
 
110
110
  def privkey
111
- account[0]
111
+ privkeys[0]
112
112
  end
113
113
 
114
114
  def pubkey
115
- account[1]
115
+ pubkeys[0]
116
116
  end
117
117
 
118
118
  def address
119
- account[2]
120
- end
121
-
122
- def account
123
- return @account if @account
124
-
125
- i = rand(self.class.account_num)
126
- @account = [privkeys[i], pubkeys[i], addresses[i]]
119
+ addresses[0]
127
120
  end
128
121
 
129
122
  def privkeys
@@ -1,4 +1,9 @@
1
1
  #!/bin/bash
2
2
 
3
3
  geth=${GETH:-geth}
4
+
5
+ echo "***** Using geth at: $geth"
6
+
7
+ echo "Starting geth attach..."
8
+
4
9
  $geth attach ipc:data/geth.ipc
@@ -1,30 +1,25 @@
1
1
  #!/bin/bash
2
2
  if [ -z "$1" ]
3
3
  then
4
- echo "Build all contracts ..."
4
+ echo "Building all contracts ..."
5
5
  for sol in `find ./contracts -name '*.sol'`
6
6
  do
7
- filename="${sol}"
8
- echo "Build ${filename}"
9
- let len=${#filename}-16
10
- # echo $len
11
- jsfile="${filename:12:len}_compiled.js"
12
- echo $jsfile
13
- ./bin/solc_helper.rb $sol $jsfile
7
+ echo "Building contract ${sol}"
8
+ let len=${#sol}-16
9
+ jsfile="${sol:12:len}_compiled.js"
10
+ ./bin/solc_helper.rb ${sol} $jsfile
14
11
  mv $jsfile builds/
15
12
  done
16
13
  echo "Done."
17
14
  else
18
- foo=$1
19
- foo="$(tr '[:lower:]' '[:upper:]' <<< ${foo:0:1})${foo:1}"
20
- sol="contracts/$1.sol"
21
- filename="${sol}"
22
- echo "Build ${filename}"
23
- let len=${#filename}-16
24
- # echo $len
25
- jsfile="${foo}_compiled.js"
26
- echo "Build $foo to $jsfile"
27
- ./bin/solc_helper.rb $sol $jsfile
15
+ sol=$1
16
+ sol="$(tr '[:lower:]' '[:upper:]' <<< ${sol:0:1})${sol:1}"
17
+ echo "Building contract ${sol}"
18
+
19
+ file="contracts/${sol}.sol"
20
+ len=${#sol}-16
21
+ jsfile="${sol}_compiled.js"
22
+ ./bin/solc_helper.rb $file $jsfile
28
23
  mv $jsfile builds/
29
24
  echo "Done."
30
25
  fi
@@ -1,12 +1,14 @@
1
1
  #!/bin/sh
2
2
 
3
3
  geth=${GETH:-geth}
4
+
4
5
  echo "***** Using geth at: $geth"
5
6
 
6
7
  echo "***** Import all pre-funded private keys"
7
8
 
8
9
  for key in `find ./private_keys -name '*.key'`
9
10
  do
11
+ echo "Notice: No need to input your password. The default password is 123456"
10
12
  ./private_keys/import.sh $key $geth
11
13
  done
12
14
 
@@ -1,2 +1,7 @@
1
1
  #! /bin/bash
2
- geth --datadir `pwd`/data init genesis.json
2
+
3
+ geth=${GETH:-geth}
4
+
5
+ echo "***** Using geth at: $geth"
6
+
7
+ $geth --datadir `pwd`/data init genesis.json
@@ -2,21 +2,22 @@
2
2
 
3
3
  geth=${GETH:-geth}
4
4
 
5
+ echo "***** Using geth at: $geth"
6
+
5
7
  if [ -z "$1" ]
6
8
  then
7
- echo "Migrate all contract ..."
8
9
  scripts=""
9
10
  for file in `find ./builds -name '*compiled.js'`
10
11
  do
11
12
  scripts="${scripts};loadScript('$file')"
12
13
  done
13
14
  scripts="${scripts};miner.start();admin.sleepBlocks(2);miner.stop()"
14
- # echo "$scripts"
15
15
  $geth --exec "$scripts" attach ipc:data/geth.ipc
16
16
  else
17
17
  file=$1
18
18
  file="$(tr '[:lower:]' '[:upper:]' <<< ${file:0:1})${file:1}"
19
19
  file+="_compiled.js"
20
- echo "Migrate $file ..."
21
20
  $geth --exec "loadScript('builds/$file');miner.start();admin.sleepBlocks(2);miner.stop()" attach ipc:data/geth.ipc
22
21
  fi
22
+
23
+ echo "Done."
@@ -1,5 +1,8 @@
1
1
  #!/bin/bash
2
-
3
2
  geth=${GETH:-geth}
4
3
 
4
+ echo "***** Using geth at: $geth"
5
+
6
+ echo "Start geth server..."
7
+
5
8
  $geth --datadir data --networkid 31415926 --rpc --rpccorsdomain "*" --nodiscover --unlock 3ae88fe370c39384fc16da2c9e768cf5d2495b48 --password <(echo -n 123456)
@@ -99,6 +99,6 @@ File.open(javascript_file_name, 'w') do |f|
99
99
  f.write("console.log('Contract Instance : #{contract_instance_variable_name}');")
100
100
  end
101
101
 
102
- File.open("db/#{current_contract}.json", "w") do |f|
103
- f.write(compiled_object.to_json)
102
+ File.open("temp/db/#{current_contract}.json", "w") do |f|
103
+ f.write(JSON.pretty_generate compiled_object)
104
104
  end
@@ -2,17 +2,25 @@
2
2
 
3
3
  geth=${GETH:-geth}
4
4
 
5
+ echo "***** Using geth at: $geth"
6
+
5
7
  scripts=""
6
8
 
7
- for file in `find ./builds -name '*compiled.js'`
8
- do
9
- scripts="${scripts};loadScript('$file')"
10
- done
9
+ if [ -z "$1" ]
10
+ then
11
+ echo "Testing all contracts on geth..."
12
+ for file in `find ./gtests -name '*.js'`
13
+ do
14
+ scripts="${scripts};loadScript('$file');"
15
+ done
16
+ else
17
+ file=$1
18
+ file="$(tr '[:lower:]' '[:upper:]' <<< ${file:0:1})${file:1}"
19
+ echo "Testing contract $file..."
20
+ file+="_test.js"
21
+ scripts="loadScript('gtests/$file');"
22
+ fi
11
23
 
12
- for file in `find ./test -name '*.js'`
13
- do
14
- scripts="${scripts};loadScript('$file');"
15
- done
24
+ $geth --exec "$scripts" attach ipc:data/geth.ipc
16
25
 
17
- echo $scripts
18
- $geth --datadir data --networkid 31415926 --rpc --rpccorsdomain "*" --nodiscover --unlock 3ae88fe370c39384fc16da2c9e768cf5d2495b48 --password <(echo -n 123456) --exec "$scripts" console 2>> ./logfile
26
+ echo "Done."
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ data
3
+ temp
@@ -6,6 +6,6 @@ set geth [lindex $argv 1];
6
6
  spawn $geth --datadir data account import $key
7
7
  expect "Passphrase:"
8
8
  send "123456\r"
9
- expect "Repeat Passphrase:"
9
+ expect "Repeat passphrase:"
10
10
  send "123456\r"
11
11
  interact
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zhang YaNing
@@ -9,22 +9,36 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-09-17 00:00:00.000000000 Z
12
+ date: 2016-09-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby-ethereum
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '0.9'
20
+ version: 0.9.6
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 0.9.6
28
+ - !ruby/object:Gem::Dependency
29
+ name: serpent
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.3.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
26
40
  - !ruby/object:Gem::Version
27
- version: '0.9'
41
+ version: 0.3.0
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: minitest
30
44
  requirement: !ruby/object:Gem::Requirement
@@ -57,6 +71,7 @@ files:
57
71
  - lib/teth/erbs/Gemfile
58
72
  - lib/teth/erbs/contract.sol
59
73
  - lib/teth/erbs/contract_test.rb
74
+ - lib/teth/erbs/migration
60
75
  - lib/teth/minitest.rb
61
76
  - lib/teth/templates/bin/attach.sh
62
77
  - lib/teth/templates/bin/build.sh
@@ -67,6 +82,7 @@ files:
67
82
  - lib/teth/templates/bin/solc_helper.rb
68
83
  - lib/teth/templates/bin/test.sh
69
84
  - lib/teth/templates/genesis.json
85
+ - lib/teth/templates/gitignore
70
86
  - lib/teth/templates/private_keys/import.sh
71
87
  - lib/teth/templates/rakefile
72
88
  homepage: https://github.com/cryptape/teth