teth 0.1.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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