Compare commits

..

600 Commits

Author SHA1 Message Date
Jeffrey Wilcke
72e2613a9f Merge branch 'release/0.9.32' 2015-06-23 19:19:33 +02:00
Jeffrey Wilcke
67e6f74e9a cmd/geth: bump 2015-06-23 19:11:20 +02:00
Jeffrey Wilcke
d21c2bfb68 Merge pull request #1314 from karalabe/handle-fetcher-attacks-2
eth/fetcher: handle and test various DOS attacks
2015-06-23 10:04:44 -07:00
Jeffrey Wilcke
6b5532ab0d Merge pull request #1279 from bas-vk/rpc-http
Integrate console and remove old rpc package structure
2015-06-23 07:44:03 -07:00
Jeffrey Wilcke
139439dcdc Merge pull request #1309 from fjl/p2p-fix-lookup-spin
p2p: throttle all discovery lookups
2015-06-23 05:36:58 -07:00
Bas van Kervel
2b3957f373 fixed relative path issue with javascript files 2015-06-23 09:38:30 +02:00
Bas van Kervel
55424a11af improved action description 2015-06-23 09:11:57 +02:00
Bas van Kervel
57c911c398 bugfix in startRPC error handling 2015-06-23 08:26:17 +02:00
Péter Szilágyi
3ce17d2862 eth/fetcher: fix a closure data race 2015-06-22 20:13:18 +03:00
Péter Szilágyi
99ca4b619b eth/fetcher: clean up test assertions 2015-06-22 18:28:38 +03:00
Péter Szilágyi
b53f701c27 eth/fetcher: remove test sleeps (15s -> 2.8s) 2015-06-22 18:08:28 +03:00
Péter Szilágyi
1989d1491a eth/fetcher: handle and (crude) test block memory DOS 2015-06-22 16:49:47 +03:00
Bas van Kervel
4ee7f6fc88 added missing change for sign test 2015-06-22 13:54:13 +02:00
Bas van Kervel
6d596b1ad1 fixed eth sign unittest 2015-06-22 13:19:59 +02:00
Péter Szilágyi
d36c25bcbc eth/fetcher: handle and test block announce DOS attacks 2015-06-22 14:07:08 +03:00
Bas van Kervel
2e0b56a72b added RPC start/stop support 2015-06-22 12:47:32 +02:00
Bas van Kervel
2737baa657 fixed unittests 2015-06-22 09:17:09 +02:00
Bas van Kervel
f87501b1c5 added batch support to console and attach actions 2015-06-22 09:17:09 +02:00
Bas van Kervel
3ff272b618 moved solidity test to new rpc structure 2015-06-22 09:17:09 +02:00
Bas van Kervel
29297d3b82 fixed bug where history file was create in cwd 2015-06-22 09:17:09 +02:00
Bas van Kervel
ce5c94e471 added attach over http/rpc support 2015-06-22 09:17:09 +02:00
Bas van Kervel
f202563777 added attach over ipc command 2015-06-22 09:17:09 +02:00
Bas van Kervel
36a6b16a3b removed console command 2015-06-22 09:17:09 +02:00
Bas van Kervel
603192cfa7 cleanup comments/code 2015-06-22 09:17:09 +02:00
Bas van Kervel
a4a4e9fcf8 removed old rpc structure and added new inproc api client 2015-06-22 09:17:09 +02:00
Bas van Kervel
3e1d635f8d fixed rpc test failure in eth.blockNumber 2015-06-22 08:54:21 +02:00
Bas van Kervel
9ac1b4e59e fixed rpc test failure in net_peerCount 2015-06-22 08:54:21 +02:00
Bas van Kervel
5fdf72b1ab fixed web3 rpc test failures 2015-06-22 08:54:21 +02:00
Bas van Kervel
c3f6c322c0 added DB api 2015-06-22 08:54:21 +02:00
Bas van Kervel
5c25403b13 refactored old rpc structure to new 2015-06-22 08:54:21 +02:00
Bas van Kervel
fd764d4ff7 added comms http 2015-06-22 08:54:21 +02:00
Bas van Kervel
60c2ccd99c made ipc handler generic and reusable 2015-06-22 08:54:21 +02:00
Jeffrey Wilcke
9cf7913c61 Merge pull request #1304 from obscuren/state-renames
core, miner, xeth: renamed gas methods
2015-06-21 16:49:47 -07:00
Jeffrey Wilcke
7633dfdc08 Merge pull request #1305 from obscuren/database-error-check
core, ethdb, trie: validate database errors
2015-06-21 16:49:14 -07:00
Felix Lange
6fb810adaa p2p: throttle all discovery lookups
Lookup calls would spin out of control when network connectivity was
lost. The throttling that was in place only took effect when the table
returned zero results, which doesn't happen very often.

The new throttling should not have a negative impact when the host is
online. Lookups against the network take some time and dials for all
results must complete or hit the cache before a new one is started. This
usually takes longer than four seconds, leaving online lookups
unaffected.

Fixes #1296
2015-06-22 01:07:58 +02:00
obscuren
398d08a8dd tests: SetGasLimit 2015-06-21 17:09:19 +02:00
obscuren
07c3de3f75 core, miner, xeth: renamed gas methods
* BuyGas => SubGas
* RefundGas => AddGas
* SetGasPool => SetGasLimit
2015-06-21 17:09:19 +02:00
obscuren
a40a91d60f trie: fixed tests 2015-06-21 17:08:47 +02:00
obscuren
c590b505ed core, ethdb, trie: validate database errors 2015-06-21 16:59:15 +02:00
Jeffrey Wilcke
3deded28a5 Merge pull request #1302 from obscuren/mist-removal
mist: R.I.P.
2015-06-21 07:58:08 -07:00
obscuren
46bd6c43db travis: removed qt deps 2015-06-20 20:33:25 +02:00
obscuren
42a14b8a09 mist: R.I.P.
/"""""/""""""".
    /     /         \             __
   /     /           \            ||
  /____ /             \           ||
 |     |  In Loving    |          ||
 |     |   Memory      |          ||
 |     |               |          ||
 |     |   2014-2015   |          ||
 |     |     * *   * * |         _||_
 |     |     *\/* *\/* |        | TT |
 |     |     *_\_  /   ...""""""| || |.""...."""""""".""
 |     |         \/.."""""..."""\ || /.""".......""""...
 |     |...."""""""........""""""^^^^"......."""""""".."
 |......"""""""""""""""........"""""...."""""..""-Jeff W.
2015-06-20 14:37:00 +02:00
Jeffrey Wilcke
9c69c051ba Merge pull request #1236 from tgerring/ethtest
ethtest improvements
2015-06-20 05:32:33 -07:00
Taylor Gerring
53e042f0c4 Added link to ARM develop build 2015-06-19 18:49:15 +02:00
Jeffrey Wilcke
4c2ba1af1d Merge pull request #1298 from karalabe/slack-n-bound
eth/fetcher: lower max cache size, add timeout slack
2015-06-19 07:46:45 -07:00
Jeffrey Wilcke
0fa2750fc9 Merge pull request #1290 from tgerring/dataargs
unit test coverage for NewDataArgs
2015-06-19 07:44:39 -07:00
Péter Szilágyi
8c4c7ea192 eth/fetcher: lower max cache size, add timeout slack 2015-06-19 16:46:16 +03:00
Taylor Gerring
d1e589289c Expand --test switch 2015-06-19 15:08:53 +02:00
Taylor Gerring
0743243dce Add --skip option to CLI
Disassociates hardcoded tests to skip when running via CLI. Tests still
skipped when running `go test`
2015-06-19 11:38:23 +02:00
Péter Szilágyi
d5871fc200 Merge pull request #1295 from karalabe/fix-broadcast-order
eth: fix the propagation/announce order for mined blocks
2015-06-19 10:15:20 +03:00
Péter Szilágyi
4180ca7fe4 eth: fix the propagation/announce order for mined blocks 2015-06-19 10:07:37 +03:00
Taylor Gerring
a9659e6dcf recover test logic 2015-06-18 23:46:42 +02:00
Taylor Gerring
8d3faf69d0 Build error fixes 2015-06-18 22:38:17 +02:00
Taylor Gerring
baea8e87e5 Rebase cleanup 2015-06-18 22:27:44 +02:00
Taylor Gerring
01ec4dbb12 Add stdin option 2015-06-18 22:24:07 +02:00
Taylor Gerring
a86452d22c Minor cleanup 2015-06-18 22:20:45 +02:00
Taylor Gerring
49336675f3 Expand CLI options to allow running all tests 2015-06-18 22:20:45 +02:00
Taylor Gerring
516362bcad Allow specifying single depth directory 2015-06-18 22:20:45 +02:00
Taylor Gerring
30444db020 Add lost rebase changes 2015-06-18 22:20:45 +02:00
Taylor Gerring
c941a39b75 Cleanup logging 2015-06-18 22:20:45 +02:00
Taylor Gerring
8507c867b9 Fix geth blocktest command 2015-06-18 22:20:45 +02:00
Taylor Gerring
6931267324 Wire ethtest to new tests structure 2015-06-18 22:20:45 +02:00
Taylor Gerring
6ff956394a DRY file loading 2015-06-18 22:20:45 +02:00
Taylor Gerring
ac0637c413 More consistent test interfaces + test skipping 2015-06-18 22:20:44 +02:00
Taylor Gerring
b6d40a9312 Cleanup/reorg 2015-06-18 22:20:44 +02:00
Taylor Gerring
c5d6fcbaba Return error up stack instead of passing testing var down 2015-06-18 22:20:44 +02:00
Taylor Gerring
24554629b1 DRY log check 2015-06-18 22:15:08 +02:00
Taylor Gerring
7c6ef0ddac Separate and identify tests runners 2015-06-18 22:15:07 +02:00
Taylor Gerring
1b26d4f220 Flatten helper directory 2015-06-18 22:15:07 +02:00
Taylor Gerring
e82100367f Fix paths 2015-06-18 22:13:42 +02:00
Taylor Gerring
a67a15528a Split tests from helper code 2015-06-18 22:13:42 +02:00
Taylor Gerring
7b9fbb088a Flatten vm directory 2015-06-18 22:13:41 +02:00
Taylor Gerring
6415ed0730 Require a first argument of test type 2015-06-18 22:13:41 +02:00
Jeffrey Wilcke
e4f9ec886b Merge pull request #1267 from SilentCicero/develop
eth_sendRawTransaction JSON RPC
2015-06-18 11:33:50 -07:00
Jeffrey Wilcke
8eaaf24b1e Merge pull request #1275 from karalabe/optimise-fetcher
eth/fetcher: separate the announce based sync into its own package
2015-06-18 11:14:26 -07:00
Péter Szilágyi
13c25036ea eth/fetcher: since uncles are allowed, drop phase test 2015-06-18 20:10:07 +03:00
Péter Szilágyi
ecd19919c5 eth/fetcher: allow backward uncle imports too 2015-06-18 19:43:47 +03:00
Péter Szilágyi
90d45f0397 eth: fix test breakage from the previous commit 2015-06-18 18:25:27 +03:00
Péter Szilágyi
b91b581b80 eth, eth/fetcher: propagate after header verify, announce only on insert 2015-06-18 18:00:19 +03:00
Péter Szilágyi
629705ad53 eth: clean the block request packet handling a bit 2015-06-18 16:09:34 +03:00
Péter Szilágyi
5ec6ecc511 eth, eth/fetcher: move propagated block import into fetcher 2015-06-18 15:56:08 +03:00
Péter Szilágyi
a9ada0b5ba eth/fetcher: make tests thread safe 2015-06-18 15:56:08 +03:00
Péter Szilágyi
37c5ff392f eth/fetcher: build longest chain until proven otherwise 2015-06-18 15:56:08 +03:00
Péter Szilágyi
2a7411bc96 eth/fetcher: fix premature queue cleanup, general polishes 2015-06-18 15:56:08 +03:00
Péter Szilágyi
497a7f1717 eth, eth/fetcher: define and enforce propagation boundaries 2015-06-18 15:56:08 +03:00
Péter Szilágyi
026ee40650 eth/fetcher: deduplicate future blocks 2015-06-18 15:56:08 +03:00
Péter Szilágyi
11c8f83a58 eth, eth/fetcher: cache future propagated blocks too 2015-06-18 15:56:08 +03:00
Péter Szilágyi
057bc237ad eth, eth/fetcher: use an import queue to store out of order blocks 2015-06-18 15:56:07 +03:00
Péter Szilágyi
8b64e041d6 eth/fetcher: add test to check for duplicate downloads 2015-06-18 15:56:07 +03:00
Péter Szilágyi
2a1b722d04 eth/fetcher: fix timer reset bug, add initial tests 2015-06-18 15:56:07 +03:00
Péter Szilágyi
7c2af1c117 eth, eth/fetcher: separate notification sync mechanism 2015-06-18 15:56:07 +03:00
Jeffrey Wilcke
2cea410656 Merge pull request #1282 from obscuren/state-cleanup
core/state: cleanup & optimisations
2015-06-18 05:29:53 -07:00
obscuren
430bcdb219 core/vm: clarified SSTORE 2015-06-18 12:25:02 +02:00
Jeffrey Wilcke
53a6145a2b Merge pull request #1287 from karalabe/fix-downloader-cancel-interrupt
eth, eth/downloader: fix processing interrupt caused by temp cancel
2015-06-18 02:50:19 -07:00
obscuren
15e169e5b6 core: ValidatedHeader (method => function)
Changed header validation method to function in preparation of
@karalabe's PR.
2015-06-18 11:47:50 +02:00
Péter Szilágyi
4365668462 eth/downloader: extend slow test to fix even slower CI server... 2015-06-18 00:42:02 +03:00
Péter Szilágyi
55dd8fd621 eth/downloader: always reenter processing if not exiting 2015-06-18 00:26:54 +03:00
Péter Szilágyi
2f4cbe22f5 eth, eth/downloader: fix processing interrupt caused by temp cancel 2015-06-18 00:04:57 +03:00
Taylor Gerring
5afebc2a4b unit test coverage for NewDataArgs 2015-06-17 18:07:45 +02:00
obscuren
f5abc9f188 core, core/vm: state improvements and tx pool speed up
Removed full tx validation during state transitions
2015-06-17 17:10:22 +02:00
obscuren
753d62a4dd core: TMP testing code 2015-06-17 17:10:13 +02:00
Jeffrey Wilcke
ae36beb38f Merge pull request #1269 from bas-vk/console-batch
added batch mode to console
2015-06-17 07:56:09 -07:00
obscuren
bdd63837ea core/state: removed trie copy 2015-06-17 13:39:19 +02:00
obscuren
aa699a1283 core/state: removed state from state object 2015-06-17 13:27:51 +02:00
obscuren
aaddc99c35 core/state: fixed state tests 2015-06-17 12:53:22 +02:00
Jeffrey Wilcke
e4b54f18c6 Merge pull request #1281 from karalabe/fix-overlapping-delivery-hang
eth/downloader: fix #1280, overlapping (good/bad) delivery hang
2015-06-17 03:24:46 -07:00
Jeffrey Wilcke
a3fdef7529 Merge pull request #1274 from Gustav-Simonsson/update_ethash_godep
Update ethash godep
2015-06-17 03:05:51 -07:00
obscuren
a977f3c0dc xeth, tests: fixed api 2015-06-17 11:44:40 +02:00
obscuren
30b27336ea core/state: remove the need for common.Value 2015-06-17 11:30:42 +02:00
obscuren
787a61bb27 core/state, core/vm: reworked storage get / set to use common.Hash 2015-06-17 11:24:40 +02:00
Péter Szilágyi
4a1e82cf3f eth/downloader: fix #1280, overlapping (good/bad) delivery hang 2015-06-17 12:03:16 +03:00
obscuren
5721fcf668 core/state, core/vm: cleanup refunds 2015-06-17 10:20:33 +02:00
Gustav Simonsson
be303ba186 Update ethash Godep (again) 2015-06-17 00:56:25 +02:00
SilentCicero
1f34daccc3 Added glog messages like Transaction 2015-06-16 12:47:34 -04:00
SilentCicero
6add45cd10 Remove Extra Loggers 2015-06-16 12:30:07 -04:00
SilentCicero
7ec8c257ff New DataArgs and eth_sendRawTransaction 2015-06-16 12:28:10 -04:00
Gustav Simonsson
a9d6846f92 Update ethash Godep 2015-06-16 12:09:39 +02:00
Gustav Simonsson
8f372c867d Update Ethereum JSON test files 2015-06-16 12:09:25 +02:00
Nick Dodson
e952bb65e7 thanks subtly :) 2015-06-16 00:06:28 -04:00
Nick Dodson
2642e091e9 NewSigArgs arg change. 2015-06-15 16:01:01 -04:00
obscuren
dfd18d245a cmd/geth: bump 0.9.31 2015-06-15 19:29:22 +02:00
obscuren
4699ebf534 Merge branch 'release/0.9.30' into develop 2015-06-15 19:29:06 +02:00
obscuren
5daf8729be Merge branch 'release/0.9.30' 2015-06-15 19:28:48 +02:00
obscuren
4673b04503 cmd/geth: bump version number 0.9.30 2015-06-15 19:14:34 +02:00
Jeffrey Wilcke
cc0b451119 Merge pull request #1260 from obscuren/tx-drop-low-tx
core: drop low gas tx
2015-06-15 09:09:44 -07:00
Jeffrey Wilcke
f2a2164184 Merge pull request #990 from zsfelfoldi/gasprice
eth: add GasPriceOracle
2015-06-15 08:44:25 -07:00
Jeffrey Wilcke
f475a01326 Merge pull request #1261 from fjl/p2p-no-writes-at-shutdown
p2p: prevent writes at shutdown time
2015-06-15 08:21:30 -07:00
obscuren
2628103f1d rpc/api: fixed default gas-(price) issue. 2015-06-15 17:21:08 +02:00
Nick Dodson
ad56aef5d2 Update utils.go 2015-06-15 11:10:40 -04:00
Nick Dodson
c3b80123e3 Update eth.go 2015-06-15 11:10:24 -04:00
Nick Dodson
f9f9352ceb Change eth_pushTx case to eth_sendRawTransaction 2015-06-15 10:50:07 -04:00
zsfelfoldi
1e3f4877c0 Changed miner and gpo min gas price to 1 szabo 2015-06-15 16:48:59 +02:00
obscuren
e79cc42dfe core: moved check for max queue to checkQueue
Moved the queue to check to the checkQueue method so no undeeded loops
need to be initiated or sorting needs to happen twice.
2015-06-15 16:46:45 +02:00
Jeffrey Wilcke
263903378b Merge pull request #1243 from karalabe/instrument-downloader-sync
eth, eth/downloader: separate concerns, clean up test suite
2015-06-15 07:43:37 -07:00
Bas van Kervel
f06f220c7c added printing support for objects 2015-06-15 16:33:36 +02:00
SilentCicero
d6233c7d2d Changed variable names 2015-06-15 10:07:32 -04:00
zsfelfoldi
b42b70eb5f fixed rpc/api.GasPrice 2015-06-15 15:55:39 +02:00
zsfelfoldi
610adfd83f fixed xeth.gpo = nil bug 2015-06-15 15:55:39 +02:00
zsfelfoldi
3c7b64ce20 removed duplicate function after rebase 2015-06-15 15:55:39 +02:00
zsfelfoldi
a977cecbe4 fixed gas price corr. factor 2015-06-15 15:55:38 +02:00
zsfelfoldi
6e212bdc6d fallback for uninitialized GPO config values 2015-06-15 15:55:38 +02:00
zsfelfoldi
2e8016c80d fixed initial base price bug 2015-06-15 15:55:38 +02:00
zsfelfoldi
0930e190a7 added missing source 2015-06-15 15:55:38 +02:00
zsfelfoldi
3f94d09c1f fixed saving receipts 2015-06-15 15:55:38 +02:00
Felix Lange
70da79f04c p2p: improve disconnect logging 2015-06-15 15:03:46 +02:00
Felix Lange
8dcbdcad0a p2p: track write errors and prevent writes during shutdown
As of this commit, we no longer rely on the protocol handler to report
write errors in a timely fashion. When a write fails, shutdown is
initiated immediately and no new writes can start. This will also
prevent new writes from starting after Server.Stop has been called.
2015-06-15 15:03:46 +02:00
Péter Szilágyi
aa250e228a eth: don't refetch non fitting blocks to avoid duplicates 2015-06-15 15:18:31 +03:00
Péter Szilágyi
cf7c44a7f6 eth/downloader: detailed comment for the race corner case 2015-06-15 15:18:04 +03:00
obscuren
21fa29111b core: reduce max allowed queued txs per address
Transactions in the queue are now capped to a maximum of 200
transactions. This number is completely arbitrary.
2015-06-15 12:16:29 +02:00
Péter Szilágyi
9c03c374e3 eth/downloader: fix import statistic reset, fetch hashes async 2015-06-15 13:05:01 +03:00
obscuren
6d817e16c1 core, miner: tx pool drops txs below ask price 2015-06-15 11:33:08 +02:00
Péter Szilágyi
b240983e2b eth, eth/downloader: do async block fetches, add dl tests 2015-06-15 12:26:05 +03:00
Péter Szilágyi
30a9939388 eth/downloader: sanity test for multi peer syncs 2015-06-15 09:22:37 +03:00
Péter Szilágyi
fc7abd9886 eth, eth/downloader: move block processing into the downlaoder 2015-06-15 09:22:37 +03:00
Péter Szilágyi
0fc71877a7 eth/downloader: add valid peer during attacks (check interference) 2015-06-15 09:22:37 +03:00
Péter Szilágyi
80833f8137 eth/downloader: instreument and test the sync peer drop 2015-06-15 09:22:37 +03:00
Péter Szilágyi
faae8b7dd8 eth: fix an accidental test compile error 2015-06-15 09:22:37 +03:00
Péter Szilágyi
2dd6a62f67 eth/downloader: support individual peers in the test suite 2015-06-15 09:22:36 +03:00
Péter Szilágyi
2937903299 eth/downloader: remove uneeded testing functions 2015-06-15 09:22:36 +03:00
Péter Szilágyi
66d3dc8690 eth, eth/downloader: move peer removal into downloader 2015-06-15 09:22:36 +03:00
SilentCicero
f9a0a13fa9 eth_pushTx send raw signed encoded TX data to the chain through RPC 2015-06-14 18:07:03 -04:00
Bas van Kervel
2a0528303f added batch mode to console 2015-06-13 19:02:46 +02:00
Jeffrey Wilcke
6f5c6150b7 Merge pull request #1255 from obscuren/chain-proc-interupt
eth, core: interrupt the chain processing on stop
2015-06-12 08:04:02 -07:00
obscuren
645dfd9693 core: changed interrupt strategy
Removed chain manager's select/channel approach when checking for
interrupts. Now using an atomic int32 instead which checked for every
block processed.
2015-06-12 16:52:54 +02:00
Jeffrey Wilcke
1bca2f6ec4 Merge pull request #1256 from obscuren/fix-printable-chars
core/vm: fixed strange output for trace logging & error reporting
2015-06-12 07:46:59 -07:00
obscuren
90c4493a10 eth, core: interupt the chain processing on stop
Added an additional channel which is used to interupt the chain manager
when it's processing blocks.
2015-06-12 13:41:34 +02:00
Jeffrey Wilcke
aaac1f0cdd Merge pull request #1254 from bas-vk/ipcwindowspathfix
Invalid named pipe name
2015-06-12 04:39:38 -07:00
obscuren
287f990891 core/vm: Improved error reporting for trace logging 2015-06-12 13:35:14 +02:00
obscuren
02d629af8f core/vm: fixed printable characters using unicode instead 2015-06-12 11:18:17 +02:00
Bas van Kervel
55a796b7c3 removed obsolete console flag 2015-06-12 09:42:57 +02:00
Bas van Kervel
359e6414e5 fixed windows ipc path issue 2015-06-12 09:32:37 +02:00
Jeffrey Wilcke
4bb9a61049 Merge pull request #1245 from bas-vk/ipcdatadirfix
ipc socket always uses default path
2015-06-11 12:01:07 -07:00
Bas van Kervel
22080e1fdd ipc socket always used default path 2015-06-11 20:35:19 +02:00
Jeffrey Wilcke
e2c2d8e15e Merge pull request #1239 from bas-vk/rpc-apis
RPC refactoring
2015-06-11 07:41:43 -07:00
Bas van Kervel
b3c07f167f fixed incomplete merge action 2015-06-11 15:06:12 +02:00
Bas van Kervel
ec6a7b35f6 removed obsolete print statement 2015-06-11 15:00:33 +02:00
Bas van Kervel
ebaa9b9feb removed binary files 2015-06-11 14:54:03 +02:00
Bas van Kervel
7584e68c21 upgrade web3.js with _extend support 2015-06-11 14:43:05 +02:00
Bas van Kervel
1fe617fa57 added net API 2015-06-11 14:40:38 +02:00
Bas van Kervel
87dace1fa9 added miner API 2015-06-11 14:20:50 +02:00
Bas van Kervel
aa258dcc5f added console binary 2015-06-11 14:18:54 +02:00
Bas van Kervel
3c93034a32 fixed windows build problem 2015-06-11 14:18:08 +02:00
Bas van Kervel
594a34a88d changed send methods for backwards compatability in geth console 2015-06-11 14:17:28 +02:00
Bas van Kervel
1b59f89095 added console command 2015-06-11 14:17:27 +02:00
Bas van Kervel
bbfa0a3dcb added API/IPC commandline flags 2015-06-11 14:15:33 +02:00
Bas van Kervel
348f1562e2 restructured eth rpc API 2015-06-11 14:13:57 +02:00
Bas van Kervel
7e41d7ac51 added shh API 2015-06-11 14:01:41 +02:00
Bas van Kervel
bd38428f33 cleanup of javascript API 2015-06-11 14:01:41 +02:00
Bas van Kervel
87b62f75a7 added txpool API 2015-06-11 14:01:41 +02:00
Bas van Kervel
c6c443385b changed console welcome message 2015-06-11 14:01:41 +02:00
Bas van Kervel
5f8e5a4875 upgrade web3.js with _extend support 2015-06-11 14:01:41 +02:00
Bas van Kervel
cc9ae39933 added admin API 2015-06-11 14:01:41 +02:00
Bas van Kervel
08d72a9245 added personal API 2015-06-11 14:01:41 +02:00
Bas van Kervel
09d0d55fc5 added debug API 2015-06-11 14:01:41 +02:00
Bas van Kervel
faab931ce1 only load supported api's 2015-06-11 14:01:40 +02:00
Bas van Kervel
d2a87f6f72 added net API 2015-06-11 14:01:40 +02:00
Bas van Kervel
4b9b633dfe added miner API 2015-06-11 14:01:40 +02:00
Bas van Kervel
cb7f2d43b6 added console binary 2015-06-11 14:01:40 +02:00
Bas van Kervel
8aea85e374 fixed windows build problem 2015-06-11 14:01:39 +02:00
Bas van Kervel
0a600a03ee fixed unittest build problem 2015-06-11 14:01:39 +02:00
Bas van Kervel
862117e4bd changed send methods for backwards compatability in geth console 2015-06-11 14:01:39 +02:00
Bas van Kervel
a1a475fb92 added console command 2015-06-11 14:01:39 +02:00
Bas van Kervel
2a0d888326 added API/IPC commandline flags 2015-06-11 14:01:39 +02:00
Bas van Kervel
8ebf2d8fad added RPC/IPC support 2015-06-11 14:01:39 +02:00
Bas van Kervel
2f55a1d798 restructured eth rpc API 2015-06-11 14:01:39 +02:00
Jeffrey Wilcke
6609d45ef4 Merge pull request #1228 from obscuren/vm-optimisations
core/vm: optimisations
2015-06-11 03:32:39 -07:00
Jeffrey Wilcke
13bd452faf Merge pull request #1227 from karalabe/block-fetcher-optimisations
eth: optimize the notification/explicit fetch mechanism
2015-06-11 03:31:41 -07:00
obscuren
37111aa4bd core: retry block now also parellise nonce checks 2015-06-11 12:06:05 +02:00
obscuren
f599a1b5f1 core/vm: added a comment regarding the uint64 vs *big.Int 2015-06-11 11:59:30 +02:00
obscuren
9e9bd35557 cmd/geth: Added optional debug flag for reprocess block 2015-06-11 11:44:39 +02:00
Jeffrey Wilcke
979ebfc126 Merge pull request #1224 from karalabe/report-import-progress
cmd/geth, eth/downloader: collect and report import progress too
2015-06-10 15:30:20 -07:00
Jeffrey Wilcke
8482855bc7 Merge pull request #1218 from tgerring/rpcsign
Updated RPC sign test
2015-06-10 15:11:19 -07:00
Jeffrey Wilcke
acb59f3243 Merge pull request #1223 from obscuren/tx-pool-vroooooom
core: fixed race condition in the transaction pool
2015-06-10 12:10:18 -07:00
obscuren
5cfae0536f cmd/evm: print trace when running programs 2015-06-10 21:09:12 +02:00
obscuren
e7627623b9 core/vm: reverse loop stack 2015-06-10 21:08:54 +02:00
obscuren
f94c5473ad core/vm: fixed a bug where Data ignored the stack ptr 2015-06-10 21:08:04 +02:00
obscuren
10af69b57c core, core/vm: moved logger and added gas cost to struct logging 2015-06-10 19:56:40 +02:00
Péter Szilágyi
3c1cccc801 eth/downloader: fetch the block hashes on the fly, when needed 2015-06-10 20:12:22 +03:00
Péter Szilágyi
e61db7145a eth: dedup fetches to ensure no blocks are pulled twice 2015-06-10 19:47:59 +03:00
Péter Szilágyi
355b1e3bb1 eth: randomly fetch announced block (don't hammer origin) 2015-06-10 19:47:59 +03:00
Péter Szilágyi
b9affbf9fe eth: discard fetched blocks that don't fit (no goroutine) 2015-06-10 19:47:59 +03:00
Taylor Gerring
2e0694b606 Updated test 2015-06-10 12:35:35 -04:00
obscuren
fc2a061d51 core/vm: unexported stack again. No longer required 2015-06-10 17:47:36 +02:00
obscuren
065aff9ffa core/vm: documentation and name changes 2015-06-10 17:47:36 +02:00
obscuren
4407524d13 core: fixed race condition for subscriptions 2015-06-10 17:13:32 +02:00
obscuren
29f7902fee core: fixed test 2015-06-10 17:13:32 +02:00
obscuren
65a48f9cd8 core: fixed race condition in the transaction pool
Removed `Stop/Start` mechanism from the transaction pool.
2015-06-10 17:13:32 +02:00
Péter Szilágyi
c4af70d0cc cmd/geth: round the import ETA before converting to string 2015-06-10 18:07:23 +03:00
Péter Szilágyi
271fb20ecb cmd/geth, eth/downloader: rough guess at the import eta 2015-06-10 18:01:05 +03:00
Jeffrey Wilcke
858a6f0be9 Merge pull request #1230 from fjl/p2p-discover-fix-ping-test
p2p/discover: deflake TestUDP_successfulPing
2015-06-10 07:51:48 -07:00
obscuren
f249ccaa89 cmd/evm: implements vm.Environment 2015-06-10 16:46:43 +02:00
Felix Lange
a8e4cb6dfe p2p/discover: use separate rand.Source instances in tests
rand.Source isn't safe for concurrent use.
2015-06-10 15:18:01 +02:00
obscuren
cf3aabb9d3 miner: update gas used after tx proc for pending block 2015-06-10 13:52:38 +02:00
Felix Lange
261a8077c4 p2p/discover: deflake TestUDP_successfulPing 2015-06-10 13:08:21 +02:00
obscuren
1774c49456 core: log tx count for each set of blocks we're importing 2015-06-10 12:57:58 +02:00
obscuren
6fb6e6679e core/vm, core/state: added storage to structured vm logging 2015-06-10 12:57:37 +02:00
obscuren
38c61f6f25 core, core/vm: added structure logging
This also reduces the time required spend in the VM
2015-06-10 12:23:49 +02:00
obscuren
ff5b3ef087 core/vm: added structured logging 2015-06-10 10:59:44 +02:00
obscuren
468501cb86 core/vm: changed program counter to uint64 2015-06-10 10:44:46 +02:00
Péter Szilágyi
b3d5ce7d48 cmd/geth, eth/downloader: collect and report import progress too 2015-06-10 01:20:35 +03:00
Jeffrey Wilcke
dffe6d32d6 Merge pull request #1222 from obscuren/state-vm-test-suit-fix
tests: check gas limit error
2015-06-09 14:20:41 -07:00
obscuren
6a5c9aff3b tests: check gas limit error 2015-06-09 22:49:33 +02:00
Felix Lange
e972a116ac Merge pull request #1221 from karalabe/fix-p2p-dial-test
p2p: fix a close race in the dial test
2015-06-09 22:00:49 +02:00
Péter Szilágyi
1cbbfbe7fa p2p: fix a close race in the dial test 2015-06-09 22:26:26 +03:00
obscuren
7e58949c3f cmd/geth: develop version bump 0.9.29 2015-06-09 21:14:11 +02:00
obscuren
667f5a09c3 Merge branch 'release/0.9.28' into develop 2015-06-09 21:12:44 +02:00
obscuren
bac9a94ddf Merge branch 'release/0.9.28' 2015-06-09 21:12:25 +02:00
obscuren
14994fa21b rpc: skip test if solc version doesn't match 2015-06-09 21:02:24 +02:00
obscuren
bc6031e7bb core, xeth: moved nonce management burden from xeth to txpool 2015-06-09 21:01:02 +02:00
obscuren
93f4852844 cmd/geth: bumped version number 0.9.28 2015-06-09 21:01:02 +02:00
Jeffrey Wilcke
5950755b12 Merge pull request #1220 from karalabe/fix-chain-deadlock2
core: fix a lock annoyance and potential deadlock
2015-06-09 12:00:47 -07:00
Péter Szilágyi
4541c22964 event/filter: hack around data race in the test 2015-06-09 21:33:39 +03:00
Péter Szilágyi
d652a58ada core: fix a race condition accessing the gas limit 2015-06-09 21:13:21 +03:00
Péter Szilágyi
fecf214175 core: fix a lock annoyance and potential deadlock 2015-06-09 21:02:26 +03:00
Jeffrey Wilcke
5f341e5db5 Merge pull request #1212 from fjl/p2p-eth-block-timeout
eth, p2p: improve write timeouts and behaviour under load
2015-06-09 09:51:09 -07:00
Felix Lange
73c355591f core, eth: document that result of GetTransactions is modifiable 2015-06-09 17:07:10 +02:00
Felix Lange
8dc3048f65 eth/downloader: fix hash fetch timeout handling
Fixes #1206
2015-06-09 17:07:10 +02:00
Felix Lange
3239aca69b p2p: bump global write timeout to 20s
The previous value of 5 seconds causes timeouts for legitimate messages
if large messages are sent.
2015-06-09 17:07:10 +02:00
Felix Lange
2c24a73e25 eth: add protocol tests
The protocol tests were commented out when eth/downloader was introduced.
2015-06-09 17:07:10 +02:00
Felix Lange
6c73a59806 eth: limit number of sent transactions based on message size
Nodes that are out of sync will queue many transactions, which causes
the initial transactions message to grow very large. Larger transactions
messages can make communication impossible if the message is too big to
send. Big transactions messages also exhaust egress bandwidth, which
degrades other peer connections.

The new approach to combat these issues is to send transactions in
smaller batches. This commit introduces a new goroutine that handles
delivery of all initial transaction transfers. Size-limited packs of
transactions are sent to one peer at a time, conserving precious egress
bandwidth.
2015-06-09 17:07:10 +02:00
Felix Lange
41b2008a66 eth: limit number of sent blocks based on message size
If blocks get larger, sending 256 at once can make messages large
enough to exceed the low-level write timeout.
2015-06-09 17:06:31 +02:00
Felix Lange
7aefe123e9 core/types: add Transaction.Size 2015-06-09 17:06:31 +02:00
Jeffrey Wilcke
fda49f2b52 Merge pull request #1213 from karalabe/polish-console-prettyprinter
jsre: patch up the pretty printer to have a decent look
2015-06-09 07:29:32 -07:00
Péter Szilágyi
d6f4c515f5 jsre: print function arguments too 2015-06-09 17:23:44 +03:00
Jeffrey Wilcke
c71ab2a6a3 Merge pull request #1219 from Gustav-Simonsson/precompiled_ec_recover_padding
Precompiled ec recover padding
2015-06-09 07:21:23 -07:00
Péter Szilágyi
7842559353 jsre: sort pretty print output, fields before funcs 2015-06-09 17:19:56 +03:00
Gustav Simonsson
6e3b58e491 Remove unneeded if check on EC recover padding 2015-06-09 16:03:05 +02:00
Jeffrey Wilcke
365576620a Merge pull request #1216 from karalabe/fix-eth-dataraces
Fix various data races in eth and core
2015-06-09 06:53:49 -07:00
Gustav Simonsson
15166f880b Skip BlockTests/bcValidBlockTests SimpleTx3 2015-06-09 15:53:31 +02:00
Gustav Simonsson
ad5b5a4895 Pad precompiled EC recover input and add validations 2015-06-09 15:41:15 +02:00
Gustav Simonsson
d8e55a5cc3 Skip VMTests RandomTests temporarily until they are fixed 2015-06-09 15:40:43 +02:00
Gustav Simonsson
e885a2912b Update Ethereum JSON test files 2015-06-09 15:39:24 +02:00
Péter Szilágyi
ebf2aabd25 core: fix up a deadlock caused by double locking 2015-06-09 16:26:44 +03:00
Jeffrey Wilcke
60b780c21b Merge pull request #1217 from tgerring/rpcsign
Fix RPC sign
2015-06-09 06:19:39 -07:00
obscuren
76148515fa skip sol on new compiler 2015-06-09 15:19:20 +02:00
Péter Szilágyi
ff84352fb7 p2p: fix close data race 2015-06-09 16:12:24 +03:00
Jeffrey Wilcke
f371e6c81a Merge pull request #1156 from tgerring/issue1145
Differentiate between 0 and unspecified gas/gasprice
2015-06-09 05:49:55 -07:00
Taylor Gerring
046411866b Fixed signing + tests 2015-06-09 08:47:20 -04:00
Péter Szilágyi
ca8cb65b73 core: fix data race accessing ChainManager.currentBlock 2015-06-09 15:30:46 +03:00
Péter Szilágyi
07baf66200 core: fix data race in accessing ChainManager.td 2015-06-09 15:23:20 +03:00
Taylor Gerring
1a96798642 gas -> gasprice 2015-06-09 08:13:26 -04:00
Taylor Gerring
1c364b6beb gas -> gasprice 2015-06-09 08:13:25 -04:00
Taylor Gerring
c8a9a4e76d Differentiate between 0 and unspecified gas/gasprice 2015-06-09 08:13:25 -04:00
Péter Szilágyi
d09ead546c eth: fix a data race in the hash announcement processing 2015-06-09 15:09:15 +03:00
Péter Szilágyi
f86707713c eth: fix data race accessing peer.td 2015-06-09 14:56:27 +03:00
Jeffrey Wilcke
3054fd4811 Merge pull request #1215 from obscuren/issue1202
core: skip genesis block for reprocess. Closes #1202
2015-06-09 04:46:13 -07:00
obscuren
7da8ebdfd0 Fixed readme links and description 2015-06-09 13:45:35 +02:00
Péter Szilágyi
44147d057d eth: fix data race accessing peer.recentHash 2015-06-09 14:27:44 +03:00
obscuren
190c1b688a core: skip genesis block for reprocess. Closes #1202 2015-06-09 13:24:32 +02:00
Jeffrey Wilcke
05cae69d72 Merge pull request #1188 from karalabe/newblockhashes-proposal
eth: implement the NewBlockHashes protocol proposal
2015-06-09 04:07:46 -07:00
Jeffrey Wilcke
087949227c Merge pull request #1153 from karalabe/downloader-banned-starvation-attack
eth/downloader: gather and ban hashes from invalid chains
2015-06-09 03:45:41 -07:00
Péter Szilágyi
3f4ce70d92 jsre: fix wrong separator comma placing due to non consistent field orders 2015-06-09 13:27:45 +03:00
Jeffrey Wilcke
11f65cf885 Merge pull request #1211 from obscuren/genesis_writout_fix
core: write accounts to statedb. Closes #1210
2015-06-09 02:55:47 -07:00
obscuren
a5b977aa90 core: write accounts to statedb. Closes #1210 2015-06-09 11:37:01 +02:00
Jeffrey Wilcke
0f1cdfa53a Merge pull request #1193 from tgerring/hotbackup
Improve export command
2015-06-08 16:32:38 -07:00
Jeffrey Wilcke
81ceac1b96 Merge pull request #1209 from obscuren/txpool_test_and_pending_fix
core: added a test for missing nonces
2015-06-08 16:04:30 -07:00
obscuren
5245bd7b20 core: added a test for missing nonces
This test showed the logic in the queue was slightly flawed sending out
transactions to its peer it couldn't even resolve itself.
2015-06-09 00:41:47 +02:00
Péter Szilágyi
8216bb901c eth: clean up pending announce download map, polish logs 2015-06-09 00:37:10 +03:00
Jeffrey Wilcke
55b7c14554 Merge pull request #1199 from obscuren/settable_genesis_nonce
core: settable genesis nonce
2015-06-08 13:43:41 -07:00
Jeffrey Wilcke
75522f95ce Merge pull request #1204 from carver/deep-log-crashfix
crash fix: skip deep log if self.chain is not caught up
2015-06-08 13:35:11 -07:00
Jason Carver
a9c058dfe0 crash fix: skip deep log if self.chain is not caught up
@see trace https://gist.github.com/eupraxic/87fdfefe702c51d5944d
2015-06-08 11:49:59 -07:00
Péter Szilágyi
9ed166c196 eth: split and handle explicitly vs. download requested blocks 2015-06-08 20:38:39 +03:00
Taylor Gerring
44e5ff7d15 Fix blocktest 2015-06-08 12:55:15 -04:00
obscuren
6244b10a8f core: settable genesis nonce
You can set the nonce of the block with `--genesisnonce`. When the
genesis nonce changes and it doesn't match with the first block in your
database it will fail. A new `datadir` must be given if the nonce of the
genesis block changes.
2015-06-08 18:33:43 +02:00
Péter Szilágyi
fdccce781e eth: fetch announced hashes from origin, periodically 2015-06-08 19:24:56 +03:00
Péter Szilágyi
8c012e103f eth: mark blocks as known when broadcasting hashes too 2015-06-08 18:44:02 +03:00
Péter Szilágyi
6f415b96b3 eth: implement the NewBlockHashes protocol proposal 2015-06-08 18:44:02 +03:00
Péter Szilágyi
4ed3509a02 eth/downloader: test registration rejection on head ban 2015-06-08 15:02:52 +03:00
Péter Szilágyi
c4f224932f eth/downloader: reject peer registration if head is banned 2015-06-08 14:46:31 +03:00
Péter Szilágyi
63c6cedb14 eth/downloader: cap the hash ban set, add test for it 2015-06-08 14:12:00 +03:00
Péter Szilágyi
4b2dd44711 eth/downloader: fix throttling test to be less timing dependent 2015-06-08 13:23:58 +03:00
Péter Szilágyi
2d627995cf eth/downloader: fix another rebase error 2015-06-08 13:23:58 +03:00
Péter Szilágyi
b40c796ff7 eth/downloader: preallocate the block cache 2015-06-08 13:23:58 +03:00
Péter Szilágyi
1d7bf3d39f eth/downloader: fix merge compile error 2015-06-08 13:23:58 +03:00
Péter Szilágyi
6d497f61c6 eth/downloader: don't block hash deliveries while pulling blocks 2015-06-08 13:23:58 +03:00
Péter Szilágyi
9da0232eef eth/downloader: update test for shitty travis 2015-06-08 13:23:58 +03:00
Péter Szilágyi
0275fcb3d3 eth/downloader: clean up and simplify the code a bit 2015-06-08 13:23:58 +03:00
Péter Szilágyi
abdfcda4dd eth/downloader: short circuit sync if head hash is banned 2015-06-08 13:23:58 +03:00
Péter Szilágyi
84bc93d8cb eth/downloader: accumulating hash bans for reconnecting attackers 2015-06-08 13:23:58 +03:00
Péter Szilágyi
eedb25b22a eth/downloader: clean up tests and unused variables 2015-06-08 13:23:57 +03:00
Jeffrey Wilcke
c6faa18ec9 Merge pull request #1198 from fjl/core-fix-nonce-check
core: fix nonce verification one more time
2015-06-08 01:31:34 -07:00
Felix Lange
6c27e2aaf6 core: add bad block for the 'missing nonce check' fork 2015-06-08 02:54:10 +02:00
Felix Lange
0b493910d3 core: fix the nonce check one more time
The block nonce verification was effectively disabled by a typo.
This time, there is an actual test for it.
2015-06-08 02:19:39 +02:00
Taylor Gerring
4ab0cedf42 Export should start with block 0 2015-06-06 10:59:56 -04:00
Taylor Gerring
2729e6294a Improved error checking 2015-06-06 10:04:13 -04:00
Taylor Gerring
ed621aae33 Cleanup 2015-06-06 09:50:23 -04:00
Jeffrey Wilcke
e822f440b0 added ARM builds 2015-06-06 14:33:08 +02:00
Taylor Gerring
d65b64c884 Allow export command to take first and last args 2015-06-06 00:02:32 -04:00
Taylor Gerring
89c9320d80 Allow exporting subset of chain 2015-06-05 23:01:54 -04:00
obscuren
43ceb0f5c7 cmd/geth: version bump 0.9.27 2015-06-05 17:36:42 +02:00
obscuren
7ab87f9f6e wip 2015-06-05 17:33:30 +02:00
Jeffrey Wilcke
b94a76d17e Merge pull request #1189 from karalabe/downloader-polishes
eth/downloader: handle timeouts more gracefully
2015-06-05 08:31:57 -07:00
Jeffrey Wilcke
8c28126984 Merge pull request #1100 from karalabe/drop-sync-peer-on-empty-hash
eth, eth/downloader: fix #1098, elevate empty hash errors to peer drops
2015-06-05 08:28:08 -07:00
Péter Szilágyi
94e525ae12 eth, eth/downloader: fix #1098, elevate empty hash errors to peer drops 2015-06-05 12:52:48 +03:00
Péter Szilágyi
328ef60b85 eth/downloader: differentiate stale and nonexistent deliveries 2015-06-05 12:37:48 +03:00
Péter Szilágyi
94e4aa6ea9 eth/downloader: log hard timeouts and reset capacity 2015-06-05 11:53:46 +03:00
Jeffrey Wilcke
067e66b348 Merge pull request #1185 from fjl/p2p-nat-timeouts
p2p/nat: request timeouts for UPnP discovery
2015-06-04 15:55:39 -07:00
Felix Lange
fc6a5ae3ec p2p/nat: add timeout for UPnP SOAP requests 2015-06-04 22:25:43 +02:00
Felix Lange
6a831ca015 Godeps: update github.com/huin/goupnp to 5cff77a69fb22f5
This includes a fix adding a timeout to router discovery requests.
2015-06-04 22:25:43 +02:00
Jeffrey Wilcke
8b4605c336 Merge pull request #1186 from obscuren/log_fixes
tests: log coalescing fixes
2015-06-04 10:49:00 -07:00
obscuren
246db4250b tests: use state logs instead own kept logs 2015-06-04 19:48:23 +02:00
Jeffrey Wilcke
45152dead5 Merge pull request #1181 from obscuren/txpool_fixes
cmd: transaction pool fixes and improvements
2015-06-04 10:47:23 -07:00
Jeffrey Wilcke
10fc733767 Merge pull request #1184 from karalabe/nonstop-block-fetches
eth/downloader: fix #1178, don't request blocks beyond the cache bounds
2015-06-04 10:42:34 -07:00
obscuren
912cf7ba04 core: added fork test & double nonce test 2015-06-04 19:28:39 +02:00
obscuren
0f51ee6c88 crypto: return common.Address rather than raw bytes 2015-06-04 19:28:39 +02:00
obscuren
dcdb4554d7 core: documented changes in tx pool 2015-06-04 16:19:22 +02:00
obscuren
cf5ad266f6 core: only change the nonce if the account nonce is lower 2015-06-04 15:44:42 +02:00
Péter Szilágyi
d754c25cc8 eth/downloader: drop log entry from peer, it's covered already 2015-06-04 16:22:55 +03:00
Péter Szilágyi
24cca2f18d eth/downloader: log after state updates, easier to debug 2015-06-04 15:10:43 +03:00
Péter Szilágyi
28c32d1b1b eth/downloader: fix #1178, don't request blocks beyond the cache bounds 2015-06-04 14:51:14 +03:00
obscuren
2bb0e48a7b skipped failing natspec tests 2015-06-04 13:17:47 +02:00
obscuren
9dd12a64a7 core: renamed txs to pending 2015-06-04 13:16:31 +02:00
obscuren
9b27fb91c0 cmd/geth, common/natspec: updating tests (still failing?) 2015-06-04 11:41:20 +02:00
obscuren
36c0db2ac9 xeth: use the correct nonce for creating transactions 2015-06-04 11:35:37 +02:00
obscuren
140d883901 core: test updates 2015-06-03 22:53:33 +02:00
obscuren
d09a6e5421 core, eth, miner: moved nonce management to tx pool.
Removed the managed tx state from the chain manager to the transaction
pool where it's much easier to keep track of nonces (and manage them).
The transaction pool now also uses the queue and pending txs differently
where queued txs are now moved over to the pending queue (i.e. txs ready
for processing and propagation).
2015-06-03 22:43:23 +02:00
Felix Lange
5197aed7db cmd/utils, eth: core.NewBlockProcessor no longer needs TxPool 2015-06-03 22:43:23 +02:00
Felix Lange
ec7a2c3442 core: don't remove transactions after block processing
The transaction pool drops processed transactions on its own
during pool maintenance.
2015-06-03 22:43:23 +02:00
Felix Lange
5721c43585 core: update documentation comments for TxPool 2015-06-03 22:43:23 +02:00
Felix Lange
ca31d71107 core: remove unused code from TxPool 2015-06-03 22:43:23 +02:00
Felix Lange
08befff8f1 core: compute less transaction hashes in TxPool 2015-06-03 22:43:23 +02:00
obscuren
770a0e7839 wip 2015-06-03 22:39:17 +02:00
obscuren
b26f5e0bb7 types: block json unmarshal method added 2015-06-03 22:39:17 +02:00
obscuren
fa4aefee44 core/vm: cleanup and renames 2015-06-03 22:39:17 +02:00
Jeffrey Wilcke
8610314918 Merge pull request #1167 from Gustav-Simonsson/check_ec_recover_err
Add missing err checks on From()
2015-06-03 10:29:47 -07:00
Jeffrey Wilcke
71d9367edc Merge pull request #1151 from fjl/parallel-nonce-2
core: re-add parallel nonce checks
2015-06-03 09:12:06 -07:00
Jeffrey Wilcke
122d2db095 Merge pull request #1150 from fjl/fix-jumpdest
core/vm: improve JUMPDEST analysis
2015-06-03 09:11:56 -07:00
Jeffrey Wilcke
0cd72369f7 Merge pull request #1176 from karalabe/congestion-control
eth/downloader: add a basic block download congestion control
2015-06-03 08:24:52 -07:00
Jeffrey Wilcke
02f785af70 Merge pull request #1166 from Gustav-Simonsson/add_ec_sig_validations
Add EC signature validations before call to libsecp256k1
2015-06-03 08:11:24 -07:00
Felix Lange
c9ed9d253a tests/files: update tests to d309b4679a58d2 2015-06-03 16:25:06 +02:00
Felix Lange
48fb0c3213 core/vm: check for 'no code' before doing any work 2015-06-03 16:25:06 +02:00
Felix Lange
ea2718c946 core/vm: improve JUMPDEST analysis
* JUMPDEST analysis is faster because less type conversions are performed.
* The map of JUMPDEST locations is now created lazily at the first JUMP.
* The result of the analysis is kept around for recursive invocations
  through CALL/CALLCODE.

Fixes #1147
2015-06-03 16:25:05 +02:00
Gustav Simonsson
edbd902a1b Initialise curve N value in package init 2015-06-03 14:44:29 +02:00
Péter Szilágyi
3ec159ab6b eth/downloader: demote peers if they exceed the soft limits at 1 blocks already 2015-06-03 15:43:12 +03:00
Péter Szilágyi
c9a546c310 eth/downloader: add a basic block download congestion control 2015-06-03 14:40:11 +03:00
Jeffrey Wilcke
827bccb64b Merge pull request #1175 from karalabe/keccak-update
crypto/sha3: pull in latest keccak from go crypto (45% speed increase)
2015-06-03 04:13:31 -07:00
Péter Szilágyi
14e7192d9c crypto/sha3: pull in latest keccak from go crypto (45% speed increase) 2015-06-03 12:00:39 +03:00
Jeffrey Wilcke
9085b10508 Merge pull request #1169 from Gustav-Simonsson/unsupport_bruncles
Unsupport bruncles
2015-06-03 01:20:59 -07:00
Gustav Simonsson
0fa9d2431f Add new 0th gen uncle test 2015-06-02 14:47:23 +02:00
Gustav Simonsson
8a76b45253 Use older version of stSpecialTest until JUMPDEST fix is merged 2015-06-02 12:25:43 +02:00
Gustav Simonsson
8962af2e42 Update Ethereum JSON test files 2015-06-02 12:15:25 +02:00
Gustav Simonsson
55bf5051ad Unsupport bruncles 2015-06-01 22:43:05 +02:00
Gustav Simonsson
5a692ba4f6 Update Ethereum JSON test files 2015-06-01 22:34:44 +02:00
Gustav Simonsson
147a699c65 Add missing err checks on From() (skip RPC for now) 2015-06-01 22:12:03 +02:00
Gustav Simonsson
32e1b104f8 Add EC signature validations before call to libsecp256k1 2015-06-01 21:06:52 +02:00
Felix Lange
55b60e699b core: insert less length zero chains
This reduces the amount of queueEvents that are sent internally.
2015-06-01 12:48:12 +02:00
Felix Lange
e7e2cbfc01 core: re-add parallel nonce checks
In this incancation, the processor waits until the nonce
has been verified before handling the block.
2015-06-01 12:47:13 +02:00
Felix Lange
5b14fdb94b Merge pull request #1161 from tgerring/bootnode
Updated SA boot node
2015-06-01 09:51:24 +02:00
Taylor Gerring
057d36b049 Update bootnode 2015-05-31 13:48:27 -05:00
Felix Lange
a906a84950 Merge pull request #1155 from karalabe/fix-chainmanager-datarace
core: fix #1154, sort out data race accessing the future blocks
2015-05-30 01:21:09 +02:00
Péter Szilágyi
b7fc85d68e core: fix #1154, sort out data race accessing the future blocks 2015-05-29 23:46:10 +03:00
Gustav Simonsson
b4818a003a Update Ethereum JSON test files 2015-05-29 13:12:54 +02:00
obscuren
0e703d92ac Merge branch 'release/0.9.26' 2015-05-28 18:21:14 +02:00
obscuren
12b90600eb core: moved guards 2015-05-28 18:18:23 +02:00
obscuren
2587b0ea62 Merge branch 'release/0.9.26' into develop 2015-05-28 18:01:54 +02:00
obscuren
f082c1b895 Merge branch 'release/0.9.26' 2015-05-28 18:01:40 +02:00
obscuren
d51d74eb55 cmd/geth: bump version v0.9.26 2015-05-28 17:43:05 +02:00
obscuren
35806ccc1c build server fix 2015-05-28 17:18:13 +02:00
Jeffrey Wilcke
b25e8b7079 Merge pull request #1142 from obscuren/100-pct-block-prop
eth: 100% block propogation
2015-05-28 08:07:11 -07:00
obscuren
e5d7627427 eth: 100% block propogation 2015-05-28 17:01:44 +02:00
Jeffrey Wilcke
a225ef9c13 Merge pull request #1140 from Gustav-Simonsson/fix_account_unlock_logging
Validate account length and avoid slicing in logging
2015-05-28 07:39:13 -07:00
Jeffrey Wilcke
b6e137b2b4 Merge pull request #1141 from obscuren/parallelisation-issue
Parallelisation issue
2015-05-28 07:37:37 -07:00
Jeffrey Wilcke
03178a77b6 Merge pull request #1132 from obscuren/log_optimisations
core: log optimisations
2015-05-28 07:35:07 -07:00
obscuren
16038b4e67 core: added bad block 2015-05-28 16:26:19 +02:00
obscuren
109f995684 core: log block hash during nonce error 2015-05-28 15:46:36 +02:00
obscuren
75f5ae80fd core: partially removed nonce parallelisation and added merge error chk
Invalid forks are now detected

Current setup of parellelisation actually inserts bad blocks. This fix
is tmp until a better one is found
2015-05-28 15:35:50 +02:00
Gustav Simonsson
9138955ba5 Validate account length and avoid slicing in logging 2015-05-28 15:20:05 +02:00
Jeffrey Wilcke
4baa5ca963 Merge pull request #1137 from obscuren/web3_update
cmd/geth: updated web3
2015-05-28 04:40:14 -07:00
obscuren
598e454d46 cmd/geth: updated web3 2015-05-28 13:24:09 +02:00
Jeffrey Wilcke
9f467c387a Merge pull request #1123 from fjl/lean-blockchain-commands
cmd/geth: leaner blockchain commands
2015-05-28 04:17:47 -07:00
Jeffrey Wilcke
8add3bb009 Merge pull request #1135 from karalabe/tempban-invalid-hashes
core, eth/downloader: expose the bad hashes, check in downloader
2015-05-28 04:13:08 -07:00
Péter Szilágyi
29b0480cfb core, eth/downloader: expose the bad hashes, check in downloader 2015-05-28 14:03:10 +03:00
Felix Lange
e84bbcce3c cmd/geth: don't flush databases after import 2015-05-28 01:20:58 +02:00
Felix Lange
e1fe75e3b6 cmd/utils: use constant for import batch size 2015-05-28 01:20:58 +02:00
Felix Lange
a8bc2181c9 cmd/utils: skip batches with known blocks during import
This makes block importing restartable.
2015-05-28 01:20:58 +02:00
Felix Lange
67effb94b6 cmd/geth, cmd/utils: make chain importing interruptible
Interrupting import with Ctrl-C could cause database corruption
because the signal wasn't handled. utils.ImportChain now checks
for a queued interrupt on every batch.
2015-05-28 01:09:26 +02:00
Felix Lange
705beb4c25 cmd/utils: print errors only once if stdout and stderr are the same file 2015-05-28 01:09:26 +02:00
Felix Lange
74706a0f02 cmd/geth, cmd/utils: rename utils.Get* -> utils.Make*
The renaming should make it clearer that these functions create a new
instance for every call. @obscuren suggested this renaming a while ago.
2015-05-28 01:09:26 +02:00
Felix Lange
8e4512a5e7 p2p/nat: bump timeout in TestAutoDiscRace 2015-05-28 01:09:26 +02:00
Felix Lange
651030c98d cmd/geth: move blockchain commands to chaincmd.go 2015-05-28 01:09:26 +02:00
Felix Lange
62671c93c4 cmd/mist: use utils.SetupLogger 2015-05-28 01:09:26 +02:00
Felix Lange
3b9808f23c cmd/geth, cmd/utils: don't use Ethereum for import, export and upgradedb
The blockchain commands don't need the full stack. With this change,
p2p, miner, downloader, etc are no longer started for blockchain
operations.
2015-05-28 01:09:26 +02:00
obscuren
e3253b5d5e core: fixed an issue with storing receipts 2015-05-28 01:00:23 +02:00
Jeffrey Wilcke
27e0d2a973 Merge pull request #1128 from karalabe/hard-disconnect-trial
eth: hard disconnect if a peer is flaky
2015-05-27 15:28:39 -07:00
Jeffrey Wilcke
5479be9f64 Merge pull request #1129 from obscuren/database_cache_removal
ethdb, common: cache removal
2015-05-27 10:00:08 -07:00
Jeffrey Wilcke
903b95fffa Merge pull request #1124 from karalabe/detaied-download-progress
cmd/geth: expand admin.progress() to something meaningful
2015-05-27 09:05:46 -07:00
obscuren
020006a8ed common, ethdb: removed caching and LastTD 2015-05-27 18:03:16 +02:00
Péter Szilágyi
5235e01b8d eth: hard disconnect if a peer is flaky 2015-05-27 18:58:51 +03:00
obscuren
7595716816 core: adjust gas calculation 2015-05-27 17:01:28 +02:00
Péter Szilágyi
3f91ee4ff8 cmd/geth: expand admin.progress() to something meaningful 2015-05-27 16:46:46 +03:00
Jeffrey Wilcke
8951a03db3 Merge pull request #1121 from obscuren/miner_time_fix
Miner time fix
2015-05-27 04:51:42 -07:00
Jeffrey Wilcke
e13f413ef5 Merge pull request #1112 from fjl/fix-console-exit
cmd/geth: exit the console cleanly when interrupted
2015-05-27 04:40:29 -07:00
Jeffrey Wilcke
69f7a1da5a Merge pull request #1122 from Gustav-Simonsson/improve_validate_header_comments
Update ValidateHeader comments
2015-05-27 04:34:34 -07:00
obscuren
912ae80350 miner: Added 5 blocks wait in prep for #1067 2015-05-27 13:33:52 +02:00
obscuren
12650e16d3 core, miner: fixed miner time issue and removed future blocks
* Miner should no longer generate blocks with a time stamp less or equal
than it's parent.
* Future blocks are no longer processed and queued directly.
  Closes #1118
2015-05-27 13:30:52 +02:00
Jeffrey Wilcke
34729c365b Merge pull request #1067 from carver/deep-mining-log
miner: log locally mined blocks after they are 5-deep in the chain
2015-05-27 04:30:31 -07:00
Gustav Simonsson
bf5f0b1d0c Update ValidateHeader comments 2015-05-27 13:30:24 +02:00
Jeffrey Wilcke
4b29e5ba85 Merge pull request #1120 from Gustav-Simonsson/revert_gas_limit_change
Revert "core: block.gasLimit - parent.gasLimit <= parent.gasLimit / G…
2015-05-27 04:23:55 -07:00
Gustav Simonsson
14955bd454 Revert "core: block.gasLimit - parent.gasLimit <= parent.gasLimit / GasLimitBoundDivisor"
This reverts commit be2b0501b5.
2015-05-27 13:01:06 +02:00
Jason Carver
de12183d38 deep-mining-log: need ring buffer to be one bigger for all-blocks-mined case 2015-05-26 18:55:52 -07:00
Jason Carver
6019f1bb0a deep-mining-log: only track non-stale blocks
if you track stale blocks, then you quickly overflow your ring buffer in the local network case where you're mining every block and generating a lot of stales.
2015-05-26 18:54:56 -07:00
obscuren
f5ce848cfe Merge branch 'release/0.9.25' into develop 2015-05-27 02:07:13 +02:00
obscuren
70867904a0 Merge branch 'release/0.9.25' 2015-05-27 02:07:03 +02:00
obscuren
2c532a7255 cmd/geth: bump version 0.9.25 2015-05-27 02:06:52 +02:00
Jeffrey Wilcke
aada35af9b Merge pull request #1114 from obscuren/develop
core: block.gasLimit - parent.gasLimit <= parent.gasLimit / GasLimitB…
2015-05-26 17:04:42 -07:00
obscuren
be2b0501b5 core: block.gasLimit - parent.gasLimit <= parent.gasLimit / GasLimitBoundDivisor 2015-05-27 01:52:03 +02:00
Jeffrey Wilcke
3590591e67 Merge pull request #1113 from obscuren/develop
core: block database version update
2015-05-26 16:47:10 -07:00
obscuren
222249e622 cmd/geth: Flush instead of close. This solves a nil ptr error 2015-05-27 01:38:41 +02:00
obscuren
b2f2806055 cmd/geth, core: Updated DB version & seedhash debug method 2015-05-27 01:38:41 +02:00
Felix Lange
9253fc337e cmd/geth: exit the console cleanly when interrupted
This fix applies mostly to unsupported terminals that do not trigger the
special interrupt handling in liner. Supported terminals were covered
because liner.Prompt returns an error if Ctrl-C is pressed.
2015-05-27 00:54:48 +02:00
Péter Szilágyi
612f01400f p2p/discover: bond with seed nodes too (runs only if findnode failed) 2015-05-26 23:30:41 +02:00
Péter Szilágyi
3630432dfb p2p/discovery: fix a cornercase loop if no seeds or bootnodes are known 2015-05-26 23:30:40 +02:00
Péter Szilágyi
f539ed1e66 p2p/discover: force refresh if the table is empty 2015-05-26 23:30:40 +02:00
Péter Szilágyi
5076170f34 p2p/discover: permit temporary bond failures for previously known nodes 2015-05-26 23:30:40 +02:00
Péter Szilágyi
6078aa08eb p2p/discover: watch find failures, evacuate on too many, rebond if failed 2015-05-26 23:30:40 +02:00
Péter Szilágyi
64174f196f p2p/discover: add support for counting findnode failures 2015-05-26 23:30:40 +02:00
Felix Lange
6a674ffea5 Merge pull request #1108 from karalabe/fine-seeding
Fine tune seeder and p2p peer handling
2015-05-26 22:03:11 +02:00
Jeffrey Wilcke
b1f7b5d1f6 Merge pull request #1111 from obscuren/neg_tx_check
core: check negative value transactions. Closes #1109
2015-05-26 11:45:23 -07:00
obscuren
c37389f19c core: check negative value transactions. Closes #1109 2015-05-26 20:38:26 +02:00
Jeffrey Wilcke
a55f408c10 Merge pull request #1090 from fjl/jsre-fixes
jsre: fixes for concurrent use, improved timer handling
2015-05-26 11:06:54 -07:00
Jeffrey Wilcke
39b1fe8e44 Merge pull request #1086 from debris/solidity_std
common/compiler: compile solidity contracts with std library
2015-05-26 10:58:09 -07:00
Jeffrey Wilcke
365eea9fba Merge pull request #1106 from karalabe/silence-useless-downloader-log
eth/downloader: silence "Added N blocks from..." if N == 0
2015-05-26 09:45:44 -07:00
Péter Szilágyi
4de8213887 cmd/geth: fix js console test for p2p server update 2015-05-26 19:35:31 +03:00
Péter Szilágyi
68898a4d6b p2p: fix Self() panic if listening is disabled 2015-05-26 19:16:05 +03:00
Péter Szilágyi
e1a0ee8fc5 cmd/geth, cmd/utils, eth, p2p: pass and honor a no discovery flag 2015-05-26 19:07:24 +03:00
Péter Szilágyi
278183c7e7 eth, p2p: start the p2p server even if maxpeers == 0 2015-05-26 17:49:37 +03:00
obscuren
ceea1a7051 Merge branch 'develop' 2015-05-26 15:35:57 +02:00
obscuren
eae0927597 core: prevent crash when last block fails 2015-05-26 15:35:51 +02:00
Péter Szilágyi
3083ec5e32 eth/downloader: silence "Added N blocks from..." if N == 0 2015-05-26 16:10:28 +03:00
obscuren
2f2dd80e48 Merge branch 'develop' 2015-05-26 14:51:41 +02:00
obscuren
d74ee40c86 cmd/geth: bumped version to 0.9.24 2015-05-26 14:51:28 +02:00
obscuren
e6b143b00d Merge branch 'develop' 2015-05-26 14:50:37 +02:00
obscuren
3386ecb59a Merge branch 'release/0.9.24' into develop 2015-05-26 14:49:06 +02:00
obscuren
52b4e51366 Merge branch 'release/0.9.24' 2015-05-26 14:48:39 +02:00
obscuren
0a85260bcd cmd/geth: bumped version to 0.9.24 2015-05-26 14:08:51 +02:00
Jeffrey Wilcke
245f30c59b Merge pull request #1014 from fjl/p2p-dialer-3000
p2p: new dialer, peer management without locks
2015-05-26 05:06:00 -07:00
Jeffrey Wilcke
fd38ea4149 Merge pull request #1099 from obscuren/fork_fix
Fork fix
2015-05-26 04:50:04 -07:00
obscuren
6c2f6f5b03 tests: removed missing block test 2015-05-26 13:48:10 +02:00
obscuren
a6b46420d0 core: ban hash 38f5bb...a714bc
Hash 38f5bbbffd74804820ffa4bab0cd540e9de229725afb98c1a7e57936f4a714bc
ignored.
2015-05-26 13:48:10 +02:00
obscuren
f6f81169fe core/vm: Fork fix. Removal of appending 0 bytes in memset 2015-05-26 13:48:10 +02:00
obscuren
03faccfb08 tests: updated 2015-05-26 13:48:10 +02:00
Jeffrey Wilcke
0de13b0bba Merge pull request #1102 from karalabe/maintain-block-origins
eth, eth/downloader: surface downloaded block origin, drop on error
2015-05-26 04:31:29 -07:00
Péter Szilágyi
eafdc1f8e3 eth, eth/downloader: surface downloaded block origin, drop on error 2015-05-26 14:00:21 +03:00
Jeffrey Wilcke
5044eb4b26 Merge pull request #1101 from obscuren/issue-1096
core/vm: Cleanups & SUB output fix. Closes #1096
2015-05-26 03:50:27 -07:00
obscuren
b419e2631a core/vm: Cleanups & SUB output fix. Closes #1096 2015-05-26 12:42:33 +02:00
Felix Lange
cc318ff8db Merge pull request #1078 from carver/patch-1
eth: expand acronym in log message from TD
2015-05-25 02:49:53 +02:00
Felix Lange
e221a449e0 cmd/geth, jsre, rpc: run all JS code on the event loop
Some JSRE methods (PrettyPrint, ToVal) bypassed the event loop. All
calls to the JS VM are now wrapped. In order to make this somewhat more
foolproof, the otto VM is now a local variable inside the event loop.
2015-05-25 02:27:37 +02:00
Felix Lange
9e1fd70b50 p2p: decrease frameReadTimeout to 30s
This detects hanging connections sooner. We send a ping every 15s and
other implementation have similar limits.
2015-05-25 01:17:14 +02:00
Felix Lange
1440f9a37a p2p: new dialer, peer management without locks
The most visible change is event-based dialing, which should be an
improvement over the timer-based system that we have at the moment.
The dialer gets a chance to compute new tasks whenever peers change or
dials complete. This is better than checking peers on a timer because
dials happen faster. The dialer can now make more precise decisions
about whom to dial based on the peer set and we can test those
decisions without actually opening any sockets.

Peer management is easier to test because the tests can inject
connections at checkpoints (after enc handshake, after protocol
handshake).

Most of the handshake stuff is now part of the RLPx code. It could be
exported or move to its own package because it is no longer entangled
with Server logic.
2015-05-25 01:17:14 +02:00
Felix Lange
9f38ef5d97 p2p/discover: add ReadRandomNodes 2015-05-25 01:17:14 +02:00
Felix Lange
64564da20b p2p: decrease maximum message size for devp2p to 1kB
The previous limit was 10MB which is unacceptable for all kinds
of reasons, the most important one being that we don't want to
allow the remote side to make us allocate 10MB at handshake time.
2015-05-25 01:17:14 +02:00
Felix Lange
7b93341836 Godeps: add github.com/davecgh/go-spew 2015-05-25 01:17:14 +02:00
Felix Lange
dbdc5fd4b3 p2p: delete Server.Broadcast 2015-05-25 01:17:14 +02:00
Felix Lange
2f249fea44 eth: stop p2p.Server on shutdown 2015-05-25 01:17:14 +02:00
Felix Lange
394826f520 Merge pull request #1066 from karalabe/peer-db-polishes
p2p/discover: evacuate self from node database during iterations
2015-05-25 01:16:23 +02:00
Marek Kotewicz
c31f8e2bd7 compile solidity contracts with std library 2015-05-24 19:12:18 +02:00
Jason Carver
f1ce5877ba do not export ring buffer struct 2015-05-23 12:09:59 -07:00
Jason Carver
8a7fb5fd34 do not export constant for when to log a deep block you mined 2015-05-23 12:09:52 -07:00
Jason Carver
97433f5ef1 expand acronym in log message from TD
to total difficulty
2015-05-22 19:12:59 -07:00
Jason Carver
ba295ec6fe Log locally mined blocks, after they are 5-deep in the chain
This helps determine which blocks are unlikely to end up as uncles

 * Store the 5 most recent locally mined block numbers
 * On every imported block, check if the 5-deep block num is in that store
 * Also confirm that the block is signed with miner's coinbase

Why not just check the coinbase? This log is useful if you're running
multiple miners and want to know if *this* miner is performing well.
2015-05-22 12:53:32 -07:00
Jeffrey Wilcke
b2b9b3b567 Merge pull request #1077 from obscuren/disasm
core/vm, rpc: added disasm to `ext_` RPC
2015-05-22 06:51:38 -07:00
obscuren
7381be8edb core/vm, rpc: added disasm to ext_ RPC 2015-05-22 15:38:46 +02:00
Jeffrey Wilcke
f7415c0bbc Merge pull request #1076 from obscuren/rpc_sign
core: added RPC sign back in
2015-05-22 04:08:51 -07:00
obscuren
6539ccae7c core: added RPC sign back in 2015-05-22 13:00:04 +02:00
Jeffrey Wilcke
01ddaf5670 Merge pull request #1072 from Gustav-Simonsson/add_random_tests
Add StateTests/RandomTests and VMTests/RandomTests
2015-05-22 02:34:48 -07:00
Jeffrey Wilcke
f5e112ae5a Merge pull request #1074 from bas-vk/issue1068
make registrar available in console
2015-05-22 02:22:49 -07:00
Bas van Kervel
821b578f7e make registrar available in console 2015-05-22 09:13:45 +02:00
Gustav Simonsson
6ad817e17b Add StateTests/RandomTests and VMTests/RandomTests 2015-05-21 23:04:46 +02:00
obscuren
13e662f6de Merge branch 'develop' 2015-05-21 19:53:35 +02:00
obscuren
054abe20b8 miner: moved break INSIDE the switch ... 2015-05-21 19:53:27 +02:00
obscuren
8c25a83708 Merge branch 'release/0.9.23' into develop 2015-05-21 18:59:26 +02:00
obscuren
2c1c78a6d9 Merge branch 'release/0.9.23' 2015-05-21 18:58:57 +02:00
Péter Szilágyi
cbd3ae6906 p2p/discover: fix #838, evacuate self entries from the node db 2015-05-21 19:41:46 +03:00
Péter Szilágyi
af24c271c7 p2p/discover: fix database presistency test folder 2015-05-21 19:28:10 +03:00
obscuren
3ea9868b65 miner: on downloader.Done/Fail stop immediately. Ignore pending evs 2015-05-21 18:14:32 +02:00
obscuren
4600ecb5c7 cmd/geth: bump version 0.9.23 2015-05-21 18:02:15 +02:00
Jeffrey Wilcke
f1cc3619f5 Merge pull request #1055 from ethersphere/autodag
automatic DAG pregeneration for smooth epoch transitions
2015-05-21 09:01:57 -07:00
Jeffrey Wilcke
af28736bd0 Merge pull request #1064 from karalabe/downloader-attacks
Fix two additional download vulnerabilities
2015-05-21 09:00:12 -07:00
Péter Szilágyi
06a041589f eth, eth/downloader: remove duplicate consts, bump hash fetch to 2K 2015-05-21 18:16:04 +03:00
zelig
bed80133e0 automatic DAG pregeneration for smooth epoch transitions
- backend: AutoDAG bool flag passed from cli/eth.Config to ethereum, autoDAG loop started if true
- backend: autoDAG loop start/stop, remove previous DAG
- cli: AutoDAG bool flag, off by default, but automatically ON if mining
- admin jsre: add startAutoDAG stopAutoDAG and makeDAG in miner section
- switch on/off DAG autogeneration when miner started/stopped on console
2015-05-21 15:53:42 +01:00
Jeffrey Wilcke
1da145675d Merge pull request #1063 from bas-vk/issue1053
prefix dapp key/value entries in extradb
2015-05-21 06:43:17 -07:00
Bas van Kervel
a61e6788db prefix dapp key/value entries in extradb 2015-05-21 15:20:38 +02:00
Jeffrey Wilcke
90b672f1af Merge pull request #1062 from Gustav-Simonsson/tests_updates
Tests updates
2015-05-21 04:49:23 -07:00
Jeffrey Wilcke
bf7dcfce36 Merge pull request #1059 from obscuren/cleanup
Cleanup
2015-05-21 04:11:36 -07:00
obscuren
907848997b miner: one-shot update loop 2015-05-21 11:57:00 +02:00
obscuren
207bd55751 eth: reduced max open files for LevelDB 2015-05-21 11:45:35 +02:00
obscuren
84cd618585 ethdb: documentation and corruption recovery 2015-05-21 11:43:05 +02:00
obscuren
ef8744d9fc core: switched back to set.Set for uncle verification 2015-05-21 11:36:39 +02:00
obscuren
ff1630834c xeth: removed Value 2015-05-21 11:36:05 +02:00
Péter Szilágyi
52db6d8be5 eth/downloader: circumvent a forged block chain with known parent attack 2015-05-21 08:37:27 +03:00
Péter Szilágyi
e8b22b9253 eth/downloader: prevent a peer from dripping bad hashes 2015-05-21 08:07:58 +03:00
Jeffrey Wilcke
9bde7fd72e Merge pull request #1043 from obscuren/test_fixes
core/vm: optimisation on RETURN and updated tests
2015-05-20 03:06:04 -07:00
Jeffrey Wilcke
8fe8ec84f6 Merge pull request #1049 from zsfelfoldi/receipts
Storing tx receipts in extraDb
2015-05-20 03:00:36 -07:00
Jeffrey Wilcke
0300eef94d Merge pull request #1048 from ethersphere/cli-fixes
CLI, JSRE admin and  Solc improvements
2015-05-20 02:31:52 -07:00
Jeffrey Wilcke
6b83a0a589 Merge pull request #1050 from karalabe/handle-slow-download-tester
eth/downloader: fix test to it doesn't time out on a slow machine
2015-05-20 02:29:23 -07:00
Jeffrey Wilcke
adaa49d2cc Merge pull request #1051 from karalabe/fix-odd-naming
eth: fix odd method names in peer set
2015-05-20 02:29:07 -07:00
Péter Szilágyi
3c8227b935 eth: fix odd method names in peer set 2015-05-20 10:34:45 +03:00
Péter Szilágyi
6f54eb6d9a eth/downloader: fix test to it doesn't time out on a slow machine 2015-05-20 10:15:42 +03:00
zsfelfoldi
00ec4132f8 Storing tx receipts in extraDb 2015-05-20 06:41:50 +02:00
zelig
e1d1417729 rpc: NewNotAvailableError instead of NewNotImplementedError if no solc 2015-05-20 05:29:28 +01:00
zelig
00f59f5014 fix eth.sign. now implemented in admin jsre until web3.js has it . 2015-05-20 04:38:20 +01:00
zelig
b0ae84aa0d multiple contract source for solidity compiler: returns contract array if multiple contracts. fixes #1023 2015-05-20 04:11:48 +01:00
zelig
ea893aca8f update web3.js to 0.4.2 2015-05-20 02:58:49 +01:00
zelig
d92172f3d4 add usage doc to wallet import 2015-05-20 02:47:13 +01:00
zelig
4201a18117 remove solc flair 2015-05-20 02:47:13 +01:00
zelig
22b694ee1e solc now in ethereum, fixes solc path setting; setSolc() didnt work 2015-05-20 02:47:13 +01:00
zelig
f9abcee0f9 fix solc tests unskip 2015-05-20 02:47:13 +01:00
obscuren
9617aa8e19 tests: added conditional skip on long running VM tests
Set the TEST_VM_COMPLEX env var to test complex vm tests which require a
lot of ram and quite some time.
2015-05-20 00:21:24 +02:00
obscuren
f5af1fdca8 core/vm: RETURN op code returns pointer to memory rather than copy 2015-05-20 00:21:23 +02:00
obscuren
648b352424 tests/vm: updated tests and skipped output for specific tests
Skipped tests due to large return value
2015-05-20 00:21:23 +02:00
Jeffrey Wilcke
79042223dc Merge pull request #1044 from obscuren/thread_safe_block_cache
core: block cache Has method thread safe
2015-05-19 15:11:41 -07:00
Jeffrey Wilcke
b14ee6ce16 Merge pull request #1046 from tgerring/issue1045
Allow unlocking multiple accounts
2015-05-19 15:11:20 -07:00
obscuren
8dac28f2e3 core: block cache Has method thread safe 2015-05-19 21:50:56 +02:00
obscuren
87a05c8f38 core: skipped tests while cache disabled 2015-05-19 21:50:26 +02:00
Taylor Gerring
32b8565022 Support multiple account unlock attempts 2015-05-19 14:46:32 -05:00
Taylor Gerring
af8ada45e7 Allow unlocking multiple accounts #1045
Separate accounts with spaces when using --unlock
2015-05-19 13:40:41 -05:00
Jeffrey Wilcke
46d6470c43 Merge pull request #1035 from karalabe/eth-threadsafe-peers
eth: make the peer-set thread safe
2015-05-19 08:50:38 -07:00
Jeffrey Wilcke
9b825e2728 Merge pull request #1036 from tgerring/issue884
JSON RPC null field updates
2015-05-19 06:44:31 -07:00
Taylor Gerring
748263d2f0 Use bytes.Repeat() instead of 32-byte literal 2015-05-19 08:14:48 -05:00
obscuren
7d9a13e0d5 core: disable cash tmp 2015-05-19 12:59:58 +02:00
Jeffrey Wilcke
6c2ad7b72e Merge pull request #1034 from obscuren/tx_pool_fix
Nonce fix for failing transactions
2015-05-18 12:28:51 -07:00
obscuren
b7baceefda xeth: remove nonce on error. Fixes #1026 2015-05-18 20:52:25 +02:00
Péter Szilágyi
4755caeb2d eth: remote a superfluous peerSet method 2015-05-18 21:35:42 +03:00
Péter Szilágyi
5422fe5125 eth: make the peer set thread safe 2015-05-18 21:33:37 +03:00
Jeffrey Wilcke
bd0c0a633b Merge pull request #1022 from obscuren/parallel_nonce_checks
Parallelise nonce checks
2015-05-18 11:13:53 -07:00
Jeffrey Wilcke
d6adadc5e3 Merge pull request #1033 from tgerring/issue1010
Add "removedb" command to Geth
2015-05-18 11:12:58 -07:00
Taylor Gerring
0864f1fc8e Remove unused confirm() method 2015-05-18 12:25:33 -05:00
Taylor Gerring
f14feea436 Refactor user prompts into utils 2015-05-18 12:24:30 -05:00
Taylor Gerring
36a4ba3248 Add user confirmation for removedb 2015-05-18 12:04:35 -05:00
obscuren
40717465bc core: fixed tests 2015-05-18 18:16:53 +02:00
obscuren
59c0d01418 core: chain manager no longer exports genesis block 2015-05-18 18:16:53 +02:00
obscuren
bc5e60cd63 miner: stale block notification 2015-05-18 18:16:53 +02:00
Taylor Gerring
fe41bd6fe8 Add "removedb" command to Geth
Removes the state and blockchain databases
2015-05-18 10:54:15 -05:00
Jeffrey Wilcke
a3a5f8b593 Merge pull request #1032 from tgerring/issue1025
Multiple CORS domains support
2015-05-18 08:49:35 -07:00
Taylor Gerring
54b5c8273d XEth comment clarification 2015-05-18 10:41:56 -05:00
Taylor Gerring
a2598e649d Permit multiple CORS domains
Separated by spaces
2015-05-18 10:31:03 -05:00
Taylor Gerring
62d76b8e1f Cleanup 2015-05-18 10:11:27 -05:00
Taylor Gerring
a528bd04db Return nil for certain fields on eth_getTransactionByHash when not part of a block 2015-05-18 10:09:00 -05:00
Jeffrey Wilcke
677796b351 Merge pull request #1031 from bas-vk/issue1012
fixed race condition in miner
2015-05-18 07:33:06 -07:00
Gustav Simonsson
6a72cd45e2 Add wrapper for BlockTests/bcWalletTest.json 2015-05-18 16:28:54 +02:00
Gustav Simonsson
1d51cada3c Handle call depth exception for CREATE 2015-05-18 16:23:20 +02:00
Taylor Gerring
d381d9a74c Return nil for certain fields on eth_getBlockByNumber pending 2015-05-18 09:16:10 -05:00
Bas van Kervel
60561cdca2 fixed issue when miner is not stopping af stop command 2015-05-18 16:09:01 +02:00
Bas van Kervel
7778740315 fixed race condition in miner 2015-05-18 15:13:58 +02:00
obscuren
c67424ecc8 core: parallelise nonce checking when processing blocks
ChainManager now uses a parallel approach to block processing where all
nonces are checked seperatly from the block processing process. This
speeds up the process by about 3 times on my i7
2015-05-18 13:59:22 +02:00
Gustav Simonsson
36419defd1 Update Ethereum JSON test files 2015-05-18 12:45:24 +02:00
obscuren
67d44519ce core: bugfix test 2. set => hash map 2015-05-18 10:49:09 +02:00
obscuren
54f0f82dd1 ret 2015-05-18 10:14:48 +02:00
obscuren
e323f0e831 core: tmp diagnostic logs 2015-05-18 10:13:50 +02:00
obscuren
280b7f23af Merge branch 'hotfix/0.9.22' into develop 2015-05-17 21:35:29 +02:00
obscuren
915fc0e581 Merge branch 'hotfix/0.9.22' 2015-05-17 21:35:15 +02:00
obscuren
3a51d5e80c cmd/geth: fixed ver num 2015-05-17 21:34:28 +02:00
Jeffrey Wilcke
443d024843 Merge pull request #1021 from obscuren/global_chain_lock
core: global chain insert lock
2015-05-17 08:54:16 -07:00
obscuren
27782bbade core: global chain insert lock 2015-05-17 00:55:02 +02:00
Jeffrey Wilcke
426c70ac0b Merge pull request #1011 from obscuren/upgradedb_fix
cmd/geth: delete state db on upgradedb command
2015-05-16 08:48:49 -07:00
obscuren
28ba374f27 cmd/geth: delete state db on upgradedb command 2015-05-16 17:43:19 +02:00
obscuren
ad99089567 Merge branch 'hotfix/0.9.21.1' into develop 2015-05-16 13:04:43 +02:00
obscuren
69f8a1b01a Merge branch 'hotfix/0.9.21-1' 2015-05-16 13:03:30 +02:00
Vitalik Buterin
61e8296bd8 Adjust miner coinbase and not just miner worker coinbase 2015-05-15 21:23:09 -04:00
obscuren
4b2ee6c30c Merge branch 'release/0.9.21' into develop 2015-05-16 00:27:35 +02:00
389 changed files with 65409 additions and 45678 deletions

View File

@@ -4,7 +4,7 @@ go:
before_install:
- sudo add-apt-repository ppa:beineri/opt-qt541 -y
- sudo apt-get update -qq
- sudo apt-get install -yqq libgmp3-dev qt54quickcontrols qt54webengine
- sudo apt-get install -yqq libgmp3-dev
install:
# - go get code.google.com/p/go.tools/cmd/goimports
# - go get github.com/golang/lint/golint

10
Godeps/Godeps.json generated
View File

@@ -15,10 +15,14 @@
"Comment": "1.2.0-95-g9b2bd2b",
"Rev": "9b2bd2b3489748d4d0a204fa4eb2ee9e89e0ebc6"
},
{
"ImportPath": "github.com/davecgh/go-spew/spew",
"Rev": "3e6e67c4dcea3ac2f25fd4731abc0e1deaf36216"
},
{
"ImportPath": "github.com/ethereum/ethash",
"Comment": "v23.1-206-gf0e6321",
"Rev": "f0e63218b721dc2f696920a92d5de1f6364e9bf7"
"Comment": "v23.1-222-g173b8ff",
"Rev": "173b8ff953610c13710061e83b95b50c73d7ea50"
},
{
"ImportPath": "github.com/howeyc/fsnotify",
@@ -27,7 +31,7 @@
},
{
"ImportPath": "github.com/huin/goupnp",
"Rev": "c57ae84388ab59076fd547f1abeab71c2edb0a21"
"Rev": "5cff77a69fb22f5f1774c4451ea2aab63d4d2f20"
},
{
"ImportPath": "github.com/jackpal/go-nat-pmp",

View File

@@ -0,0 +1,450 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"reflect"
"sort"
"strconv"
"unsafe"
)
const (
// ptrSize is the size of a pointer on the current arch.
ptrSize = unsafe.Sizeof((*byte)(nil))
)
var (
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
// flagKindWidth and flagKindShift indicate various bits that the
// reflect package uses internally to track kind information.
//
// flagRO indicates whether or not the value field of a reflect.Value is
// read-only.
//
// flagIndir indicates whether the value field of a reflect.Value is
// the actual data or a pointer to the data.
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
)
func init() {
// Older versions of reflect.Value stored small integers directly in the
// ptr field (which is named val in the older versions). Versions
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// Commit 90a7c3c86944 changed the flag positions such that the low
// order bits are the kind. This code extracts the kind from the flags
// field and ensures it's the correct type. When it's not, the flag
// order has been changed to the newer format, so the flags are updated
// accordingly.
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
upfv := *(*uintptr)(upf)
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
flagKindShift = 0
flagRO = 1 << 5
flagIndir = 1 << 6
}
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
// the typical safety restrictions preventing access to unaddressable and
// unexported data. It works by digging the raw pointer to the underlying
// value out of the protected value and generating a new unprotected (unsafe)
// reflect.Value to it.
//
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
indirects := 1
vt := v.Type()
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
if rvf&flagIndir != 0 {
vt = reflect.PtrTo(v.Type())
indirects++
} else if offsetScalar != 0 {
// The value is in the scalar field when it's not one of the
// reference types.
switch vt.Kind() {
case reflect.Uintptr:
case reflect.Chan:
case reflect.Func:
case reflect.Map:
case reflect.Ptr:
case reflect.UnsafePointer:
default:
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
offsetScalar)
}
}
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
}
// Some constants in the form of bytes to avoid string overhead. This mirrors
// the technique used in the fmt package.
var (
panicBytes = []byte("(PANIC=")
plusBytes = []byte("+")
iBytes = []byte("i")
trueBytes = []byte("true")
falseBytes = []byte("false")
interfaceBytes = []byte("(interface {})")
commaNewlineBytes = []byte(",\n")
newlineBytes = []byte("\n")
openBraceBytes = []byte("{")
openBraceNewlineBytes = []byte("{\n")
closeBraceBytes = []byte("}")
asteriskBytes = []byte("*")
colonBytes = []byte(":")
colonSpaceBytes = []byte(": ")
openParenBytes = []byte("(")
closeParenBytes = []byte(")")
spaceBytes = []byte(" ")
pointerChainBytes = []byte("->")
nilAngleBytes = []byte("<nil>")
maxNewlineBytes = []byte("<max depth reached>\n")
maxShortBytes = []byte("<max>")
circularBytes = []byte("<already shown>")
circularShortBytes = []byte("<shown>")
invalidAngleBytes = []byte("<invalid>")
openBracketBytes = []byte("[")
closeBracketBytes = []byte("]")
percentBytes = []byte("%")
precisionBytes = []byte(".")
openAngleBytes = []byte("<")
closeAngleBytes = []byte(">")
openMapBytes = []byte("map[")
closeMapBytes = []byte("]")
lenEqualsBytes = []byte("len=")
capEqualsBytes = []byte("cap=")
)
// hexDigits is used to map a decimal value to a hex digit.
var hexDigits = "0123456789abcdef"
// catchPanic handles any panics that might occur during the handleMethods
// calls.
func catchPanic(w io.Writer, v reflect.Value) {
if err := recover(); err != nil {
w.Write(panicBytes)
fmt.Fprintf(w, "%v", err)
w.Write(closeParenBytes)
}
}
// handleMethods attempts to call the Error and String methods on the underlying
// type the passed reflect.Value represents and outputes the result to Writer w.
//
// It handles panics in any called methods by catching and displaying the error
// as the formatted value.
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
// We need an interface to check if the type implements the error or
// Stringer interface. However, the reflect package won't give us an
// interface on certain things like unexported struct fields in order
// to enforce visibility rules. We use unsafe to bypass these restrictions
// since this package does not mutate the values.
if !v.CanInterface() {
v = unsafeReflectValue(v)
}
// Choose whether or not to do error and Stringer interface lookups against
// the base type or a pointer to the base type depending on settings.
// Technically calling one of these methods with a pointer receiver can
// mutate the value, however, types which choose to satisify an error or
// Stringer interface with a pointer receiver should not be mutating their
// state inside these interface methods.
var viface interface{}
if !cs.DisablePointerMethods {
if !v.CanAddr() {
v = unsafeReflectValue(v)
}
viface = v.Addr().Interface()
} else {
if v.CanAddr() {
v = v.Addr()
}
viface = v.Interface()
}
// Is it an error or Stringer?
switch iface := viface.(type) {
case error:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.Error()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.Error()))
return true
case fmt.Stringer:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.String()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.String()))
return true
}
return false
}
// printBool outputs a boolean value as true or false to Writer w.
func printBool(w io.Writer, val bool) {
if val {
w.Write(trueBytes)
} else {
w.Write(falseBytes)
}
}
// printInt outputs a signed integer value to Writer w.
func printInt(w io.Writer, val int64, base int) {
w.Write([]byte(strconv.FormatInt(val, base)))
}
// printUint outputs an unsigned integer value to Writer w.
func printUint(w io.Writer, val uint64, base int) {
w.Write([]byte(strconv.FormatUint(val, base)))
}
// printFloat outputs a floating point value using the specified precision,
// which is expected to be 32 or 64bit, to Writer w.
func printFloat(w io.Writer, val float64, precision int) {
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
}
// printComplex outputs a complex value using the specified float precision
// for the real and imaginary parts to Writer w.
func printComplex(w io.Writer, c complex128, floatPrecision int) {
r := real(c)
w.Write(openParenBytes)
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
i := imag(c)
if i >= 0 {
w.Write(plusBytes)
}
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
w.Write(iBytes)
w.Write(closeParenBytes)
}
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
// Null pointer.
num := uint64(p)
if num == 0 {
w.Write(nilAngleBytes)
return
}
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
buf := make([]byte, 18)
// It's simpler to construct the hex string right to left.
base := uint64(16)
i := len(buf) - 1
for num >= base {
buf[i] = hexDigits[num%base]
num /= base
i--
}
buf[i] = hexDigits[num]
// Add '0x' prefix.
i--
buf[i] = 'x'
i--
buf[i] = '0'
// Strip unused leading bytes.
buf = buf[i:]
w.Write(buf)
}
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
// elements to be sorted.
type valuesSorter struct {
values []reflect.Value
strings []string // either nil or same len and values
cs *ConfigState
}
// newValuesSorter initializes a valuesSorter instance, which holds a set of
// surrogate keys on which the data should be sorted. It uses flags in
// ConfigState to decide if and how to populate those surrogate keys.
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
vs := &valuesSorter{values: values, cs: cs}
if canSortSimply(vs.values[0].Kind()) {
return vs
}
if !cs.DisableMethods {
vs.strings = make([]string, len(values))
for i := range vs.values {
b := bytes.Buffer{}
if !handleMethods(cs, &b, vs.values[i]) {
vs.strings = nil
break
}
vs.strings[i] = b.String()
}
}
if vs.strings == nil && cs.SpewKeys {
vs.strings = make([]string, len(values))
for i := range vs.values {
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
}
}
return vs
}
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
// directly, or whether it should be considered for sorting by surrogate keys
// (if the ConfigState allows it).
func canSortSimply(kind reflect.Kind) bool {
// This switch parallels valueSortLess, except for the default case.
switch kind {
case reflect.Bool:
return true
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return true
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
case reflect.Uintptr:
return true
case reflect.Array:
return true
}
return false
}
// Len returns the number of values in the slice. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Len() int {
return len(s.values)
}
// Swap swaps the values at the passed indices. It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Swap(i, j int) {
s.values[i], s.values[j] = s.values[j], s.values[i]
if s.strings != nil {
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
}
}
// valueSortLess returns whether the first value should sort before the second
// value. It is used by valueSorter.Less as part of the sort.Interface
// implementation.
func valueSortLess(a, b reflect.Value) bool {
switch a.Kind() {
case reflect.Bool:
return !a.Bool() && b.Bool()
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
return a.Int() < b.Int()
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
return a.Uint() < b.Uint()
case reflect.Float32, reflect.Float64:
return a.Float() < b.Float()
case reflect.String:
return a.String() < b.String()
case reflect.Uintptr:
return a.Uint() < b.Uint()
case reflect.Array:
// Compare the contents of both arrays.
l := a.Len()
for i := 0; i < l; i++ {
av := a.Index(i)
bv := b.Index(i)
if av.Interface() == bv.Interface() {
continue
}
return valueSortLess(av, bv)
}
}
return a.String() < b.String()
}
// Less returns whether the value at index i should sort before the
// value at index j. It is part of the sort.Interface implementation.
func (s *valuesSorter) Less(i, j int) bool {
if s.strings == nil {
return valueSortLess(s.values[i], s.values[j])
}
return s.strings[i] < s.strings[j]
}
// sortValues is a sort function that handles both native types and any type that
// can be converted to error or Stringer. Other inputs are sorted according to
// their Value.String() value to ensure display stability.
func sortValues(values []reflect.Value, cs *ConfigState) {
if len(values) == 0 {
return
}
sort.Sort(newValuesSorter(values, cs))
}

View File

@@ -0,0 +1,298 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"fmt"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
)
// custom type to test Stinger interface on non-pointer receiver.
type stringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with non-pointer receivers.
func (s stringer) String() string {
return "stringer " + string(s)
}
// custom type to test Stinger interface on pointer receiver.
type pstringer string
// String implements the Stringer interface for testing invocation of custom
// stringers on types with only pointer receivers.
func (s *pstringer) String() string {
return "stringer " + string(*s)
}
// xref1 and xref2 are cross referencing structs for testing circular reference
// detection.
type xref1 struct {
ps2 *xref2
}
type xref2 struct {
ps1 *xref1
}
// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
// reference for testing detection.
type indirCir1 struct {
ps2 *indirCir2
}
type indirCir2 struct {
ps3 *indirCir3
}
type indirCir3 struct {
ps1 *indirCir1
}
// embed is used to test embedded structures.
type embed struct {
a string
}
// embedwrap is used to test embedded structures.
type embedwrap struct {
*embed
e *embed
}
// panicer is used to intentionally cause a panic for testing spew properly
// handles them
type panicer int
func (p panicer) String() string {
panic("test panic")
}
// customError is used to test custom error interface invocation.
type customError int
func (e customError) Error() string {
return fmt.Sprintf("error: %d", int(e))
}
// stringizeWants converts a slice of wanted test output into a format suitable
// for a test error message.
func stringizeWants(wants []string) string {
s := ""
for i, want := range wants {
if i > 0 {
s += fmt.Sprintf("want%d: %s", i+1, want)
} else {
s += "want: " + want
}
}
return s
}
// testFailed returns whether or not a test failed by checking if the result
// of the test is in the slice of wanted strings.
func testFailed(result string, wants []string) bool {
for _, want := range wants {
if result == want {
return false
}
}
return true
}
type sortableStruct struct {
x int
}
func (ss sortableStruct) String() string {
return fmt.Sprintf("ss.%d", ss.x)
}
type unsortableStruct struct {
x int
}
type sortTestCase struct {
input []reflect.Value
expected []reflect.Value
}
func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
getInterfaces := func(values []reflect.Value) []interface{} {
interfaces := []interface{}{}
for _, v := range values {
interfaces = append(interfaces, v.Interface())
}
return interfaces
}
for _, test := range tests {
spew.SortValues(test.input, cs)
// reflect.DeepEqual cannot really make sense of reflect.Value,
// probably because of all the pointer tricks. For instance,
// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
// instead.
input := getInterfaces(test.input)
expected := getInterfaces(test.expected)
if !reflect.DeepEqual(input, expected) {
t.Errorf("Sort mismatch:\n %v != %v", input, expected)
}
}
}
// TestSortValues ensures the sort functionality for relect.Value based sorting
// works as intended.
func TestSortValues(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
embedA := v(embed{"a"})
embedB := v(embed{"b"})
embedC := v(embed{"c"})
tests := []sortTestCase{
// No values.
{
[]reflect.Value{},
[]reflect.Value{},
},
// Bools.
{
[]reflect.Value{v(false), v(true), v(false)},
[]reflect.Value{v(false), v(false), v(true)},
},
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Uints.
{
[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
},
// Floats.
{
[]reflect.Value{v(2.0), v(1.0), v(3.0)},
[]reflect.Value{v(1.0), v(2.0), v(3.0)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// Array
{
[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
},
// Uintptrs.
{
[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
},
// SortableStructs.
{
// Note: not sorted - DisableMethods is set.
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
// Invalid.
{
[]reflect.Value{embedB, embedA, embedC},
[]reflect.Value{embedB, embedA, embedC},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithMethods ensures the sort functionality for relect.Value
// based sorting works as intended when using string methods.
func TestSortValuesWithMethods(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
// Note: not sorted - SpewKeys is false.
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
helpTestSortValues(tests, &cs, t)
}
// TestSortValuesWithSpew ensures the sort functionality for relect.Value
// based sorting works as intended when using spew to stringify keys.
func TestSortValuesWithSpew(t *testing.T) {
v := reflect.ValueOf
a := v("a")
b := v("b")
c := v("c")
tests := []sortTestCase{
// Ints.
{
[]reflect.Value{v(2), v(1), v(3)},
[]reflect.Value{v(1), v(2), v(3)},
},
// Strings.
{
[]reflect.Value{b, a, c},
[]reflect.Value{a, b, c},
},
// SortableStructs.
{
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
},
// UnsortableStructs.
{
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
},
}
cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
helpTestSortValues(tests, &cs, t)
}

View File

@@ -0,0 +1,294 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"io"
"os"
)
// ConfigState houses the configuration options used by spew to format and
// display values. There is a global instance, Config, that is used to control
// all top-level Formatter and Dump functionality. Each ConfigState instance
// provides methods equivalent to the top-level functions.
//
// The zero value for ConfigState provides no indentation. You would typically
// want to set it to a space or a tab.
//
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
// with default settings. See the documentation of NewDefaultConfig for default
// values.
type ConfigState struct {
// Indent specifies the string to use for each indentation level. The
// global config instance that all top-level functions use set this to a
// single space by default. If you would like more indentation, you might
// set this to a tab with "\t" or perhaps two spaces with " ".
Indent string
// MaxDepth controls the maximum number of levels to descend into nested
// data structures. The default, 0, means there is no limit.
//
// NOTE: Circular data structures are properly detected, so it is not
// necessary to set this value unless you specifically want to limit deeply
// nested data structures.
MaxDepth int
// DisableMethods specifies whether or not error and Stringer interfaces are
// invoked for types that implement them.
DisableMethods bool
// DisablePointerMethods specifies whether or not to check for and invoke
// error and Stringer interfaces on types which only accept a pointer
// receiver when the current type is not a pointer.
//
// NOTE: This might be an unsafe action since calling one of these methods
// with a pointer receiver could technically mutate the value, however,
// in practice, types which choose to satisify an error or Stringer
// interface with a pointer receiver should not be mutating their state
// inside these interface methods.
DisablePointerMethods bool
// ContinueOnMethod specifies whether or not recursion should continue once
// a custom error or Stringer interface is invoked. The default, false,
// means it will print the results of invoking the custom error or Stringer
// interface and return immediately instead of continuing to recurse into
// the internals of the data type.
//
// NOTE: This flag does not have any effect if method invocation is disabled
// via the DisableMethods or DisablePointerMethods options.
ContinueOnMethod bool
// SortKeys specifies map keys should be sorted before being printed. Use
// this to have a more deterministic, diffable output. Note that only
// native types (bool, int, uint, floats, uintptr and string) and types
// that support the error or Stringer interfaces (if methods are
// enabled) are supported, with other types sorted according to the
// reflect.Value.String() output which guarantees display stability.
SortKeys bool
// SpewKeys specifies that, as a last resort attempt, map keys should
// be spewed to strings and sorted by those strings. This is only
// considered if SortKeys is true.
SpewKeys bool
}
// Config is the active configuration of the top-level functions.
// The configuration can be changed by modifying the contents of spew.Config.
var Config = ConfigState{Indent: " "}
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the formatted string as a value that satisfies error. See NewFormatter
// for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, c.convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, c.convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, c.convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a Formatter interface returned by c.NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, c.convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
return fmt.Print(c.convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, c.convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
return fmt.Println(c.convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprint(a ...interface{}) string {
return fmt.Sprint(c.convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a Formatter interface returned by c.NewFormatter. It returns
// the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, c.convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a Formatter interface returned by c.NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
func (c *ConfigState) Sprintln(a ...interface{}) string {
return fmt.Sprintln(c.convertArgs(a)...)
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
c.Printf, c.Println, or c.Printf.
*/
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(c, v)
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
fdump(c, w, a...)
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by modifying the public members
of c. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func (c *ConfigState) Dump(a ...interface{}) {
fdump(c, os.Stdout, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func (c *ConfigState) Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(c, &buf, a...)
return buf.String()
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a spew Formatter interface using
// the ConfigState associated with s.
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = newFormatter(c, arg)
}
return formatters
}
// NewDefaultConfig returns a ConfigState with the following default settings.
//
// Indent: " "
// MaxDepth: 0
// DisableMethods: false
// DisablePointerMethods: false
// ContinueOnMethod: false
// SortKeys: false
func NewDefaultConfig() *ConfigState {
return &ConfigState{Indent: " "}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
Package spew implements a deep pretty printer for Go data structures to aid in
debugging.
A quick overview of the additional features spew provides over the built-in
printing facilities for Go data types are as follows:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output (only when using
Dump style)
There are two different approaches spew allows for dumping Go data structures:
* Dump style which prints with newlines, customizable indentation,
and additional debug information such as types and all pointer addresses
used to indirect to the final value
* A custom Formatter interface that integrates cleanly with the standard fmt
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
similar to the default %v while providing the additional functionality
outlined above and passing unsupported format verbs such as %x and %q
along to fmt
Quick Start
This section demonstrates how to quickly get started with spew. See the
sections below for further details on formatting and configuration options.
To dump a variable with full newlines, indentation, type, and pointer
information use Dump, Fdump, or Sdump:
spew.Dump(myVar1, myVar2, ...)
spew.Fdump(someWriter, myVar1, myVar2, ...)
str := spew.Sdump(myVar1, myVar2, ...)
Alternatively, if you would prefer to use format strings with a compacted inline
printing style, use the convenience wrappers Printf, Fprintf, etc with
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
%#+v (adds types and pointer addresses):
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
Configuration Options
Configuration of spew is handled by fields in the ConfigState type. For
convenience, all of the top-level functions use a global state available
via the spew.Config global.
It is also possible to create a ConfigState instance that provides methods
equivalent to the top-level functions. This allows concurrent configuration
options. See the ConfigState documentation for more details.
The following configuration options are available:
* Indent
String to use for each indentation level for Dump functions.
It is a single space by default. A popular alternative is "\t".
* MaxDepth
Maximum number of levels to descend into nested data structures.
There is no limit by default.
* DisableMethods
Disables invocation of error and Stringer interface methods.
Method invocation is enabled by default.
* DisablePointerMethods
Disables invocation of error and Stringer interface methods on types
which only accept pointer receivers from non-pointer variables.
Pointer method invocation is enabled by default.
* ContinueOnMethod
Enables recursion into types after invoking error and Stringer interface
methods. Recursion after method invocation is disabled by default.
* SortKeys
Specifies map keys should be sorted before being printed. Use
this to have a more deterministic, diffable output. Note that
only native types (bool, int, uint, floats, uintptr and string)
and types which implement error or Stringer interfaces are
supported with other types sorted according to the
reflect.Value.String() output which guarantees display
stability. Natural map order is used by default.
* SpewKeys
Specifies that, as a last resort attempt, map keys should be
spewed to strings and sorted by those strings. This is only
considered if SortKeys is true.
Dump Usage
Simply call spew.Dump with a list of variables you want to dump:
spew.Dump(myVar1, myVar2, ...)
You may also call spew.Fdump if you would prefer to output to an arbitrary
io.Writer. For example, to dump to standard error:
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
A third option is to call spew.Sdump to get the formatted output as a string:
str := spew.Sdump(myVar1, myVar2, ...)
Sample Dump Output
See the Dump example for details on the setup of the types and variables being
shown here.
(main.Foo) {
unexportedField: (*main.Bar)(0xf84002e210)({
flag: (main.Flag) flagTwo,
data: (uintptr) <nil>
}),
ExportedField: (map[interface {}]interface {}) (len=1) {
(string) (len=3) "one": (bool) true
}
}
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
command as shown.
([]uint8) (len=32 cap=32) {
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
00000020 31 32 |12|
}
Custom Formatter
Spew provides a custom formatter that implements the fmt.Formatter interface
so that it integrates cleanly with standard fmt package printing functions. The
formatter is useful for inline printing of smaller data types similar to the
standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Custom Formatter Usage
The simplest way to make use of the spew custom formatter is to call one of the
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
functions have syntax you are most likely already familiar with:
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
spew.Println(myVar, myVar2)
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
See the Index for the full list convenience functions.
Sample Formatter Output
Double pointer to a uint8:
%v: <**>5
%+v: <**>(0xf8400420d0->0xf8400420c8)5
%#v: (**uint8)5
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
Pointer to circular struct with a uint8 field and a pointer to itself:
%v: <*>{1 <*><shown>}
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
See the Printf example for details on the setup of variables being shown
here.
Errors
Since it is possible for custom Stringer/error interfaces to panic, spew
detects them and handles them internally by printing the panic information
inline with the output. Since spew is intended to provide deep pretty printing
capabilities on structures, it intentionally does not return any errors.
*/
package spew

View File

@@ -0,0 +1,506 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"os"
"reflect"
"regexp"
"strconv"
"strings"
)
var (
// uint8Type is a reflect.Type representing a uint8. It is used to
// convert cgo types to uint8 slices for hexdumping.
uint8Type = reflect.TypeOf(uint8(0))
// cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump
// them.
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
)
// dumpState contains information about the state of a dump operation.
type dumpState struct {
w io.Writer
depth int
pointers map[uintptr]int
ignoreNextType bool
ignoreNextIndent bool
cs *ConfigState
}
// indent performs indentation according to the depth level and cs.Indent
// option.
func (d *dumpState) indent() {
if d.ignoreNextIndent {
d.ignoreNextIndent = false
return
}
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
}
// unpackValue returns values inside of non-nil interfaces when possible.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface && !v.IsNil() {
v = v.Elem()
}
return v
}
// dumpPtr handles formatting of pointers by indirecting them as necessary.
func (d *dumpState) dumpPtr(v reflect.Value) {
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range d.pointers {
if depth >= d.depth {
delete(d.pointers, k)
}
}
// Keep list of all dereferenced pointers to show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by dereferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
cycleFound = true
indirects--
break
}
d.pointers[addr] = d.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type information.
d.w.Write(openParenBytes)
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
d.w.Write([]byte(ve.Type().String()))
d.w.Write(closeParenBytes)
// Display pointer information.
if len(pointerChain) > 0 {
d.w.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
d.w.Write(pointerChainBytes)
}
printHexPtr(d.w, addr)
}
d.w.Write(closeParenBytes)
}
// Display dereferenced value.
d.w.Write(openParenBytes)
switch {
case nilFound == true:
d.w.Write(nilAngleBytes)
case cycleFound == true:
d.w.Write(circularBytes)
default:
d.ignoreNextType = true
d.dump(ve)
}
d.w.Write(closeParenBytes)
}
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
// reflection) arrays and slices are dumped in hexdump -C fashion.
func (d *dumpState) dumpSlice(v reflect.Value) {
// Determine whether this type should be hex dumped or not. Also,
// for types which should be hexdumped, try to use the underlying data
// first, then fall back to trying to convert them to a uint8 slice.
var buf []uint8
doConvert := false
doHexDump := false
numEntries := v.Len()
if numEntries > 0 {
vt := v.Index(0).Type()
vts := vt.String()
switch {
// C types that need to be converted.
case cCharRE.MatchString(vts):
fallthrough
case cUnsignedCharRE.MatchString(vts):
fallthrough
case cUint8tCharRE.MatchString(vts):
doConvert = true
// Try to use existing uint8 slices and fall back to converting
// and copying if that fails.
case vt.Kind() == reflect.Uint8:
// We need an addressable interface to convert the type back
// into a byte slice. However, the reflect package won't give
// us an interface on certain things like unexported struct
// fields in order to enforce visibility rules. We use unsafe
// to bypass these restrictions since this package does not
// mutate the values.
vs := v
if !vs.CanInterface() || !vs.CanAddr() {
vs = unsafeReflectValue(vs)
}
vs = vs.Slice(0, numEntries)
// Use the existing uint8 slice if it can be type
// asserted.
iface := vs.Interface()
if slice, ok := iface.([]uint8); ok {
buf = slice
doHexDump = true
break
}
// The underlying data needs to be converted if it can't
// be type asserted to a uint8 slice.
doConvert = true
}
// Copy and convert the underlying type if needed.
if doConvert && vt.ConvertibleTo(uint8Type) {
// Convert and copy each element into a uint8 byte
// slice.
buf = make([]uint8, numEntries)
for i := 0; i < numEntries; i++ {
vv := v.Index(i)
buf[i] = uint8(vv.Convert(uint8Type).Uint())
}
doHexDump = true
}
}
// Hexdump the entire slice as needed.
if doHexDump {
indent := strings.Repeat(d.cs.Indent, d.depth)
str := indent + hex.Dump(buf)
str = strings.Replace(str, "\n", "\n"+indent, -1)
str = strings.TrimRight(str, d.cs.Indent)
d.w.Write([]byte(str))
return
}
// Recursively call dump for each item.
for i := 0; i < numEntries; i++ {
d.dump(d.unpackValue(v.Index(i)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
// dump is the main workhorse for dumping a value. It uses the passed reflect
// value to figure out what kind of object we are dealing with and formats it
// appropriately. It is a recursive function, however circular data structures
// are detected and handled properly.
func (d *dumpState) dump(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
d.w.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
d.indent()
d.dumpPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !d.ignoreNextType {
d.indent()
d.w.Write(openParenBytes)
d.w.Write([]byte(v.Type().String()))
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
d.ignoreNextType = false
// Display length and capacity if the built-in len and cap functions
// work with the value's kind and the len/cap itself is non-zero.
valueLen, valueCap := 0, 0
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Chan:
valueLen, valueCap = v.Len(), v.Cap()
case reflect.Map, reflect.String:
valueLen = v.Len()
}
if valueLen != 0 || valueCap != 0 {
d.w.Write(openParenBytes)
if valueLen != 0 {
d.w.Write(lenEqualsBytes)
printInt(d.w, int64(valueLen), 10)
}
if valueCap != 0 {
if valueLen != 0 {
d.w.Write(spaceBytes)
}
d.w.Write(capEqualsBytes)
printInt(d.w, int64(valueCap), 10)
}
d.w.Write(closeParenBytes)
d.w.Write(spaceBytes)
}
// Call Stringer/error interfaces if they exist and the handle methods flag
// is enabled
if !d.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(d.cs, d.w, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(d.w, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(d.w, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(d.w, v.Uint(), 10)
case reflect.Float32:
printFloat(d.w, v.Float(), 32)
case reflect.Float64:
printFloat(d.w, v.Float(), 64)
case reflect.Complex64:
printComplex(d.w, v.Complex(), 32)
case reflect.Complex128:
printComplex(d.w, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
d.dumpSlice(v)
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.String:
d.w.Write([]byte(strconv.Quote(v.String())))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
d.w.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
d.w.Write(nilAngleBytes)
break
}
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
numEntries := v.Len()
keys := v.MapKeys()
if d.cs.SortKeys {
sortValues(keys, d.cs)
}
for i, key := range keys {
d.dump(d.unpackValue(key))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.MapIndex(key)))
if i < (numEntries - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Struct:
d.w.Write(openBraceNewlineBytes)
d.depth++
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
d.indent()
d.w.Write(maxNewlineBytes)
} else {
vt := v.Type()
numFields := v.NumField()
for i := 0; i < numFields; i++ {
d.indent()
vtf := vt.Field(i)
d.w.Write([]byte(vtf.Name))
d.w.Write(colonSpaceBytes)
d.ignoreNextIndent = true
d.dump(d.unpackValue(v.Field(i)))
if i < (numFields - 1) {
d.w.Write(commaNewlineBytes)
} else {
d.w.Write(newlineBytes)
}
}
}
d.depth--
d.indent()
d.w.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(d.w, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(d.w, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it in case any new
// types are added.
default:
if v.CanInterface() {
fmt.Fprintf(d.w, "%v", v.Interface())
} else {
fmt.Fprintf(d.w, "%v", v.String())
}
}
}
// fdump is a helper function to consolidate the logic from the various public
// methods which take varying writers and config states.
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
for _, arg := range a {
if arg == nil {
w.Write(interfaceBytes)
w.Write(spaceBytes)
w.Write(nilAngleBytes)
w.Write(newlineBytes)
continue
}
d := dumpState{w: w, cs: cs}
d.pointers = make(map[uintptr]int)
d.dump(reflect.ValueOf(arg))
d.w.Write(newlineBytes)
}
}
// Fdump formats and displays the passed arguments to io.Writer w. It formats
// exactly the same as Dump.
func Fdump(w io.Writer, a ...interface{}) {
fdump(&Config, w, a...)
}
// Sdump returns a string with the passed arguments formatted exactly the same
// as Dump.
func Sdump(a ...interface{}) string {
var buf bytes.Buffer
fdump(&Config, &buf, a...)
return buf.String()
}
/*
Dump displays the passed parameters to standard out with newlines, customizable
indentation, and additional debug information such as complete types and all
pointer addresses used to indirect to the final value. It provides the
following features over the built-in printing facilities provided by the fmt
package:
* Pointers are dereferenced and followed
* Circular data structures are detected and handled properly
* Custom Stringer/error interfaces are optionally invoked, including
on unexported types
* Custom types which only implement the Stringer/error interfaces via
a pointer receiver are optionally invoked when passing non-pointer
variables
* Byte arrays and slices are dumped like the hexdump -C command which
includes offsets, byte values in hex, and ASCII output
The configuration options are controlled by an exported package global,
spew.Config. See ConfigState for options documentation.
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
get the formatted result as a string.
*/
func Dump(a ...interface{}) {
fdump(&Config, os.Stdout, a...)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when both cgo is supported and "-tags testcgo" is added to the go test
// command line. This means the cgo tests are only added (and hence run) when
// specifially requested. This configuration is used because spew itself
// does not require cgo to run even though it does handle certain cgo types
// specially. Rather than forcing all clients to require cgo and an external
// C compiler just to run the tests, this scheme makes them optional.
// +build cgo,testcgo
package spew_test
import (
"fmt"
"github.com/davecgh/go-spew/spew/testdata"
)
func addCgoDumpTests() {
// C char pointer.
v := testdata.GetCgoCharPointer()
nv := testdata.GetCgoNullCharPointer()
pv := &v
vcAddr := fmt.Sprintf("%p", v)
vAddr := fmt.Sprintf("%p", pv)
pvAddr := fmt.Sprintf("%p", &pv)
vt := "*testdata._Ctype_char"
vs := "116"
addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
addDumpTest(nv, "("+vt+")(<nil>)\n")
// C char array.
v2, v2l, v2c := testdata.GetCgoCharArray()
v2Len := fmt.Sprintf("%d", v2l)
v2Cap := fmt.Sprintf("%d", v2c)
v2t := "[6]testdata._Ctype_char"
v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
"{\n 00000000 74 65 73 74 32 00 " +
" |test2.|\n}"
addDumpTest(v2, "("+v2t+") "+v2s+"\n")
// C unsigned char array.
v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
v3Len := fmt.Sprintf("%d", v3l)
v3Cap := fmt.Sprintf("%d", v3c)
v3t := "[6]testdata._Ctype_unsignedchar"
v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
"{\n 00000000 74 65 73 74 33 00 " +
" |test3.|\n}"
addDumpTest(v3, "("+v3t+") "+v3s+"\n")
// C signed char array.
v4, v4l, v4c := testdata.GetCgoSignedCharArray()
v4Len := fmt.Sprintf("%d", v4l)
v4Cap := fmt.Sprintf("%d", v4c)
v4t := "[6]testdata._Ctype_schar"
v4t2 := "testdata._Ctype_schar"
v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
") 0\n}"
addDumpTest(v4, "("+v4t+") "+v4s+"\n")
// C uint8_t array.
v5, v5l, v5c := testdata.GetCgoUint8tArray()
v5Len := fmt.Sprintf("%d", v5l)
v5Cap := fmt.Sprintf("%d", v5c)
v5t := "[6]testdata._Ctype_uint8_t"
v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
"{\n 00000000 74 65 73 74 35 00 " +
" |test5.|\n}"
addDumpTest(v5, "("+v5t+") "+v5s+"\n")
// C typedefed unsigned char array.
v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
v6Len := fmt.Sprintf("%d", v6l)
v6Cap := fmt.Sprintf("%d", v6c)
v6t := "[6]testdata._Ctype_custom_uchar_t"
v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
"{\n 00000000 74 65 73 74 36 00 " +
" |test6.|\n}"
addDumpTest(v6, "("+v6t+") "+v6s+"\n")
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when either cgo is not supported or "-tags testcgo" is not added to the go
// test command line. This file intentionally does not setup any cgo tests in
// this scenario.
// +build !cgo !testcgo
package spew_test
func addCgoDumpTests() {
// Don't add any tests for cgo since this file is only compiled when
// there should not be any cgo tests.
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"fmt"
"github.com/davecgh/go-spew/spew"
)
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
flag Flag
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
// This example demonstrates how to use Dump to dump variables to stdout.
func ExampleDump() {
// The following package level declarations are assumed for this example:
/*
type Flag int
const (
flagOne Flag = iota
flagTwo
)
var flagStrings = map[Flag]string{
flagOne: "flagOne",
flagTwo: "flagTwo",
}
func (f Flag) String() string {
if s, ok := flagStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown flag (%d)", int(f))
}
type Bar struct {
flag Flag
data uintptr
}
type Foo struct {
unexportedField Bar
ExportedField map[interface{}]interface{}
}
*/
// Setup some sample data structures for the example.
bar := Bar{Flag(flagTwo), uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
f := Flag(5)
b := []byte{
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32,
}
// Dump!
spew.Dump(s1, f, b)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// flag: (spew_test.Flag) flagTwo,
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Flag) Unknown flag (5)
// ([]uint8) (len=34 cap=34) {
// 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
// 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
// 00000020 31 32 |12|
// }
//
}
// This example demonstrates how to use Printf to display a variable with a
// format string and inline formatting.
func ExamplePrintf() {
// Create a double pointer to a uint 8.
ui8 := uint8(5)
pui8 := &ui8
ppui8 := &pui8
// Create a circular data type.
type circular struct {
ui8 uint8
c *circular
}
c := circular{ui8: 1}
c.c = &c
// Print!
spew.Printf("ppui8: %v\n", ppui8)
spew.Printf("circular: %v\n", c)
// Output:
// ppui8: <**>5
// circular: {1 <*>{1 <*><shown>}}
}
// This example demonstrates how to use a ConfigState.
func ExampleConfigState() {
// Modify the indent level of the ConfigState only. The global
// configuration is not modified.
scs := spew.ConfigState{Indent: "\t"}
// Output using the ConfigState instance.
v := map[string]int{"one": 1}
scs.Printf("v: %v\n", v)
scs.Dump(v)
// Output:
// v: map[one:1]
// (map[string]int) (len=1) {
// (string) (len=3) "one": (int) 1
// }
}
// This example demonstrates how to use ConfigState.Dump to dump variables to
// stdout
func ExampleConfigState_Dump() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances with different indentation.
scs := spew.ConfigState{Indent: "\t"}
scs2 := spew.ConfigState{Indent: " "}
// Setup some sample data structures for the example.
bar := Bar{Flag(flagTwo), uintptr(0)}
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
// Dump using the ConfigState instances.
scs.Dump(s1)
scs2.Dump(s1)
// Output:
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// flag: (spew_test.Flag) flagTwo,
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
// (spew_test.Foo) {
// unexportedField: (spew_test.Bar) {
// flag: (spew_test.Flag) flagTwo,
// data: (uintptr) <nil>
// },
// ExportedField: (map[interface {}]interface {}) (len=1) {
// (string) (len=3) "one": (bool) true
// }
// }
//
}
// This example demonstrates how to use ConfigState.Printf to display a variable
// with a format string and inline formatting.
func ExampleConfigState_Printf() {
// See the top-level Dump example for details on the types used in this
// example.
// Create two ConfigState instances and modify the method handling of the
// first ConfigState only.
scs := spew.NewDefaultConfig()
scs2 := spew.NewDefaultConfig()
scs.DisableMethods = true
// Alternatively
// scs := spew.ConfigState{Indent: " ", DisableMethods: true}
// scs2 := spew.ConfigState{Indent: " "}
// This is of type Flag which implements a Stringer and has raw value 1.
f := flagTwo
// Dump using the ConfigState instances.
scs.Printf("f: %v\n", f)
scs2.Printf("f: %v\n", f)
// Output:
// f: 1
// f: flagTwo
}

View File

@@ -0,0 +1,419 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"bytes"
"fmt"
"reflect"
"strconv"
"strings"
)
// supportedFlags is a list of all the character flags supported by fmt package.
const supportedFlags = "0-+# "
// formatState implements the fmt.Formatter interface and contains information
// about the state of a formatting operation. The NewFormatter function can
// be used to get a new Formatter which can be used directly as arguments
// in standard fmt package printing calls.
type formatState struct {
value interface{}
fs fmt.State
depth int
pointers map[uintptr]int
ignoreNextType bool
cs *ConfigState
}
// buildDefaultFormat recreates the original format string without precision
// and width information to pass in to fmt.Sprintf in the case of an
// unrecognized type. Unless new types are added to the language, this
// function won't ever be called.
func (f *formatState) buildDefaultFormat() (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
buf.WriteRune('v')
format = buf.String()
return format
}
// constructOrigFormat recreates the original format string including precision
// and width information to pass along to the standard fmt package. This allows
// automatic deferral of all format strings this package doesn't support.
func (f *formatState) constructOrigFormat(verb rune) (format string) {
buf := bytes.NewBuffer(percentBytes)
for _, flag := range supportedFlags {
if f.fs.Flag(int(flag)) {
buf.WriteRune(flag)
}
}
if width, ok := f.fs.Width(); ok {
buf.WriteString(strconv.Itoa(width))
}
if precision, ok := f.fs.Precision(); ok {
buf.Write(precisionBytes)
buf.WriteString(strconv.Itoa(precision))
}
buf.WriteRune(verb)
format = buf.String()
return format
}
// unpackValue returns values inside of non-nil interfaces when possible and
// ensures that types for values which have been unpacked from an interface
// are displayed when the show types flag is also set.
// This is useful for data types like structs, arrays, slices, and maps which
// can contain varying types packed inside an interface.
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface {
f.ignoreNextType = false
if !v.IsNil() {
v = v.Elem()
}
}
return v
}
// formatPtr handles formatting of pointers by indirecting them as necessary.
func (f *formatState) formatPtr(v reflect.Value) {
// Display nil if top level pointer is nil.
showTypes := f.fs.Flag('#')
if v.IsNil() && (!showTypes || f.ignoreNextType) {
f.fs.Write(nilAngleBytes)
return
}
// Remove pointers at or below the current depth from map used to detect
// circular refs.
for k, depth := range f.pointers {
if depth >= f.depth {
delete(f.pointers, k)
}
}
// Keep list of all dereferenced pointers to possibly show later.
pointerChain := make([]uintptr, 0)
// Figure out how many levels of indirection there are by derferencing
// pointers and unpacking interfaces down the chain while detecting circular
// references.
nilFound := false
cycleFound := false
indirects := 0
ve := v
for ve.Kind() == reflect.Ptr {
if ve.IsNil() {
nilFound = true
break
}
indirects++
addr := ve.Pointer()
pointerChain = append(pointerChain, addr)
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
cycleFound = true
indirects--
break
}
f.pointers[addr] = f.depth
ve = ve.Elem()
if ve.Kind() == reflect.Interface {
if ve.IsNil() {
nilFound = true
break
}
ve = ve.Elem()
}
}
// Display type or indirection level depending on flags.
if showTypes && !f.ignoreNextType {
f.fs.Write(openParenBytes)
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
f.fs.Write([]byte(ve.Type().String()))
f.fs.Write(closeParenBytes)
} else {
if nilFound || cycleFound {
indirects += strings.Count(ve.Type().String(), "*")
}
f.fs.Write(openAngleBytes)
f.fs.Write([]byte(strings.Repeat("*", indirects)))
f.fs.Write(closeAngleBytes)
}
// Display pointer information depending on flags.
if f.fs.Flag('+') && (len(pointerChain) > 0) {
f.fs.Write(openParenBytes)
for i, addr := range pointerChain {
if i > 0 {
f.fs.Write(pointerChainBytes)
}
printHexPtr(f.fs, addr)
}
f.fs.Write(closeParenBytes)
}
// Display dereferenced value.
switch {
case nilFound == true:
f.fs.Write(nilAngleBytes)
case cycleFound == true:
f.fs.Write(circularShortBytes)
default:
f.ignoreNextType = true
f.format(ve)
}
}
// format is the main workhorse for providing the Formatter interface. It
// uses the passed reflect value to figure out what kind of object we are
// dealing with and formats it appropriately. It is a recursive function,
// however circular data structures are detected and handled properly.
func (f *formatState) format(v reflect.Value) {
// Handle invalid reflect values immediately.
kind := v.Kind()
if kind == reflect.Invalid {
f.fs.Write(invalidAngleBytes)
return
}
// Handle pointers specially.
if kind == reflect.Ptr {
f.formatPtr(v)
return
}
// Print type information unless already handled elsewhere.
if !f.ignoreNextType && f.fs.Flag('#') {
f.fs.Write(openParenBytes)
f.fs.Write([]byte(v.Type().String()))
f.fs.Write(closeParenBytes)
}
f.ignoreNextType = false
// Call Stringer/error interfaces if they exist and the handle methods
// flag is enabled.
if !f.cs.DisableMethods {
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
if handled := handleMethods(f.cs, f.fs, v); handled {
return
}
}
}
switch kind {
case reflect.Invalid:
// Do nothing. We should never get here since invalid has already
// been handled above.
case reflect.Bool:
printBool(f.fs, v.Bool())
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
printInt(f.fs, v.Int(), 10)
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
printUint(f.fs, v.Uint(), 10)
case reflect.Float32:
printFloat(f.fs, v.Float(), 32)
case reflect.Float64:
printFloat(f.fs, v.Float(), 64)
case reflect.Complex64:
printComplex(f.fs, v.Complex(), 32)
case reflect.Complex128:
printComplex(f.fs, v.Complex(), 64)
case reflect.Slice:
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
fallthrough
case reflect.Array:
f.fs.Write(openBracketBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
numEntries := v.Len()
for i := 0; i < numEntries; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(v.Index(i)))
}
}
f.depth--
f.fs.Write(closeBracketBytes)
case reflect.String:
f.fs.Write([]byte(v.String()))
case reflect.Interface:
// The only time we should get here is for nil interfaces due to
// unpackValue calls.
if v.IsNil() {
f.fs.Write(nilAngleBytes)
}
case reflect.Ptr:
// Do nothing. We should never get here since pointers have already
// been handled above.
case reflect.Map:
// nil maps should be indicated as different than empty maps
if v.IsNil() {
f.fs.Write(nilAngleBytes)
break
}
f.fs.Write(openMapBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
keys := v.MapKeys()
if f.cs.SortKeys {
sortValues(keys, f.cs)
}
for i, key := range keys {
if i > 0 {
f.fs.Write(spaceBytes)
}
f.ignoreNextType = true
f.format(f.unpackValue(key))
f.fs.Write(colonBytes)
f.ignoreNextType = true
f.format(f.unpackValue(v.MapIndex(key)))
}
}
f.depth--
f.fs.Write(closeMapBytes)
case reflect.Struct:
numFields := v.NumField()
f.fs.Write(openBraceBytes)
f.depth++
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
f.fs.Write(maxShortBytes)
} else {
vt := v.Type()
for i := 0; i < numFields; i++ {
if i > 0 {
f.fs.Write(spaceBytes)
}
vtf := vt.Field(i)
if f.fs.Flag('+') || f.fs.Flag('#') {
f.fs.Write([]byte(vtf.Name))
f.fs.Write(colonBytes)
}
f.format(f.unpackValue(v.Field(i)))
}
}
f.depth--
f.fs.Write(closeBraceBytes)
case reflect.Uintptr:
printHexPtr(f.fs, uintptr(v.Uint()))
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
printHexPtr(f.fs, v.Pointer())
// There were not any other types at the time this code was written, but
// fall back to letting the default fmt package handle it if any get added.
default:
format := f.buildDefaultFormat()
if v.CanInterface() {
fmt.Fprintf(f.fs, format, v.Interface())
} else {
fmt.Fprintf(f.fs, format, v.String())
}
}
}
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
// details.
func (f *formatState) Format(fs fmt.State, verb rune) {
f.fs = fs
// Use standard formatting for verbs that are not v.
if verb != 'v' {
format := f.constructOrigFormat(verb)
fmt.Fprintf(fs, format, f.value)
return
}
if f.value == nil {
if fs.Flag('#') {
fs.Write(interfaceBytes)
}
fs.Write(nilAngleBytes)
return
}
f.format(reflect.ValueOf(f.value))
}
// newFormatter is a helper function to consolidate the logic from the various
// public methods which take varying config states.
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
fs := &formatState{value: v, cs: cs}
fs.pointers = make(map[uintptr]int)
return fs
}
/*
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
interface. As a result, it integrates cleanly with standard fmt package
printing functions. The formatter is useful for inline printing of smaller data
types similar to the standard %v format specifier.
The custom formatter only responds to the %v (most compact), %+v (adds pointer
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
combinations. Any other verbs such as %x and %q will be sent to the the
standard fmt package for formatting. In addition, the custom formatter ignores
the width and precision arguments (however they will still work on the format
specifiers not handled by the custom formatter).
Typically this function shouldn't be called directly. It is much easier to make
use of the custom formatter by calling one of the convenience functions such as
Printf, Println, or Fprintf.
*/
func NewFormatter(v interface{}) fmt.Formatter {
return newFormatter(&Config, v)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
This test file is part of the spew package rather than than the spew_test
package because it needs access to internals to properly test certain cases
which are not possible via the public interface since they should never happen.
*/
package spew
import (
"bytes"
"reflect"
"testing"
"unsafe"
)
// dummyFmtState implements a fake fmt.State to use for testing invalid
// reflect.Value handling. This is necessary because the fmt package catches
// invalid values before invoking the formatter on them.
type dummyFmtState struct {
bytes.Buffer
}
func (dfs *dummyFmtState) Flag(f int) bool {
if f == int('+') {
return true
}
return false
}
func (dfs *dummyFmtState) Precision() (int, bool) {
return 0, false
}
func (dfs *dummyFmtState) Width() (int, bool) {
return 0, false
}
// TestInvalidReflectValue ensures the dump and formatter code handles an
// invalid reflect value properly. This needs access to internal state since it
// should never happen in real code and therefore can't be tested via the public
// API.
func TestInvalidReflectValue(t *testing.T) {
i := 1
// Dump invalid reflect value.
v := new(reflect.Value)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(*v)
s := buf.String()
want := "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter invalid reflect value.
buf2 := new(dummyFmtState)
f := formatState{value: *v, cs: &Config, fs: buf2}
f.format(*v)
s = buf2.String()
want = "<invalid>"
if s != want {
t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
}
}
// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
// the maximum kind value which does not exist. This is needed to test the
// fallback code which punts to the standard fmt library for new types that
// might get added to the language.
func changeKind(v *reflect.Value, readOnly bool) {
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
if readOnly {
*rvf |= flagRO
} else {
*rvf &= ^uintptr(flagRO)
}
}
// TestAddedReflectValue tests functionaly of the dump and formatter code which
// falls back to the standard fmt library for new types that might get added to
// the language.
func TestAddedReflectValue(t *testing.T) {
i := 1
// Dump using a reflect.Value that is exported.
v := reflect.ValueOf(int8(5))
changeKind(&v, false)
buf := new(bytes.Buffer)
d := dumpState{w: buf, cs: &Config}
d.dump(v)
s := buf.String()
want := "(int8) 5"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Dump using a reflect.Value that is not exported.
changeKind(&v, true)
buf.Reset()
d.dump(v)
s = buf.String()
want = "(int8) <int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is exported.
changeKind(&v, false)
buf2 := new(dummyFmtState)
f := formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "5"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
i++
// Formatter using a reflect.Value that is not exported.
changeKind(&v, true)
buf2.Reset()
f = formatState{value: v, cs: &Config, fs: buf2}
f.format(v)
s = buf2.String()
want = "<int8 Value>"
if s != want {
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
}
}
// SortValues makes the internal sortValues function available to the test
// package.
func SortValues(values []reflect.Value, cs *ConfigState) {
sortValues(values, cs)
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew
import (
"fmt"
"io"
)
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the formatted string as a value that satisfies error. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Errorf(format string, a ...interface{}) (err error) {
return fmt.Errorf(format, convertArgs(a)...)
}
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprint(w, convertArgs(a)...)
}
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(w, format, convertArgs(a)...)
}
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
// passed with a default Formatter interface returned by NewFormatter. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
return fmt.Fprintln(w, convertArgs(a)...)
}
// Print is a wrapper for fmt.Print that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
func Print(a ...interface{}) (n int, err error) {
return fmt.Print(convertArgs(a)...)
}
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Printf(format, convertArgs(a)...)
}
// Println is a wrapper for fmt.Println that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the number of bytes written and any write error encountered. See
// NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
func Println(a ...interface{}) (n int, err error) {
return fmt.Println(convertArgs(a)...)
}
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprint(a ...interface{}) string {
return fmt.Sprint(convertArgs(a)...)
}
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
// passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintf(format string, a ...interface{}) string {
return fmt.Sprintf(format, convertArgs(a)...)
}
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
// were passed with a default Formatter interface returned by NewFormatter. It
// returns the resulting string. See NewFormatter for formatting details.
//
// This function is shorthand for the following syntax:
//
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
func Sprintln(a ...interface{}) string {
return fmt.Sprintln(convertArgs(a)...)
}
// convertArgs accepts a slice of arguments and returns a slice of the same
// length with each argument converted to a default spew Formatter interface.
func convertArgs(args []interface{}) (formatters []interface{}) {
formatters = make([]interface{}, len(args))
for index, arg := range args {
formatters[index] = NewFormatter(arg)
}
return formatters
}

View File

@@ -0,0 +1,308 @@
/*
* Copyright (c) 2013 Dave Collins <dave@davec.name>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package spew_test
import (
"bytes"
"fmt"
"github.com/davecgh/go-spew/spew"
"io/ioutil"
"os"
"testing"
)
// spewFunc is used to identify which public function of the spew package or
// ConfigState a test applies to.
type spewFunc int
const (
fCSFdump spewFunc = iota
fCSFprint
fCSFprintf
fCSFprintln
fCSPrint
fCSPrintln
fCSSdump
fCSSprint
fCSSprintf
fCSSprintln
fCSErrorf
fCSNewFormatter
fErrorf
fFprint
fFprintln
fPrint
fPrintln
fSdump
fSprint
fSprintf
fSprintln
)
// Map of spewFunc values to names for pretty printing.
var spewFuncStrings = map[spewFunc]string{
fCSFdump: "ConfigState.Fdump",
fCSFprint: "ConfigState.Fprint",
fCSFprintf: "ConfigState.Fprintf",
fCSFprintln: "ConfigState.Fprintln",
fCSSdump: "ConfigState.Sdump",
fCSPrint: "ConfigState.Print",
fCSPrintln: "ConfigState.Println",
fCSSprint: "ConfigState.Sprint",
fCSSprintf: "ConfigState.Sprintf",
fCSSprintln: "ConfigState.Sprintln",
fCSErrorf: "ConfigState.Errorf",
fCSNewFormatter: "ConfigState.NewFormatter",
fErrorf: "spew.Errorf",
fFprint: "spew.Fprint",
fFprintln: "spew.Fprintln",
fPrint: "spew.Print",
fPrintln: "spew.Println",
fSdump: "spew.Sdump",
fSprint: "spew.Sprint",
fSprintf: "spew.Sprintf",
fSprintln: "spew.Sprintln",
}
func (f spewFunc) String() string {
if s, ok := spewFuncStrings[f]; ok {
return s
}
return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
}
// spewTest is used to describe a test to be performed against the public
// functions of the spew package or ConfigState.
type spewTest struct {
cs *spew.ConfigState
f spewFunc
format string
in interface{}
want string
}
// spewTests houses the tests to be performed against the public functions of
// the spew package and ConfigState.
//
// These tests are only intended to ensure the public functions are exercised
// and are intentionally not exhaustive of types. The exhaustive type
// tests are handled in the dump and format tests.
var spewTests []spewTest
// redirStdout is a helper function to return the standard output from f as a
// byte slice.
func redirStdout(f func()) ([]byte, error) {
tempFile, err := ioutil.TempFile("", "ss-test")
if err != nil {
return nil, err
}
fileName := tempFile.Name()
defer os.Remove(fileName) // Ignore error
origStdout := os.Stdout
os.Stdout = tempFile
f()
os.Stdout = origStdout
tempFile.Close()
return ioutil.ReadFile(fileName)
}
func initSpewTests() {
// Config states with various settings.
scsDefault := spew.NewDefaultConfig()
scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
// Variables for tests on types which implement Stringer interface with and
// without a pointer receiver.
ts := stringer("test")
tps := pstringer("test")
// depthTester is used to test max depth handling for structs, array, slices
// and maps.
type depthTester struct {
ic indirCir1
arr [1]string
slice []string
m map[string]int
}
dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
map[string]int{"one": 1}}
// Variable for tests on types which implement error interface.
te := customError(10)
spewTests = []spewTest{
{scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
{scsDefault, fCSFprint, "", int16(32767), "32767"},
{scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
{scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
{scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
{scsDefault, fCSPrintln, "", uint8(255), "255\n"},
{scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
{scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
{scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
{scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
{scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
{scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
{scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
{scsDefault, fFprint, "", float32(3.14), "3.14"},
{scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
{scsDefault, fPrint, "", true, "true"},
{scsDefault, fPrintln, "", false, "false\n"},
{scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
{scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
{scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
{scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
{scsNoMethods, fCSFprint, "", ts, "test"},
{scsNoMethods, fCSFprint, "", &ts, "<*>test"},
{scsNoMethods, fCSFprint, "", tps, "test"},
{scsNoMethods, fCSFprint, "", &tps, "<*>test"},
{scsNoPmethods, fCSFprint, "", ts, "stringer test"},
{scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
{scsNoPmethods, fCSFprint, "", tps, "test"},
{scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
" m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
"(len=4) (stringer test) \"test\"\n"},
{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
"(error: 10) 10\n"},
}
}
// TestSpew executes all of the tests described by spewTests.
func TestSpew(t *testing.T) {
initSpewTests()
t.Logf("Running %d tests", len(spewTests))
for i, test := range spewTests {
buf := new(bytes.Buffer)
switch test.f {
case fCSFdump:
test.cs.Fdump(buf, test.in)
case fCSFprint:
test.cs.Fprint(buf, test.in)
case fCSFprintf:
test.cs.Fprintf(buf, test.format, test.in)
case fCSFprintln:
test.cs.Fprintln(buf, test.in)
case fCSPrint:
b, err := redirStdout(func() { test.cs.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSPrintln:
b, err := redirStdout(func() { test.cs.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fCSSdump:
str := test.cs.Sdump(test.in)
buf.WriteString(str)
case fCSSprint:
str := test.cs.Sprint(test.in)
buf.WriteString(str)
case fCSSprintf:
str := test.cs.Sprintf(test.format, test.in)
buf.WriteString(str)
case fCSSprintln:
str := test.cs.Sprintln(test.in)
buf.WriteString(str)
case fCSErrorf:
err := test.cs.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fCSNewFormatter:
fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
case fErrorf:
err := spew.Errorf(test.format, test.in)
buf.WriteString(err.Error())
case fFprint:
spew.Fprint(buf, test.in)
case fFprintln:
spew.Fprintln(buf, test.in)
case fPrint:
b, err := redirStdout(func() { spew.Print(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fPrintln:
b, err := redirStdout(func() { spew.Println(test.in) })
if err != nil {
t.Errorf("%v #%d %v", test.f, i, err)
continue
}
buf.Write(b)
case fSdump:
str := spew.Sdump(test.in)
buf.WriteString(str)
case fSprint:
str := spew.Sprint(test.in)
buf.WriteString(str)
case fSprintf:
str := spew.Sprintf(test.format, test.in)
buf.WriteString(str)
case fSprintln:
str := spew.Sprintln(test.in)
buf.WriteString(str)
default:
t.Errorf("%v #%d unrecognized function", test.f, i)
continue
}
s := buf.String()
if test.want != s {
t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
continue
}
}
}

View File

@@ -0,0 +1,82 @@
// Copyright (c) 2013 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when both cgo is supported and "-tags testcgo" is added to the go test
// command line. This code should really only be in the dumpcgo_test.go file,
// but unfortunately Go will not allow cgo in test files, so this is a
// workaround to allow cgo types to be tested. This configuration is used
// because spew itself does not require cgo to run even though it does handle
// certain cgo types specially. Rather than forcing all clients to require cgo
// and an external C compiler just to run the tests, this scheme makes them
// optional.
// +build cgo,testcgo
package testdata
/*
#include <stdint.h>
typedef unsigned char custom_uchar_t;
char *ncp = 0;
char *cp = "test";
char ca[6] = {'t', 'e', 's', 't', '2', '\0'};
unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'};
signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'};
uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
*/
import "C"
// GetCgoNullCharPointer returns a null char pointer via cgo. This is only
// used for tests.
func GetCgoNullCharPointer() interface{} {
return C.ncp
}
// GetCgoCharPointer returns a char pointer via cgo. This is only used for
// tests.
func GetCgoCharPointer() interface{} {
return C.cp
}
// GetCgoCharArray returns a char array via cgo and the array's len and cap.
// This is only used for tests.
func GetCgoCharArray() (interface{}, int, int) {
return C.ca, len(C.ca), cap(C.ca)
}
// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
// array's len and cap. This is only used for tests.
func GetCgoUnsignedCharArray() (interface{}, int, int) {
return C.uca, len(C.uca), cap(C.uca)
}
// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
// and cap. This is only used for tests.
func GetCgoSignedCharArray() (interface{}, int, int) {
return C.sca, len(C.sca), cap(C.sca)
}
// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
// cap. This is only used for tests.
func GetCgoUint8tArray() (interface{}, int, int) {
return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
}
// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
// cgo and the array's len and cap. This is only used for tests.
func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
return C.tuca, len(C.tuca), cap(C.tuca)
}

View File

@@ -9,13 +9,6 @@ if (WIN32 AND WANT_CRYPTOPP)
endif()
add_subdirectory(src/libethash)
# bin2h.cmake doesn't work
if (NOT OpenCL_FOUND)
find_package(OpenCL)
endif()
if (OpenCL_FOUND)
add_subdirectory(src/libethash-cl)
endif()
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
add_subdirectory(test/c)

View File

@@ -119,6 +119,12 @@ func (l *Light) Verify(block pow.Block) bool {
if !ret.success {
return false
}
// avoid mixdigest malleability as it's not included in a block's "hashNononce"
if block.MixDigest() != h256ToHash(ret.mix_hash) {
return false
}
// Make sure cache is live until after the C call.
// This is important because a GC might happen and execute
// the finalizer before the call completes.

View File

@@ -39,6 +39,7 @@ var validBlocks = []*testBlock{
hashNoNonce: common.HexToHash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"),
difficulty: big.NewInt(132416),
nonce: 0x495732e0ed7a801c,
mixDigest: common.HexToHash("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5"),
},
// from proof of concept nine testnet, epoch 1
{
@@ -46,6 +47,7 @@ var validBlocks = []*testBlock{
hashNoNonce: common.HexToHash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"),
difficulty: big.NewInt(1532671),
nonce: 0x318df1c8adef7e5e,
mixDigest: common.HexToHash("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84"),
},
// from proof of concept nine testnet, epoch 2
{
@@ -53,6 +55,7 @@ var validBlocks = []*testBlock{
hashNoNonce: common.HexToHash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"),
difficulty: big.NewInt(2467358),
nonce: 0x50377003e5d830ca,
mixDigest: common.HexToHash("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063"),
},
}
@@ -73,8 +76,9 @@ func TestEthashConcurrentVerify(t *testing.T) {
defer os.RemoveAll(eth.Full.Dir)
block := &testBlock{difficulty: big.NewInt(10)}
nonce, _ := eth.Search(block, nil)
nonce, md := eth.Search(block, nil)
block.nonce = nonce
block.mixDigest = common.BytesToHash(md)
// Verify the block concurrently to check for data races.
var wg sync.WaitGroup
@@ -98,21 +102,26 @@ func TestEthashConcurrentSearch(t *testing.T) {
eth.Turbo(true)
defer os.RemoveAll(eth.Full.Dir)
// launch n searches concurrently.
type searchRes struct {
n uint64
md []byte
}
var (
block = &testBlock{difficulty: big.NewInt(35000)}
nsearch = 10
wg = new(sync.WaitGroup)
found = make(chan uint64)
found = make(chan searchRes)
stop = make(chan struct{})
)
rand.Read(block.hashNoNonce[:])
wg.Add(nsearch)
// launch n searches concurrently.
for i := 0; i < nsearch; i++ {
go func() {
nonce, _ := eth.Search(block, stop)
nonce, md := eth.Search(block, stop)
select {
case found <- nonce:
case found <- searchRes{n: nonce, md: md}:
case <-stop:
}
wg.Done()
@@ -120,12 +129,14 @@ func TestEthashConcurrentSearch(t *testing.T) {
}
// wait for one of them to find the nonce
nonce := <-found
res := <-found
// stop the others
close(stop)
wg.Wait()
if block.nonce = nonce; !eth.Verify(block) {
block.nonce = res.n
block.mixDigest = common.BytesToHash(res.md)
if !eth.Verify(block) {
t.Error("Block could not be verified")
}
}
@@ -140,8 +151,9 @@ func TestEthashSearchAcrossEpoch(t *testing.T) {
for i := epochLength - 40; i < epochLength+40; i++ {
block := &testBlock{number: i, difficulty: big.NewInt(90)}
rand.Read(block.hashNoNonce[:])
nonce, _ := eth.Search(block, nil)
nonce, md := eth.Search(block, nil)
block.nonce = nonce
block.mixDigest = common.BytesToHash(md)
if !eth.Verify(block) {
t.Fatalf("Block could not be verified")
}

View File

@@ -1,47 +0,0 @@
cmake_minimum_required(VERSION 2.8)
set(LIBRARY ethash-cl)
set(CMAKE_BUILD_TYPE Release)
include(bin2h.cmake)
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl
VARIABLE_NAME ethash_cl_miner_kernel
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
if (NOT MSVC)
# Initialize CXXFLAGS for c++11
set(CMAKE_CXX_FLAGS "-Wall -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
# Compiler-specific C++11 activation.
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
endif ()
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else ()
message(FATAL_ERROR "Your C++ compiler does not support C++11.")
endif ()
endif()
set(OpenCL_FOUND TRUE)
set(OpenCL_INCLUDE_DIRS /usr/include/CL)
set(OpenCL_LIBRARIES -lOpenCL)
if (NOT OpenCL_FOUND)
find_package(OpenCL)
endif()
if (OpenCL_FOUND)
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -Werror -pedantic -fPIC ${CMAKE_CXX_FLAGS}")
include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
include_directories(..)
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp)
TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash)
endif()

View File

@@ -1,86 +0,0 @@
# https://gist.github.com/sivachandran/3a0de157dccef822a230
include(CMakeParseArguments)
# Function to wrap a given string into multiple lines at the given column position.
# Parameters:
# VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING)
set(oneValueArgs VARIABLE AT_COLUMN)
cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
math(EXPR offset "0")
while(stringLength GREATER 0)
if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
math(EXPR length "${WRAP_STRING_AT_COLUMN}")
else()
math(EXPR length "${stringLength}")
endif()
string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
set(lines "${lines}\n${line}")
math(EXPR stringLength "${stringLength} - ${length}")
math(EXPR offset "${offset} + ${length}")
endwhile()
set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction()
# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
# will contain a byte array and integer variable holding the size of the array.
# Parameters
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append
# to this name and will be used a variable name for size variable.
# HEADER_FILE - The path of header file.
# APPEND - If specified appends to the header file instead of overwriting it
# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be
# useful if the source file is a text file and we want to use the file contents
# as string. But the size variable holds size of the byte array without this
# null byte.
# Usage:
# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
function(BIN2H)
set(options APPEND NULL_TERMINATE)
set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
# reads source file contents as hex string
file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
string(LENGTH ${hexString} hexStringLength)
# appends null byte if asked
if(BIN2H_NULL_TERMINATE)
set(hexString "${hexString}00")
endif()
# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
wrap_string(VARIABLE hexString AT_COLUMN 32)
math(EXPR arraySize "${hexStringLength} / 2")
# adds '0x' prefix and comma suffix before and after every byte respectively
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
# removes trailing comma
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier
IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
# declares byte array and the length variables
set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
if(BIN2H_APPEND)
file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
else()
file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
endif()
endfunction()

File diff suppressed because it is too large Load Diff

View File

@@ -1,384 +0,0 @@
/*
This file is part of c-ethash.
c-ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
c-ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethash_cl_miner.cpp
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <assert.h>
#include <queue>
#include <vector>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h"
#define ETHASH_BYTES 32
// workaround lame platforms
#if !CL_VERSION_1_2
#define CL_MAP_WRITE_INVALIDATE_REGION CL_MAP_WRITE
#define CL_MEM_HOST_READ_ONLY 0
#endif
#undef min
#undef max
using namespace std;
static void add_definition(std::string& source, char const* id, unsigned value)
{
char buf[256];
sprintf(buf, "#define %s %uu\n", id, value);
source.insert(source.begin(), buf, buf + strlen(buf));
}
ethash_cl_miner::search_hook::~search_hook() {}
ethash_cl_miner::ethash_cl_miner()
: m_opencl_1_1()
{
}
std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId)
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
cout << "No OpenCL platforms found." << endl;
return std::string();
}
// get GPU device of the selected platform
std::vector<cl::Device> devices;
unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
cout << "No OpenCL devices found." << endl;
return std::string();
}
// use selected default device
unsigned device_num = std::min<unsigned>(_deviceId, devices.size() - 1);
cl::Device& device = devices[device_num];
std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
return "{ \"platform\": \"" + platforms[platform_num].getInfo<CL_PLATFORM_NAME>() + "\", \"device\": \"" + device.getInfo<CL_DEVICE_NAME>() + "\", \"version\": \"" + device_version + "\" }";
}
unsigned ethash_cl_miner::get_num_devices(unsigned _platformId)
{
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
cout << "No OpenCL platforms found." << endl;
return 0;
}
std::vector<cl::Device> devices;
unsigned platform_num = std::min<unsigned>(_platformId, platforms.size() - 1);
platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
cout << "No OpenCL devices found." << endl;
return 0;
}
return devices.size();
}
void ethash_cl_miner::finish()
{
if (m_queue())
m_queue.finish();
}
bool ethash_cl_miner::init(uint64_t block_number, std::function<void(void*)> _fillDAG, unsigned workgroup_size, unsigned _platformId, unsigned _deviceId)
{
// store params
m_fullSize = ethash_get_datasize(block_number);
// get all platforms
std::vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
if (platforms.empty())
{
cout << "No OpenCL platforms found." << endl;
return false;
}
// use selected platform
_platformId = std::min<unsigned>(_platformId, platforms.size() - 1);
cout << "Using platform: " << platforms[_platformId].getInfo<CL_PLATFORM_NAME>().c_str() << endl;
// get GPU device of the default platform
std::vector<cl::Device> devices;
platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices);
if (devices.empty())
{
cout << "No OpenCL devices found." << endl;
return false;
}
// use selected device
cl::Device& device = devices[std::min<unsigned>(_deviceId, devices.size() - 1)];
std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
cout << "Using device: " << device.getInfo<CL_DEVICE_NAME>().c_str() << "(" << device_version.c_str() << ")" << endl;
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{
cout << "OpenCL 1.0 is not supported." << endl;
return false;
}
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
m_opencl_1_1 = true;
// create context
m_context = cl::Context(std::vector<cl::Device>(&device, &device + 1));
m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8
m_workgroup_size = ((workgroup_size + 7) / 8) * 8;
// patch source code
std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE);
add_definition(code, "GROUP_SIZE", m_workgroup_size);
add_definition(code, "DAG_SIZE", (unsigned)(m_fullSize / ETHASH_MIX_BYTES));
add_definition(code, "ACCESSES", ETHASH_ACCESSES);
add_definition(code, "MAX_OUTPUTS", c_max_search_results);
//debugf("%s", code.c_str());
// create miner OpenCL program
cl::Program::Sources sources;
sources.push_back({code.c_str(), code.size()});
cl::Program program(m_context, sources);
try
{
program.build({device});
}
catch (cl::Error err)
{
cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device).c_str();
return false;
}
m_hash_kernel = cl::Kernel(program, "ethash_hash");
m_search_kernel = cl::Kernel(program, "ethash_search");
// create buffer for dag
m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, m_fullSize);
// create buffer for header
m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32);
// compute dag on CPU
{
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, m_fullSize);
// memcpying 1GB: horrible... really. horrible. but necessary since we can't mmap *and* gpumap.
_fillDAG(dag_ptr);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
}
// create mining buffers
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size);
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t));
}
return true;
}
void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count)
{
struct pending_batch
{
unsigned base;
unsigned count;
unsigned buf;
};
std::queue<pending_batch> pending;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header);
/*
__kernel void ethash_combined_hash(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
*/
m_hash_kernel.setArg(1, m_header);
m_hash_kernel.setArg(2, m_dag);
m_hash_kernel.setArg(3, nonce);
m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop
unsigned buf = 0;
for (unsigned i = 0; i < count || !pending.empty(); )
{
// how many this batch
if (i < count)
{
unsigned const this_count = std::min<unsigned>(count - i, c_hash_batch_size);
unsigned const batch_count = std::max<unsigned>(this_count, m_workgroup_size);
// supply output hash buffer to kernel
m_hash_kernel.setArg(0, m_hash_buf[buf]);
// execute it!
m_queue.enqueueNDRangeKernel(
m_hash_kernel,
cl::NullRange,
cl::NDRange(batch_count),
cl::NDRange(m_workgroup_size)
);
m_queue.flush();
pending.push({i, this_count, buf});
i += this_count;
buf = (buf + 1) % c_num_buffers;
}
// read results
if (i == count || pending.size() == c_num_buffers)
{
pending_batch const& batch = pending.front();
// could use pinned host pointer instead, but this path isn't that important.
uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES);
memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES);
m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes);
pending.pop();
}
}
}
void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook)
{
struct pending_batch
{
uint64_t start_nonce;
unsigned buf;
};
std::queue<pending_batch> pending;
static uint32_t const c_zero = 0;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
#if CL_VERSION_1_2 && 0
cl::Event pre_return_event;
if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else
#endif
{
m_queue.finish();
}
/*
__kernel void ethash_combined_search(
__global hash32_t* g_hashes, // 0
__constant hash32_t const* g_header, // 1
__global hash128_t const* g_dag, // 2
ulong start_nonce, // 3
ulong target, // 4
uint isolate // 5
)
*/
m_search_kernel.setArg(1, m_header);
m_search_kernel.setArg(2, m_dag);
// pass these to stop the compiler unrolling the loops
m_search_kernel.setArg(4, target);
m_search_kernel.setArg(5, ~0u);
unsigned buf = 0;
for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size)
{
// supply output buffer to kernel
m_search_kernel.setArg(0, m_search_buf[buf]);
m_search_kernel.setArg(3, start_nonce);
// execute it!
m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size);
pending.push({start_nonce, buf});
buf = (buf + 1) % c_num_buffers;
// read results
if (pending.size() == c_num_buffers)
{
pending_batch const& batch = pending.front();
// could use pinned host pointer instead
uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t));
unsigned num_found = std::min<unsigned>(results[0], c_max_search_results);
uint64_t nonces[c_max_search_results];
for (unsigned i = 0; i != num_found; ++i)
{
nonces[i] = batch.start_nonce + results[i+1];
}
m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results);
bool exit = num_found && hook.found(nonces, num_found);
exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit
if (exit)
break;
// reset search buffer if we're still going
if (num_found)
m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero);
pending.pop();
}
}
// not safe to return until this is ready
#if CL_VERSION_1_2 && 0
if (!m_opencl_1_1)
{
pre_return_event.wait();
}
#endif
}

View File

@@ -1,57 +0,0 @@
#pragma once
#define __CL_ENABLE_EXCEPTIONS
#define CL_USE_DEPRECATED_OPENCL_2_0_APIS
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include "cl.hpp"
#pragma clang diagnostic pop
#else
#include "cl.hpp"
#endif
#include <time.h>
#include <functional>
#include <libethash/ethash.h>
class ethash_cl_miner
{
public:
struct search_hook
{
virtual ~search_hook(); // always a virtual destructor for a class with virtuals.
// reports progress, return true to abort
virtual bool found(uint64_t const* nonces, uint32_t count) = 0;
virtual bool searched(uint64_t start_nonce, uint32_t count) = 0;
};
public:
ethash_cl_miner();
bool init(uint64_t block_number, std::function<void(void*)> _fillDAG, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0);
static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0);
static unsigned get_num_devices(unsigned _platformId = 0);
void finish();
void hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count);
void search(uint8_t const* header, uint64_t target, search_hook& hook);
private:
enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 };
uint64_t m_fullSize;
cl::Context m_context;
cl::CommandQueue m_queue;
cl::Kernel m_hash_kernel;
cl::Kernel m_search_kernel;
cl::Buffer m_dag;
cl::Buffer m_header;
cl::Buffer m_hash_buf[c_num_buffers];
cl::Buffer m_search_buf[c_num_buffers];
unsigned m_workgroup_size;
bool m_opencl_1_1;
};

View File

@@ -1,460 +0,0 @@
// author Tim Hughes <tim@twistedfury.com>
// Tested on Radeon HD 7850
// Hashrate: 15940347 hashes/s
// Bandwidth: 124533 MB/s
// search kernel should fit in <= 84 VGPRS (3 wavefronts)
#define THREADS_PER_HASH (128 / 16)
#define HASHES_PER_LOOP (GROUP_SIZE / THREADS_PER_HASH)
#define FNV_PRIME 0x01000193
__constant uint2 const Keccak_f1600_RC[24] = {
(uint2)(0x00000001, 0x00000000),
(uint2)(0x00008082, 0x00000000),
(uint2)(0x0000808a, 0x80000000),
(uint2)(0x80008000, 0x80000000),
(uint2)(0x0000808b, 0x00000000),
(uint2)(0x80000001, 0x00000000),
(uint2)(0x80008081, 0x80000000),
(uint2)(0x00008009, 0x80000000),
(uint2)(0x0000008a, 0x00000000),
(uint2)(0x00000088, 0x00000000),
(uint2)(0x80008009, 0x00000000),
(uint2)(0x8000000a, 0x00000000),
(uint2)(0x8000808b, 0x00000000),
(uint2)(0x0000008b, 0x80000000),
(uint2)(0x00008089, 0x80000000),
(uint2)(0x00008003, 0x80000000),
(uint2)(0x00008002, 0x80000000),
(uint2)(0x00000080, 0x80000000),
(uint2)(0x0000800a, 0x00000000),
(uint2)(0x8000000a, 0x80000000),
(uint2)(0x80008081, 0x80000000),
(uint2)(0x00008080, 0x80000000),
(uint2)(0x80000001, 0x00000000),
(uint2)(0x80008008, 0x80000000),
};
void keccak_f1600_round(uint2* a, uint r, uint out_size)
{
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
a[i] = a[i].yx;
#endif
uint2 b[25];
uint2 t;
// Theta
b[0] = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20];
b[1] = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21];
b[2] = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22];
b[3] = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23];
b[4] = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24];
t = b[4] ^ (uint2)(b[1].x << 1 | b[1].y >> 31, b[1].y << 1 | b[1].x >> 31);
a[0] ^= t;
a[5] ^= t;
a[10] ^= t;
a[15] ^= t;
a[20] ^= t;
t = b[0] ^ (uint2)(b[2].x << 1 | b[2].y >> 31, b[2].y << 1 | b[2].x >> 31);
a[1] ^= t;
a[6] ^= t;
a[11] ^= t;
a[16] ^= t;
a[21] ^= t;
t = b[1] ^ (uint2)(b[3].x << 1 | b[3].y >> 31, b[3].y << 1 | b[3].x >> 31);
a[2] ^= t;
a[7] ^= t;
a[12] ^= t;
a[17] ^= t;
a[22] ^= t;
t = b[2] ^ (uint2)(b[4].x << 1 | b[4].y >> 31, b[4].y << 1 | b[4].x >> 31);
a[3] ^= t;
a[8] ^= t;
a[13] ^= t;
a[18] ^= t;
a[23] ^= t;
t = b[3] ^ (uint2)(b[0].x << 1 | b[0].y >> 31, b[0].y << 1 | b[0].x >> 31);
a[4] ^= t;
a[9] ^= t;
a[14] ^= t;
a[19] ^= t;
a[24] ^= t;
// Rho Pi
b[0] = a[0];
b[10] = (uint2)(a[1].x << 1 | a[1].y >> 31, a[1].y << 1 | a[1].x >> 31);
b[7] = (uint2)(a[10].x << 3 | a[10].y >> 29, a[10].y << 3 | a[10].x >> 29);
b[11] = (uint2)(a[7].x << 6 | a[7].y >> 26, a[7].y << 6 | a[7].x >> 26);
b[17] = (uint2)(a[11].x << 10 | a[11].y >> 22, a[11].y << 10 | a[11].x >> 22);
b[18] = (uint2)(a[17].x << 15 | a[17].y >> 17, a[17].y << 15 | a[17].x >> 17);
b[3] = (uint2)(a[18].x << 21 | a[18].y >> 11, a[18].y << 21 | a[18].x >> 11);
b[5] = (uint2)(a[3].x << 28 | a[3].y >> 4, a[3].y << 28 | a[3].x >> 4);
b[16] = (uint2)(a[5].y << 4 | a[5].x >> 28, a[5].x << 4 | a[5].y >> 28);
b[8] = (uint2)(a[16].y << 13 | a[16].x >> 19, a[16].x << 13 | a[16].y >> 19);
b[21] = (uint2)(a[8].y << 23 | a[8].x >> 9, a[8].x << 23 | a[8].y >> 9);
b[24] = (uint2)(a[21].x << 2 | a[21].y >> 30, a[21].y << 2 | a[21].x >> 30);
b[4] = (uint2)(a[24].x << 14 | a[24].y >> 18, a[24].y << 14 | a[24].x >> 18);
b[15] = (uint2)(a[4].x << 27 | a[4].y >> 5, a[4].y << 27 | a[4].x >> 5);
b[23] = (uint2)(a[15].y << 9 | a[15].x >> 23, a[15].x << 9 | a[15].y >> 23);
b[19] = (uint2)(a[23].y << 24 | a[23].x >> 8, a[23].x << 24 | a[23].y >> 8);
b[13] = (uint2)(a[19].x << 8 | a[19].y >> 24, a[19].y << 8 | a[19].x >> 24);
b[12] = (uint2)(a[13].x << 25 | a[13].y >> 7, a[13].y << 25 | a[13].x >> 7);
b[2] = (uint2)(a[12].y << 11 | a[12].x >> 21, a[12].x << 11 | a[12].y >> 21);
b[20] = (uint2)(a[2].y << 30 | a[2].x >> 2, a[2].x << 30 | a[2].y >> 2);
b[14] = (uint2)(a[20].x << 18 | a[20].y >> 14, a[20].y << 18 | a[20].x >> 14);
b[22] = (uint2)(a[14].y << 7 | a[14].x >> 25, a[14].x << 7 | a[14].y >> 25);
b[9] = (uint2)(a[22].y << 29 | a[22].x >> 3, a[22].x << 29 | a[22].y >> 3);
b[6] = (uint2)(a[9].x << 20 | a[9].y >> 12, a[9].y << 20 | a[9].x >> 12);
b[1] = (uint2)(a[6].y << 12 | a[6].x >> 20, a[6].x << 12 | a[6].y >> 20);
// Chi
a[0] = bitselect(b[0] ^ b[2], b[0], b[1]);
a[1] = bitselect(b[1] ^ b[3], b[1], b[2]);
a[2] = bitselect(b[2] ^ b[4], b[2], b[3]);
a[3] = bitselect(b[3] ^ b[0], b[3], b[4]);
if (out_size >= 4)
{
a[4] = bitselect(b[4] ^ b[1], b[4], b[0]);
a[5] = bitselect(b[5] ^ b[7], b[5], b[6]);
a[6] = bitselect(b[6] ^ b[8], b[6], b[7]);
a[7] = bitselect(b[7] ^ b[9], b[7], b[8]);
a[8] = bitselect(b[8] ^ b[5], b[8], b[9]);
if (out_size >= 8)
{
a[9] = bitselect(b[9] ^ b[6], b[9], b[5]);
a[10] = bitselect(b[10] ^ b[12], b[10], b[11]);
a[11] = bitselect(b[11] ^ b[13], b[11], b[12]);
a[12] = bitselect(b[12] ^ b[14], b[12], b[13]);
a[13] = bitselect(b[13] ^ b[10], b[13], b[14]);
a[14] = bitselect(b[14] ^ b[11], b[14], b[10]);
a[15] = bitselect(b[15] ^ b[17], b[15], b[16]);
a[16] = bitselect(b[16] ^ b[18], b[16], b[17]);
a[17] = bitselect(b[17] ^ b[19], b[17], b[18]);
a[18] = bitselect(b[18] ^ b[15], b[18], b[19]);
a[19] = bitselect(b[19] ^ b[16], b[19], b[15]);
a[20] = bitselect(b[20] ^ b[22], b[20], b[21]);
a[21] = bitselect(b[21] ^ b[23], b[21], b[22]);
a[22] = bitselect(b[22] ^ b[24], b[22], b[23]);
a[23] = bitselect(b[23] ^ b[20], b[23], b[24]);
a[24] = bitselect(b[24] ^ b[21], b[24], b[20]);
}
}
// Iota
a[0] ^= Keccak_f1600_RC[r];
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
a[i] = a[i].yx;
#endif
}
void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
{
for (uint i = in_size; i != 25; ++i)
{
a[i] = 0;
}
#if __ENDIAN_LITTLE__
a[in_size] ^= 0x0000000000000001;
a[24-out_size*2] ^= 0x8000000000000000;
#else
a[in_size] ^= 0x0100000000000000;
a[24-out_size*2] ^= 0x0000000000000080;
#endif
// Originally I unrolled the first and last rounds to interface
// better with surrounding code, however I haven't done this
// without causing the AMD compiler to blow up the VGPR usage.
uint r = 0;
do
{
// This dynamic branch stops the AMD compiler unrolling the loop
// and additionally saves about 33% of the VGPRs, enough to gain another
// wavefront. Ideally we'd get 4 in flight, but 3 is the best I can
// massage out of the compiler. It doesn't really seem to matter how
// much we try and help the compiler save VGPRs because it seems to throw
// that information away, hence the implementation of keccak here
// doesn't bother.
if (isolate)
{
keccak_f1600_round((uint2*)a, r++, 25);
}
}
while (r < 23);
// final round optimised for digest size
keccak_f1600_round((uint2*)a, r++, out_size);
}
#define copy(dst, src, count) for (uint i = 0; i != count; ++i) { (dst)[i] = (src)[i]; }
#define countof(x) (sizeof(x) / sizeof(x[0]))
uint fnv(uint x, uint y)
{
return x * FNV_PRIME ^ y;
}
uint4 fnv4(uint4 x, uint4 y)
{
return x * FNV_PRIME ^ y;
}
uint fnv_reduce(uint4 v)
{
return fnv(fnv(fnv(v.x, v.y), v.z), v.w);
}
typedef union
{
ulong ulongs[32 / sizeof(ulong)];
uint uints[32 / sizeof(uint)];
} hash32_t;
typedef union
{
ulong ulongs[64 / sizeof(ulong)];
uint4 uint4s[64 / sizeof(uint4)];
} hash64_t;
typedef union
{
uint uints[128 / sizeof(uint)];
uint4 uint4s[128 / sizeof(uint4)];
} hash128_t;
hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
{
hash64_t init;
uint const init_size = countof(init.ulongs);
uint const hash_size = countof(header->ulongs);
// sha3_512(header .. nonce)
ulong state[25];
copy(state, header->ulongs, hash_size);
state[hash_size] = nonce;
keccak_f1600_no_absorb(state, hash_size + 1, init_size, isolate);
copy(init.ulongs, state, init_size);
return init;
}
uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
{
uint4 mix = init;
// share init0
if (thread_id == 0)
*share = mix.x;
barrier(CLK_LOCAL_MEM_FENCE);
uint init0 = *share;
uint a = 0;
do
{
bool update_share = thread_id == (a/4) % THREADS_PER_HASH;
#pragma unroll
for (uint i = 0; i != 4; ++i)
{
if (update_share)
{
uint m[4] = { mix.x, mix.y, mix.z, mix.w };
*share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE;
}
barrier(CLK_LOCAL_MEM_FENCE);
mix = fnv4(mix, g_dag[*share].uint4s[thread_id]);
}
}
while ((a += 4) != (ACCESSES & isolate));
return fnv_reduce(mix);
}
hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
{
ulong state[25];
hash32_t hash;
uint const hash_size = countof(hash.ulongs);
uint const init_size = countof(init->ulongs);
uint const mix_size = countof(mix->ulongs);
// keccak_256(keccak_512(header..nonce) .. mix);
copy(state, init->ulongs, init_size);
copy(state + init_size, mix->ulongs, mix_size);
keccak_f1600_no_absorb(state, init_size+mix_size, hash_size, isolate);
// copy out
copy(hash.ulongs, state, hash_size);
return hash;
}
hash32_t compute_hash_simple(
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
uint isolate
)
{
hash64_t init = init_hash(g_header, nonce, isolate);
hash128_t mix;
for (uint i = 0; i != countof(mix.uint4s); ++i)
{
mix.uint4s[i] = init.uint4s[i % countof(init.uint4s)];
}
uint mix_val = mix.uints[0];
uint init0 = mix.uints[0];
uint a = 0;
do
{
uint pi = fnv(init0 ^ a, mix_val) % DAG_SIZE;
uint n = (a+1) % countof(mix.uints);
#pragma unroll
for (uint i = 0; i != countof(mix.uints); ++i)
{
mix.uints[i] = fnv(mix.uints[i], g_dag[pi].uints[i]);
mix_val = i == n ? mix.uints[i] : mix_val;
}
}
while (++a != (ACCESSES & isolate));
// reduce to output
hash32_t fnv_mix;
for (uint i = 0; i != countof(fnv_mix.uints); ++i)
{
fnv_mix.uints[i] = fnv_reduce(mix.uint4s[i]);
}
return final_hash(&init, &fnv_mix, isolate);
}
typedef union
{
struct
{
hash64_t init;
uint pad; // avoid lds bank conflicts
};
hash32_t mix;
} compute_hash_share;
hash32_t compute_hash(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
uint isolate
)
{
uint const gid = get_global_id(0);
// Compute one init hash per work item.
hash64_t init = init_hash(g_header, nonce, isolate);
// Threads work together in this phase in groups of 8.
uint const thread_id = gid % THREADS_PER_HASH;
uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH;
hash32_t mix;
uint i = 0;
do
{
// share init with other threads
if (i == thread_id)
share[hash_id].init = init;
barrier(CLK_LOCAL_MEM_FENCE);
uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))];
barrier(CLK_LOCAL_MEM_FENCE);
uint thread_mix = inner_loop(thread_init, thread_id, share[hash_id].mix.uints, g_dag, isolate);
share[hash_id].mix.uints[thread_id] = thread_mix;
barrier(CLK_LOCAL_MEM_FENCE);
if (i == thread_id)
mix = share[hash_id].mix;
barrier(CLK_LOCAL_MEM_FENCE);
}
while (++i != (THREADS_PER_HASH & isolate));
return final_hash(&init, &mix, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash_simple(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
{
uint const gid = get_global_id(0);
g_hashes[gid] = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_search_simple(
__global volatile uint* restrict g_output,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
ulong target,
uint isolate
)
{
uint const gid = get_global_id(0);
hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
g_output[slot] = gid;
}
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
g_hashes[gid] = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_search(
__global volatile uint* restrict g_output,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong start_nonce,
ulong target,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
hash32_t hash = compute_hash(share, g_header, g_dag, start_nonce + gid, isolate);
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
g_output[slot] = gid;
}
}

View File

@@ -32,6 +32,9 @@
#include <libkern/OSByteOrder.h>
#define ethash_swap_u32(input_) OSSwapInt32(input_)
#define ethash_swap_u64(input_) OSSwapInt64(input_)
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
#define ethash_swap_u32(input_) bswap32(input_)
#define ethash_swap_u64(input_) bswap64(input_)
#else // posix
#include <byteswap.h>
#define ethash_swap_u32(input_) __bswap_32(input_)

View File

@@ -364,6 +364,7 @@ static bool ethash_mmap(struct ethash_full* ret, FILE* f)
{
int fd;
char* mmapped_data;
errno = 0;
ret->file = f;
if ((fd = ethash_fileno(ret->file)) == -1) {
return false;
@@ -400,38 +401,48 @@ ethash_full_t ethash_full_new_internal(
ret->file_size = (size_t)full_size;
switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
case ETHASH_IO_FAIL:
// ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
goto fail_free_full;
case ETHASH_IO_MEMO_MATCH:
if (!ethash_mmap(ret, f)) {
ETHASH_CRITICAL("mmap failure()");
goto fail_close_file;
}
return ret;
case ETHASH_IO_MEMO_SIZE_MISMATCH:
// if a DAG of same filename but unexpected size is found, silently force new file creation
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
goto fail_free_full;
}
// fallthrough to the mismatch case here, DO NOT go through match
case ETHASH_IO_MEMO_MISMATCH:
if (!ethash_mmap(ret, f)) {
ETHASH_CRITICAL("mmap failure()");
goto fail_close_file;
}
break;
}
if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
ETHASH_CRITICAL("Failure at computing DAG data.");
goto fail_free_full_data;
}
// after the DAG has been filled then we finalize it by writting the magic number at the beginning
if (fseek(f, 0, SEEK_SET) != 0) {
ETHASH_CRITICAL("Could not seek to DAG file start to write magic number.");
goto fail_free_full_data;
}
uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
ETHASH_CRITICAL("Could not write magic number to DAG's beginning.");
goto fail_free_full_data;
}
if (fflush(f) != 0) {// make sure the magic number IS there
ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?");
goto fail_free_full_data;
}
fflush(f); // make sure the magic number IS there
return ret;
fail_free_full_data:

View File

@@ -21,6 +21,7 @@
#include "io.h"
#include <string.h>
#include <stdio.h>
#include <errno.h>
enum ethash_io_rc ethash_io_prepare(
char const* dirname,
@@ -32,15 +33,19 @@ enum ethash_io_rc ethash_io_prepare(
{
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL;
// reset errno before io calls
errno = 0;
// assert directory exists
if (!ethash_mkdir(dirname)) {
ETHASH_CRITICAL("Could not create the ethash directory");
goto end;
}
ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
if (!tmpfile) {
ETHASH_CRITICAL("Could not create the full DAG pathname");
goto end;
}
@@ -52,6 +57,7 @@ enum ethash_io_rc ethash_io_prepare(
size_t found_size;
if (!ethash_file_size(f, &found_size)) {
fclose(f);
ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile);
goto free_memo;
}
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
@@ -64,6 +70,7 @@ enum ethash_io_rc ethash_io_prepare(
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
// I/O error
fclose(f);
ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
@@ -80,15 +87,25 @@ enum ethash_io_rc ethash_io_prepare(
// file does not exist, will need to be created
f = ethash_fopen(tmpfile, "wb+");
if (!f) {
ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile);
goto free_memo;
}
// make sure it's of the proper size
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
fclose(f);
ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
if (fputc('\n', f) == EOF) {
fclose(f);
ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
if (fflush(f) != 0) {
fclose(f);
ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
fputc('\n', f);
fflush(f);
ret = ETHASH_IO_MEMO_MISMATCH;
goto set_file;

View File

@@ -54,6 +54,23 @@ enum ethash_io_rc {
#define snprintf(...) sprintf_s(__VA_ARGS__)
#endif
/**
* Logs a critical error in important parts of ethash. Should mostly help
* figure out what kind of problem (I/O, memory e.t.c.) causes a NULL
* ethash_full_t
*/
#ifdef ETHASH_PRINT_CRITICAL_OUTPUT
#define ETHASH_CRITICAL(...) \
do \
{ \
printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while (0)
#else
#define ETHASH_CRITICAL(...)
#endif
/**
* Prepares io for ethash
*

View File

@@ -26,6 +26,8 @@
#include <libgen.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
FILE* ethash_fopen(char const* file_name, char const* mode)
{
@@ -89,6 +91,13 @@ bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
static const char dir_suffix[] = ".ethash/";
strbuf[0] = '\0';
char* home_dir = getenv("HOME");
if (!home_dir || strlen(home_dir) == 0)
{
struct passwd* pwd = getpwuid(getuid());
if (pwd)
home_dir = pwd->pw_dir;
}
size_t len = strlen(home_dir);
if (!ethash_strncat(strbuf, buffsize, home_dir, len)) {
return false;

View File

@@ -87,9 +87,9 @@ bool ethash_file_size(FILE* f, size_t* ret_size)
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
{
static const char dir_suffix[] = "Appdata\\Ethash\\";
static const char dir_suffix[] = "Ethash\\";
strbuf[0] = '\0';
if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, (WCHAR*)strbuf))) {
if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) {
return false;
}
if (!ethash_strncat(strbuf, buffsize, "\\", 1)) {

View File

@@ -292,12 +292,13 @@ BOOST_AUTO_TEST_CASE(test_ethash_io_memo_file_size_mismatch) {
BOOST_AUTO_TEST_CASE(test_ethash_get_default_dirname) {
char result[256];
// this is really not an easy thing to test for in a unit test, so yeah it does look ugly
// this is really not an easy thing to test for in a unit test
// TODO: Improve this test ...
#ifdef _WIN32
char homedir[256];
BOOST_REQUIRE(SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, (WCHAR*)homedir)));
BOOST_REQUIRE(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, (CHAR*)homedir)));
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
std::string res = std::string(homedir) + std::string("\\Appdata\\Ethash\\");
std::string res = std::string(homedir) + std::string("\\AppData\\Local\\Ethash\\");
#else
char* homedir = getenv("HOME");
BOOST_REQUIRE(ethash_get_default_dirname(result, 256));
@@ -305,7 +306,7 @@ BOOST_AUTO_TEST_CASE(test_ethash_get_default_dirname) {
#endif
BOOST_CHECK_MESSAGE(strcmp(res.c_str(), result) == 0,
"Expected \"" + res + "\" but got \"" + std::string(result) + "\""
);
);
}
BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {

View File

@@ -19,7 +19,7 @@ import (
"fmt"
"net/http"
"net/url"
"time"
"golang.org/x/net/html/charset"
"github.com/huin/goupnp/httpu"
@@ -64,7 +64,6 @@ func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
maybe := &results[i]
loc, err := response.Location()
if err != nil {
maybe.Err = ContextError{"unexpected bad location from search", err}
continue
}
@@ -93,7 +92,11 @@ func DiscoverDevices(searchTarget string) ([]MaybeRootDevice, error) {
}
func requestXml(url string, defaultSpace string, doc interface{}) error {
resp, err := http.Get(url)
timeout := time.Duration(3 * time.Second)
client := http.Client{
Timeout: timeout,
}
resp, err := client.Get(url)
if err != nil {
return err
}

View File

@@ -2,25 +2,28 @@
Ethereum Go Client © 2014 Jeffrey Wilcke.
| Linux | OSX | Windows | Tests
----------|---------|-----|---------|------
develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/Linux%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/OSX%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20Go%20develop%20branch)](https://build.ethdev.com/builders/Windows%20Go%20develop%20branch/builds/-1) | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=develop)](https://travis-ci.org/ethereum/go-ethereum) [![Coverage Status](https://coveralls.io/repos/ethereum/go-ethereum/badge.svg?branch=develop)](https://coveralls.io/r/ethereum/go-ethereum?branch=develop)
master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20master%20branch)](https://build.ethdev.com/builders/Linux%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20Go%20master%20branch)](https://build.ethdev.com/builders/OSX%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20Go%20master%20branch)](https://build.ethdev.com/builders/Windows%20Go%20master%20branch/builds/-1) | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) [![Coverage Status](https://coveralls.io/repos/ethereum/go-ethereum/badge.svg?branch=master)](https://coveralls.io/r/ethereum/go-ethereum?branch=master)
| Linux | OSX | ARM | Windows | Tests
----------|---------|-----|-----|---------|------
develop | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/Linux%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20develop%20branch)](https://build.ethdev.com/builders/OSX%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=ARM%20Go%20develop%20branch)](https://build.ethdev.com/builders/ARM%20Go%20develop%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20Go%20develop%20branch)](https://build.ethdev.com/builders/Windows%20Go%20develop%20branch/builds/-1) | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=develop)](https://travis-ci.org/ethereum/go-ethereum) [![Coverage Status](https://coveralls.io/repos/ethereum/go-ethereum/badge.svg?branch=develop)](https://coveralls.io/r/ethereum/go-ethereum?branch=develop)
master | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Linux%20Go%20master%20branch)](https://build.ethdev.com/builders/Linux%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=OSX%20Go%20master%20branch)](https://build.ethdev.com/builders/OSX%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=ARM%20Go%20master%20branch)](https://build.ethdev.com/builders/ARM%20Go%20master%20branch/builds/-1) | [![Build+Status](https://build.ethdev.com/buildstatusimage?builder=Windows%20Go%20master%20branch)](https://build.ethdev.com/builders/Windows%20Go%20master%20branch/builds/-1) | [![Buildr+Status](https://travis-ci.org/ethereum/go-ethereum.svg?branch=master)](https://travis-ci.org/ethereum/go-ethereum) [![Coverage Status](https://coveralls.io/repos/ethereum/go-ethereum/badge.svg?branch=master)](https://coveralls.io/r/ethereum/go-ethereum?branch=master)
[![Bugs](https://badge.waffle.io/ethereum/go-ethereum.png?label=bug&title=Bugs)](https://waffle.io/ethereum/go-ethereum)
[![Stories in Ready](https://badge.waffle.io/ethereum/go-ethereum.png?label=ready&title=Ready)](https://waffle.io/ethereum/go-ethereum)
[![Stories in Progress](https://badge.waffle.io/ethereum/go-ethereum.svg?label=in%20progress&title=In Progress)](http://waffle.io/ethereum/go-ethereum)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ethereum/go-ethereum?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Automated (dev) builds
Automated development builds
======================
The following builds are build automatically by our build servers after each push to the [develop](https://github.com/ethereum/go-ethereum/tree/develop) branch.
* [Docker](https://registry.hub.docker.com/u/ethereum/client-go/)
* [OS X](http://build.ethdev.com/builds/OSX%20Go%20develop%20branch/Mist-OSX-latest.dmg)
* Ubuntu
[trusty](https://build.ethdev.com/builds/Linux%20Go%20develop%20deb%20i386-trusty/latest/) |
[utopic](https://build.ethdev.com/builds/Linux%20Go%20develop%20deb%20i386-utopic/latest/)
* [Windows 64-bit](https://build.ethdev.com/builds/Windows%20Go%20develop%20branch/Geth-Win64-latest.7z)
* [Windows 64-bit](https://build.ethdev.com/builds/Windows%20Go%20develop%20branch/Geth-Win64-latest.zip)
* [ARM](https://build.ethdev.com/builds/ARM%20Go%20develop%20branch/geth-ARM-latest.tar.bz2)
Building the source
===================

View File

@@ -16,7 +16,7 @@ for pkg in $(go list ./...); do
# drop the namespace prefix.
dir=${pkg##github.com/ethereum/go-ethereum/}
if [[ $dir != "tests/vm" ]]; then
if [[ $dir != "tests" ]]; then
go test -covermode=count -coverprofile=$dir/profile.tmp $pkg
fi
if [[ -f $dir/profile.tmp ]]; then

View File

@@ -17,217 +17,201 @@
/**
* @authors:
* Jeffrey Wilcke <i@jev.io>
* Taylor Gerring <taylor.gerring@gmail.com>
*/
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"math/big"
"os"
"strconv"
"path/filepath"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger"
"github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/tests/helper"
"github.com/ethereum/go-ethereum/tests"
)
type Log struct {
AddressF string `json:"address"`
DataF string `json:"data"`
TopicsF []string `json:"topics"`
BloomF string `json:"bloom"`
}
var (
continueOnError = false
testExtension = ".json"
defaultTest = "all"
defaultDir = "."
allTests = []string{"BlockTests", "StateTests", "TransactionTests", "VMTests"}
skipTests = []string{}
func (self Log) Address() []byte { return common.Hex2Bytes(self.AddressF) }
func (self Log) Data() []byte { return common.Hex2Bytes(self.DataF) }
func (self Log) RlpData() interface{} { return nil }
func (self Log) Topics() [][]byte {
t := make([][]byte, len(self.TopicsF))
for i, topic := range self.TopicsF {
t[i] = common.Hex2Bytes(topic)
TestFlag = cli.StringFlag{
Name: "test",
Usage: "Test type (string): VMTests, TransactionTests, StateTests, BlockTests",
Value: defaultTest,
}
return t
}
type Account struct {
Balance string
Code string
Nonce string
Storage map[string]string
}
func StateObjectFromAccount(db common.Database, addr string, account Account) *state.StateObject {
obj := state.NewStateObject(common.HexToAddress(addr), db)
obj.SetBalance(common.Big(account.Balance))
if common.IsHex(account.Code) {
account.Code = account.Code[2:]
FileFlag = cli.StringFlag{
Name: "file",
Usage: "Test file or directory. Directories are searched for .json files 1 level deep",
Value: defaultDir,
EnvVar: "ETHEREUM_TEST_PATH",
}
obj.SetCode(common.Hex2Bytes(account.Code))
obj.SetNonce(common.Big(account.Nonce).Uint64())
ContinueOnErrorFlag = cli.BoolFlag{
Name: "continue",
Usage: "Continue running tests on error (true) or [default] exit immediately (false)",
}
ReadStdInFlag = cli.BoolFlag{
Name: "stdin",
Usage: "Accept input from stdin instead of reading from file",
}
SkipTestsFlag = cli.StringFlag{
Name: "skip",
Usage: "Tests names to skip",
}
)
return obj
}
func runTestWithReader(test string, r io.Reader) error {
glog.Infoln("runTest", test)
var err error
switch strings.ToLower(test) {
case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
err = tests.RunBlockTestWithReader(r, skipTests)
case "st", "state", "statetest", "statetests":
err = tests.RunStateTestWithReader(r, skipTests)
case "tx", "transactiontest", "transactiontests":
err = tests.RunTransactionTestsWithReader(r, skipTests)
case "vm", "vmtest", "vmtests":
err = tests.RunVmTestWithReader(r, skipTests)
default:
err = fmt.Errorf("Invalid test type specified: %v", test)
}
type VmTest struct {
Callcreates interface{}
Env Env
Exec map[string]string
Transaction map[string]string
Logs []Log
Gas string
Out string
Post map[string]Account
Pre map[string]Account
PostStateRoot string
}
type Env struct {
CurrentCoinbase string
CurrentDifficulty string
CurrentGasLimit string
CurrentNumber string
CurrentTimestamp interface{}
PreviousHash string
}
func RunVmTest(r io.Reader) (failed int) {
tests := make(map[string]VmTest)
data, _ := ioutil.ReadAll(r)
err := json.Unmarshal(data, &tests)
if err != nil {
log.Fatalln(err)
return err
}
vm.Debug = true
glog.SetV(4)
glog.SetToStderr(true)
for name, test := range tests {
db, _ := ethdb.NewMemDatabase()
statedb := state.New(common.Hash{}, db)
for addr, account := range test.Pre {
obj := StateObjectFromAccount(db, addr, account)
statedb.SetStateObject(obj)
}
return nil
}
func getFiles(path string) ([]string, error) {
glog.Infoln("getFiles", path)
var files []string
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return nil, err
}
switch mode := fi.Mode(); {
case mode.IsDir():
fi, _ := ioutil.ReadDir(path)
files = make([]string, len(fi))
for i, v := range fi {
// only go 1 depth and leave directory entires blank
if !v.IsDir() && v.Name()[len(v.Name())-len(testExtension):len(v.Name())] == testExtension {
files[i] = filepath.Join(path, v.Name())
glog.Infoln("Found file", files[i])
}
}
case mode.IsRegular():
files = make([]string, 1)
files[0] = path
}
return files, nil
}
func runSuite(test, file string) {
var tests []string
if test == defaultTest {
tests = allTests
} else {
tests = []string{test}
}
for _, curTest := range tests {
glog.Infoln("runSuite", curTest, file)
var err error
var files []string
if test == defaultTest {
files, err = getFiles(filepath.Join(file, curTest))
env := make(map[string]string)
env["currentCoinbase"] = test.Env.CurrentCoinbase
env["currentDifficulty"] = test.Env.CurrentDifficulty
env["currentGasLimit"] = test.Env.CurrentGasLimit
env["currentNumber"] = test.Env.CurrentNumber
env["previousHash"] = test.Env.PreviousHash
if n, ok := test.Env.CurrentTimestamp.(float64); ok {
env["currentTimestamp"] = strconv.Itoa(int(n))
} else {
env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
files, err = getFiles(file)
}
if err != nil {
glog.Fatalln(err)
}
ret, logs, _, _ := helper.RunState(statedb, env, test.Transaction)
statedb.Sync()
rexp := helper.FromHex(test.Out)
if bytes.Compare(rexp, ret) != 0 {
glog.V(logger.Info).Infof("%s's return failed. Expected %x, got %x\n", name, rexp, ret)
failed = 1
if len(files) == 0 {
glog.Warningln("No files matched path")
}
for addr, account := range test.Post {
obj := statedb.GetStateObject(common.HexToAddress(addr))
if obj == nil {
for _, curFile := range files {
// Skip blank entries
if len(curFile) == 0 {
continue
}
if len(test.Exec) == 0 {
if obj.Balance().Cmp(common.Big(account.Balance)) != 0 {
glog.V(logger.Info).Infof("%s's : (%x) balance failed. Expected %v, got %v => %v\n", name, obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance()))
failed = 1
r, err := os.Open(curFile)
if err != nil {
glog.Fatalln(err)
}
defer r.Close()
err = runTestWithReader(curTest, r)
if err != nil {
if continueOnError {
glog.Errorln(err)
} else {
glog.Fatalln(err)
}
}
for addr, value := range account.Storage {
v := obj.GetState(common.HexToHash(addr)).Bytes()
vexp := helper.FromHex(value)
if bytes.Compare(v, vexp) != 0 {
glog.V(logger.Info).Infof("%s's : (%x: %s) storage failed. Expected %x, got %x (%v %v)\n", name, obj.Address().Bytes()[0:4], addr, vexp, v, common.BigD(vexp), common.BigD(v))
failed = 1
}
}
}
statedb.Sync()
//if !bytes.Equal(common.Hex2Bytes(test.PostStateRoot), statedb.Root()) {
if common.HexToHash(test.PostStateRoot) != statedb.Root() {
glog.V(logger.Info).Infof("%s's : Post state root failed. Expected %s, got %x", name, test.PostStateRoot, statedb.Root())
failed = 1
}
if len(test.Logs) > 0 {
if len(test.Logs) != len(logs) {
glog.V(logger.Info).Infof("log length failed. Expected %d, got %d", len(test.Logs), len(logs))
failed = 1
} else {
for i, log := range test.Logs {
if common.HexToAddress(log.AddressF) != logs[i].Address {
glog.V(logger.Info).Infof("'%s' log address failed. Expected %v got %x", name, log.AddressF, logs[i].Address)
failed = 1
}
if !bytes.Equal(logs[i].Data, helper.FromHex(log.DataF)) {
glog.V(logger.Info).Infof("'%s' log data failed. Expected %v got %x", name, log.DataF, logs[i].Data)
failed = 1
}
if len(log.TopicsF) != len(logs[i].Topics) {
glog.V(logger.Info).Infof("'%s' log topics length failed. Expected %d got %d", name, len(log.TopicsF), logs[i].Topics)
failed = 1
} else {
for j, topic := range log.TopicsF {
if common.HexToHash(topic) != logs[i].Topics[j] {
glog.V(logger.Info).Infof("'%s' log topic[%d] failed. Expected %v got %x", name, j, topic, logs[i].Topics[j])
failed = 1
}
}
}
genBloom := common.LeftPadBytes(types.LogsBloom(state.Logs{logs[i]}).Bytes(), 256)
if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) {
glog.V(logger.Info).Infof("'%s' bloom failed.", name)
failed = 1
}
}
}
}
if failed == 1 {
glog.V(logger.Info).Infoln(string(statedb.Dump()))
}
logger.Flush()
}
}
return
func setupApp(c *cli.Context) {
flagTest := c.GlobalString(TestFlag.Name)
flagFile := c.GlobalString(FileFlag.Name)
continueOnError = c.GlobalBool(ContinueOnErrorFlag.Name)
useStdIn := c.GlobalBool(ReadStdInFlag.Name)
skipTests = strings.Split(c.GlobalString(SkipTestsFlag.Name), " ")
if !useStdIn {
runSuite(flagTest, flagFile)
} else {
if err := runTestWithReader(flagTest, os.Stdin); err != nil {
glog.Fatalln(err)
}
}
}
func main() {
helper.Logger.SetLogLevel(5)
vm.Debug = true
glog.SetToStderr(true)
if len(os.Args) > 1 {
os.Exit(RunVmTest(strings.NewReader(os.Args[1])))
} else {
os.Exit(RunVmTest(os.Stdin))
app := cli.NewApp()
app.Name = "ethtest"
app.Usage = "go-ethereum test interface"
app.Action = setupApp
app.Version = "0.2.0"
app.Author = "go-ethereum team"
app.Flags = []cli.Flag{
TestFlag,
FileFlag,
ContinueOnErrorFlag,
ReadStdInFlag,
SkipTestsFlag,
}
if err := app.Run(os.Args); err != nil {
glog.Fatalln(err)
}
}

View File

@@ -59,6 +59,7 @@ func main() {
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel)))
vm.Debug = true
db, _ := ethdb.NewMemDatabase()
statedb := state.New(common.Hash{}, db)
sender := statedb.CreateAccount(common.StringToAddress("sender"))
@@ -80,6 +81,8 @@ func main() {
fmt.Println(string(statedb.Dump()))
}
vm.StdErrFormat(vmenv.StructLogs())
var mem runtime.MemStats
runtime.ReadMemStats(&mem)
fmt.Printf("vm took %v\n", time.Since(tstart))
@@ -104,6 +107,7 @@ type VMEnv struct {
depth int
Gas *big.Int
time int64
logs []vm.StructLog
}
func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VMEnv {
@@ -133,6 +137,12 @@ func (self *VMEnv) GetHash(n uint64) common.Hash {
}
return common.Hash{}
}
func (self *VMEnv) AddStructLog(log vm.StructLog) {
self.logs = append(self.logs, log)
}
func (self *VMEnv) StructLogs() []vm.StructLog {
return self.logs
}
func (self *VMEnv) AddLog(log *state.Log) {
self.state.AddLog(log)
}

View File

@@ -1,775 +0,0 @@
package main
import (
"encoding/json"
"errors"
"fmt"
"math/big"
"strconv"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/compiler"
"github.com/ethereum/go-ethereum/common/natspec"
"github.com/ethereum/go-ethereum/common/resolver"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/xeth"
"github.com/robertkrimen/otto"
"gopkg.in/fatih/set.v0"
)
/*
node admin bindings
*/
func (js *jsre) adminBindings() {
ethO, _ := js.re.Get("eth")
eth := ethO.Object()
eth.Set("pendingTransactions", js.pendingTransactions)
eth.Set("resend", js.resend)
js.re.Set("admin", struct{}{})
t, _ := js.re.Get("admin")
admin := t.Object()
admin.Set("addPeer", js.addPeer)
admin.Set("startRPC", js.startRPC)
admin.Set("stopRPC", js.stopRPC)
admin.Set("nodeInfo", js.nodeInfo)
admin.Set("peers", js.peers)
admin.Set("newAccount", js.newAccount)
admin.Set("unlock", js.unlock)
admin.Set("import", js.importChain)
admin.Set("export", js.exportChain)
admin.Set("verbosity", js.verbosity)
admin.Set("progress", js.downloadProgress)
admin.Set("setSolc", js.setSolc)
admin.Set("contractInfo", struct{}{})
t, _ = admin.Get("contractInfo")
cinfo := t.Object()
// newRegistry officially not documented temporary option
cinfo.Set("start", js.startNatSpec)
cinfo.Set("stop", js.stopNatSpec)
cinfo.Set("newRegistry", js.newRegistry)
cinfo.Set("get", js.getContractInfo)
cinfo.Set("register", js.register)
cinfo.Set("registerUrl", js.registerUrl)
// cinfo.Set("verify", js.verify)
admin.Set("miner", struct{}{})
t, _ = admin.Get("miner")
miner := t.Object()
miner.Set("start", js.startMining)
miner.Set("stop", js.stopMining)
miner.Set("hashrate", js.hashrate)
miner.Set("setExtra", js.setExtra)
miner.Set("setGasPrice", js.setGasPrice)
admin.Set("debug", struct{}{})
t, _ = admin.Get("debug")
debug := t.Object()
js.re.Set("sleep", js.sleep)
debug.Set("backtrace", js.backtrace)
debug.Set("printBlock", js.printBlock)
debug.Set("dumpBlock", js.dumpBlock)
debug.Set("getBlockRlp", js.getBlockRlp)
debug.Set("setHead", js.setHead)
debug.Set("processBlock", js.debugBlock)
// undocumented temporary
debug.Set("waitForBlocks", js.waitForBlocks)
}
// generic helper to getBlock by Number/Height or Hex depending on autodetected input
// if argument is missing the current block is returned
// if block is not found or there is problem with decoding
// the appropriate value is returned and block is guaranteed to be nil
func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
var block *types.Block
if len(call.ArgumentList) > 0 {
if call.Argument(0).IsNumber() {
num, _ := call.Argument(0).ToInteger()
block = js.ethereum.ChainManager().GetBlockByNumber(uint64(num))
} else if call.Argument(0).IsString() {
hash, _ := call.Argument(0).ToString()
block = js.ethereum.ChainManager().GetBlock(common.HexToHash(hash))
} else {
return nil, errors.New("invalid argument for dump. Either hex string or number")
}
} else {
block = js.ethereum.ChainManager().CurrentBlock()
}
if block == nil {
return nil, errors.New("block not found")
}
return block, nil
}
func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
txs := js.ethereum.TxPool().GetTransactions()
// grab the accounts from the account manager. This will help with determening which
// transactions should be returned.
accounts, err := js.ethereum.AccountManager().Accounts()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
// Add the accouns to a new set
accountSet := set.New()
for _, account := range accounts {
accountSet.Add(account.Address)
}
//ltxs := make([]*tx, len(txs))
var ltxs []*tx
for _, tx := range txs {
// no need to check err
if from, _ := tx.From(); accountSet.Has(from) {
ltxs = append(ltxs, newTx(tx))
}
}
return js.re.ToVal(ltxs)
}
func (js *jsre) resend(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) == 0 {
fmt.Println("first argument must be a transaction")
return otto.FalseValue()
}
v, err := call.Argument(0).Export()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
if tx, ok := v.(*tx); ok {
gl, gp := tx.GasLimit, tx.GasPrice
if len(call.ArgumentList) > 1 {
gp = call.Argument(1).String()
}
if len(call.ArgumentList) > 2 {
gl = call.Argument(2).String()
}
ret, err := js.xeth.Transact(tx.From, tx.To, tx.Nonce, tx.Value, gl, gp, tx.Data)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
js.ethereum.TxPool().RemoveTransactions(types.Transactions{tx.tx})
return js.re.ToVal(ret)
}
fmt.Println("first argument must be a transaction")
return otto.FalseValue()
}
func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
block, err := js.getBlock(call)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
old := vm.Debug
vm.Debug = true
_, err = js.ethereum.BlockProcessor().RetryProcess(block)
if err != nil {
glog.Infoln(err)
}
vm.Debug = old
return otto.UndefinedValue()
}
func (js *jsre) setHead(call otto.FunctionCall) otto.Value {
block, err := js.getBlock(call)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
js.ethereum.ChainManager().SetHead(block)
return otto.UndefinedValue()
}
func (js *jsre) downloadProgress(call otto.FunctionCall) otto.Value {
current, max := js.ethereum.Downloader().Stats()
return js.re.ToVal(fmt.Sprintf("%d/%d", current, max))
}
func (js *jsre) getBlockRlp(call otto.FunctionCall) otto.Value {
block, err := js.getBlock(call)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
encoded, _ := rlp.EncodeToBytes(block)
return js.re.ToVal(fmt.Sprintf("%x", encoded))
}
func (js *jsre) setExtra(call otto.FunctionCall) otto.Value {
extra, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
if len(extra) > 1024 {
fmt.Println("error: cannot exceed 1024 bytes")
return otto.UndefinedValue()
}
js.ethereum.Miner().SetExtra([]byte(extra))
return otto.UndefinedValue()
}
func (js *jsre) setGasPrice(call otto.FunctionCall) otto.Value {
gasPrice, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
js.ethereum.Miner().SetGasPrice(common.String2Big(gasPrice))
return otto.UndefinedValue()
}
func (js *jsre) hashrate(otto.FunctionCall) otto.Value {
return js.re.ToVal(js.ethereum.Miner().HashRate())
}
func (js *jsre) backtrace(call otto.FunctionCall) otto.Value {
tracestr, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
glog.GetTraceLocation().Set(tracestr)
return otto.UndefinedValue()
}
func (js *jsre) verbosity(call otto.FunctionCall) otto.Value {
v, err := call.Argument(0).ToInteger()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
glog.SetV(int(v))
return otto.UndefinedValue()
}
func (js *jsre) startMining(call otto.FunctionCall) otto.Value {
var (
threads int64
err error
)
if len(call.ArgumentList) > 0 {
threads, err = call.Argument(0).ToInteger()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
} else {
threads = int64(js.ethereum.MinerThreads)
}
err = js.ethereum.StartMining(int(threads))
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}
func (js *jsre) stopMining(call otto.FunctionCall) otto.Value {
js.ethereum.StopMining()
return otto.TrueValue()
}
func (js *jsre) startRPC(call otto.FunctionCall) otto.Value {
addr, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
port, err := call.Argument(1).ToInteger()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
corsDomain := js.corsDomain
if len(call.ArgumentList) > 2 {
corsDomain, err = call.Argument(2).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
}
config := rpc.RpcConfig{
ListenAddress: addr,
ListenPort: uint(port),
CorsDomain: corsDomain,
}
xeth := xeth.New(js.ethereum, nil)
err = rpc.Start(xeth, config)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}
func (js *jsre) stopRPC(call otto.FunctionCall) otto.Value {
if rpc.Stop() == nil {
return otto.TrueValue()
}
return otto.FalseValue()
}
func (js *jsre) addPeer(call otto.FunctionCall) otto.Value {
nodeURL, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
err = js.ethereum.AddPeer(nodeURL)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}
func (js *jsre) unlock(call otto.FunctionCall) otto.Value {
addr, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
seconds, err := call.Argument(2).ToInteger()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
if seconds == 0 {
seconds = accounts.DefaultAccountUnlockDuration
}
arg := call.Argument(1)
var passphrase string
if arg.IsUndefined() {
fmt.Println("Please enter a passphrase now.")
passphrase, err = readPassword("Passphrase: ", true)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
} else {
passphrase, err = arg.ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
}
am := js.ethereum.AccountManager()
err = am.TimedUnlock(common.HexToAddress(addr), passphrase, time.Duration(seconds)*time.Second)
if err != nil {
fmt.Printf("Unlock account failed '%v'\n", err)
return otto.FalseValue()
}
return otto.TrueValue()
}
func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
arg := call.Argument(0)
var passphrase string
if arg.IsUndefined() {
fmt.Println("The new account will be encrypted with a passphrase.")
fmt.Println("Please enter a passphrase now.")
auth, err := readPassword("Passphrase: ", true)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
confirm, err := readPassword("Repeat Passphrase: ", false)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
if auth != confirm {
fmt.Println("Passphrases did not match.")
return otto.FalseValue()
}
passphrase = auth
} else {
var err error
passphrase, err = arg.ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
}
acct, err := js.ethereum.AccountManager().NewAccount(passphrase)
if err != nil {
fmt.Printf("Could not create the account: %v", err)
return otto.UndefinedValue()
}
return js.re.ToVal(acct.Address.Hex())
}
func (js *jsre) nodeInfo(call otto.FunctionCall) otto.Value {
return js.re.ToVal(js.ethereum.NodeInfo())
}
func (js *jsre) peers(call otto.FunctionCall) otto.Value {
return js.re.ToVal(js.ethereum.PeersInfo())
}
func (js *jsre) importChain(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) == 0 {
fmt.Println("require file name. admin.importChain(filename)")
return otto.FalseValue()
}
fn, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
if err := utils.ImportChain(js.ethereum.ChainManager(), fn); err != nil {
fmt.Println("Import error: ", err)
return otto.FalseValue()
}
return otto.TrueValue()
}
func (js *jsre) exportChain(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) == 0 {
fmt.Println("require file name: admin.exportChain(filename)")
return otto.FalseValue()
}
fn, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
if err := utils.ExportChain(js.ethereum.ChainManager(), fn); err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}
func (js *jsre) printBlock(call otto.FunctionCall) otto.Value {
block, err := js.getBlock(call)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
fmt.Println(block)
return otto.UndefinedValue()
}
func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
block, err := js.getBlock(call)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
statedb := state.New(block.Root(), js.ethereum.StateDb())
dump := statedb.RawDump()
return js.re.ToVal(dump)
}
func (js *jsre) waitForBlocks(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) > 2 {
fmt.Println("requires 0, 1 or 2 arguments: admin.debug.waitForBlock(minHeight, timeout)")
return otto.FalseValue()
}
var n, timeout int64
var timer <-chan time.Time
var height *big.Int
var err error
args := len(call.ArgumentList)
if args == 2 {
timeout, err = call.Argument(1).ToInteger()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
timer = time.NewTimer(time.Duration(timeout) * time.Second).C
}
if args >= 1 {
n, err = call.Argument(0).ToInteger()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
height = big.NewInt(n)
}
if args == 0 {
height = js.xeth.CurrentBlock().Number()
height.Add(height, common.Big1)
}
wait := js.wait
js.wait <- height
select {
case <-timer:
// if times out make sure the xeth loop does not block
go func() {
select {
case wait <- nil:
case <-wait:
}
}()
return otto.UndefinedValue()
case height = <-wait:
}
return js.re.ToVal(height.Uint64())
}
func (js *jsre) sleep(call otto.FunctionCall) otto.Value {
sec, err := call.Argument(0).ToInteger()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
time.Sleep(time.Duration(sec) * time.Second)
return otto.UndefinedValue()
}
func (js *jsre) setSolc(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) != 1 {
fmt.Println("needs 1 argument: admin.contractInfo.setSolc(solcPath)")
return otto.FalseValue()
}
solcPath, err := call.Argument(0).ToString()
if err != nil {
return otto.FalseValue()
}
solc, err := js.xeth.SetSolc(solcPath)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
fmt.Println(solc.Info())
return otto.TrueValue()
}
func (js *jsre) register(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) != 4 {
fmt.Println("requires 4 arguments: admin.contractInfo.register(fromaddress, contractaddress, contract, filename)")
return otto.UndefinedValue()
}
sender, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
address, err := call.Argument(1).ToString()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
raw, err := call.Argument(2).Export()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
jsonraw, err := json.Marshal(raw)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
var contract compiler.Contract
err = json.Unmarshal(jsonraw, &contract)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
filename, err := call.Argument(3).ToString()
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
contenthash, err := compiler.ExtractInfo(&contract, filename)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
// sender and contract address are passed as hex strings
codeb := js.xeth.CodeAtBytes(address)
codehash := common.BytesToHash(crypto.Sha3(codeb))
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
registry := resolver.New(js.xeth)
_, err = registry.RegisterContentHash(common.HexToAddress(sender), codehash, contenthash)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
return js.re.ToVal(contenthash.Hex())
}
func (js *jsre) registerUrl(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) != 3 {
fmt.Println("requires 3 arguments: admin.contractInfo.register(fromaddress, contenthash, filename)")
return otto.FalseValue()
}
sender, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
contenthash, err := call.Argument(1).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
url, err := call.Argument(2).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
registry := resolver.New(js.xeth)
_, err = registry.RegisterUrl(common.HexToAddress(sender), common.HexToHash(contenthash), url)
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}
func (js *jsre) getContractInfo(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) != 1 {
fmt.Println("requires 1 argument: admin.contractInfo.register(contractaddress)")
return otto.FalseValue()
}
addr, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
infoDoc, err := natspec.FetchDocsForContract(addr, js.xeth, ds)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
var info compiler.ContractInfo
err = json.Unmarshal(infoDoc, &info)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
return js.re.ToVal(info)
}
func (js *jsre) startNatSpec(call otto.FunctionCall) otto.Value {
js.ethereum.NatSpec = true
return otto.TrueValue()
}
func (js *jsre) stopNatSpec(call otto.FunctionCall) otto.Value {
js.ethereum.NatSpec = false
return otto.TrueValue()
}
func (js *jsre) newRegistry(call otto.FunctionCall) otto.Value {
if len(call.ArgumentList) != 1 {
fmt.Println("requires 1 argument: admin.contractInfo.newRegistry(adminaddress)")
return otto.FalseValue()
}
addr, err := call.Argument(0).ToString()
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
registry := resolver.New(js.xeth)
err = registry.CreateContracts(common.HexToAddress(addr))
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}
// internal transaction type which will allow us to resend transactions using `eth.resend`
type tx struct {
tx *types.Transaction
To string
From string
Nonce string
Value string
Data string
GasLimit string
GasPrice string
}
func newTx(t *types.Transaction) *tx {
from, _ := t.From()
var to string
if t := t.To(); t != nil {
to = t.Hex()
}
return &tx{
tx: t,
To: to,
From: from.Hex(),
Value: t.Amount.String(),
Nonce: strconv.Itoa(int(t.Nonce())),
Data: "0x" + common.Bytes2Hex(t.Data()),
GasLimit: t.GasLimit.String(),
GasPrice: t.GasPrice().String(),
}
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/ethereum/go-ethereum/tests"
)
var blocktestCmd = cli.Command{
var blocktestCommand = cli.Command{
Action: runBlockTest,
Name: "blocktest",
Usage: `loads a block test file`,
@@ -86,6 +86,7 @@ func runBlockTest(ctx *cli.Context) {
}
func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, error) {
// TODO remove in favor of logic contained in tests package
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
cfg.NewDB = func(path string) (common.Database, error) { return ethdb.NewMemDatabase() }
cfg.MaxPeers = 0 // disable network
@@ -96,9 +97,9 @@ func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, er
if err != nil {
return nil, err
}
if err := ethereum.Start(); err != nil {
return nil, err
}
// if err := ethereum.Start(); err != nil {
// return nil, err
// }
// import the genesis block
ethereum.ResetWithGenesisBlock(test.Genesis)

183
cmd/geth/chaincmd.go Normal file
View File

@@ -0,0 +1,183 @@
package main
import (
"fmt"
"os"
"path/filepath"
"strconv"
"time"
"github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/logger/glog"
)
var (
importCommand = cli.Command{
Action: importChain,
Name: "import",
Usage: `import a blockchain file`,
}
exportCommand = cli.Command{
Action: exportChain,
Name: "export",
Usage: `export blockchain into file`,
Description: `
Requires a first argument of the file to write to.
Optional second and third arguments control the first and
last block to write. In this mode, the file will be appended
if already existing.
`,
}
upgradedbCommand = cli.Command{
Action: upgradeDB,
Name: "upgradedb",
Usage: "upgrade chainblock database",
}
removedbCommand = cli.Command{
Action: removeDB,
Name: "removedb",
Usage: "Remove blockchain and state databases",
}
dumpCommand = cli.Command{
Action: dump,
Name: "dump",
Usage: `dump a specific block from storage`,
Description: `
The arguments are interpreted as block numbers or hashes.
Use "ethereum dump 0" to dump the genesis block.
`,
}
)
func importChain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
chain, blockDB, stateDB, extraDB := utils.MakeChain(ctx)
start := time.Now()
err := utils.ImportChain(chain, ctx.Args().First())
closeAll(blockDB, stateDB, extraDB)
if err != nil {
utils.Fatalf("Import error: %v", err)
}
fmt.Printf("Import done in %v", time.Since(start))
}
func exportChain(ctx *cli.Context) {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
chain, _, _, _ := utils.MakeChain(ctx)
start := time.Now()
var err error
fp := ctx.Args().First()
if len(ctx.Args()) < 3 {
err = utils.ExportChain(chain, fp)
} else {
// This can be improved to allow for numbers larger than 9223372036854775807
first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64)
last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
if ferr != nil || lerr != nil {
utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
}
if first < 0 || last < 0 {
utils.Fatalf("Export error: block number must be greater than 0\n")
}
err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
}
if err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v", time.Since(start))
}
func removeDB(ctx *cli.Context) {
confirm, err := utils.PromptConfirm("Remove local databases?")
if err != nil {
utils.Fatalf("%v", err)
}
if confirm {
fmt.Println("Removing chain and state databases...")
start := time.Now()
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
fmt.Printf("Removed in %v\n", time.Since(start))
} else {
fmt.Println("Operation aborted")
}
}
func upgradeDB(ctx *cli.Context) {
glog.Infoln("Upgrading blockchain database")
chain, blockDB, stateDB, extraDB := utils.MakeChain(ctx)
v, _ := blockDB.Get([]byte("BlockchainVersion"))
bcVersion := int(common.NewValue(v).Uint())
if bcVersion == 0 {
bcVersion = core.BlockChainVersion
}
// Export the current chain.
filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405"))
exportFile := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename)
if err := utils.ExportChain(chain, exportFile); err != nil {
utils.Fatalf("Unable to export chain for reimport %s", err)
}
closeAll(blockDB, stateDB, extraDB)
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
// Import the chain file.
chain, blockDB, stateDB, extraDB = utils.MakeChain(ctx)
blockDB.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
err := utils.ImportChain(chain, exportFile)
closeAll(blockDB, stateDB, extraDB)
if err != nil {
utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
} else {
os.Remove(exportFile)
glog.Infoln("Import finished")
}
}
func dump(ctx *cli.Context) {
chain, _, stateDB, _ := utils.MakeChain(ctx)
for _, arg := range ctx.Args() {
var block *types.Block
if hashish(arg) {
block = chain.GetBlock(common.HexToHash(arg))
} else {
num, _ := strconv.Atoi(arg)
block = chain.GetBlockByNumber(uint64(num))
}
if block == nil {
fmt.Println("{}")
utils.Fatalf("block not found")
} else {
state := state.New(block.Root(), stateDB)
fmt.Printf("%s\n", state.Dump())
}
}
}
// hashish returns true for strings that look like hashes.
func hashish(x string) bool {
_, err := strconv.Atoi(x)
return err != nil
}
func closeAll(dbs ...common.Database) {
for _, db := range dbs {
db.Close()
}
}

View File

@@ -1 +1 @@
{"code":"605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056","info":{"abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"compilerVersion":"0.9.17","developerDoc":{"methods":{}},"language":"Solidity","languageVersion":"0","source":"contract test {\n /// @notice Will multiply `a` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply `a` by 7."}}}}}
{"code":"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056","info":{"abiDefinition":[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}],"compilerVersion":"0.9.23","developerDoc":{"methods":{}},"language":"Solidity","languageVersion":"0","source":"contract test {\n /// @notice Will multiply `a` by 7.\n function multiply(uint a) returns(uint d) {\n return a * 7;\n }\n}\n","userDoc":{"methods":{"multiply(uint256)":{"notice":"Will multiply `a` by 7."}}}}}

View File

@@ -22,9 +22,12 @@ import (
"fmt"
"math/big"
"os"
"os/signal"
"path/filepath"
"strings"
"sort"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/docserver"
@@ -32,9 +35,13 @@ import (
"github.com/ethereum/go-ethereum/eth"
re "github.com/ethereum/go-ethereum/jsre"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/xeth"
"github.com/peterh/liner"
"github.com/robertkrimen/otto"
"github.com/ethereum/go-ethereum/rpc/shared"
)
type prompter interface {
@@ -47,7 +54,8 @@ type dumbterm struct{ r *bufio.Reader }
func (r dumbterm) Prompt(p string) (string, error) {
fmt.Print(p)
return r.r.ReadString('\n')
line, err := r.r.ReadString('\n')
return strings.TrimSuffix(line, "\n"), err
}
func (r dumbterm) PasswordPrompt(p string) (string, error) {
@@ -68,23 +76,83 @@ type jsre struct {
ps1 string
atexit func()
corsDomain string
client comms.EthereumClient
prompter
}
func newJSRE(ethereum *eth.Ethereum, libPath, solcPath, corsDomain string, interactive bool, f xeth.Frontend) *jsre {
js := &jsre{ethereum: ethereum, ps1: "> "}
// set default cors domain used by startRpc from CLI flag
js.corsDomain = corsDomain
var (
loadedModulesMethods map[string][]string
)
func keywordCompleter(line string) []string {
results := make([]string, 0)
if strings.Contains(line, ".") {
elements := strings.Split(line, ".")
if len(elements) == 2 {
module := elements[0]
partialMethod := elements[1]
if methods, found := loadedModulesMethods[module]; found {
for _, method := range methods {
if strings.HasPrefix(method, partialMethod) { // e.g. debug.se
results = append(results, module+"."+method)
}
}
}
}
} else {
for module, methods := range loadedModulesMethods {
if line == module { // user typed in full module name, show all methods
for _, method := range methods {
results = append(results, module+"."+method)
}
} else if strings.HasPrefix(module, line) { // partial method name, e.g. admi
results = append(results, module)
}
}
}
return results
}
func apiWordCompleter(line string, pos int) (head string, completions []string, tail string) {
if len(line) == 0 {
return "", nil, ""
}
i := 0
for i = pos - 1; i > 0; i-- {
if line[i] == '.' || (line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') {
continue
}
if i >= 3 && line[i] == '3' && line[i-3] == 'w' && line[i-2] == 'e' && line[i-1] == 'b' {
continue
}
i += 1
break
}
begin := line[:i]
keyword := line[i:pos]
end := line[pos:]
completionWords := keywordCompleter(keyword)
return begin, completionWords, end
}
func newLightweightJSRE(libPath string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
js := &jsre{ps1: "> "}
js.wait = make(chan *big.Int)
js.client = client
if f == nil {
f = js
}
js.xeth = xeth.New(ethereum, f)
js.wait = js.xeth.UpdateState()
// update state in separare forever blocks
js.xeth.SetSolc(solcPath)
js.re = re.New(libPath)
js.apiBindings(f)
js.adminBindings()
if err := js.apiBindings(f); err != nil {
utils.Fatalf("Unable to initialize console - %v", err)
}
if !liner.TerminalSupported() || !interactive {
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
@@ -92,6 +160,9 @@ func newJSRE(ethereum *eth.Ethereum, libPath, solcPath, corsDomain string, inter
lr := liner.NewLiner()
js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) })
lr.SetCtrlCAborts(true)
js.loadAutoCompletion()
lr.SetWordCompleter(apiWordCompleter)
lr.SetTabCompletionStyle(liner.TabPrints)
js.prompter = lr
js.atexit = func() {
js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
@@ -102,25 +173,132 @@ func newJSRE(ethereum *eth.Ethereum, libPath, solcPath, corsDomain string, inter
return js
}
func (js *jsre) apiBindings(f xeth.Frontend) {
xe := xeth.New(js.ethereum, f)
ethApi := rpc.NewEthereumApi(xe)
jeth := rpc.NewJeth(ethApi, js.re.ToVal, js.re)
func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre {
js := &jsre{ethereum: ethereum, ps1: "> "}
// set default cors domain used by startRpc from CLI flag
js.corsDomain = corsDomain
if f == nil {
f = js
}
js.xeth = xeth.New(ethereum, f)
js.wait = js.xeth.UpdateState()
js.client = client
if clt, ok := js.client.(*comms.InProcClient); ok {
if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, ethereum); err == nil {
clt.Initialize(api.Merge(offeredApis...))
}
}
// update state in separare forever blocks
js.re = re.New(libPath)
if err := js.apiBindings(f); err != nil {
utils.Fatalf("Unable to connect - %v", err)
}
if !liner.TerminalSupported() || !interactive {
js.prompter = dumbterm{bufio.NewReader(os.Stdin)}
} else {
lr := liner.NewLiner()
js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) })
lr.SetCtrlCAborts(true)
js.loadAutoCompletion()
lr.SetWordCompleter(apiWordCompleter)
lr.SetTabCompletionStyle(liner.TabPrints)
js.prompter = lr
js.atexit = func() {
js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) })
lr.Close()
close(js.wait)
}
}
return js
}
func (self *jsre) loadAutoCompletion() {
if modules, err := self.supportedApis(); err == nil {
loadedModulesMethods = make(map[string][]string)
for module, _ := range modules {
loadedModulesMethods[module] = api.AutoCompletion[module]
}
}
}
func (self *jsre) batch(statement string) {
val, err := self.re.Run(statement)
if err != nil {
fmt.Printf("error: %v", err)
} else if val.IsDefined() && val.IsObject() {
obj, _ := self.re.Get("ret_result")
fmt.Printf("%v", obj)
} else if val.IsDefined() {
fmt.Printf("%v", val)
}
if self.atexit != nil {
self.atexit()
}
self.re.Stop(false)
}
// show summary of current geth instance
func (self *jsre) welcome() {
self.re.Eval(`console.log('instance: ' + web3.version.client);`)
self.re.Eval(`console.log(' datadir: ' + admin.datadir);`)
self.re.Eval(`console.log("coinbase: " + eth.coinbase);`)
self.re.Eval(`var lastBlockTimestamp = 1000 * eth.getBlock(eth.blockNumber).timestamp`)
self.re.Eval(`console.log("at block: " + eth.blockNumber + " (" + new Date(lastBlockTimestamp).toLocaleDateString()
+ " " + new Date(lastBlockTimestamp).toLocaleTimeString() + ")");`)
if modules, err := self.supportedApis(); err == nil {
loadedModules := make([]string, 0)
for api, version := range modules {
loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version))
}
sort.Strings(loadedModules)
self.re.Eval(fmt.Sprintf("var modules = '%s';", strings.Join(loadedModules, " ")))
self.re.Eval(`console.log(" modules: " + modules);`)
}
}
func (self *jsre) supportedApis() (map[string]string, error) {
return self.client.SupportedModules()
}
func (js *jsre) apiBindings(f xeth.Frontend) error {
apis, err := js.supportedApis()
if err != nil {
return err
}
apiNames := make([]string, 0, len(apis))
for a, _ := range apis {
apiNames = append(apiNames, a)
}
apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.ethereum)
if err != nil {
utils.Fatalf("Unable to determine supported api's: %v", err)
}
jeth := rpc.NewJeth(api.Merge(apiImpl...), js.re, js.client)
js.re.Set("jeth", struct{}{})
t, _ := js.re.Get("jeth")
jethObj := t.Object()
jethObj.Set("send", jeth.Send)
jethObj.Set("sendAsync", jeth.Send)
err := js.re.Compile("bignumber.js", re.BigNumber_JS)
err = js.re.Compile("bignumber.js", re.BigNumber_JS)
if err != nil {
utils.Fatalf("Error loading bignumber.js: %v", err)
}
err = js.re.Compile("ethereum.js", re.Ethereum_JS)
err = js.re.Compile("ethereum.js", re.Web3_JS)
if err != nil {
utils.Fatalf("Error loading ethereum.js: %v", err)
utils.Fatalf("Error loading web3.js: %v", err)
}
_, err = js.re.Eval("var web3 = require('web3');")
@@ -132,17 +310,29 @@ func (js *jsre) apiBindings(f xeth.Frontend) {
if err != nil {
utils.Fatalf("Error setting web3 provider: %v", err)
}
_, err = js.re.Eval(`
var eth = web3.eth;
var shh = web3.shh;
var db = web3.db;
var net = web3.net;
`)
// load only supported API's in javascript runtime
shortcuts := "var eth = web3.eth; "
for _, apiName := range apiNames {
if apiName == shared.Web3ApiName {
continue // manually mapped
}
if err = js.re.Compile(fmt.Sprintf("%s.js", apiName), api.Javascript(apiName)); err == nil {
shortcuts += fmt.Sprintf("var %s = web3.%s; ", apiName, apiName)
} else {
utils.Fatalf("Error loading %s.js: %v", apiName, err)
}
}
_, err = js.re.Eval(shortcuts)
if err != nil {
utils.Fatalf("Error setting namespaces: %v", err)
}
js.re.Eval(globalRegistrar + "registrar = new GlobalRegistrar(\"" + globalRegistrarAddr + "\");")
js.re.Eval(globalRegistrar + "registrar = GlobalRegistrar.at(\"" + globalRegistrarAddr + "\");")
return nil
}
var ds, _ = docserver.New("/")
@@ -183,34 +373,61 @@ func (self *jsre) exec(filename string) error {
}
func (self *jsre) interactive() {
for {
input, err := self.Prompt(self.ps1)
if err != nil {
break
}
if input == "" {
continue
}
str += input + "\n"
self.setIndent()
if indentCount <= 0 {
if input == "exit" {
break
// Read input lines.
prompt := make(chan string)
inputln := make(chan string)
go func() {
defer close(inputln)
for {
line, err := self.Prompt(<-prompt)
if err != nil {
return
}
inputln <- line
}
}()
// Wait for Ctrl-C, too.
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
defer func() {
if self.atexit != nil {
self.atexit()
}
self.re.Stop(false)
}()
for {
prompt <- self.ps1
select {
case <-sig:
fmt.Println("caught interrupt, exiting")
return
case input, ok := <-inputln:
if !ok || indentCount <= 0 && input == "exit" {
return
}
if input == "" {
continue
}
str += input + "\n"
self.setIndent()
if indentCount <= 0 {
hist := str[:len(str)-1]
self.AppendHistory(hist)
self.parseInput(str)
str = ""
}
hist := str[:len(str)-1]
self.AppendHistory(hist)
self.parseInput(str)
str = ""
}
}
if self.atexit != nil {
self.atexit()
}
self.re.Stop(false)
}
func (self *jsre) withHistory(op func(*os.File)) {
hist, err := os.OpenFile(filepath.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
datadir := common.DefaultDataDir()
if self.ethereum != nil {
datadir = self.ethereum.DataDir
}
hist, err := os.OpenFile(filepath.Join(datadir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
fmt.Printf("unable to open history file: %v\n", err)
return

View File

@@ -20,11 +20,13 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/codec"
)
const (
testSolcPath = ""
solcVersion = "0.9.17"
solcVersion = "0.9.23"
testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674"
testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182"
@@ -34,6 +36,8 @@ const (
)
var (
versionRE = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`))
testNodeKey = crypto.ToECDSA(common.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f"))
testGenesis = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}`
)
@@ -66,15 +70,17 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
}
// set up mock genesis with balance on the testAddress
core.GenesisData = []byte(testGenesis)
core.GenesisAccounts = []byte(testGenesis)
ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore"))
am := accounts.NewManager(ks)
ethereum, err := eth.New(&eth.Config{
NodeKey: testNodeKey,
DataDir: tmp,
AccountManager: am,
MaxPeers: 0,
Name: "test",
SolcPath: testSolcPath,
})
if err != nil {
t.Fatal("%v", err)
@@ -101,7 +107,8 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
t.Errorf("Error creating DocServer: %v", err)
}
tf := &testjethre{ds: ds, stateDb: ethereum.ChainManager().State().Copy()}
repl := newJSRE(ethereum, assetPath, testSolcPath, "", false, tf)
client := comms.NewInProcClient(codec.JSON)
repl := newJSRE(ethereum, assetPath, "", client, false, tf)
tf.jsre = repl
return tmp, tf, ethereum
}
@@ -120,8 +127,8 @@ func TestNodeInfo(t *testing.T) {
}
defer ethereum.Stop()
defer os.RemoveAll(tmp)
want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","NodeUrl":"enode://00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000@0.0.0.0:0","TCPPort":0,"Td":"0"}`
checkEvalJSON(t, repl, `admin.nodeInfo()`, want)
want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5","NodeUrl":"enode://4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5@0.0.0.0:0","TCPPort":0,"Td":"131072"}`
checkEvalJSON(t, repl, `admin.nodeInfo`, want)
}
func TestAccounts(t *testing.T) {
@@ -135,7 +142,7 @@ func TestAccounts(t *testing.T) {
checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`)
val, err := repl.re.Run(`admin.newAccount("password")`)
val, err := repl.re.Run(`personal.newAccount("password")`)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
@@ -157,7 +164,7 @@ func TestBlockChain(t *testing.T) {
defer ethereum.Stop()
defer os.RemoveAll(tmp)
// get current block dump before export/import.
val, err := repl.re.Run("JSON.stringify(admin.debug.dumpBlock())")
val, err := repl.re.Run("JSON.stringify(debug.dumpBlock(eth.blockNumber))")
if err != nil {
t.Errorf("expected no error, got %v", err)
}
@@ -172,14 +179,16 @@ func TestBlockChain(t *testing.T) {
tmpfile := filepath.Join(extmp, "export.chain")
tmpfileq := strconv.Quote(tmpfile)
checkEvalJSON(t, repl, `admin.export(`+tmpfileq+`)`, `true`)
ethereum.ChainManager().Reset()
checkEvalJSON(t, repl, `admin.exportChain(`+tmpfileq+`)`, `true`)
if _, err := os.Stat(tmpfile); err != nil {
t.Fatal(err)
}
// check import, verify that dumpBlock gives the same result.
checkEvalJSON(t, repl, `admin.import(`+tmpfileq+`)`, `true`)
checkEvalJSON(t, repl, `admin.debug.dumpBlock()`, beforeExport)
checkEvalJSON(t, repl, `admin.importChain(`+tmpfileq+`)`, `true`)
checkEvalJSON(t, repl, `debug.dumpBlock(eth.blockNumber)`, beforeExport)
}
func TestMining(t *testing.T) {
@@ -201,10 +210,13 @@ func TestRPC(t *testing.T) {
defer ethereum.Stop()
defer os.RemoveAll(tmp)
checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004)`, `true`)
checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004, "*", "web3,eth,net")`, `true`)
}
func TestCheckTestAccountBalance(t *testing.T) {
t.Skip() // i don't think it tests the correct behaviour here. it's actually testing
// internals which shouldn't be tested. This now fails because of a change in the core
// and i have no means to fix this, sorry - @obscuren
tmp, repl, ethereum := testJEthRE(t)
if err := ethereum.Start(); err != nil {
t.Errorf("error starting ethereum: %v", err)
@@ -226,11 +238,11 @@ func TestSignature(t *testing.T) {
defer ethereum.Stop()
defer os.RemoveAll(tmp)
val, err := repl.re.Run(`eth.sign({from: "` + testAddress + `", data: "` + testHash + `"})`)
val, err := repl.re.Run(`eth.sign("` + testAddress + `", "` + testHash + `")`)
// This is a very preliminary test, lacking actual signature verification
if err != nil {
t.Errorf("Error runnig js: %v", err)
t.Errorf("Error running js: %v", err)
return
}
output := val.String()
@@ -245,7 +257,6 @@ func TestSignature(t *testing.T) {
func TestContract(t *testing.T) {
t.Skip()
tmp, repl, ethereum := testJEthRE(t)
if err := ethereum.Start(); err != nil {
t.Errorf("error starting ethereum: %v", err)
@@ -257,7 +268,9 @@ func TestContract(t *testing.T) {
var txc uint64
coinbase := common.HexToAddress(testAddress)
resolver.New(repl.xeth).CreateContracts(coinbase)
// time.Sleep(1000 * time.Millisecond)
// checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `2`)
source := `contract test {\n` +
" /// @notice Will multiply `a` by 7." + `\n` +
` function multiply(uint a) returns(uint d) {\n` +
@@ -277,10 +290,9 @@ func TestContract(t *testing.T) {
// if solc is found with right version, test it, otherwise read from file
sol, err := compiler.New("")
if err != nil {
t.Logf("solc not found: skipping compiler test")
t.Logf("solc not found: mocking contract compilation step")
} else if sol.Version() != solcVersion {
err = fmt.Errorf("solc wrong version found (%v, expect %v): skipping compiler test", sol.Version(), solcVersion)
t.Log(err)
t.Logf("WARNING: solc different version found (%v, test written for %v, may need to update)", sol.Version(), solcVersion)
}
if err != nil {
@@ -293,10 +305,10 @@ func TestContract(t *testing.T) {
t.Errorf("%v", err)
}
} else {
checkEvalJSON(t, repl, `contract = eth.compile.solidity(source)`, string(contractInfo))
checkEvalJSON(t, repl, `contract = eth.compile.solidity(source).test`, string(contractInfo))
}
checkEvalJSON(t, repl, `contract.code`, `"605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056"`)
checkEvalJSON(t, repl, `contract.code`, `"0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"`)
checkEvalJSON(
t, repl,
@@ -306,15 +318,16 @@ func TestContract(t *testing.T) {
callSetup := `abiDef = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]');
Multiply7 = eth.contract(abiDef);
multiply7 = new Multiply7(contractaddress);
multiply7 = Multiply7.at(contractaddress);
`
// time.Sleep(1500 * time.Millisecond)
_, err = repl.re.Run(callSetup)
if err != nil {
t.Errorf("unexpected error registering, got %v", err)
t.Errorf("unexpected error setting up contract, got %v", err)
}
// updatespec
// checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `3`)
// why is this sometimes failing?
// checkEvalJSON(t, repl, `multiply7.multiply.call(6)`, `42`)
expNotice := ""
@@ -322,20 +335,23 @@ multiply7 = new Multiply7(contractaddress);
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
}
// why 0?
checkEvalJSON(t, repl, `eth.getBlock("pending", true).transactions.length`, `0`)
txc, repl.xeth = repl.xeth.ApplyTestTxs(repl.stateDb, coinbase, txc)
checkEvalJSON(t, repl, `admin.contractInfo.start()`, `true`)
checkEvalJSON(t, repl, `multiply7.multiply.sendTransaction(6, { from: primary, gas: "1000000", gasPrice: "100000" })`, `undefined`)
expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x4a6c99e127191d2ee302e42182c338344b39a37a47cdbb17ab0f26b6802eb4d1'): {"params":[{"to":"0x5dcaace5982778b409c524873b319667eba5d074","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}`
expNotice = `About to submit transaction (no NatSpec info found for contract: content hash not found for '0x87e2802265838c7f14bb69eecd2112911af6767907a702eeaa445239fb20711b'): {"params":[{"to":"0x5dcaace5982778b409c524873b319667eba5d074","data": "0xc6888fa10000000000000000000000000000000000000000000000000000000000000006"}]}`
if repl.lastConfirm != expNotice {
t.Errorf("incorrect confirmation message: expected %v, got %v", expNotice, repl.lastConfirm)
}
var contenthash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"`
if sol != nil {
modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"`+sol.Version()+`"`))
_ = modContractInfo
// contenthash = crypto.Sha3(modContractInfo)
}
checkEvalJSON(t, repl, `filename = "/tmp/info.json"`, `"/tmp/info.json"`)
checkEvalJSON(t, repl, `contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename)`, `"0x0d067e2dd99a4d8f0c0279738b17130dd415a89f24a23f0e7cf68c546ae3089d"`)
checkEvalJSON(t, repl, `contenthash = admin.contractInfo.register(primary, contractaddress, contract, filename)`, contenthash)
checkEvalJSON(t, repl, `admin.contractInfo.registerUrl(primary, contenthash, "file://"+filename)`, `true`)
if err != nil {
t.Errorf("unexpected error registering, got %v", err)

View File

@@ -21,36 +21,32 @@
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
_ "net/http/pprof"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"github.com/codegangsta/cli"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
"github.com/peterh/liner"
)
import _ "net/http/pprof"
const (
ClientIdentifier = "Geth"
Version = "0.9.21.1"
Version = "0.9.32"
)
var (
@@ -70,7 +66,12 @@ func init() {
app.Action = run
app.HideVersion = true // we have a command to print the version
app.Commands = []cli.Command{
blocktestCmd,
blocktestCommand,
importCommand,
exportCommand,
upgradedbCommand,
removedbCommand,
dumpCommand,
{
Action: makedag,
Name: "makedag",
@@ -101,7 +102,15 @@ The output of this command is supposed to be machine-readable.
Usage: "import ethereum presale wallet",
},
},
},
Description: `
get wallet import /path/to/my/presale.wallet
will prompt for your password and imports your ether presale account.
It can be used non-interactively with the --password option taking a
passwordfile as argument containing the wallet password in plaintext.
`},
{
Action: accountList,
Name: "account",
@@ -111,7 +120,7 @@ The output of this command is supposed to be machine-readable.
Manage accounts lets you create new accounts, list all existing accounts,
import a private key into a new account.
'account help' shows a list of subcommands or help for one subcommand.
' help' shows a list of subcommands or help for one subcommand.
It supports interactive mode, when you are prompted for password as well as
non-interactive mode where passwords are supplied via a given password file.
@@ -187,15 +196,6 @@ nodes.
},
},
},
{
Action: dump,
Name: "dump",
Usage: `dump a specific block from storage`,
Description: `
The arguments are interpreted as block numbers or hashes.
Use "ethereum dump 0" to dump the genesis block.
`,
},
{
Action: console,
Name: "console",
@@ -204,6 +204,16 @@ Use "ethereum dump 0" to dump the genesis block.
The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
`},
{
Action: attach,
Name: "attach",
Usage: `Geth Console: interactive JavaScript environment (connect to node)`,
Description: `
The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.
This command allows to open a console on a running geth node.
`,
},
{
@@ -215,26 +225,12 @@ The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
`,
},
{
Action: importchain,
Name: "import",
Usage: `import a blockchain file`,
},
{
Action: exportchain,
Name: "export",
Usage: `export blockchain into file`,
},
{
Action: upgradeDb,
Name: "upgradedb",
Usage: "upgrade chainblock database",
},
}
app.Flags = []cli.Flag{
utils.IdentityFlag,
utils.UnlockedAccountFlag,
utils.PasswordFileFlag,
utils.GenesisNonceFlag,
utils.BootnodesFlag,
utils.DataDirFlag,
utils.BlockchainVersionFlag,
@@ -246,13 +242,20 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
utils.GasPriceFlag,
utils.MinerThreadsFlag,
utils.MiningEnabledFlag,
utils.AutoDAGFlag,
utils.NATFlag,
utils.NatspecEnabledFlag,
utils.NoDiscoverFlag,
utils.NodeKeyFileFlag,
utils.NodeKeyHexFlag,
utils.RPCEnabledFlag,
utils.RPCListenAddrFlag,
utils.RPCPortFlag,
utils.RpcApiFlag,
utils.IPCDisabledFlag,
utils.IPCApiFlag,
utils.IPCPathFlag,
utils.ExecFlag,
utils.WhisperEnabledFlag,
utils.VMDebugFlag,
utils.ProtocolVersionFlag,
@@ -267,19 +270,20 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
utils.PProfEanbledFlag,
utils.PProfPortFlag,
utils.SolcPathFlag,
utils.GpoMinGasPriceFlag,
utils.GpoMaxGasPriceFlag,
utils.GpoFullBlockRatioFlag,
utils.GpobaseStepDownFlag,
utils.GpobaseStepUpFlag,
utils.GpobaseCorrectionFactorFlag,
}
app.Before = func(ctx *cli.Context) error {
utils.SetupLogger(ctx)
if ctx.GlobalBool(utils.PProfEanbledFlag.Name) {
utils.StartPProf(ctx)
}
return nil
}
// missing:
// flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
// flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
// flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
}
func main() {
@@ -304,6 +308,44 @@ func run(ctx *cli.Context) {
ethereum.WaitForShutdown()
}
func attach(ctx *cli.Context) {
// Wrap the standard output with a colorified stream (windows)
if isatty.IsTerminal(os.Stdout.Fd()) {
if pr, pw, err := os.Pipe(); err == nil {
go io.Copy(colorable.NewColorableStdout(), pr)
os.Stdout = pw
}
}
var client comms.EthereumClient
var err error
if ctx.Args().Present() {
client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON)
} else {
cfg := comms.IpcConfig{
Endpoint: ctx.GlobalString(utils.IPCPathFlag.Name),
}
client, err = comms.NewIpcClient(cfg, codec.JSON)
}
if err != nil {
utils.Fatalf("Unable to attach to geth node - %v", err)
}
repl := newLightweightJSRE(
ctx.GlobalString(utils.JSpathFlag.Name),
client,
true,
nil)
if ctx.GlobalString(utils.ExecFlag.Name) != "" {
repl.batch(ctx.GlobalString(utils.ExecFlag.Name))
} else {
repl.welcome()
repl.interactive()
}
}
func console(ctx *cli.Context) {
// Wrap the standard output with a colorified stream (windows)
if isatty.IsTerminal(os.Stdout.Fd()) {
@@ -319,16 +361,24 @@ func console(ctx *cli.Context) {
utils.Fatalf("%v", err)
}
client := comms.NewInProcClient(codec.JSON)
startEth(ctx, ethereum)
repl := newJSRE(
ethereum,
ctx.String(utils.JSpathFlag.Name),
ctx.String(utils.SolcPathFlag.Name),
ctx.GlobalString(utils.JSpathFlag.Name),
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
client,
true,
nil,
)
repl.interactive()
if ctx.GlobalString(utils.ExecFlag.Name) != "" {
repl.batch(ctx.GlobalString(utils.ExecFlag.Name))
} else {
repl.welcome()
repl.interactive()
}
ethereum.Stop()
ethereum.WaitForShutdown()
@@ -341,12 +391,13 @@ func execJSFiles(ctx *cli.Context) {
utils.Fatalf("%v", err)
}
client := comms.NewInProcClient(codec.JSON)
startEth(ctx, ethereum)
repl := newJSRE(
ethereum,
ctx.String(utils.JSpathFlag.Name),
ctx.String(utils.SolcPathFlag.Name),
ctx.GlobalString(utils.JSpathFlag.Name),
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
client,
false,
nil,
)
@@ -361,12 +412,20 @@ func execJSFiles(ctx *cli.Context) {
func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) {
var err error
// Load startup keys. XXX we are going to need a different format
// Attempt to unlock the account
passphrase = getPassPhrase(ctx, "", false)
if len(account) == 0 {
if !((len(account) == 40) || (len(account) == 42)) { // with or without 0x
utils.Fatalf("Invalid account address '%s'", account)
}
err = am.Unlock(common.HexToAddress(account), passphrase)
// Attempt to unlock the account 3 times
attempts := 3
for tries := 0; tries < attempts; tries++ {
msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", account, tries+1, attempts)
passphrase = getPassPhrase(ctx, msg, false)
err = am.Unlock(common.HexToAddress(account), passphrase)
if err == nil {
break
}
}
if err != nil {
utils.Fatalf("Unlock account failed '%v'", err)
}
@@ -381,17 +440,25 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
am := eth.AccountManager()
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
if len(account) > 0 {
if account == "primary" {
primaryAcc, err := am.Primary()
if err != nil {
utils.Fatalf("no primary account: %v", err)
accounts := strings.Split(account, " ")
for _, account := range accounts {
if len(account) > 0 {
if account == "primary" {
primaryAcc, err := am.Primary()
if err != nil {
utils.Fatalf("no primary account: %v", err)
}
account = primaryAcc.Hex()
}
account = primaryAcc.Hex()
unlockAccount(ctx, am, account)
}
unlockAccount(ctx, am, account)
}
// Start auxiliary services if enabled.
if !ctx.GlobalBool(utils.IPCDisabledFlag.Name) {
if err := utils.StartIPC(eth, ctx); err != nil {
utils.Fatalf("Error string IPC: %v", err)
}
}
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
if err := utils.StartRPC(eth, ctx); err != nil {
utils.Fatalf("Error starting RPC: %v", err)
@@ -405,7 +472,7 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
}
func accountList(ctx *cli.Context) {
am := utils.GetAccountManager(ctx)
am := utils.MakeAccountManager(ctx)
accts, err := am.Accounts()
if err != nil {
utils.Fatalf("Could not list accounts: %v", err)
@@ -421,12 +488,12 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
if len(passfile) == 0 {
fmt.Println(desc)
auth, err := readPassword("Passphrase: ", true)
auth, err := utils.PromptPassword("Passphrase: ", true)
if err != nil {
utils.Fatalf("%v", err)
}
if confirmation {
confirm, err := readPassword("Repeat Passphrase: ", false)
confirm, err := utils.PromptPassword("Repeat Passphrase: ", false)
if err != nil {
utils.Fatalf("%v", err)
}
@@ -447,7 +514,7 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase
}
func accountCreate(ctx *cli.Context) {
am := utils.GetAccountManager(ctx)
am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
acct, err := am.NewAccount(passphrase)
if err != nil {
@@ -466,7 +533,7 @@ func importWallet(ctx *cli.Context) {
utils.Fatalf("Could not read wallet file: %v", err)
}
am := utils.GetAccountManager(ctx)
am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "", false)
acct, err := am.ImportPreSaleKey(keyJson, passphrase)
@@ -481,7 +548,7 @@ func accountImport(ctx *cli.Context) {
if len(keyfile) == 0 {
utils.Fatalf("keyfile must be given as argument")
}
am := utils.GetAccountManager(ctx)
am := utils.MakeAccountManager(ctx)
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
acct, err := am.Import(keyfile, passphrase)
if err != nil {
@@ -490,133 +557,6 @@ func accountImport(ctx *cli.Context) {
fmt.Printf("Address: %x\n", acct)
}
func importchain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
cfg.SkipBcVersionCheck = true
ethereum, err := eth.New(cfg)
if err != nil {
utils.Fatalf("%v\n", err)
}
chainmgr := ethereum.ChainManager()
start := time.Now()
err = utils.ImportChain(chainmgr, ctx.Args().First())
if err != nil {
utils.Fatalf("Import error: %v\n", err)
}
// force database flush
ethereum.BlockDb().Close()
ethereum.StateDb().Close()
ethereum.ExtraDb().Close()
fmt.Printf("Import done in %v", time.Since(start))
return
}
func exportchain(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
utils.Fatalf("This command requires an argument.")
}
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
cfg.SkipBcVersionCheck = true
ethereum, err := eth.New(cfg)
if err != nil {
utils.Fatalf("%v\n", err)
}
chainmgr := ethereum.ChainManager()
start := time.Now()
err = utils.ExportChain(chainmgr, ctx.Args().First())
if err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v", time.Since(start))
return
}
func upgradeDb(ctx *cli.Context) {
fmt.Println("Upgrade blockchain DB")
cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx)
cfg.SkipBcVersionCheck = true
ethereum, err := eth.New(cfg)
if err != nil {
utils.Fatalf("%v\n", err)
}
v, _ := ethereum.BlockDb().Get([]byte("BlockchainVersion"))
bcVersion := int(common.NewValue(v).Uint())
if bcVersion == 0 {
bcVersion = core.BlockChainVersion
}
filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405"))
exportFile := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename)
err = utils.ExportChain(ethereum.ChainManager(), exportFile)
if err != nil {
utils.Fatalf("Unable to export chain for reimport %s\n", err)
}
ethereum.BlockDb().Close()
ethereum.StateDb().Close()
ethereum.ExtraDb().Close()
os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
ethereum, err = eth.New(cfg)
if err != nil {
utils.Fatalf("%v\n", err)
}
ethereum.BlockDb().Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
err = utils.ImportChain(ethereum.ChainManager(), exportFile)
if err != nil {
utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)\n", err, exportFile)
}
// force database flush
ethereum.BlockDb().Close()
ethereum.StateDb().Close()
ethereum.ExtraDb().Close()
os.Remove(exportFile)
fmt.Println("Import finished")
}
func dump(ctx *cli.Context) {
chainmgr, _, stateDb := utils.GetChain(ctx)
for _, arg := range ctx.Args() {
var block *types.Block
if hashish(arg) {
block = chainmgr.GetBlock(common.HexToHash(arg))
} else {
num, _ := strconv.Atoi(arg)
block = chainmgr.GetBlockByNumber(uint64(num))
}
if block == nil {
fmt.Println("{}")
utils.Fatalf("block not found")
} else {
statedb := state.New(block.Root(), stateDb)
fmt.Printf("%s\n", statedb.Dump())
}
}
}
func makedag(ctx *cli.Context) {
args := ctx.Args()
wrongArgs := func() {
@@ -659,24 +599,3 @@ func version(c *cli.Context) {
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
}
// hashish returns true for strings that look like hashes.
func hashish(x string) bool {
_, err := strconv.Atoi(x)
return err != nil
}
func readPassword(prompt string, warnTerm bool) (string, error) {
if liner.TerminalSupported() {
lr := liner.NewLiner()
defer lr.Close()
return lr.PasswordPrompt(prompt)
}
if warnTerm {
fmt.Println("!! Unsupported terminal, password will be echoed.")
}
fmt.Print(prompt)
input, err := bufio.NewReader(os.Stdin).ReadString('\n')
fmt.Println()
return input, err
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

View File

@@ -1,436 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
ApplicationWindow {
id: win
visible: false
title: "IceCREAM"
minimumWidth: 1280
minimumHeight: 700
width: 1290
height: 750
property alias codeText: codeEditor.text
property alias dataText: rawDataField.text
onClosing: {
//dbg.Stop()
}
menuBar: MenuBar {
Menu {
title: "Edit"
MenuItem {
text: "Focus code"
shortcut: "Ctrl+1"
onTriggered: {
codeEditor.focus = true
}
}
MenuItem {
text: "Focus data"
shortcut: "Ctrl+2"
onTriggered: {
rawDataField.focus = true
}
}
MenuItem {
text: "Command"
shortcut: "Ctrl+l"
onTriggered: {
dbgCommand.focus = true
}
}
}
Menu {
title: "Debugger"
MenuItem {
text: "Run"
shortcut: "Ctrl+r"
onTriggered: debugCurrent()
}
MenuItem {
text: "Stop"
onTriggered: dbp.stop()
}
MenuSeparator {}
MenuItem {
text: "Next"
shortcut: "Ctrl+n"
onTriggered: dbg.next()
}
MenuItem {
text: "Continue"
shortcut: "Ctrl+g"
onTriggered: dbg.continue()
}
}
}
SplitView {
anchors.fill: parent
property var asmModel: ListModel {
id: asmModel
}
TableView {
id: asmTableView
width: 200
headerVisible: false
TableViewColumn{ role: "value" ; title: "" ; width: asmTableView.width - 2 }
model: asmModel
/*
alternatingRowColors: false
itemDelegate: Item {
Rectangle {
anchors.fill: parent
color: "#DDD"
Text {
anchors {
left: parent.left
right: parent.right
leftMargin: 10
verticalCenter: parent.verticalCenter
}
color: "#333"
elide: styleData.elideMode
text: styleData.value
font.pixelSize: 11
MouseArea {
acceptedButtons: Qt.LeftButton
anchors.fill: parent
onClicked: {
mouse.accepted = true
}
}
}
}
}
*/
}
Rectangle {
color: "#00000000"
anchors.left: asmTableView.right
anchors.right: parent.right
SplitView {
orientation: Qt.Vertical
anchors.fill: parent
Rectangle {
color: "#00000000"
height: 330
anchors.left: parent.left
anchors.right: parent.right
TextArea {
id: codeEditor
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: settings.left
focus: true
/*
Timer {
id: compileTimer
interval: 500 ; running: true ; repeat: true
onTriggered: {
dbg.autoComp(codeEditor.text)
}
}
*/
}
Column {
id: settings
spacing: 5
width: 300
height: parent.height
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
Label {
text: "Arbitrary data"
}
TextArea {
id: rawDataField
anchors.left: parent.left
anchors.right: parent.right
height: 150
}
Label {
text: "Amount"
}
TextField {
id: txValue
width: 200
placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ }
}
Label {
text: "Amount of gas"
}
TextField {
id: txGas
width: 200
validator: RegExpValidator { regExp: /\d*/ }
text: "10000"
placeholderText: "Gas"
}
Label {
text: "Gas price"
}
TextField {
id: txGasPrice
width: 200
placeholderText: "Gas price"
text: "1000000000000"
validator: RegExpValidator { regExp: /\d*/ }
}
}
}
SplitView {
orientation: Qt.Vertical
id: inspectorPane
height: 500
SplitView {
orientation: Qt.Horizontal
height: 150
TableView {
id: stackTableView
property var stackModel: ListModel {
id: stackModel
}
height: parent.height
width: 300
TableViewColumn{ role: "value" ; title: "Local VM stack" ; width: stackTableView.width - 2 }
model: stackModel
}
TableView {
id: memoryTableView
property var memModel: ListModel {
id: memModel
}
height: parent.height
width: parent.width - stackTableView.width
TableViewColumn{ id:mnumColmn ; role: "num" ; title: "#" ; width: 50 }
TableViewColumn{ role: "value" ; title: "Memory" ; width: 650 }
model: memModel
}
}
Rectangle {
height: 100
width: parent.width
TableView {
id: storageTableView
property var memModel: ListModel {
id: storageModel
}
height: parent.height
width: parent.width
TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2 - 1}
TableViewColumn{ role: "value" ; title: "Storage" ; width: storageTableView.width / 2 - 1}
model: storageModel
}
}
Rectangle {
height: 200
width: parent.width * 0.66
TableView {
id: logTableView
property var logModel: ListModel {
id: logModel
}
height: parent.height
width: parent.width
TableViewColumn{ id: message ; role: "message" ; title: "log" ; width: logTableView.width - 2 }
model: logModel
}
}
}
}
}
}
function exec() {
dbg.execCommand(dbgCommand.text);
dbgCommand.text = "";
}
statusBar: StatusBar {
height: 30
TextField {
id: dbgCommand
y: 1
x: asmTableView.width
width: 500
placeholderText: "Debugger (type 'help')"
Keys.onReturnPressed: {
exec()
}
}
RowLayout {
anchors.left: dbgCommand.right
anchors.leftMargin: 10
spacing: 5
y: parent.height / 2 - this.height / 2
Text {
objectName: "stackFrame"
font.pixelSize: 10
text: "<b>stack ptr</b>: 0"
}
Text {
objectName: "stackSize"
font.pixelSize: 10
text: "<b>stack size</b>: 0"
}
Text {
objectName: "memSize"
font.pixelSize: 10
text: "<b>mem size</b>: 0"
}
}
}
toolBar: ToolBar {
height: 30
RowLayout {
spacing: 10
Button {
property var enabled: true
id: debugStart
onClicked: {
debugCurrent()
}
text: "Debug"
}
Button {
property var enabled: true
id: debugNextButton
onClicked: {
dbg.next()
}
text: "Next"
}
Button {
id: debugContinueButton
onClicked: {
dbg.continue()
}
text: "Continue"
}
}
ComboBox {
visible: false
id: snippets
anchors.right: parent.right
model: ListModel {
ListElement { text: "Snippets" ; value: "" }
ListElement { text: "Call Contract" ; value: "var[2] in = { \"arg1\", 0xdeadbeef };\nvar ret;\n\nvar success = call(0x0c542ddea93dae0c2fcb2cf175f03ad80d6be9a0, 0, 7000, in, ret)\n\nreturn ret" }
}
onCurrentIndexChanged: {
if(currentIndex != 0) {
var code = snippets.model.get(currentIndex).value;
codeEditor.insert(codeEditor.cursorPosition, code)
}
}
}
}
function debugCurrent() {
dbg.debug(txValue.text, txGas.text, txGasPrice.text, codeEditor.text, rawDataField.text)
}
function setAsm(asm) {
asmModel.append({asm: asm})
}
function clearAsm() {
asmModel.clear()
}
function setInstruction(num) {
asmTableView.selection.clear()
asmTableView.selection.select(num)
asmTableView.positionViewAtRow(num, ListView.Center)
}
function setMem(mem) {
memModel.append({num: mem.num, value: mem.value})
}
function clearMem(){
memModel.clear()
}
function setStack(stack) {
stackModel.append({value: stack})
}
function addDebugMessage(message){
debuggerLog.append({value: message})
}
function clearStack() {
stackModel.clear()
}
function clearStorage() {
storageModel.clear()
}
function setStorage(storage) {
storageModel.append({key: storage.key, value: storage.value})
}
function setLog(msg) {
// Remove first item once we've reached max log items
if(logModel.count > 250) {
logModel.remove(0)
}
if(msg.len != 0) {
if(logTableView.flickableItem.atYEnd) {
logModel.append({message: msg})
logTableView.positionViewAtRow(logTableView.rowCount - 1, ListView.Contain)
} else {
logModel.append({message: msg})
}
}
}
function clearLog() {
logModel.clear()
}
}

View File

@@ -1,55 +0,0 @@
<!doctype>
<html>
<head>
<title>Hello world</title>
<script src="../ext/bignumber.min.js"></script>
<script src="../ext/ethereum.js/dist/ethereum.js"></script>
<script>
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
var eth = web3.eth;
var desc = [{
"name": "multiply(uint256)",
"inputs": [{
"name": "a",
"type": "uint256"
}],
"outputs": [{
"name": "d",
"type": "uint256"
}]
}];
var address = web3.eth.transact({
data: "0x603880600c6000396000f3006001600060e060020a600035048063c6888fa114601857005b6021600435602b565b8060005260206000f35b600081600702905091905056",
gasPrice: "1000000000000000",
gas: "10000",
});
var contract = web3.eth.contract(address, desc);
function calculate() {
var param = parseInt(document.getElementById('value').value);
var res = contract.call().multiply(param);
document.getElementById('result').innerText = res.toString(10);
}
</script>
</head>
<body>
<h3>Contract content</h3>
<textarea style="height:100px; width: 300px;" disabled="disabled">
contract test {
function multiply(uint a) returns(uint d) {
return a * 7;
}
}
</textarea>
<code><pre>
603880600c6000396000f3006001600060e060020a600035048063c6888fa1140
05b6021600435602b565b8060005260206000f35b600081600702905091905056</pre></code>
<hr>
<div>7 x <input type="number" id="value" onkeyup='calculate()'></input> =
<span id="result"></spa>
</body>
</html>

View File

@@ -1,40 +0,0 @@
<!doctype>
<html>
<head>
<script src="../ext/bignumber.min.js"></script>
<script src="../ext/ethereum.js/dist/ethereum.js"></script>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
function watchBalance() {
var coinbase = web3.eth.coinbase;
var originalBalance = 0;
var balance = web3.eth.balanceAt(coinbase);
var originalBalance = web3.toDecimal(balance);
document.getElementById('original').innerText = 'original balance: ' + originalBalance + ' watching...';
web3.eth.watch({altered: coinbase}).changed(function() {
balance = web3.eth.balanceAt(coinbase)
var currentBalance = web3.toDecimal(balance);
document.getElementById("current").innerText = 'current: ' + currentBalance;
document.getElementById("diff").innerText = 'diff: ' + (currentBalance - originalBalance);
});
}
</script>
</head>
<body>
<h1>coinbase balance</h1>
<button type="button" onClick="watchBalance();">watch balance</button>
<div></div>
<div id="original"></div>
<div id="current"></div>
<div id="diff"></div>
</body>
</html>

View File

@@ -1,22 +0,0 @@
<html>
<head>
<script src="../ext/bignumber.min.js"></script>
<script src="../ext/ethereum.js/dist/ethereum.js"></script>
<script>
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545'));
var eth = web3.eth;
function bomb() {
for (var i = 0; i < 200; i++) {
eth.transact({})
}
}
</script>
</head>
<body>
<button onclick="bomb();">BOOM!</button>
</body>
</html>

View File

@@ -1,147 +0,0 @@
<!doctype>
<html>
<title>JevCoin</title>
<head>
<script type="text/javascript" src="../ext/bignumber.min.js"></script>
<script type="text/javascript" src="../ext/ethereum.js/dist/web3-light.min.js"></script>
</head>
<body>
<h1>JevCoin <code id="contract_addr"></code></h1>
<div>
<strong>Balance</strong>
<span id="balance"></strong>
</div>
<div>
<span>Address:</span>
<input type="text" id="address" style="width:200px">
<span>Amount:</span>
<input type="text" id="amount" style="width:200px">
<button onclick="transact()">Send</button>
<span id="message"></span>
</div>
<hr>
<table width="100%" id="table">
<tr><td style="width:40%;">Address</td><td>Balance</td></tr>
<tbody id="table_body"></tbody>
</table>
</body>
<script type="text/javascript">
var eth = web3.eth;
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
var desc = [{
"name": "balance(address)",
"type": "function",
"inputs": [{
"name": "who",
"type": "address"
}],
"constant": true,
"outputs": [{
"name": "value",
"type": "uint256"
}]
}, {
"name": "send(address,uint256)",
"type": "function",
"inputs": [{
"name": "to",
"type": "address"
}, {
"name": "value",
"type": "uint256"
}],
"outputs": []
}, {
"name":"Changed",
"type":"event",
"inputs": [
{"name":"from","type":"address","indexed":true},
{"name":"amount","type":"uint256","indexed":true},
],
}];
var address = localStorage.getItem("address");
// deploy if not exist
if(address === null) {
var code = "0x60056013565b61014f8061003a6000396000f35b620f42406000600033600160a060020a0316815260200190815260200160002081905550560060e060020a600035048063d0679d3414610020578063e3d670d71461003457005b61002e600435602435610049565b60006000f35b61003f600435610129565b8060005260206000f35b806000600033600160a060020a03168152602001908152602001600020541061007157610076565b610125565b806000600033600160a060020a03168152602001908152602001600020908154039081905550806000600084600160a060020a031681526020019081526020016000209081540190819055508033600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a38082600160a060020a03167fb52dda022b6c1a1f40905a85f257f689aa5d69d850e49cf939d688fbe5af594660006000a35b5050565b60006000600083600160a060020a0316815260200190815260200160002054905091905056";
address = web3.eth.sendTransaction({from: eth.accounts[0], data: code, gas: "1000000"});
localStorage.setItem("address", address);
}
document.querySelector("#contract_addr").innerHTML = address;
var Contract = web3.eth.contract(desc);
contract = new Contract(address);
var filter = contract.Changed({from: eth.accounts[0]})
filter.watch(function(logs) {
console.log(logs);
refresh();
});
window.filter = filter;
function refresh() {
document.querySelector("#balance").innerHTML = contract.balance(eth.coinbase);
}
function transact() {
var to = document.querySelector("#address");
if( to.value.length == 0 ) {
to = "0x4205b06c2cfa0e30359edcab94543266cb6fa1d3";
} else {
if (to.value.substr(0,2) != "0x")
to.value = "0x"+to.value;
}
var value = document.querySelector("#amount");
var amount = parseInt( value.value );
console.log("transact: ", to.value, " => ", amount)
contract.sendTransaction({from: eth.accounts[0]}).send( to.value, amount );
to.value = "";
value.value = "";
var message = document.querySelector("#message")
message.innerHTML = "Submitted";
setTimeout(function() {
message.innerHTML = "";
}, 1000);
}
refresh();
</script>
</html>
<!--
contract JevCoin {
function JevCoin()
{
balances[msg.sender] = 1000000;
}
event Changed(address indexed from, uint indexed amount);
function send(address to, uint value)
{
if( balances[msg.sender] < value ) return;
balances[msg.sender] -= value;
balances[to] += value;
Changed(msg.sender, value);
Changed(to, value);
}
function balance(address who) constant returns(uint t)
{
t = balances[who];
}
mapping(address => uint256) balances;
}
-!>

View File

@@ -1,65 +0,0 @@
var walletABI = [
{
"name":"confirm",
"type":"function",
"constant":false,
"inputs":[
{"name":"_h","type":"hash256"}
],
"outputs":[]
},{
"name":"execute",
"constant":false,
"type":"function",
"inputs":[
{"name":"_to","type":"address"},
{"name":"_value","type":"uint256"},
{"name":"_data","type":"bytes"}
],
"outputs":[
{"name":"_r","type":"hash256"}
]
},{
"name":"kill",
"type":"function",
"constant":false,
"inputs":[
{"name":"_to","type":"address"}
],
"outputs":[]
},{
"name":"changeOwner",
"type":"function",
"constant":false,
"inputs":[
{"name":"_from","type":"address"},
{"name":"_to","type":"address"}
],
"outputs":[]
},{
"name":"CashIn",
"type":"event",
"inputs":[
{"indexed":false,"name":"value","type":"uint256"}
]
},{
"name":"SingleTransact",
"type":"event",
"inputs":[
{"indexed":true,"name":"out","type":"string32"},
{"indexed":false,"name":"owner","type":"address"},
{"indexed":false,"name":"value","type":"uint256"},
{"indexed":false,"name":"to","type":"address"}
]
},{
"name":"MultiTransact",
"type":"event",
"inputs":[
{"indexed":true,"name":"out","type":"string32"},
{"indexed":false,"name":"owner","type":"address"},
{"indexed":false,"name":"operation","type":"hash256"},
{"indexed":false,"name":"value","type":"uint256"},
{"indexed":false,"name":"to","type":"address"}
]
}
];

View File

@@ -1,84 +0,0 @@
<!doctype>
<html>
<head>
<meta name="badge" content="10">
<script type="text/javascript" src="../ext/bignumber.min.js"></script>
<script type="text/javascript" src="../ext/ethereum.js/dist/ethereum.js"></script>
</head>
<body>
<h1>Info</h1>
<table width="100%">
<tr>
<td>Block number</td>
<td id="number"></td>
</tr>
<tr>
<td>Peer count</td>
<td id="peer_count"></td>
</tr>
<tr>
<td>Default block</td>
<td id="default_block"></td>
</tr>
<tr>
<td>Accounts</td>
<td id="accounts"></td>
</tr>
<tr>
<td>Balance</td>
<td id="balance"></td>
<tr>
<td>Gas price</td>
<td id="gas_price"></td>
</tr>
<tr>
<td>Mining</td>
<td id="mining"></td>
</tr>
<tr>
<td>Listening</td>
<td id="listening"></td>
</tr>
<tr>
<td>Coinbase</td>
<td id="coinbase"></td>
</tr>
</table>
</body>
<script type="text/javascript">
var web3 = require('web3');
var eth = web3.eth;
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545'));
eth.defaultBlock = -2
document.querySelector("#number").innerHTML = eth.number;
document.querySelector("#coinbase").innerHTML = eth.coinbase
document.querySelector("#peer_count").innerHTML = eth.peerCount;
document.querySelector("#default_block").innerHTML = eth.defaultBlock;
document.querySelector("#accounts").innerHTML = eth.accounts;
document.querySelector("#balance").innerHTML = web3.toEth(eth.balanceAt(eth.accounts[0]));
document.querySelector("#gas_price").innerHTML = eth.gasPrice;
document.querySelector("#mining").innerHTML = eth.mining;
document.querySelector("#listening").innerHTML = eth.listening;
eth.watch('chain').changed(function() {
document.querySelector("#number").innerHTML = eth.number;
});
</script>
</html>

View File

@@ -1,70 +0,0 @@
<!doctype>
<html>
<title>Whisper test</title>
<head>
<script type="text/javascript" src="../ext/bignumber.min.js"></script>
<script type="text/javascript" src="../ext/ethereum.js/dist/ethereum.js"></script>
</head>
<body>
<h1>Whisper test</h1>
<button onclick="test()">Send</button>
<button onclick="test2()">Private send</button>
<table width="100%" id="table">
<tr>
<td>Count</td>
<td id="count"></td>
</tr>
<tr>
<td>ID</td>
<td id="id"></td>
</tr>
<tr>
<td>Has identity</td>
<td id="known"></td>
</tr>
</table>
</body>
<script type="text/javascript">
var web3 = require('web3');
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8080'));
var shh = web3.shh;
var id = shh.newIdentity();
document.querySelector("#id").innerHTML = id;
document.querySelector("#known").innerHTML = shh.haveIdentity(id);
var watch = shh.watch({topics: ["test"]})
watch.arrived(function(message) {
document.querySelector("#table").innerHTML += "<tr><td colspan='2'>"+JSON.stringify(message)+"</td></tr>";
});
var selfWatch = shh.watch({to: id, topics: ["test"]})
selfWatch.arrived(function(message) {
document.querySelector("#table").innerHTML += "<tr><td>To me</td><td>"+JSON.stringify(message)+"</td></tr>";
});
function test() {
shh.post({topics: ["test"], payload: web3.fromAscii("test it")});
count();
}
function test2() {
shh.post({to: id, topics: ["test"], payload: web3.fromAscii("Private")});
count();
}
function count() {
document.querySelector("#count").innerHTML = watch.messages().length;
}
</script>
</html>

View File

@@ -1,5 +0,0 @@
{
"directory": "example/js/",
"cwd": "./",
"analytics": false
}

View File

@@ -1,12 +0,0 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

View File

@@ -1,18 +0,0 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global
*.swp
/tmp
*/**/*un~
*un~
.DS_Store
*/**/.DS_Store
ethereum/ethereum
ethereal/ethereal
example/js
node_modules
bower_components
npm-debug.log

View File

@@ -1,50 +0,0 @@
{
"predef": [
"console",
"require",
"equal",
"test",
"testBoth",
"testWithDefault",
"raises",
"deepEqual",
"start",
"stop",
"ok",
"strictEqual",
"module",
"expect",
"reject",
"impl"
],
"esnext": true,
"proto": true,
"node" : true,
"browser" : true,
"browserify" : true,
"boss" : true,
"curly": false,
"debug": true,
"devel": true,
"eqeqeq": true,
"evil": true,
"forin": false,
"immed": false,
"laxbreak": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": false,
"nomen": false,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true,
"sub": true,
"strict": false,
"white": false,
"shadow": true,
"eqnull": true
}

View File

@@ -1,9 +0,0 @@
example/js
node_modules
test
.gitignore
.editorconfig
.travis.yml
.npmignore
component.json
testling.html

View File

@@ -1,13 +0,0 @@
language: node_js
node_js:
- "0.11"
- "0.10"
before_script:
- npm install
- npm install jshint
script:
- "jshint *.js lib"
after_script:
- npm run-script build
- npm test

File diff suppressed because one or more lines are too long

View File

@@ -1,66 +0,0 @@
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
var ethx = {
prototype: Object,
watch: function(options) {
return new Filter(options);
},
note: function() {
var args = Array.prototype.slice.call(arguments, 0);
var o = []
for(var i = 0; i < args.length; i++) {
o.push(args[i].toString())
}
eth.notef(o);
},
};
var Filter = function(options) {
this.callbacks = [];
this.options = options;
if(options === "chain") {
this.id = eth.newFilterString(options);
} else if(typeof options === "object") {
this.id = eth.newFilter(options);
}
};
Filter.prototype.changed = function(callback) {
this.callbacks.push(callback);
var self = this;
messages.connect(function(messages, id) {
if(id == self.id) {
for(var i = 0; i < self.callbacks.length; i++) {
self.callbacks[i].call(self, messages);
}
}
});
};
Filter.prototype.uninstall = function() {
eth.uninstallFilter(this.id)
}
Filter.prototype.messages = function() {
return eth.messages(this.id)
}

View File

@@ -1,30 +0,0 @@
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
// this function is included locally, but you can also include separately via a header definition
function request(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = (function(req) {
return function() {
if(req.readyState === 4) {
callback(req);
}
}
})(xhr);
xhr.open('GET', url, true);
xhr.send('');
}

View File

@@ -1,36 +0,0 @@
// Copyright (c) 2015, ETHDEV. All rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
// this function is included locally, but you can also include separately via a header definition
document.onkeydown = function(evt) {
// This functions keeps track of keyboard inputs in order to allow copy, paste and other features
evt = evt || window.event;
if (evt.ctrlKey && evt.keyCode == 67) {
window.document.execCommand("copy");
} else if (evt.ctrlKey && evt.keyCode == 88) {
window.document.execCommand("cut");
} else if (evt.ctrlKey && evt.keyCode == 86) {
window.document.execCommand("paste");
} else if (evt.ctrlKey && evt.keyCode == 90) {
window.document.execCommand("undo");
} else if (evt.ctrlKey && evt.shiftKey && evt.keyCode == 90) {
window.document.execCommand("redo");
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,83 +0,0 @@
<!doctype>
<html>
<head>
<title>Ethereum</title>
<script type="text/javascript" src="../ext/bignumber.min.js"></script>
<script type="text/javascript" src="../ext/ethereum.js/dist/ethereum.js"></script>
<style type="text/css">
body {
font-family: Helvetica;
}
div.logo {
width: 192px;
margin: 40px auto;
}
</style>
</head>
<body>
<div class="logo"><img src="logo.png"></img></div>
<h1>Info</h1>
<table width="100%">
<tr>
<td>Block number</td>
<td id="number"></td>
</tr>
<tr>
<td>Peer count</td>
<td id="peer_count"></td>
</tr>
<tr>
<td>Accounts</td>
<td id="accounts"></td>
</tr>
<tr>
<td>Gas price</td>
<td id="gas_price"></td>
</tr>
<tr>
<td>Mining</td>
<td id="mining"></td>
</tr>
<tr>
<td>Listening</td>
<td id="listening"></td>
</tr>
<tr>
<td>Coinbase</td>
<td id="coinbase"></td>
</tr>
</table>
</body>
<script type="text/javascript">
var web3 = require('web3');
var eth = web3.eth;
web3.setProvider(new web3.providers.HttpSyncProvider('http://localhost:8545'));
document.querySelector("#number").innerHTML = eth.number;
document.querySelector("#coinbase").innerHTML = eth.coinbase
document.querySelector("#peer_count").innerHTML = eth.peerCount;
document.querySelector("#accounts").innerHTML = eth.accounts;
document.querySelector("#gas_price").innerHTML = eth.gasPrice;
document.querySelector("#mining").innerHTML = eth.mining;
document.querySelector("#listening").innerHTML = eth.listening;
eth.watch('pending').changed(function() {
console.log("pending changed");
});
eth.watch('chain').changed(function() {
document.querySelector("#number").innerHTML = eth.number;
});
</script>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,272 +0,0 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
overflow: auto;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
/* CURSOR */
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
}
/* Can style cursor different in overwrite (non-insert) mode */
div.CodeMirror-overwrite div.CodeMirror-cursor {}
.cm-tab { display: inline-block; }
.CodeMirror-ruler {
border-left: 1px solid #ccc;
position: absolute;
}
/* DEFAULT THEME */
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable,
.cm-s-default .cm-punctuation,
.cm-s-default .cm-property,
.cm-s-default .cm-operator {}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-s-default .cm-error {color: #f00;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
line-height: 1;
position: relative;
overflow: hidden;
background: white;
color: black;
}
.CodeMirror-scroll {
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-sizer {
position: relative;
border-right: 30px solid transparent;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
padding-bottom: 30px;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
-moz-box-sizing: content-box;
box-sizing: content-box;
padding-bottom: 30px;
margin-bottom: -32px;
display: inline-block;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-lines {
cursor: text;
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
border-right: none;
width: 0;
}
div.CodeMirror-cursors {
visibility: hidden;
position: relative;
z-index: 1;
}
.CodeMirror-focused div.CodeMirror-cursors {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.CodeMirror-crosshair { cursor: crosshair; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
.CodeMirror span { *vertical-align: text-bottom; }
/* Used to force a border model for a node */
.cm-force-border { padding-right: .1px; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
}
}

View File

@@ -1,53 +0,0 @@
<!doctype>
<html>
<head>
<style type="text/css">
html, body {
margin: 0; padding: 0;
min-height: 100%;
}
#debugger {
height: 100%;
font-family: "Monaco"
}
#debugger .line {
overflow: none;
}
#debugger .col1, #debugger .col2 {
float: left;
padding: 3px;
}
#debugger .col1 {
width: 10px;
padding-left: 10px
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#debugger .col2 {
width: 90%;
}
.prompt {
color: "#5089D4";
}
</style>
</head>
<body>
<div id="debugger">
<div class="line">
<div class="col1 prompt">
&gt;
</div>
<div class="col2" contenteditable>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,23 +0,0 @@
.cm-s-eclipse span.cm-meta {color: #FF1717;}
.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; }
.cm-s-eclipse span.cm-atom {color: #219;}
.cm-s-eclipse span.cm-number {color: #164;}
.cm-s-eclipse span.cm-def {color: #00f;}
.cm-s-eclipse span.cm-variable {color: black;}
.cm-s-eclipse span.cm-variable-2 {color: #0000C0;}
.cm-s-eclipse span.cm-variable-3 {color: #0000C0;}
.cm-s-eclipse span.cm-property {color: black;}
.cm-s-eclipse span.cm-operator {color: black;}
.cm-s-eclipse span.cm-comment {color: #3F7F5F;}
.cm-s-eclipse span.cm-string {color: #2A00FF;}
.cm-s-eclipse span.cm-string-2 {color: #f50;}
.cm-s-eclipse span.cm-qualifier {color: #555;}
.cm-s-eclipse span.cm-builtin {color: #30a;}
.cm-s-eclipse span.cm-bracket {color: #cc7;}
.cm-s-eclipse span.cm-tag {color: #170;}
.cm-s-eclipse span.cm-attribute {color: #00c;}
.cm-s-eclipse span.cm-link {color: #219;}
.cm-s-eclipse span.cm-error {color: #f00;}
.cm-s-eclipse .CodeMirror-activeline-background {background: #e8f2ff !important;}
.cm-s-eclipse .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;}

View File

@@ -1,80 +0,0 @@
<!doctype>
<html>
<head>
<title>Mutan Editor</title>
<link rel="stylesheet" href="codemirror.css">
<link rel="stylesheet" href="eclipse.css">
<script src="lib/codemirror.js"></script>
<script src="lib/matchbrackets.js"></script>
<script src="lib/go.js"></script>
<script src="muted.js"></script>
<style type="text/css">
html, body {
margin: 0; padding: 0;
min-height: 100%;
}
#debugger {
height: 30%;
font-family: "Monaco";
border-top: 5px solid grey;
}
#debugger .line {
overflow: none;
}
#debugger .col1, #debugger .col2 {
float: left;
padding: 3px;
}
#debugger .col1 {
width: 10px;
padding-left: 10px
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#debugger .col2 {
width: 90%;
}
.prompt {
color: "#5089D4";
}
.CodeMirror {
height: 70%;
font-size: 14pt;
}
</style>
</head>
<body>
<textarea id="editor"></textarea>
<div id="debugger">
<div class="line">
<div class="col1 prompt">
&gt;
</div>
<div class="col2" contenteditable>
</div>
</div>
</div>
<script>
var textArea = document.querySelector("#editor")
var editor = CodeMirror.fromTextArea(textArea, {
theme: "eclipse",
mode: "text/html",
lineNumbers: true,
mode: "text/x-go",
indentUnit: 8,
tabSize: 8,
indentWithTabs: true,
});
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,182 +0,0 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("go", function(config) {
var indentUnit = config.indentUnit;
var keywords = {
"break":true, "case":true, "chan":true, "const":true, "continue":true,
"default":true, "defer":true, "else":true, "fallthrough":true, "for":true,
"func":true, "go":true, "goto":true, "if":true, "import":true,
"interface":true, "map":true, "package":true, "range":true, "return":true,
"select":true, "struct":true, "switch":true, "type":true, "var":true,
"bool":true, "byte":true, "complex64":true, "complex128":true,
"float32":true, "float64":true, "int8":true, "int16":true, "int32":true,
"int64":true, "string":true, "uint8":true, "uint16":true, "uint32":true,
"uint64":true, "int":true, "uint":true, "uintptr":true, "big": true,
"main": true, "init": true, "this":true
};
var atoms = {
"true":true, "false":true, "iota":true, "nil":true, "append":true,
"cap":true, "close":true, "complex":true, "copy":true, "imag":true,
"len":true, "make":true, "new":true, "panic":true, "print":true,
"println":true, "real":true, "recover":true,
};
var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
var curPunc;
function tokenBase(stream, state) {
var ch = stream.next();
if (ch == '"' || ch == "'" || ch == "`") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
if (/[\d\.]/.test(ch)) {
if (ch == ".") {
stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
} else if (ch == "0") {
stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
} else {
stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
}
return "number";
}
if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
curPunc = ch;
return null;
}
if (ch == "/") {
if (stream.eat("*")) {
state.tokenize = tokenComment;
return tokenComment(stream, state);
}
if (stream.eat("/")) {
stream.skipToEnd();
return "comment";
}
}
if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return "operator";
}
stream.eatWhile(/[\w\$_]/);
var cur = stream.current();
if (keywords.propertyIsEnumerable(cur)) {
if (cur == "case" || cur == "default") curPunc = "case";
return "keyword";
}
if (atoms.propertyIsEnumerable(cur)) return "atom";
return "variable";
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote && !escaped) {end = true; break;}
escaped = !escaped && next == "\\";
}
if (end || !(escaped || quote == "`"))
state.tokenize = tokenBase;
return "string";
};
}
function tokenComment(stream, state) {
var maybeEnd = false, ch;
while (ch = stream.next()) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
}
maybeEnd = (ch == "*");
}
return "comment";
}
function Context(indented, column, type, align, prev) {
this.indented = indented;
this.column = column;
this.type = type;
this.align = align;
this.prev = prev;
}
function pushContext(state, col, type) {
return state.context = new Context(state.indented, col, type, null, state.context);
}
function popContext(state) {
var t = state.context.type;
if (t == ")" || t == "]" || t == "}")
state.indented = state.context.indented;
return state.context = state.context.prev;
}
// Interface
return {
startState: function(basecolumn) {
return {
tokenize: null,
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
indented: 0,
startOfLine: true
};
},
token: function(stream, state) {
var ctx = state.context;
if (stream.sol()) {
if (ctx.align == null) ctx.align = false;
state.indented = stream.indentation();
state.startOfLine = true;
if (ctx.type == "case") ctx.type = "}";
}
if (stream.eatSpace()) return null;
curPunc = null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style == "comment") return style;
if (ctx.align == null) ctx.align = true;
if (curPunc == "{") pushContext(state, stream.column(), "}");
else if (curPunc == "[") pushContext(state, stream.column(), "]");
else if (curPunc == "(") pushContext(state, stream.column(), ")");
else if (curPunc == "case") ctx.type = "case";
else if (curPunc == "}" && ctx.type == "}") ctx = popContext(state);
else if (curPunc == ctx.type) popContext(state);
state.startOfLine = false;
return style;
},
indent: function(state, textAfter) {
if (state.tokenize != tokenBase && state.tokenize != null) return 0;
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
state.context.type = "}";
return ctx.indented;
}
var closing = firstChar == ctx.type;
if (ctx.align) return ctx.column + (closing ? 0 : 1);
else return ctx.indented + (closing ? 0 : indentUnit);
},
electricChars: "{}):",
fold: "brace",
blockCommentStart: "/*",
blockCommentEnd: "*/",
lineComment: "//"
};
});
CodeMirror.defineMIME("text/x-go", "go");
});

View File

@@ -1,117 +0,0 @@
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
(document.documentMode == null || document.documentMode < 8);
var Pos = CodeMirror.Pos;
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
function findMatchingBracket(cm, where, strict, config) {
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
if (!match) return null;
var dir = match.charAt(1) == ">" ? 1 : -1;
if (strict && (dir > 0) != (pos == where.ch)) return null;
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
if (found == null) return null;
return {from: Pos(where.line, pos), to: found && found.pos,
match: found && found.ch == match.charAt(0), forward: dir > 0};
}
// bracketRegex is used to specify which type of bracket to scan
// should be a regexp, e.g. /[[\]]/
//
// Note: If "where" is on an open bracket, then this bracket is ignored.
//
// Returns false when no bracket was found, null when it reached
// maxScanLines and gave up
function scanForBracket(cm, where, dir, style, config) {
var maxScanLen = (config && config.maxScanLineLength) || 10000;
var maxScanLines = (config && config.maxScanLines) || 1000;
var stack = [];
var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
var line = cm.getLine(lineNo);
if (!line) continue;
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
if (line.length > maxScanLen) continue;
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
for (; pos != end; pos += dir) {
var ch = line.charAt(pos);
if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
var match = matching[ch];
if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
else stack.pop();
}
}
}
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
}
function matchBrackets(cm, autoclear, config) {
// Disable brace matching in long lines, since it'll cause hugely slow updates
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
var marks = [], ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
}
}
if (marks.length) {
// Kludge to work around the IE bug from issue #1193, where text
// input stops going to the textare whever this fires.
if (ie_lt8 && cm.state.focused) cm.display.input.focus();
var clear = function() {
cm.operation(function() {
for (var i = 0; i < marks.length; i++) marks[i].clear();
});
};
if (autoclear) setTimeout(clear, 800);
else return clear;
}
}
var currentlyHighlighted = null;
function doMatchBrackets(cm) {
cm.operation(function() {
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
});
}
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init)
cm.off("cursorActivity", doMatchBrackets);
if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {};
cm.on("cursorActivity", doMatchBrackets);
}
});
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
return findMatchingBracket(this, pos, strict, config);
});
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
return scanForBracket(this, pos, dir, style, config);
});
});

View File

@@ -1,78 +0,0 @@
// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301 USA
// Helper function for generating pseudo callbacks and sending data to the QML part of the application
function postData(data, cb) {
data._seed = Math.floor(Math.random() * 1000000)
if(cb) {
Muted._callbacks[data._seed] = cb;
}
if(data.args === undefined) {
data.args = [];
}
navigator.qt.postMessage(JSON.stringify(data));
}
window.Muted = {
prototype: Object(),
}
window.Muted._callbacks = {}
window.Muted._onCallbacks = {}
function debug(/**/) {
console.log("hello world")
var args = arguments;
var msg = ""
for(var i = 0; i < args.length; i++){
if(typeof args[i] == "object") {
msg += " " + JSON.stringify(args[i])
} else {
msg += args[i]
}
}
document.querySelector("#debugger").innerHTML += "<div class='line'><div class='col1'></div><div class='col2'>"+msg+"</div></div>";
}
console.log = function() {
var args = []
for(var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
postData({call:"log", args:args})
}
navigator.qt.onmessage = function(ev) {
var data = JSON.parse(ev.data)
if(data._event !== undefined) {
Muted.trigger(data._event, data.data);
} else {
if(data._seed) {
var cb = Muted._callbacks[data._seed];
if(cb) {
// Call the callback
cb(data.data);
// Remove the "trigger" callback
delete Muted._callbacks[ev._seed];
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

View File

@@ -1,22 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import Ethereum 1.0
ApplicationWindow {
minimumWidth: 500
maximumWidth: 500
maximumHeight: 400
minimumHeight: 400
function onNewBlockCb(block) {
console.log("Please overwrite onNewBlock(block):", block)
}
function onObjectChangeCb(stateObject) {
console.log("Please overwrite onObjectChangeCb(object)", stateObject)
}
function onStorageChangeCb(storageObject) {
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
console.log("Please overwrite onStorageChangeCb(object)", ev)
}
}

View File

@@ -1,486 +0,0 @@
import QtQuick 2.1
import QtWebKit 3.0
import QtWebKit.experimental 1.0
import QtQuick.Controls 1.0;
import QtQuick.Controls.Styles 1.0
import QtQuick.Layouts 1.0;
import QtQuick.Window 2.1;
import Ethereum 1.0
Rectangle {
id: window
anchors.fill: parent
color: "#00000000"
property var title: "DApps"
property var iconSource: "../browser.png"
property var menuItem
property var hideUrl: true
property alias url: webview.url
property alias windowTitle: webview.title
property alias webView: webview
property var cleanPath: false
property var open: function(url) {
if(!window.cleanPath) {
var uri = url;
if(!/.*\:\/\/.*/.test(uri)) {
uri = "http://" + uri;
}
var reg = /(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.eth)(.*)/
if(reg.test(uri)) {
uri.replace(reg, function(match, pre, domain, path) {
uri = pre;
var lookup = eth.lookupDomain(domain.substring(0, domain.length - 4));
var ip = [];
for(var i = 0, l = lookup.length; i < l; i++) {
ip.push(lookup.charCodeAt(i))
}
if(ip.length != 0) {
uri += lookup;
} else {
uri += domain;
}
uri += path;
});
}
window.cleanPath = true;
webview.url = uri;
//uriNav.text = uri.text.replace(/(^https?\:\/\/(?:www\.)?)([a-zA-Z0-9_\-]*\.\w{2,3})(.*)/, "$1$2<span style='color:#CCC'>$3</span>");
uriNav.text = uri;
} else {
// Prevent inf loop.
window.cleanPath = false;
}
}
Component.onCompleted: {
webview.url = "http://etherian.io"
}
function messages(messages, id) {
// Bit of a cheat to get proper JSON
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
webview.postEvent("eth_changed", id, m);
}
function onShhMessage(message, id) {
webview.postEvent("shh_changed", id, message)
}
Item {
objectName: "root"
id: root
anchors.fill: parent
state: "inspectorShown"
RowLayout {
id: navBar
height: 40
anchors {
left: parent.left
right: parent.right
leftMargin: 7
}
Button {
id: back
onClicked: {
webview.goBack()
}
style: ButtonStyle {
background: Image {
source: "../back.png"
width: 30
height: 30
}
}
}
TextField {
anchors {
left: back.right
right: toggleInspector.left
leftMargin: 10
rightMargin: 10
}
text: webview.url;
id: uriNav
y: parent.height / 2 - this.height / 2
Keys.onReturnPressed: {
webview.url = this.text;
}
}
Button {
id: toggleInspector
anchors {
right: parent.right
}
iconSource: "../bug.png"
onClicked: {
if(inspector.visible == true){
inspector.visible = false
}else{
inspector.visible = true
inspector.url = webview.experimental.remoteInspectorUrl
}
}
}
}
// Border
Rectangle {
id: divider
anchors {
left: parent.left
right: parent.right
top: navBar.bottom
}
z: -1
height: 1
color: "#CCCCCC"
}
ScrollView {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
top: divider.bottom
}
WebView {
objectName: "webView"
id: webview
anchors.fill: parent
function sendMessage(data) {
webview.experimental.postMessage(JSON.stringify(data))
}
experimental.preferences.javascriptEnabled: true
experimental.preferences.webAudioEnabled: true
experimental.preferences.pluginsEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true
experimental.preferences.webGLEnabled: true
experimental.preferences.notificationsEnabled: true
experimental.preferences.localStorageEnabled: true
experimental.userAgent:"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Mist/0.1 Safari/537.36"
experimental.itemSelector: MouseArea {
// To avoid conflicting with ListView.model when inside Initiator context.
property QtObject selectorModel: model
anchors.fill: parent
onClicked: selectorModel.reject()
Menu {
visible: true
id: itemSelector
Instantiator {
model: selectorModel.items
delegate: MenuItem {
text: model.text
onTriggered: {
selectorModel.accept(index)
}
}
onObjectAdded: itemSelector.insertItem(index, object)
onObjectRemoved: itemSelector.removeItem(object)
}
}
Component.onCompleted: {
itemSelector.popup()
}
}
experimental.userScripts: ["../ext/q.js", "../ext/ethereum.js/dist/ethereum.min.js", "../ext/setup.js"]
experimental.onMessageReceived: {
//console.log("[onMessageReceived]: ", message.data)
var data = JSON.parse(message.data)
try {
switch(data.call) {
case "eth_compile":
postData(data._id, eth.compile(data.args[0]))
break
case "eth_coinbase":
postData(data._id, eth.coinBase())
case "eth_account":
postData(data._id, eth.key().address);
case "eth_istening":
postData(data._id, eth.isListening())
break
case "eth_mining":
postData(data._id, eth.isMining())
break
case "eth_peerCount":
postData(data._id, eth.peerCount())
break
case "eth_countAt":
require(1)
postData(data._id, eth.txCountAt(data.args[0]))
break
case "eth_codeAt":
require(1)
var code = eth.codeAt(data.args[0])
postData(data._id, code);
break
case "eth_blockByNumber":
require(1)
var block = eth.blockByNumber(data.args[0])
postData(data._id, block)
break
case "eth_blockByHash":
require(1)
var block = eth.blockByHash(data.args[0])
postData(data._id, block)
break
require(2)
var block = eth.blockByHash(data.args[0])
postData(data._id, block.transactions[data.args[1]])
break
case "eth_transactionByHash":
case "eth_transactionByNumber":
require(2)
var block;
if (data.call === "transactionByHash")
block = eth.blockByHash(data.args[0])
else
block = eth.blockByNumber(data.args[0])
var tx = block.transactions.get(data.args[1])
postData(data._id, tx)
break
case "eth_uncleByHash":
case "eth_uncleByNumber":
require(2)
var block;
if (data.call === "uncleByHash")
block = eth.blockByHash(data.args[0])
else
block = eth.blockByNumber(data.args[0])
var uncle = block.uncles.get(data.args[1])
postData(data._id, uncle)
break
case "transact":
require(5)
var tx = eth.transact(data.args)
postData(data._id, tx)
break
case "eth_stateAt":
require(2);
var storage = eth.storageAt(data.args[0], data.args[1]);
postData(data._id, storage)
break
case "eth_call":
require(1);
var ret = eth.call(data.args)
postData(data._id, ret)
break
case "eth_balanceAt":
require(1);
postData(data._id, eth.balanceAt(data.args[0]));
break
case "eth_watch":
require(2)
eth.watch(data.args[0], data.args[1])
case "eth_disconnect":
require(1)
postData(data._id, null)
break;
case "eth_newFilterString":
require(1)
var id = eth.newFilterString(data.args[0], window)
postData(data._id, id);
break;
case "eth_newFilter":
require(1)
var id = eth.newFilter(data.args[0], window)
postData(data._id, id);
break;
case "eth_filterLogs":
require(1);
var messages = eth.messages(data.args[0]);
var m = JSON.parse(JSON.parse(JSON.stringify(messages)))
postData(data._id, m);
break;
case "eth_deleteFilter":
require(1);
eth.uninstallFilter(data.args[0])
break;
case "shh_newFilter":
require(1);
var id = shh.watch(data.args[0], window);
postData(data._id, id);
break;
case "shh_newIdentity":
var id = shh.newIdentity()
postData(data._id, id)
break
case "shh_post":
require(1);
var params = data.args[0];
var fields = ["payload", "to", "from"];
for(var i = 0; i < fields.length; i++) {
params[fields[i]] = params[fields[i]] || "";
}
if(typeof params.payload !== "object") { params.payload = [params.payload]; } //params.payload = params.payload.join(""); }
params.topics = params.topics || [];
params.priority = params.priority || 1000;
params.ttl = params.ttl || 100;
shh.post(params.payload, params.to, params.from, params.topics, params.priority, params.ttl);
break;
case "shh_getMessages":
require(1);
var m = shh.messages(data.args[0]);
var messages = JSON.parse(JSON.parse(JSON.stringify(m)));
postData(data._id, messages);
break;
case "ssh_newGroup":
postData(data._id, "");
break;
}
} catch(e) {
console.log(data.call + ": " + e)
postData(data._id, null);
}
}
function post(seed, data) {
postData(data._id, data)
}
function require(args, num) {
if(args.length < num) {
throw("required argument count of "+num+" got "+args.length);
}
}
function postData(seed, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: seed}))
}
function postEvent(event, id, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _id: id, _event: event}))
}
function onWatchedCb(data, id) {
var messages = JSON.parse(data)
postEvent("watched:"+id, messages)
}
function onNewBlockCb(block) {
postEvent("block:new", block)
}
function onObjectChangeCb(stateObject) {
postEvent("object:"+stateObject.address(), stateObject)
}
function onStorageChangeCb(storageObject) {
var ev = ["storage", storageObject.stateAddress, storageObject.address].join(":");
postEvent(ev, [storageObject.address, storageObject.value])
}
}
}
Rectangle {
id: sizeGrip
color: "gray"
visible: false
height: 10
anchors {
left: root.left
right: root.right
}
y: Math.round(root.height * 2 / 3)
MouseArea {
anchors.fill: parent
drag.target: sizeGrip
drag.minimumY: 0
drag.maximumY: root.height
drag.axis: Drag.YAxis
}
}
WebView {
id: inspector
visible: false
anchors {
left: root.left
right: root.right
top: sizeGrip.bottom
bottom: root.bottom
}
}
states: [
State {
name: "inspectorShown"
PropertyChanges {
target: inspector
}
}
]
}
}

View File

@@ -1,155 +0,0 @@
import QtQuick 2.0
import Ethereum 1.0
// Which ones do we actually need?
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import QtQuick.Dialogs 1.1
ApplicationWindow {
id: wizardRoot
width: 500
height: 400
title: "Ethereal first run setup"
Column {
spacing: 5
anchors.leftMargin: 10
anchors.left: parent.left
Text {
visible: true
text: "<h2>Ethereal setup</h2>"
}
Column {
id: restoreColumn
spacing: 5
Text {
visible: true
font.pointSize: 14
text: "Restore your Ethereum account"
id: restoreLabel
}
TextField {
id: txPrivKey
width: 480
placeholderText: "Private key or mnemonic words"
focus: true
onTextChanged: {
if(this.text.length == 64){
detailLabel.text = "Private (hex) key detected."
actionButton.enabled = true
}
else if(this.text.split(" ").length == 24){
detailLabel.text = "Mnemonic key detected."
actionButton.enabled = true
}else{
detailLabel.text = ""
actionButton.enabled = false
}
}
}
Row {
spacing: 10
Button {
id: actionButton
text: "Restore"
enabled: false
onClicked: {
var success = lib.importAndSetPrivKey(txPrivKey.text)
if(success){
importedDetails.visible = true
restoreColumn.visible = false
newKey.visible = false
wizardRoot.height = 120
}
}
}
Text {
id: detailLabel
font.pointSize: 12
anchors.topMargin: 10
}
}
}
Column {
id: importedDetails
visible: false
Text {
text: "<b>Your account has been imported. Please close the application and restart it again to let the changes take effect.</b>"
wrapMode: Text.WordWrap
width: 460
}
}
Column {
spacing: 5
id: newDetailsColumn
visible: false
Text {
font.pointSize: 14
text: "Your account details"
}
Label {
text: "Address"
}
TextField {
id: addressInput
readOnly:true
width: 480
}
Label {
text: "Private key"
}
TextField {
id: privkeyInput
readOnly:true
width: 480
}
Label {
text: "Mnemonic words"
}
TextField {
id: mnemonicInput
readOnly:true
width: 480
}
Label {
text: "<b>A new account has been created. Please take the time to write down the <i>24 words</i>. You can use those to restore your account at a later date.</b>"
wrapMode: Text.WordWrap
width: 480
}
Label {
text: "Please restart the application once you have completed the steps above."
wrapMode: Text.WordWrap
width: 480
}
}
}
Button {
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 10
anchors.bottomMargin: 10
id: newKey
text: "I don't have an account yet"
onClicked: {
var res = lib.createAndSetPrivKey()
mnemonicInput.text = res[0]
addressInput.text = res[1]
privkeyInput.text = res[2]
// Hide restore
restoreColumn.visible = false
// Show new details
newDetailsColumn.visible = true
newKey.visible = false
}
}
}

Some files were not shown because too many files have changed in this diff Show More