Compare commits

..

263 Commits
0.2.2 ... 2

Author SHA1 Message Date
198ef97108 Merge branch 'hotfix/2' 2014-05-28 11:53:07 +02:00
138b7fe2d8 Consolidated external qml files to hopefully prevent crashing bug 2014-05-28 11:52:52 +02:00
87a669aeda Merge branch 'develop' 2014-05-27 16:23:59 +02:00
969b4a4a36 Added some shortcuts 2014-05-27 16:23:53 +02:00
118860abb2 Merge branch 'release/poc5-rc10' into develop 2014-05-27 16:11:08 +02:00
0dda955f90 Merge branch 'release/poc5-rc10' 2014-05-27 16:11:01 +02:00
34b861c19c bump 2014-05-27 16:10:15 +02:00
a0f73c2703 Minor fixes and improvements to the ui 2014-05-27 16:09:04 +02:00
2be9823010 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop
Conflicts:
	ethereal/assets/qml/wallet.qml
2014-05-27 13:31:57 +02:00
47417506c3 New debugger implemented 2014-05-27 13:28:11 +02:00
d0b31e2030 New debugger 2014-05-27 13:09:47 +02:00
6fe42f007c Uhm what 2014-05-27 12:46:02 +02:00
1ab865a994 Adding new blocks on broadcast 2014-05-27 11:49:42 +02:00
4fd267a778 Sep debugger from main 2014-05-27 10:42:37 +02:00
07204f129e Increase size for asm 2014-05-27 10:38:51 +02:00
47a58b40cd Removed recursive function for loop 2014-05-27 10:29:39 +02:00
474c85bc9d Fix merge conflict 2014-05-27 10:29:12 +02:00
d694e00a33 Fixed debugger 2014-05-26 21:11:38 +02:00
f7eb4e587f Remove extra log statement 2014-05-26 17:18:34 +02:00
5fc6ee6a4a Implemented simple block/tx explorer 2014-05-26 17:07:20 +02:00
5374a95c58 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-05-26 10:53:58 +02:00
26ecf4b780 Merge branch 'release/poc5-rc9' into develop 2014-05-26 00:42:03 +02:00
0d89c1d212 Merge branch 'release/poc5-rc9' 2014-05-26 00:41:55 +02:00
818bc84591 Bump 2014-05-26 00:39:05 +02:00
b42c70be9c Recv send for txs 2014-05-26 00:10:38 +02:00
d35380c19e New main script through init return value 2014-05-23 14:37:03 +02:00
36683f2e29 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-05-23 10:29:17 +02:00
5f8911f7cb Custom identifier 2014-05-22 10:38:37 +02:00
6b115659ca Hide inspector by default 2014-05-22 10:27:21 +02:00
8419ba0ec0 Fix merge conflicts 2014-05-22 10:26:39 +02:00
01b833146f Added mining stop and start 2014-05-22 00:25:48 +02:00
b902de20c7 Fixes #49 2014-05-21 23:46:16 +02:00
3f5b348451 Fixes #50 2014-05-21 23:36:55 +02:00
93d79babc9 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-05-21 14:07:45 +02:00
941e0ba60a Merge branch 'release/poc5-rc8' into develop 2014-05-21 14:05:01 +02:00
7f1a4c377c Merge branch 'release/poc5-rc8' 2014-05-21 14:04:54 +02:00
3ddaf56afd Bumped 2014-05-21 14:04:11 +02:00
10e2c40b59 Improved on some ui elements 2014-05-21 14:00:54 +02:00
68f4a12a8b Fixed unconfirmed balance string 2014-05-21 13:37:46 +02:00
34008da807 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-05-21 12:14:55 +02:00
16bd88c10a Removed method name 2014-05-21 12:14:39 +02:00
0bccf1c3cd Wait with mining until up to date 2014-05-21 11:45:19 +02:00
d16d56d39f Updated readme to reflect options 2014-05-20 22:13:39 +02:00
93e12250c7 Switch variables as intended 2014-05-20 22:12:42 +02:00
f4551a7e9f Changed flag parsing 2014-05-20 22:12:22 +02:00
563c035eb5 Refactored some of the functions 2014-05-20 19:28:48 +02:00
de1dfae717 Forked version of otto so we can support lowerCased methods 2014-05-20 17:49:12 +02:00
4198969302 Merge branch 'release/poc5-rc7' into develop 2014-05-20 17:09:36 +02:00
c07c454935 Merge branch 'release/poc5-rc7' 2014-05-20 17:09:26 +02:00
34014c1c51 Bump 2014-05-20 17:08:23 +02:00
0cf617ef0c Implemented GUI watchers for rapid reload. Implements #46 2014-05-20 16:58:13 +02:00
0ef7f63729 Removed old console in favor of the new JS REPL 2014-05-20 12:57:43 +02:00
a05adb1128 Refactored file structure 2014-05-20 12:48:34 +02:00
dfc3cb441b Increase default peer amount to 10 2014-05-20 11:52:36 +02:00
92eaa98e83 Added js interpret mode 2014-05-19 17:01:40 +02:00
017bbbb582 Improved REPL output 2014-05-19 16:32:45 +02:00
16421106d4 Added multi-line support 2014-05-19 13:04:31 +02:00
3b7707c3fd Improved console
* Added watch
2014-05-19 12:15:03 +02:00
30842eb8d0 Changed logging 2014-05-19 12:14:47 +02:00
43f88b2bbb Removed nonce incrementing 2014-05-19 12:14:32 +02:00
770808ce0d Readline repl for linux & osx 2014-05-17 15:15:46 +02:00
2ac292dc7a Merge branch 'feature/otto' into develop 2014-05-15 22:17:23 +02:00
6a78e080e6 Tell config which loggers to use 2014-05-15 22:17:09 +02:00
0a03484188 Implemented JavaScript console 2014-05-15 22:15:14 +02:00
cbce882f5e Basic javascript console 2014-05-15 20:45:19 +02:00
3a2bddc160 Refactored to reactor. Fixes #42 2014-05-15 14:06:06 +02:00
9ba3c6d1af Merge branch 'release/poc5-rc6' into develop 2014-05-14 21:34:37 +02:00
942f552c62 Merge branch 'release/poc5-rc6' 2014-05-14 21:34:21 +02:00
a73ae8727d Bumped version 2014-05-14 21:34:01 +02:00
278ee3f16c Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-05-14 14:57:16 +02:00
9a057021c3 Update wallet value for coinbase rewards. Implements #44 & #43 2014-05-14 14:57:05 +02:00
a1dcc5cd17 Prevent crash during import of privkeys.
@obscuren please check if this was commented out for a reason
2014-05-14 14:11:45 +02:00
c9db87277b Fix merge conflicts 2014-05-14 14:04:43 +02:00
2c7b625daa Make sure we have a coinbase address to mine with 2014-05-14 13:55:55 +02:00
f18ec51cb3 Switched to new keyring methods 2014-05-14 13:55:08 +02:00
9fce273ce9 Refactored RPC client to utils so it can be reused 2014-05-14 13:32:49 +02:00
2012e0c67a Rewritten a check to only start mining once we are caught up with all peers 2014-05-14 13:26:15 +02:00
e8147cf7c6 Refactored mining into utils and exposed it to ethereal. Partly fixes #43 2014-05-14 12:41:30 +02:00
0d9c948b9b Generate coinbase from privatekey, not pubkey. Partily fixes #43 2014-05-14 12:24:49 +02:00
faa3073625 Changed validators to regexp validators
IntValidator limits to 32bit int (JavaScript limitation) and therefor
the input fields are limited in length.
2014-05-13 22:25:05 +02:00
809b4ae0f6 Merge branch 'develop' 2014-05-13 16:39:32 +02:00
7f94b266c7 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-05-13 16:39:23 +02:00
1adfc272a8 Merge branch 'release/poc5-rc4' 2014-05-13 16:37:47 +02:00
9caf53f8c6 Bumped 2014-05-13 16:37:15 +02:00
fca36cc03d Typo 2014-05-13 16:36:29 +02:00
b71094b01c Removed harcoded addresses from GetBlock JS bindings. Fixes #39 2014-05-13 16:32:35 +02:00
edc281ac5f Depcrecated set 2014-05-13 14:53:46 +02:00
ee2cef3b2e Adding new API test case html 2014-05-13 14:49:21 +02:00
54eff2d778 Change coinbase to be the address not public key 2014-05-13 14:48:45 +02:00
20ea78945e Implemented new JS/EthPub methods
- getTxCountAt
- getPeerCount
- getIsMining
- getIsListening
- getCoinbase
2014-05-13 14:43:08 +02:00
dd60382fc3 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop
Conflicts:
	ethereal/ethereum.go
	ethereum/ethereum.go
2014-05-13 12:46:40 +02:00
32c6126593 Fix 2014-05-13 12:45:47 +02:00
03371b74d7 Public ethereum interface uses EthManager 2014-05-13 12:42:01 +02:00
c99aa7bdcf Fix merge conflict 2014-05-13 12:40:45 +02:00
5208b04821 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-05-13 12:08:54 +02:00
9a03df7bd8 Implemented a flag for a different RPC port; --rpcport 2014-05-13 12:00:48 +02:00
67820506cb Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-05-13 11:59:13 +02:00
8c9e6746ce Fixed wallet crash for new account. Fixes #38 2014-05-13 11:59:03 +02:00
b9876df5dc Added support to NewJsonRpc to return an error as well as an interface 2014-05-13 11:50:39 +02:00
a5963d1377 Enable seed again 2014-05-13 11:34:47 +02:00
c3ad210846 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-05-12 17:23:16 +02:00
618f523124 Actually start the Ethereum server on starting the GUI 2014-05-12 17:23:14 +02:00
c7132e5d22 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-05-12 13:56:37 +02:00
c43ea30e75 Refactored some code and fixed #37 2014-05-12 13:56:29 +02:00
cf7ab07264 Disable seed by default
Seed host seems down, only causes timeouts, not helpful
2014-05-12 13:41:52 +02:00
5d15563ea7 PreProcess => PreParse 2014-05-12 12:22:16 +02:00
a3cc4b0b80 Merge branch 'release/poc5-rc3' into develop 2014-05-10 16:25:08 +02:00
721d3a9a57 Merge branch 'release/poc5-rc3' 2014-05-10 16:25:01 +02:00
23fc50c61b Upgraded to new mutan 2014-05-10 16:22:57 +02:00
faa3aa14ed Merge branch 'release/poc5-rc2' into develop 2014-05-10 02:03:30 +02:00
b0023f66b0 Merge branch 'release/poc5-rc2' 2014-05-10 02:03:22 +02:00
109395daaa Bump 2014-05-10 02:02:59 +02:00
f73a5f067a fxed 2014-05-10 02:00:18 +02:00
1471585af0 Moved Ext app js to its own dir 2014-05-10 01:57:10 +02:00
0bf2d24cb0 Changed seeding 2014-05-09 14:51:02 +02:00
f59f515def Cleanup 2014-05-08 18:24:28 +02:00
71defc11fa Fixed closure 2014-05-08 14:20:17 +02:00
53eb59ed81 Normalized font 2014-05-05 20:56:48 +02:00
fb903619e8 Merge branch 'release/poc5-rc1' into develop 2014-05-05 15:56:11 +02:00
a77dcd1041 Merge branch 'release/poc5-rc1' 2014-05-05 15:56:05 +02:00
70221c36e3 bump 2014-05-05 15:55:20 +02:00
c9852c4929 Renamed etherpc to ethrpc
All work and no play makes Maran a dull boy
2014-05-05 15:15:04 +02:00
cb9ca992de Merge branch 'develop' into feature/rpc 2014-05-05 14:17:20 +02:00
e94e5ac75d Implemented rpc for ethereal and ethereum 2014-05-05 14:16:14 +02:00
91824af46b Changed getkey and secrettoaddress 2014-05-05 13:09:11 +02:00
dd45197bcd Added storage watch 2014-05-05 11:56:05 +02:00
bcb3ad7332 Fix circular deps 2014-05-02 20:01:25 +02:00
2582d719b2 Updated sample coin 2014-05-02 14:08:38 +02:00
231ad9b562 Merge branch 'develop' into feature/rpc 2014-05-02 14:08:08 +02:00
ed64434dcc Moved public interface 2014-05-02 13:55:58 +02:00
60f9966cd8 Merge branch 'develop' into feature/rpc 2014-05-02 13:35:44 +02:00
f1da6f0564 Fixed samplecoin 2014-05-02 13:35:12 +02:00
3424bf17ca Moved RPC Server and implemented it as a package 2014-05-02 13:35:03 +02:00
ee04c6ff67 Added string conversion API
* bin
* pad
* unpad
* conversion bin/hex/dec
2014-05-02 12:08:52 +02:00
5a692b9f2b Moved API 2014-05-02 12:08:15 +02:00
471bd398f3 Moved Ext ethereum api
Moved the external ethereum api which can be used by any 3rd party
application.
2014-05-02 12:07:24 +02:00
1b597b8ca9 Initial commit 2014-05-02 12:01:50 +02:00
9e481804a7 Added a 'set' method to change window settings for external applications 2014-05-01 22:59:16 +02:00
76cd14ab7b Moved and improved sample coin 2014-05-01 22:15:34 +02:00
abb2bebf7f Fixed minor issue with upnp where 'err' wasn't checked resulting in crash 2014-05-01 19:02:35 +02:00
da7828f336 Fixed tx nonce 2014-04-30 17:13:12 +02:00
c5481b7654 getBalanceAt getStorageAt, fixed get balance api call 2014-04-30 14:54:59 +02:00
183dbcc6a0 fixed state object changes for eth api 2014-04-30 14:42:57 +02:00
e85d5dd428 API changes 2014-04-30 01:44:12 +02:00
64c2550b31 Split off External applications from main library
External applications now accept containers which function as the
frontend where the ExtApplication functions as the backend. Containers
execute within their own engine and have their own context and are
destroyed when released.
2014-04-30 01:44:02 +02:00
922974c760 Added muted 2014-04-28 23:24:42 +02:00
c0de11955b Merge pull request #34 from compleatang/develop
PreProcess moved to Mutan package
2014-04-28 22:00:07 +02:00
a0f35d3248 PreProcess moved to Mutan package 2014-04-28 11:40:05 +02:00
68e5568804 Draft mut(an)ed(itor) 2014-04-28 00:25:01 +02:00
883810b533 Using mutan assembler stage 2014-04-27 18:05:48 +02:00
0e8ca84b67 Updated version number 2014-04-27 16:52:48 +02:00
e16fd323e8 Leverage the new watch & address:changed functionality 2014-04-26 01:47:04 +02:00
d0438ac10a Moved 2014-04-25 19:24:39 +02:00
6ca99709d2 Merge 2014-04-25 10:34:57 +02:00
bbde892d50 Added callback mechanism and updated UI
* UI Now updates when a new block has been broadcasted
* Added a on, off and trigger
2014-04-24 14:43:00 +02:00
c535d0d246 Added new block sub for webapp 2014-04-24 14:42:31 +02:00
bb72347acf Minor fixes and sample coin "improvements" 2014-04-24 00:01:22 +02:00
43f1214f97 Refactored code 2014-04-23 15:54:34 +02:00
b962779a13 Minor update and fixes to the gui and console 2014-04-23 11:51:48 +02:00
a3c8f83562 Updated test coin 2014-04-23 11:51:34 +02:00
aec3e26ea0 Round one HTML external applications using QML(Qt5) WebKit2 w/o native bindings 2014-04-21 00:58:02 +02:00
6d5d539a85 Round one HTML external applications using QML(Qt5) WebKit2 w/o native bindings 2014-04-21 00:57:57 +02:00
a0c97b663d Updated closure call 2014-04-20 02:05:20 +02:00
59a7b13019 typo interrupt 2014-04-16 15:01:22 +01:00
32b09d652d non-interactive option
- add -y flag for non-interactive use
- refactor main
- output to logfile (not ideal..) but not to all ethutil loggers for privacy
2014-04-16 14:57:51 +01:00
f4c13f8656 logfile
- add logfile option to ethereum client flags
- fallback to StdOut
- Logger appended to ethutil.Config.Log loggers
- wrapper uses ethutil.Config.Log
2014-04-16 13:37:04 +01:00
7f0c974008 empty string -> empty byte array 2014-04-16 13:36:52 +01:00
9cf77cdbad Moved compiling related object to utils package 2014-04-16 04:08:37 +02:00
1cd7d4456b Updated to use new state object 2014-04-16 04:08:25 +02:00
6b644c17a7 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-04-15 16:18:04 -04:00
7cb065489c added init and main functions to script 2014-04-15 16:13:04 -04:00
c23a971a1f Fix up paneling 2014-04-14 17:14:07 -04:00
91c75c9305 Adding log messages to debug panel 2014-04-14 17:08:15 -04:00
28a48f1d9a Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-04-14 13:48:15 -04:00
8a2698ad5e Add send to contract 2014-04-14 13:46:59 -04:00
d092d05a31 Merge 2014-04-12 00:13:11 -04:00
ce43a9500f Debug steps 2014-04-12 00:12:10 -04:00
ab8d96258e Added isContract to gui 2014-04-11 17:05:02 -04:00
3f82d5172f remove test menu 2014-04-11 16:47:55 -04:00
11aa7da6c3 Initial refactor for wallet qml 2014-04-11 16:44:13 -04:00
5768b18a3b Refactored simple send to use states 2014-04-11 15:18:38 -04:00
710bbed1a2 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-04-11 13:36:27 -04:00
a9a6585913 Debugger 2014-04-11 13:36:25 -04:00
4d18798468 Fix merge conflicts 2014-04-11 13:33:08 -04:00
cf1ae41bc0 Improved (hopefully) the send transaction tab 2014-04-11 13:26:14 -04:00
8280dd65e6 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-04-11 12:50:36 -04:00
3238894a3b Added wip debugger 2014-04-11 12:50:31 -04:00
e2bf5d1270 Implemented key importing/generation for the GUI 2014-04-10 14:53:12 -04:00
834e43622c Merge branch 'feature/mnemonic' into develop 2014-04-09 11:08:35 -04:00
d9ce5f5f82 Merge pull request #32 from cabreraalex/develop
Fixed up grammar and spelling in README
2014-04-09 17:02:00 +02:00
cc5501b12f Importing mnemonic support 2014-04-09 10:29:52 -04:00
52b63459e9 Merge branch 'develop' into feature/mnemonic 2014-04-09 10:07:36 -04:00
1e94cb5286 Nonce handling 2014-04-09 16:01:11 +02:00
cd799926d2 Fixed up grammar and spelling in README 2014-04-07 15:58:36 -04:00
2edf133b46 Added mnemonic priv key 2014-04-07 13:59:42 +02:00
5da03f2e36 Merge branch 'develop' into miner 2014-04-05 11:20:37 +02:00
ee5e7f2b35 Fix merge conflict 2014-04-01 13:18:42 +02:00
5660d598df Added tx output 2014-04-01 10:40:34 +02:00
e403b28eea Fixed miner 2014-03-31 01:02:00 +02:00
97b98b1250 Fixed an issue with sending gas to a contract 2014-03-31 00:22:50 +02:00
ebbc5e7cb8 Updated to new mutan api 2014-03-30 22:03:29 +02:00
3fb7ae2fa1 Removed CreateTx 2014-03-27 19:45:55 +01:00
c5215fd4fb Added gas and gas price.
* library's `createTx` method changed so it accepts a gas price
* dev console accepts code as well as the library
2014-03-27 19:41:42 +01:00
1257e8b4b3 Merge branch 'master' into develop 2014-03-27 15:24:56 +01:00
1323f60c07 Merge pull request #31 from ethersphere/master
assetPath configurable on command line for ethereal GUI
2014-03-27 15:24:36 +01:00
e65c4ee93e Updated transaction constructor 2014-03-27 15:22:20 +01:00
49c710bf44 assetPath configurable on command line for ethereal GUI
- solves the problem of non-standard installs
- add AssetPath to config as string var
- introduced UiLib constructor which falls back to defaultAssetPath (earlier behaviour) if no assetPath is set
- defaultAssetPath now internal concern of UiLib
- gui.Start(assetPath) argument passed from ethereal main() as set Init() in config.go
- informative log message if wallet.qml fails to open
2014-03-27 17:14:04 +07:00
a30f5730b3 Reimplement new miner creation 2014-03-24 10:56:42 +01:00
6724d27c0c Merge master into miner branch 2014-03-24 10:26:19 +01:00
642630db15 Moved node to ethereum 2014-03-22 12:03:10 +01:00
45ec9c88e4 Moved node to ethereum 2014-03-22 12:03:03 +01:00
fe79a8f724 Merge branch 'develop' of https://github.com/WeMeetAgain/go-ethereum into WeMeetAgain-develop
Conflicts:
	ethereal/Makefile
2014-03-22 11:32:01 +01:00
1f2547b8a7 Major re-organisation.
The Ethereum node and Gui are now separated.
2014-03-22 01:02:24 +01:00
22b4e9b617 . 2014-03-22 00:35:53 +01:00
0db86e4485 Updated to work with the new chain 2014-03-21 11:16:41 +01:00
3002570085 Mining rework 2014-03-20 11:20:10 +01:00
07734c1e1c Merge conflicts 2014-03-17 10:42:36 +01:00
85e0447684 Fixed asset path error. Fixes #29 2014-03-16 18:34:34 +01:00
13e18e1d8f working linux makefile
when building develop branch, checkout of eth-go develop branch is required
2014-03-15 16:46:10 -07:00
1c983ed80c More mining stuff 2014-03-11 15:17:23 +01:00
96fcc1da32 Initial smart-miner stuff 2014-03-10 12:38:31 +01:00
fbd53f0e34 Renamed block manager to state manager 2014-03-05 10:57:14 +01:00
f7fb5b902c Conform to the new server model 2014-03-05 10:44:43 +01:00
8275059856 Moved qml files, conform to the new server model.
QML files got moved to their own directories. QML now has a ui helper
which should find assets in the correct resource directory
2014-03-05 10:44:33 +01:00
833a1a4eab Block mining log 2014-03-03 11:32:58 +01:00
3d2c3b0107 Using asset path helper (includes a debug path atm) 2014-03-03 00:54:41 +01:00
a482b0cc1b WIP Makefile 2014-03-03 00:54:05 +01:00
00533003b7 Get rid of the xpm files 2014-03-03 00:53:24 +01:00
b0be847416 Updated to use the state on the blocks 2014-03-03 00:53:10 +01:00
570ab249b3 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-03-01 19:53:24 +01:00
c6d6ca283d Update README.md 2014-02-28 17:04:45 +01:00
30c5922aa4 Update README.md 2014-02-28 17:02:38 +01:00
59a68b316f Update README.md 2014-02-28 17:02:24 +01:00
893da20ead Merge pull request #21 from jarradh/master
Search bin directory for qml
2014-02-28 16:46:34 +01:00
aa7c53b7ef Search bin directory for qml 2014-02-28 16:41:30 +01:00
a9d89d1f59 Merge branch 'develop' 2014-02-28 13:08:55 +01:00
f6a9aa4110 fixed about window 2014-02-28 13:08:41 +01:00
b72d3528bf Merge branch 'release/0.3.0' into develop 2014-02-28 12:20:59 +01:00
0adfa489de Merge branch 'release/0.3.0' 2014-02-28 12:20:47 +01:00
560a7073f4 Fixed connection button spamming 2014-02-28 12:18:19 +01:00
3a35d45ea8 Updated readme 2014-02-28 12:17:43 +01:00
075acec9e7 Changed to new get keys method on database interface 2014-02-28 12:17:26 +01:00
5e7f8cca4f Exit after importing a key 2014-02-28 12:17:02 +01:00
8d1d72abee Improved overall UI design and added a bunch of icons 2014-02-28 12:16:46 +01:00
dba1ba3822 Currency to string 2014-02-25 11:24:04 +01:00
6451a7187a Minor UI change 2014-02-25 10:55:44 +01:00
78b6e7ad95 Proper Nonce 2014-02-25 10:54:37 +01:00
e60ff6ca41 Moved ui lib 2014-02-25 10:54:15 +01:00
fe9eb47288 Minor fixes that to reflect changes in library 2014-02-24 13:51:16 +01:00
0656f465b0 Added transactions window 2014-02-23 01:56:04 +01:00
aa33a4b2fb Added some ui elements to make it easier to connect to nodes 2014-02-22 23:19:38 +01:00
2b967558ce Working out UI 2014-02-22 01:52:47 +01:00
3e8b27c9dc WIP library, sample app 2014-02-21 17:29:59 +01:00
95a48cea18 Peer amount update 2014-02-21 13:23:35 +01:00
aaac0c9998 Initial block chain fetching of existing blocks 2014-02-21 13:06:17 +01:00
05c353eca0 Added a basic <UNSTABLE> UI 2014-02-21 12:37:40 +01:00
d7ecc92c41 Fixed broken links. Fixes #18 2014-02-21 00:47:07 +01:00
6736c03711 Added editor for contracts 2014-02-18 12:09:36 +01:00
ab7dc92404 Added import/exporting of private keys 2014-02-18 12:09:26 +01:00
8c8554f558 Added license name and updated block output from the dev console 2014-02-18 01:34:33 +01:00
5257c25ee2 Merge branch 'master' into develop 2014-02-15 13:27:43 +01:00
6db8b5d06a Added link to dev package 2014-02-15 13:27:23 +01:00
86e6699528 Merge branch 'release/0.2.2' into develop 2014-02-15 12:10:31 +01:00
60 changed files with 12947 additions and 562 deletions

1
.gitignore vendored
View File

@ -9,4 +9,5 @@
*un~
.DS_Store
*/**/.DS_Store
./ethereum/ethereum

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013 Geff Obscura
Copyright (c) 2013 Jeffrey Wilcke
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -3,87 +3,70 @@ Ethereum
[![Build Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
Ethereum Go developer client (c) Jeffrey Wilcke
Ethereum Go Client © 2014 Jeffrey Wilcke.
Ethereum is currently in its testing phase. The current state is "Proof
of Concept 2". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge).
Current state: Proof of Concept 5.0 RC10.
Ethereum Go is split up in several sub packages Please refer to each
individual package for more information.
1. [eth](https://github.com/ethereum/eth-go)
2. [ethchain](https://github.com/ethereum/ethchain-go)
3. [ethwire](https://github.com/ethereum/ethwire-go)
4. [ethdb](https://github.com/ethereum/ethdb-go)
5. [ethutil](https://github.com/ethereum/ethutil-go)
The [eth](https://github.com/ethereum/eth-go) is the top-level package
of the Ethereum protocol. It functions as the Ethereum bootstrapping and
peer communication layer. The [ethchain](https://github.com/ethereum/ethchain-go)
contains the Ethereum blockchain, block manager, transaction and
transaction handlers. The [ethwire](https://github.com/ethereum/ethwire-go) contains
the Ethereum [wire protocol](http://wiki.ethereum.org/index.php/Wire_Protocol) which can be used
to hook in to the Ethereum network. [ethutil](https://github.com/ethereum/ethutil-go) contains
utility functions which are not Ethereum specific. The utility package
contains the [patricia trie](http://wiki.ethereum.org/index.php/Patricia_Tree),
[RLP Encoding](http://wiki.ethereum.org/index.php/RLP) and hex encoding
helpers. The [ethdb](https://github.com/ethereum/ethdb-go) package
contains the LevelDB interface and memory DB interface.
This executable is the front-end (currently nothing but a dev console) for
the Ethereum Go implementation.
For the development package please see the [eth-go package](https://github.com/ethereum/eth-go).
Build
=======
For build instruction please see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge)
To build Ethereal (GUI):
`go get github.com/ethereum/go-ethereum/ethereal`
Command line options
To build the node (CLI):
`go get github.com/ethereum/go-ethereum/ethereum`
For further, detailed, build instruction please see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go))
General command line options
====================
```
-c Launch the developer console
Shared between ethereum and ethereal
-m Start mining blocks
-genaddr Generates a new address and private key (destructive action)
-p Port on which the server will accept incomming connections (= 30303)
-upnp Enable UPnP (= false)
-x Desired amount of peers (= 5)
-h This help
```
-p Port on which the server will accept incomming connections
-upnp Enable UPnP
-x Desired amount of peers
-r Start JSON RPC
-dir Data directory used to store configs and databases
-import Import a private key
-h This
Developer console commands
==========================
Ethereum only
ethereum [options] [filename]
-js Start the JavaScript REPL
filename Load the given file and interpret as JavaScript
Etheral only
-asset_path absolute path to GUI assets directory
```
addp <host>:<port> Connect to the given host
tx <addr> <amount> Send <amount> Wei to the specified <addr>
```
See the "help" command for *developer* options.
Contribution
============
If you'd like to contribute to Ethereum Go please fork, fix, commit and
send a pull request. Commits who do not comply with the coding standards
are ignored. If you send pull requests make absolute sure that you
commit on the `develop` branch and that you do not merge to master.
Commits that are directly based on master are simply ignored.
If you would like to contribute to Ethereum Go, please fork, fix, commit and
send a pull request to the main repository. Commits which do not comply with the coding standards explained below
will be ignored. If you send a pull request, make sure that you
commit to the `develop` branch and that you do not merge to `master`.
Commits that are directly based off of the `master` branch instead of the `develop` branch will be ignored.
To make life easier try [git flow](http://nvie.com/posts/a-successful-git-branching-model/) it sets
this all up and streamlines your work flow.
To make this process simpler try following the [git flow](http://nvie.com/posts/a-successful-git-branching-model/) branching model, as it sets this process up and streamlines work flow.
Coding standards
================
Sources should be formatted according to the [Go Formatting
Code should be formatted according to the [Go Formatting
Style](http://golang.org/doc/effective_go.html#formatting).
Unless structs fields are supposed to be directly accesible, provide
Getters and hide the fields through Go's exporting facility.
Unless struct fields are supposed to be directly accessible, provide
getters and hide the fields through Go's exporting facility.
When you comment put meaningfull comments. Describe in detail what you
want to achieve.
Make comments in your code meaningful and only use them when necessary. Describe in detail what your code is trying to achieve. For example, this would be redundant and unnecessary commenting:
*wrong*
@ -94,12 +77,7 @@ if x > y {
}
```
Everyone reading the source probably know what you wanted to achieve
with above code. Those are **not** meaningful comments.
Everyone reading the source code should know what this code snippet was meant to achieve, and so those are **not** meaningful comments.
While the project isn't 100% tested I want you to write tests non the
less. I haven't got time to evaluate everyone's code in detail so I
expect you to write tests for me so I don't have to test your code
manually. (If you want to contribute by just writing tests that's fine
too!)
While this project is constantly tested and run, code tests should be written regardless. There is not time to evaluate every person's code specifically, so it is expected of you to write tests for the code so that it does not have to be tested manually. In fact, contributing by simply writing tests is perfectly fine!

View File

@ -1,28 +0,0 @@
package main
import (
"flag"
)
var StartConsole bool
var StartMining bool
var UseUPnP bool
var OutboundPort string
var ShowGenesis bool
var AddPeer string
var MaxPeer int
var GenAddr bool
var UseSeed bool
func Init() {
flag.BoolVar(&StartConsole, "c", false, "debug and testing console")
flag.BoolVar(&StartMining, "m", false, "start dagger mining")
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.StringVar(&OutboundPort, "p", "30303", "listening port")
flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers")
flag.Parse()
}

View File

@ -1,218 +0,0 @@
package main
import (
"bufio"
"encoding/hex"
"errors"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
_ "math/big"
"os"
"strings"
)
type Console struct {
db *ethdb.MemDatabase
trie *ethutil.Trie
ethereum *eth.Ethereum
}
func NewConsole(s *eth.Ethereum) *Console {
db, _ := ethdb.NewMemDatabase()
trie := ethutil.NewTrie(db, "")
return &Console{db: db, trie: trie, ethereum: s}
}
func (i *Console) ValidateInput(action string, argumentLength int) error {
err := false
var expArgCount int
switch {
case action == "update" && argumentLength != 2:
err = true
expArgCount = 2
case action == "get" && argumentLength != 1:
err = true
expArgCount = 1
case action == "dag" && argumentLength != 2:
err = true
expArgCount = 2
case action == "decode" && argumentLength != 1:
err = true
expArgCount = 1
case action == "encode" && argumentLength != 1:
err = true
expArgCount = 1
case action == "gettx" && argumentLength != 1:
err = true
expArgCount = 1
case action == "tx" && argumentLength != 2:
err = true
expArgCount = 2
case action == "getaddr" && argumentLength != 1:
err = true
expArgCount = 1
case action == "contract" && argumentLength != 1:
err = true
expArgCount = 1
case action == "say" && argumentLength != 1:
err = true
expArgCount = 1
case action == "addp" && argumentLength != 1:
err = true
expArgCount = 1
case action == "block" && argumentLength != 1:
err = true
expArgCount = 1
}
if err {
return errors.New(fmt.Sprintf("'%s' requires %d args, got %d", action, expArgCount, argumentLength))
} else {
return nil
}
}
func (i *Console) PrintRoot() {
root := ethutil.NewValue(i.trie.Root)
if len(root.Bytes()) != 0 {
fmt.Println(hex.EncodeToString(root.Bytes()))
} else {
fmt.Println(i.trie.Root)
}
}
func (i *Console) ParseInput(input string) bool {
scanner := bufio.NewScanner(strings.NewReader(input))
scanner.Split(bufio.ScanWords)
count := 0
var tokens []string
for scanner.Scan() {
count++
tokens = append(tokens, scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading input:", err)
}
if len(tokens) == 0 {
return true
}
err := i.ValidateInput(tokens[0], count-1)
if err != nil {
fmt.Println(err)
} else {
switch tokens[0] {
case "update":
i.trie.Update(tokens[1], tokens[2])
i.PrintRoot()
case "get":
fmt.Println(i.trie.Get(tokens[1]))
case "root":
i.PrintRoot()
case "rawroot":
fmt.Println(i.trie.Root)
case "print":
i.db.Print()
case "dag":
fmt.Println(ethchain.DaggerVerify(ethutil.Big(tokens[1]), // hash
ethutil.BigPow(2, 36), // diff
ethutil.Big(tokens[2]))) // nonce
case "decode":
value := ethutil.NewValueFromBytes([]byte(tokens[1]))
fmt.Println(value)
case "getaddr":
encoded, _ := hex.DecodeString(tokens[1])
addr := i.ethereum.BlockManager.BlockChain().CurrentBlock.GetAddr(encoded)
fmt.Println("addr:", addr)
case "block":
encoded, _ := hex.DecodeString(tokens[1])
block := i.ethereum.BlockManager.BlockChain().GetBlock(encoded)
fmt.Println(block)
case "say":
i.ethereum.Broadcast(ethwire.MsgTalkTy, []interface{}{tokens[1]})
case "addp":
i.ethereum.ConnectToPeer(tokens[1])
case "pcount":
fmt.Println("peers:", i.ethereum.Peers().Len())
case "encode":
fmt.Printf("%q\n", ethutil.Encode(tokens[1]))
case "tx":
recipient, err := hex.DecodeString(tokens[1])
if err != nil {
fmt.Println("recipient err:", err)
} else {
tx := ethchain.NewTransaction(recipient, ethutil.Big(tokens[2]), []string{""})
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
keyRing := ethutil.NewValueFromBytes(data)
tx.Sign(keyRing.Get(0).Bytes())
fmt.Printf("%x\n", tx.Hash())
i.ethereum.TxPool.QueueTransaction(tx)
}
case "gettx":
addr, _ := hex.DecodeString(tokens[1])
data, _ := ethutil.Config.Db.Get(addr)
if len(data) != 0 {
decoder := ethutil.NewValueFromBytes(data)
fmt.Println(decoder)
} else {
fmt.Println("gettx: tx not found")
}
case "contract":
contract := ethchain.NewTransaction([]byte{}, ethutil.Big(tokens[1]), []string{"PUSH", "1234"})
fmt.Printf("%x\n", contract.Hash())
i.ethereum.TxPool.QueueTransaction(contract)
case "exit", "quit", "q":
return false
case "help":
fmt.Printf("COMMANDS:\n" +
"\033[1m= DB =\033[0m\n" +
"update KEY VALUE - Updates/Creates a new value for the given key\n" +
"get KEY - Retrieves the given key\n" +
"root - Prints the hex encoded merkle root\n" +
"rawroot - Prints the raw merkle root\n" +
"block HASH - Prints the block\n" +
"getaddr ADDR - Prints the account associated with the address\n" +
"\033[1m= Dagger =\033[0m\n" +
"dag HASH NONCE - Verifies a nonce with the given hash with dagger\n" +
"\033[1m= Encoding =\033[0m\n" +
"decode STR\n" +
"encode STR\n" +
"\033[1m= Other =\033[0m\n" +
"addp HOST:PORT\n" +
"tx TO AMOUNT\n" +
"contract AMOUNT\n")
default:
fmt.Println("Unknown command:", tokens[0])
}
}
return true
}
func (i *Console) Start() {
fmt.Printf("Eth Console. Type (help) for help\n")
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf("eth >>> ")
str, _, err := reader.ReadLine()
if err != nil {
fmt.Println("Error reading input", err)
} else {
if !i.ParseInput(string(str)) {
return
}
}
}
}

22
ethereal/Makefile Normal file
View File

@ -0,0 +1,22 @@
UNAME = $(shell uname)
FILES=qml *.png
GOPATH=$(PWD)
# Default is building
all:
go get -d
cp *.go $(GOPATH)/src/github.com/ethereum/go-ethereum
cp -r ui $(GOPATH)/src/github.com/ethereum/go-ethereum
go build
install:
# Linux build
ifeq ($(UNAME),Linux)
cp -r assets/* /usr/share/ethereal
cp go-ethereum /usr/local/bin/ethereal
endif
# OS X build
ifeq ($(UNAME),Darwin)
# Execute py script
endif

View File

@ -0,0 +1,236 @@
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 {
visible: false
title: "IceCream"
minimumWidth: 1280
minimumHeight: 900
width: 1290
height: 900
MenuBar {
Menu {
title: "Debugger"
MenuItem {
text: "Run"
shortcut: "Ctrl+r"
onTriggered: debugCurrent()
}
MenuItem {
text: "Next"
shortcut: "Ctrl+n"
onTriggered: dbg.next()
}
}
}
SplitView {
anchors.fill: parent
property var asmModel: ListModel {
id: asmModel
}
TableView {
id: asmTableView
width: 200
TableViewColumn{ role: "value" ; title: "" ; width: 100 }
model: asmModel
}
Rectangle {
color: "#00000000"
anchors.left: asmTableView.right
anchors.right: parent.right
SplitView {
orientation: Qt.Vertical
anchors.fill: parent
Rectangle {
color: "#00000000"
height: 500
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
}
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: 250
TableView {
id: stackTableView
property var stackModel: ListModel {
id: stackModel
}
height: parent.height
width: 300
TableViewColumn{ role: "value" ; title: "Stack" ; width: 200 }
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: 750}
model: memModel
}
}
SplitView {
height: 300
TableView {
id: storageTableView
property var memModel: ListModel {
id: storageModel
}
height: parent.height
width: parent.width - stackTableView.width
TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2}
TableViewColumn{ role: "value" ; title: "value" ; width: storageTableView.width / 2}
model: storageModel
}
}
}
}
}
}
toolBar: ToolBar {
RowLayout {
spacing: 5
Button {
property var enabled: true
id: debugStart
onClicked: {
debugCurrent()
}
text: "Debug"
}
Button {
property var enabled: true
id: debugNextButton
onClicked: {
dbg.next()
}
text: "Next"
}
}
}
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-1)
}
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})
}
}

380
ethereal/assets/ext/big.js Normal file
View File

@ -0,0 +1,380 @@
var bigInt = (function () {
var base = 10000000, logBase = 7;
var sign = {
positive: false,
negative: true
};
var normalize = function (first, second) {
var a = first.value, b = second.value;
var length = a.length > b.length ? a.length : b.length;
for (var i = 0; i < length; i++) {
a[i] = a[i] || 0;
b[i] = b[i] || 0;
}
for (var i = length - 1; i >= 0; i--) {
if (a[i] === 0 && b[i] === 0) {
a.pop();
b.pop();
} else break;
}
if (!a.length) a = [0], b = [0];
first.value = a;
second.value = b;
};
var parse = function (text, first) {
if (typeof text === "object") return text;
text += "";
var s = sign.positive, value = [];
if (text[0] === "-") {
s = sign.negative;
text = text.slice(1);
}
var base = 10;
if (text.slice(0, 2) == "0x") {
base = 16;
text = text.slice(2);
}
else {
var texts = text.split("e");
if (texts.length > 2) throw new Error("Invalid integer");
if (texts[1]) {
var exp = texts[1];
if (exp[0] === "+") exp = exp.slice(1);
exp = parse(exp);
if (exp.lesser(0)) throw new Error("Cannot include negative exponent part for integers");
while (exp.notEquals(0)) {
texts[0] += "0";
exp = exp.prev();
}
}
text = texts[0];
}
if (text === "-0") text = "0";
text = text.toUpperCase();
var isValid = (base == 16 ? /^[0-9A-F]*$/ : /^[0-9]+$/).test(text);
if (!isValid) throw new Error("Invalid integer");
if (base == 16) {
var val = bigInt(0);
while (text.length) {
v = text.charCodeAt(0) - 48;
if (v > 9)
v -= 7;
text = text.slice(1);
val = val.times(16).plus(v);
}
return val;
}
else {
while (text.length) {
var divider = text.length > logBase ? text.length - logBase : 0;
value.push(+text.slice(divider));
text = text.slice(0, divider);
}
var val = bigInt(value, s);
if (first) normalize(first, val);
return val;
}
};
var goesInto = function (a, b) {
var a = bigInt(a, sign.positive), b = bigInt(b, sign.positive);
if (a.equals(0)) throw new Error("Cannot divide by 0");
var n = 0;
do {
var inc = 1;
var c = bigInt(a.value, sign.positive), t = c.times(10);
while (t.lesser(b)) {
c = t;
inc *= 10;
t = t.times(10);
}
while (c.lesserOrEquals(b)) {
b = b.minus(c);
n += inc;
}
} while (a.lesserOrEquals(b));
return {
remainder: b.value,
result: n
};
};
var bigInt = function (value, s) {
var self = {
value: value,
sign: s
};
var o = {
value: value,
sign: s,
negate: function (m) {
var first = m || self;
return bigInt(first.value, !first.sign);
},
abs: function (m) {
var first = m || self;
return bigInt(first.value, sign.positive);
},
add: function (n, m) {
var s, first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
s = first.sign;
if (first.sign !== second.sign) {
first = bigInt(first.value, sign.positive);
second = bigInt(second.value, sign.positive);
return s === sign.positive ?
o.subtract(first, second) :
o.subtract(second, first);
}
normalize(first, second);
var a = first.value, b = second.value;
var result = [],
carry = 0;
for (var i = 0; i < a.length || carry > 0; i++) {
var sum = (a[i] || 0) + (b[i] || 0) + carry;
carry = sum >= base ? 1 : 0;
sum -= carry * base;
result.push(sum);
}
return bigInt(result, s);
},
plus: function (n, m) {
return o.add(n, m);
},
subtract: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
if (first.sign !== second.sign) return o.add(first, o.negate(second));
if (first.sign === sign.negative) return o.subtract(o.negate(second), o.negate(first));
if (o.compare(first, second) === -1) return o.negate(o.subtract(second, first));
var a = first.value, b = second.value;
var result = [],
borrow = 0;
for (var i = 0; i < a.length; i++) {
var tmp = a[i] - borrow;
borrow = tmp < b[i] ? 1 : 0;
var minuend = (borrow * base) + tmp - b[i];
result.push(minuend);
}
return bigInt(result, sign.positive);
},
minus: function (n, m) {
return o.subtract(n, m);
},
multiply: function (n, m) {
var s, first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
s = first.sign !== second.sign;
var a = first.value, b = second.value;
var resultSum = [];
for (var i = 0; i < a.length; i++) {
resultSum[i] = [];
var j = i;
while (j--) {
resultSum[i].push(0);
}
}
var carry = 0;
for (var i = 0; i < a.length; i++) {
var x = a[i];
for (var j = 0; j < b.length || carry > 0; j++) {
var y = b[j];
var product = y ? (x * y) + carry : carry;
carry = product > base ? Math.floor(product / base) : 0;
product -= carry * base;
resultSum[i].push(product);
}
}
var max = -1;
for (var i = 0; i < resultSum.length; i++) {
var len = resultSum[i].length;
if (len > max) max = len;
}
var result = [], carry = 0;
for (var i = 0; i < max || carry > 0; i++) {
var sum = carry;
for (var j = 0; j < resultSum.length; j++) {
sum += resultSum[j][i] || 0;
}
carry = sum > base ? Math.floor(sum / base) : 0;
sum -= carry * base;
result.push(sum);
}
return bigInt(result, s);
},
times: function (n, m) {
return o.multiply(n, m);
},
divmod: function (n, m) {
var s, first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
s = first.sign !== second.sign;
if (bigInt(first.value, first.sign).equals(0)) return {
quotient: bigInt([0], sign.positive),
remainder: bigInt([0], sign.positive)
};
if (second.equals(0)) throw new Error("Cannot divide by zero");
var a = first.value, b = second.value;
var result = [], remainder = [];
for (var i = a.length - 1; i >= 0; i--) {
var n = [a[i]].concat(remainder);
var quotient = goesInto(b, n);
result.push(quotient.result);
remainder = quotient.remainder;
}
result.reverse();
return {
quotient: bigInt(result, s),
remainder: bigInt(remainder, first.sign)
};
},
divide: function (n, m) {
return o.divmod(n, m).quotient;
},
over: function (n, m) {
return o.divide(n, m);
},
mod: function (n, m) {
return o.divmod(n, m).remainder;
},
pow: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m));
else second = parse(n, first);
var a = first, b = second;
if (b.lesser(0)) return ZERO;
if (b.equals(0)) return ONE;
var result = bigInt(a.value, a.sign);
if (b.mod(2).equals(0)) {
var c = result.pow(b.over(2));
return c.times(c);
} else {
return result.times(result.pow(b.minus(1)));
}
},
next: function (m) {
var first = m || self;
return o.add(first, 1);
},
prev: function (m) {
var first = m || self;
return o.subtract(first, 1);
},
compare: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m, first));
else second = parse(n, first);
normalize(first, second);
if (first.value.length === 1 && second.value.length === 1 && first.value[0] === 0 && second.value[0] === 0) return 0;
if (second.sign !== first.sign) return first.sign === sign.positive ? 1 : -1;
var multiplier = first.sign === sign.positive ? 1 : -1;
var a = first.value, b = second.value;
for (var i = a.length - 1; i >= 0; i--) {
if (a[i] > b[i]) return 1 * multiplier;
if (b[i] > a[i]) return -1 * multiplier;
}
return 0;
},
compareAbs: function (n, m) {
var first = self, second;
if (m) (first = parse(n)) && (second = parse(m, first));
else second = parse(n, first);
first.sign = second.sign = sign.positive;
return o.compare(first, second);
},
equals: function (n, m) {
return o.compare(n, m) === 0;
},
notEquals: function (n, m) {
return !o.equals(n, m);
},
lesser: function (n, m) {
return o.compare(n, m) < 0;
},
greater: function (n, m) {
return o.compare(n, m) > 0;
},
greaterOrEquals: function (n, m) {
return o.compare(n, m) >= 0;
},
lesserOrEquals: function (n, m) {
return o.compare(n, m) <= 0;
},
isPositive: function (m) {
var first = m || self;
return first.sign === sign.positive;
},
isNegative: function (m) {
var first = m || self;
return first.sign === sign.negative;
},
isEven: function (m) {
var first = m || self;
return first.value[0] % 2 === 0;
},
isOdd: function (m) {
var first = m || self;
return first.value[0] % 2 === 1;
},
toString: function (m) {
var first = m || self;
var str = "", len = first.value.length;
while (len--) {
if (first.value[len].toString().length === 8) str += first.value[len];
else str += (base.toString() + first.value[len]).slice(-logBase);
}
while (str[0] === "0") {
str = str.slice(1);
}
if (!str.length) str = "0";
var s = (first.sign === sign.positive || str == "0") ? "" : "-";
return s + str;
},
toHex: function (m) {
var first = m || self;
var str = "";
var l = this.abs();
while (l > 0) {
var qr = l.divmod(256);
var b = qr.remainder.toJSNumber();
str = (b >> 4).toString(16) + (b & 15).toString(16) + str;
l = qr.quotient;
}
return (this.isNegative() ? "-" : "") + "0x" + str;
},
toJSNumber: function (m) {
return +o.toString(m);
},
valueOf: function (m) {
return o.toJSNumber(m);
}
};
return o;
};
var ZERO = bigInt([0], sign.positive);
var ONE = bigInt([1], sign.positive);
var MINUS_ONE = bigInt([1], sign.negative);
var fnReturn = function (a) {
if (typeof a === "undefined") return ZERO;
return parse(a);
};
fnReturn.zero = ZERO;
fnReturn.one = ONE;
fnReturn.minusOne = MINUS_ONE;
return fnReturn;
})();
if (typeof module !== "undefined") {
module.exports = bigInt;
}

View File

@ -0,0 +1,138 @@
// Main Ethereum library
window.eth = {
prototype: Object(),
// Retrieve block
//
// Either supply a number or a string. Type is determent for the lookup method
// string - Retrieves the block by looking up the hash
// number - Retrieves the block by looking up the block number
getBlock: function(numberOrHash, cb) {
var func;
if(typeof numberOrHash == "string") {
func = "getBlockByHash";
} else {
func = "getBlockByNumber";
}
postData({call: func, args: [numberOrHash]}, cb);
},
// Create transaction
//
// Transact between two state objects
transact: function(sec, recipient, value, gas, gasPrice, data, cb) {
postData({call: "transact", args: [sec, recipient, value, gas, gasPrice, data]}, cb);
},
create: function(sec, value, gas, gasPrice, init, body, cb) {
postData({call: "create", args: [sec, value, gas, gasPrice, init, body]}, cb);
},
getStorageAt: function(address, storageAddress, cb) {
postData({call: "getStorage", args: [address, storageAddress]}, cb);
},
getKey: function(cb) {
postData({call: "getKey"}, cb);
},
getTxCountAt: function(address, cb) {
postData({call: "getTxCountAt", args: [address]}, cb);
},
getIsMining: function(cb){
postData({call: "getIsMining"}, cb)
},
getIsListening: function(cb){
postData({call: "getIsListening"}, cb)
},
getCoinBase: function(cb){
postData({call: "getCoinBase"}, cb);
},
getPeerCount: function(cb){
postData({call: "getPeerCount"}, cb);
},
getBalanceAt: function(address, cb) {
postData({call: "getBalance", args: [address]}, cb);
},
getSecretToAddress: function(sec, cb) {
postData({call: "getSecretToAddress", args: [sec]}, cb);
},
watch: function(address, storageAddrOrCb, cb) {
var ev;
if(cb === undefined) {
cb = storageAddrOrCb;
storageAddrOrCb = "";
ev = "object:"+address;
} else {
ev = "storage:"+address+":"+storageAddrOrCb;
}
eth.on(ev, cb)
postData({call: "watch", args: [address, storageAddrOrCb]});
},
disconnect: function(address, storageAddrOrCb, cb) {
var ev;
if(cb === undefined) {
cb = storageAddrOrCb;
storageAddrOrCb = "";
ev = "object:"+address;
} else {
ev = "storage:"+address+":"+storageAddrOrCb;
}
eth.off(ev, cb)
postData({call: "disconnect", args: [address, storageAddrOrCb]});
},
set: function(props) {
postData({call: "set", args: props});
},
on: function(event, cb) {
if(eth._onCallbacks[event] === undefined) {
eth._onCallbacks[event] = [];
}
eth._onCallbacks[event].push(cb);
return this
},
off: function(event, cb) {
if(eth._onCallbacks[event] !== undefined) {
var callbacks = eth._onCallbacks[event];
for(var i = 0; i < callbacks.length; i++) {
if(callbacks[i] === cb) {
delete callbacks[i];
}
}
}
return this
},
trigger: function(event, data) {
var callbacks = eth._onCallbacks[event];
if(callbacks !== undefined) {
for(var i = 0; i < callbacks.length; i++) {
// Figure out whether the returned data was an array
// array means multiple return arguments (multiple params)
if(data instanceof Array) {
callbacks[i].apply(this, data);
} else {
callbacks[i].call(this, data);
}
}
}
},
}
window.eth._callbacks = {}
window.eth._onCallbacks = {}

View File

@ -0,0 +1,58 @@
function debug(/**/) {
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]
}
}
postData({call:"debug", args:[msg]})
document.getElementById("debug").innerHTML += "<br>" + msg
}
// 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) {
eth._callbacks[data._seed] = cb;
}
if(data.args === undefined) {
data.args = [];
}
navigator.qt.postMessage(JSON.stringify(data));
}
navigator.qt.onmessage = function(ev) {
var data = JSON.parse(ev.data)
if(data._event !== undefined) {
eth.trigger(data._event, data.data);
} else {
if(data._seed) {
var cb = eth._callbacks[data._seed];
if(cb) {
// Figure out whether the returned data was an array
// array means multiple return arguments (multiple params)
if(data.data instanceof Array) {
cb.apply(this, data.data)
} else {
cb.call(this, data.data)
}
// Remove the "trigger" callback
delete eth._callbacks[ev._seed];
}
}
}
}
window.onerror = function(message, file, lineNumber, column, errorObj) {
debug(file, message, lineNumber+":"+column, errorObj);
return false;
}

View File

@ -0,0 +1,58 @@
String.prototype.pad = function(l, r) {
if (r === undefined) {
r = l
if (!(this.substr(0, 2) == "0x" || /^\d+$/.test(this)))
l = 0
}
var ret = this.bin();
while (ret.length < l)
ret = "\0" + ret
while (ret.length < r)
ret = ret + "\0"
return ret;
}
String.prototype.unpad = function() {
var i = this.length;
while (i && this[i - 1] == "\0")
--i
return this.substr(0, i)
}
String.prototype.bin = function() {
if (this.substr(0, 2) == "0x") {
bytes = []
var i = 2;
// Check if it's odd - pad with a zero if so.
if (this.length % 2)
bytes.push(parseInt(this.substr(i++, 1), 16))
for (; i < this.length - 1; i += 2)
bytes.push(parseInt(this.substr(i, 2), 16));
return String.fromCharCode.apply(String, bytes);
} else if (/^\d+$/.test(this))
return bigInt(this.substr(0)).toHex().bin()
// Otherwise we'll return the "String" object instead of an actual string
return this.substr(0, this.length)
}
String.prototype.unbin = function() {
var i, l, o = '';
for(i = 0, l = this.length; i < l; i++) {
var n = this.charCodeAt(i).toString(16);
o += n.length < 2 ? '0' + n : n;
}
return "0x" + o;
}
String.prototype.dec = function() {
return bigInt(this.substr(0)).toString()
}
String.prototype.hex = function() {
return bigInt(this.substr(0)).toHex()
}

BIN
ethereal/assets/facet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
ethereal/assets/heart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,272 @@
/* 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

@ -0,0 +1,53 @@
<!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

@ -0,0 +1,23 @@
.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

@ -0,0 +1,80 @@
<!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

@ -0,0 +1,182 @@
(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

@ -0,0 +1,117 @@
(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

@ -0,0 +1,61 @@
// 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];
}
}
}
}

BIN
ethereal/assets/net.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
ethereal/assets/network.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
ethereal/assets/new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -0,0 +1,155 @@
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
}
}
}

View File

@ -0,0 +1,74 @@
import QtQuick 2.0
import QtWebKit 3.0
import QtWebKit.experimental 1.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Window 2.1;
import Ethereum 1.0
ApplicationWindow {
id: window
title: "muted"
width: 900
height: 600
minimumHeight: 300
property alias url: webView.url
property alias webView: webView
Item {
id: root
anchors.fill: parent
WebView {
objectName: "webView"
id: webView
anchors {
top: root.top
right: root.right
left: root.left
bottom: root.bottom
//bottom: sizeGrip.top
}
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.onMessageReceived: {
var data = JSON.parse(message.data)
switch(data.call) {
case "log":
console.log.apply(this, data.args)
break;
}
}
function postData(seed, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _seed: seed}))
}
function postEvent(event, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
}
}
/*
Rectangle {
id: sizeGrip
color: "gray"
height: 5
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 - sizeGrip.height
drag.axis: Drag.YAxis
}
}
*/
}
}

View File

@ -0,0 +1,35 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import Ethereum 1.0
ApplicationWindow {
minimumWidth: 500
maximumWidth: 500
maximumHeight: 100
minimumHeight: 100
title: "Ethereum Dice"
TextField {
id: textField
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
placeholderText: "Amount"
}
Label {
id: txHash
anchors.bottom: textField.top
anchors.bottomMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
}
Button {
anchors.top: textField.bottom
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 5
text: "Place bet"
onClicked: {
txHash.text = eth.createTx("e6716f9544a56c530d868e4bfbacb172315bdead", textField.text)
}
}
}

View File

@ -0,0 +1,9 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
Rectangle {
id: transactionView
visible: false
Text { text: "TX VIEW" }
}

View File

@ -0,0 +1,987 @@
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: root
width: 900
height: 600
minimumHeight: 300
title: "Ethereal"
MenuBar {
Menu {
title: "File"
MenuItem {
text: "Import App"
shortcut: "Ctrl+o"
onTriggered: openAppDialog.open()
}
}
Menu {
title: "Tools"
MenuItem {
text: "Muted"
shortcut: "Ctrl+e"
onTriggered: ui.muted("")
}
MenuItem {
text: "Debugger"
shortcut: "Ctrl+d"
onTriggered: ui.startDebugger()
}
}
Menu {
title: "Network"
MenuItem {
text: "Add Peer"
shortcut: "Ctrl+p"
onTriggered: {
addPeerWin.visible = true
}
}
MenuItem {
text: "Start"
onTriggered: ui.connect()
}
}
Menu {
title: "Help"
MenuItem {
text: "About"
onTriggered: {
aboutWin.visible = true
}
}
}
}
property var blockModel: ListModel {
id: blockModel
}
function setView(view) {
networkView.visible = false
historyView.visible = false
newTxView.visible = false
infoView.visible = false
view.visible = true
//root.title = "Ethereal - " = view.title
}
SplitView {
anchors.fill: parent
resizing: false
Rectangle {
id: menu
Layout.minimumWidth: 80
Layout.maximumWidth: 80
anchors.bottom: parent.bottom
anchors.top: parent.top
//color: "#D9DDE7"
color: "#252525"
ColumnLayout {
y: 50
anchors.left: parent.left
anchors.right: parent.right
height: 200
Image {
source: ui.assetPath("tx.png")
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onClicked: {
setView(historyView)
}
}
}
Image {
source: ui.assetPath("new.png")
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onClicked: {
setView(newTxView)
}
}
}
Image {
source: ui.assetPath("net.png")
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onClicked: {
setView(networkView)
}
}
}
Image {
source: ui.assetPath("heart.png")
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onClicked: {
setView(infoView)
}
}
}
}
}
Rectangle {
id: mainView
color: "#00000000"
anchors.right: parent.right
anchors.left: menu.right
anchors.bottom: parent.bottom
anchors.top: parent.top
property var txModel: ListModel {
id: txModel
}
Rectangle {
id: historyView
anchors.fill: parent
property var title: "Transactions"
TableView {
id: txTableView
anchors.fill: parent
TableViewColumn{ role: "inout" ; title: "" ; width: 40 }
TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
TableViewColumn{ role: "address" ; title: "Address" ; width: 430 }
TableViewColumn{ role: "contract" ; title: "Contract" ; width: 100 }
model: txModel
}
}
Rectangle {
id: newTxView
property var title: "New transaction"
visible: false
anchors.fill: parent
color: "#00000000"
TabView{
anchors.fill: parent
anchors.rightMargin: 5
anchors.leftMargin: 5
anchors.topMargin: 5
anchors.bottomMargin: 5
id: newTransactionTab
Component.onCompleted:{
addTab("Simple send", newTransaction)
addTab("Contracts", newContract)
}
}
}
Rectangle {
id: networkView
property var title: "Network"
visible: false
anchors.fill: parent
TableView {
id: blockTable
width: parent.width
anchors.top: parent.top
anchors.bottom: logView.top
TableViewColumn{ role: "number" ; title: "#" ; width: 100 }
TableViewColumn{ role: "hash" ; title: "Hash" ; width: 560 }
TableViewColumn{ role: "txAmount" ; title: "Tx amount" ; width: 100 }
model: blockModel
onDoubleClicked: {
popup.visible = true
popup.setDetails(blockModel.get(row))
}
}
property var logModel: ListModel {
id: logModel
}
TableView {
id: logView
width: parent.width
height: 150
anchors.bottom: parent.bottom
TableViewColumn{ role: "description" ; title: "log" }
model: logModel
}
}
Rectangle {
id: infoView
property var title: "Information"
visible: false
color: "#00000000"
anchors.fill: parent
Label {
id: addressLabel
text: "Address"
anchors {
margins: 5
top: parent.top
left: parent.left
}
}
TextField {
anchors {
margins: 5
left: addressLabel.right
top: parent.top
}
text: pub.getKey().address
width: 500
}
}
/*
signal addPlugin(string name)
Component {
id: pluginWindow
Rectangle {
anchors.fill: parent
Label {
id: pluginTitle
anchors.centerIn: parent
text: "Hello world"
}
Component.onCompleted: setView(this)
}
}
onAddPlugin: {
var pluginWin = pluginWindow.createObject(mainView)
console.log(pluginWin)
pluginWin.pluginTitle.text = "Test"
}
*/
}
}
FileDialog {
id: openAppDialog
title: "Open QML Application"
onAccepted: {
//ui.open(openAppDialog.fileUrl.toString())
//ui.openHtml(Qt.resolvedUrl(ui.assetPath("test.html")))
ui.openHtml(openAppDialog.fileUrl.toString())
}
}
statusBar: StatusBar {
RowLayout {
anchors.fill: parent
Button {
property var enabled: true
id: debuggerWindow
onClicked: {
ui.startDebugger()
}
text: "Debugger"
}
Button {
id: importAppButton
anchors.left: debuggerWindow.right
anchors.leftMargin: 5
onClicked: openAppDialog.open()
text: "Import App"
}
Label {
anchors.left: importAppButton.right
anchors.leftMargin: 5
id: walletValueLabel
}
Label {
anchors.right: peerImage.left
anchors.rightMargin: 5
id: peerLabel
font.pixelSize: 8
text: "0 / 0"
}
Image {
id: peerImage
anchors.right: parent.right
width: 10; height: 10
source: ui.assetPath("network.png")
}
}
}
Window {
id: popup
visible: false
property var block
width: 800
height: 280
x: root.x
y: root.y + root.height
Component{
id: blockDetailsDelegate
Rectangle {
color: "#252525"
width: popup.width
height: 200
Column {
anchors.leftMargin: 10
anchors.topMargin: 5
anchors.top: parent.top
anchors.left: parent.left
Text { text: '<h3>Block details</h3>'; color: "#F2F2F2"}
Text { text: '<b>Block number:</b> ' + number; color: "#F2F2F2"}
Text { text: '<b>Hash:</b> ' + hash; color: "#F2F2F2"}
Text { text: '<b>Block found at:</b> ' + prettyTime; color: "#F2F2F2"}
}
}
}
ListView {
model: singleBlock
delegate: blockDetailsDelegate
anchors.top: parent.top
height: 70
anchors.leftMargin: 20
id: listViewThing
Layout.maximumHeight: 40
}
TableView {
id: txView
anchors.top: listViewThing.bottom
anchors.topMargin: 50
width: parent.width
TableViewColumn{width: 90; role: "value" ; title: "Value" }
TableViewColumn{width: 200; role: "hash" ; title: "Hash" }
TableViewColumn{width: 200; role: "sender" ; title: "Sender" }
TableViewColumn{width: 200;role: "address" ; title: "Receiver" }
TableViewColumn{width: 60; role: "gas" ; title: "Gas" }
TableViewColumn{width: 60; role: "gasPrice" ; title: "Gas Price" }
TableViewColumn{width: 60; role: "isContract" ; title: "Contract" }
model: transactionModel
onClicked: {
var tx = transactionModel.get(row)
if(tx.data) {
popup.showContractData(tx.data)
}else{
popup.height = 230
}
}
}
function showContractData(data) {
contractData.text = data
popup.height = 400
}
Rectangle {
width: popup.width
height: 300
anchors.left: listViewThing.left
anchors.top: txView.bottom
Label {
text: "<h4>Contract data</h4>"
anchors.top: parent.top
anchors.left: parent.left
id: contractLabel
anchors.leftMargin: 10
}
TextArea {
id: contractData
text: "Contract"
anchors.top: contractLabel.bottom
anchors.left: parent.left
wrapMode: Text.Wrap
width: parent.width - 30
height: 80
anchors.leftMargin: 10
}
}
property var transactionModel: ListModel {
id: transactionModel
}
property var singleBlock: ListModel {
id: singleBlock
}
function setDetails(block){
singleBlock.set(0,block)
popup.height = 230
transactionModel.clear()
if(block.txs != undefined){
for(var i = 0; i < block.txs.count; ++i) {
transactionModel.insert(0, block.txs.get(i))
}
if(block.txs.get(0).data){
popup.showContractData(block.txs.get(0).data)
}
}
txView.forceActiveFocus()
}
}
Window {
id: addPeerWin
visible: false
minimumWidth: 230
maximumWidth: 230
maximumHeight: 50
minimumHeight: 50
TextField {
id: addrField
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 10
placeholderText: "address:port"
onAccepted: {
ui.connectToPeer(addrField.text)
addPeerWin.visible = false
}
}
Button {
anchors.left: addrField.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 5
text: "Add"
onClicked: {
ui.connectToPeer(addrField.text)
addPeerWin.visible = false
}
}
Component.onCompleted: {
addrField.focus = true
}
}
Window {
id: aboutWin
visible: false
title: "About"
minimumWidth: 350
maximumWidth: 350
maximumHeight: 200
minimumHeight: 200
Image {
id: aboutIcon
height: 150
width: 150
fillMode: Image.PreserveAspectFit
smooth: true
source: ui.assetPath("facet.png")
x: 10
y: 10
}
Text {
anchors.left: aboutIcon.right
anchors.leftMargin: 10
font.pointSize: 12
text: "<h2>Ethereal</h2><br><h3>Development</h3>Jeffrey Wilcke<br>Maran Hidskes<br>"
}
}
ApplicationWindow {
id: debugWindow
visible: false
title: "Debugger"
minimumWidth: 600
minimumHeight: 600
width: 800
height: 600
Item {
id: keyHandler
focus: true
Keys.onPressed: {
if (event.key == Qt.Key_Space) {
ui.next()
}
}
}
SplitView {
anchors.fill: parent
property var asmModel: ListModel {
id: asmModel
}
TableView {
id: asmTableView
width: 200
TableViewColumn{ role: "value" ; title: "" ; width: 100 }
model: asmModel
}
Rectangle {
anchors.left: asmTableView.right
anchors.right: parent.right
SplitView {
orientation: Qt.Vertical
anchors.fill: parent
TableView {
property var memModel: ListModel {
id: memModel
}
height: parent.height/2
width: parent.width
TableViewColumn{ id:mnumColmn ; role: "num" ; title: "#" ; width: 50}
TableViewColumn{ role: "value" ; title: "Memory" ; width: 750}
model: memModel
}
SplitView {
orientation: Qt.Horizontal
id: debugSplitView
TableView {
property var debuggerLog: ListModel {
id: debuggerLog
}
TableViewColumn{ role: "value"; title: "Debug messages" }
model: debuggerLog
}
TableView {
property var stackModel: ListModel {
id: stackModel
}
height: parent.height/2
width: parent.width
TableViewColumn{ role: "value" ; title: "Stack" ; width: debugSplitView.width }
model: stackModel
}
}
}
}
}
statusBar: StatusBar {
RowLayout {
anchors.fill: parent
Button {
property var enabled: true
id: debugNextButton
onClicked: {
ui.next()
}
text: "Next"
}
}
}
}
function setAsm(asm) {
asmModel.append({asm: asm})
}
function setInstruction(num) {
asmTableView.selection.clear()
asmTableView.selection.select(num-1)
}
function clearAsm() {
asmModel.clear()
}
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){
console.log("WOOP:")
debuggerLog.append({value: message})
}
function clearStack() {
stackModel.clear()
}
function loadPlugin(name) {
console.log("Loading plugin" + name)
mainView.addPlugin(name)
}
function setWalletValue(value) {
walletValueLabel.text = value
}
function addTx(tx, inout) {
var isContract
if (tx.contract == true){
isContract = "Yes"
}else{
isContract = "No"
}
txModel.insert(0, {inout: inout, hash: tx.hash, address: tx.address, value: tx.value, contract: isContract})
}
function addBlock(block, initial) {
var txs = JSON.parse(block.transactions);
var amount = 0
if(initial == undefined){
initial = false
}
if(txs != null){
amount = txs.length
}
if(initial){
blockModel.append({number: block.number, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
}else{
blockModel.insert(0, {number: block.number, hash: block.hash, txs: txs, txAmount: amount, time: block.time, prettyTime: convertToPretty(block.time)})
}
}
function addLog(str) {
if(str.len != 0) {
logModel.append({description: str})
}
}
function setPeers(text) {
peerLabel.text = text
}
function convertToPretty(unixTs){
var a = new Date(unixTs*1000);
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = date+' '+month+' '+year+' '+hour+':'+min+':'+sec ;
return time;
}
// *******************************************
// Components
// *******************************************
// New Contract component
Component {
id: newContract
Column {
id: mainContractColumn
function contractFormReady(){
if(codeView.text.length > 0 && txValue.text.length > 0 && txGas.text.length > 0 && txGasPrice.length > 0) {
txButton.state = "READY"
}else{
txButton.state = "NOTREADY"
}
}
states: [
State{
name: "ERROR"
PropertyChanges { target: txResult; visible:true}
PropertyChanges { target: codeView; visible:true}
},
State {
name: "DONE"
PropertyChanges { target: txValue; visible:false}
PropertyChanges { target: txGas; visible:false}
PropertyChanges { target: txGasPrice; visible:false}
PropertyChanges { target: codeView; visible:false}
PropertyChanges { target: txButton; visible:false}
PropertyChanges { target: txDataLabel; visible:false}
PropertyChanges { target: txResult; visible:true}
PropertyChanges { target: txOutput; visible:true}
PropertyChanges { target: newTxButton; visible:true}
},
State {
name: "SETUP"
PropertyChanges { target: txValue; visible:true; text: ""}
PropertyChanges { target: txGas; visible:true; text: ""}
PropertyChanges { target: txGasPrice; visible:true; text: ""}
PropertyChanges { target: codeView; visible:true; text: ""}
PropertyChanges { target: txButton; visible:true}
PropertyChanges { target: txDataLabel; visible:true}
PropertyChanges { target: txResult; visible:false}
PropertyChanges { target: txOutput; visible:false}
PropertyChanges { target: newTxButton; visible:false}
}
]
width: 400
spacing: 5
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: 5
anchors.topMargin: 5
TextField {
id: txValue
width: 200
placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: {
contractFormReady()
}
}
TextField {
id: txGas
width: 200
validator: RegExpValidator { regExp: /\d*/ }
placeholderText: "Gas"
onTextChanged: {
contractFormReady()
}
}
TextField {
id: txGasPrice
width: 200
placeholderText: "Gas price"
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: {
contractFormReady()
}
}
Row {
id: rowContract
ExclusiveGroup { id: contractTypeGroup }
RadioButton {
id: createContractRadio
text: "Create contract"
checked: true
exclusiveGroup: contractTypeGroup
onClicked: {
txFuelRecipient.visible = false
txDataLabel.text = "Contract code"
}
}
RadioButton {
id: runContractRadio
text: "Run contract"
exclusiveGroup: contractTypeGroup
onClicked: {
txFuelRecipient.visible = true
txDataLabel.text = "Contract arguments"
}
}
}
Label {
id: txDataLabel
text: "Contract code"
}
TextArea {
id: codeView
height: 300
anchors.topMargin: 5
Layout.fillWidth: true
width: parent.width /2
onTextChanged: {
contractFormReady()
}
}
TextField {
id: txFuelRecipient
placeholderText: "Contract address"
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
visible: false
width: 530
}
Button {
id: txButton
/* enabled: false */
states: [
State {
name: "READY"
PropertyChanges { target: txButton; /*enabled: true*/}
},
State {
name: "NOTREADY"
PropertyChanges { target: txButton; /*enabled:false*/}
}
]
text: "Send"
onClicked: {
//this.enabled = false
var res = eth.create(txFuelRecipient.text, txValue.text, txGas.text, txGasPrice.text, codeView.text)
if(res[1]) {
txResult.text = "Your contract <b>could not</b> be send over the network:\n<b>"
txResult.text += res[1].error()
txResult.text += "</b>"
mainContractColumn.state = "ERROR"
} else {
txResult.text = "Your transaction has been submitted:\n"
txOutput.text = res[0].address
mainContractColumn.state = "DONE"
}
}
}
Text {
id: txResult
visible: false
}
TextField {
id: txOutput
visible: false
width: 530
}
Button {
id: newTxButton
visible: false
text: "Create an other contract"
onClicked: {
this.visible = false
txResult.text = ""
txOutput.text = ""
mainContractColumn.state = "SETUP"
}
}
Button {
id: debugButton
text: "Debug"
onClicked: {
var res = ui.debugTx("", txValue.text, txGas.text, txGasPrice.text, codeView.text)
debugWindow.visible = true
}
}
}
}
// New Transaction component
Component {
id: newTransaction
Column {
id: simpleSendColumn
states: [
State{
name: "ERROR"
},
State {
name: "DONE"
PropertyChanges { target: txSimpleValue; visible:false}
PropertyChanges { target: txSimpleRecipient; visible:false}
PropertyChanges { target:newSimpleTxButton; visible:false}
PropertyChanges { target: txSimpleResult; visible:true}
PropertyChanges { target: txSimpleOutput; visible:true}
PropertyChanges { target:newSimpleTxButton; visible:true}
},
State {
name: "SETUP"
PropertyChanges { target: txSimpleValue; visible:true; text: ""}
PropertyChanges { target: txSimpleRecipient; visible:true; text: ""}
PropertyChanges { target: txSimpleButton; visible:true}
PropertyChanges { target:newSimpleTxButton; visible:false}
}
]
spacing: 5
anchors.leftMargin: 5
anchors.topMargin: 5
anchors.top: parent.top
anchors.left: parent.left
function checkFormState(){
if(txSimpleRecipient.text.length == 40 && txSimpleValue.text.length > 0) {
txSimpleButton.state = "READY"
}else{
txSimpleButton.state = "NOTREADY"
}
}
TextField {
id: txSimpleRecipient
placeholderText: "Recipient address"
Layout.fillWidth: true
validator: RegExpValidator { regExp: /[a-f0-9]{40}/ }
width: 530
onTextChanged: { checkFormState() }
}
TextField {
id: txSimpleValue
width: 200
placeholderText: "Amount"
anchors.rightMargin: 5
validator: RegExpValidator { regExp: /\d*/ }
onTextChanged: { checkFormState() }
}
Button {
id: txSimpleButton
/*enabled: false*/
states: [
State {
name: "READY"
PropertyChanges { target: txSimpleButton; /*enabled: true*/}
},
State {
name: "NOTREADY"
PropertyChanges { target: txSimpleButton; /*enabled: false*/}
}
]
text: "Send"
onClicked: {
//this.enabled = false
var res = eth.transact(txSimpleRecipient.text, txSimpleValue.text,"","","")
if(res[1]) {
txSimpleResult.text = "There has been an error broadcasting your transaction:" + res[1].error()
} else {
txSimpleResult.text = "Your transaction has been broadcasted over the network.\nYour transaction id is:"
txSimpleOutput.text = res[0].hash
this.visible = false
simpleSendColumn.state = "DONE"
}
}
}
Text {
id: txSimpleResult
visible: false
}
TextField {
id: txSimpleOutput
visible: false
width: 530
}
Button {
id: newSimpleTxButton
visible: false
text: "Create an other transaction"
onClicked: {
this.visible = false
simpleSendColumn.state = "SETUP"
}
}
}
}
}

View File

@ -0,0 +1,211 @@
import QtQuick 2.0
import QtWebKit 3.0
import QtWebKit.experimental 1.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Window 2.1;
import Ethereum 1.0
ApplicationWindow {
id: window
title: "Ethereum"
width: 900
height: 600
minimumHeight: 300
property alias url: webview.url
property alias webView: webview
Item {
objectName: "root"
id: root
anchors.fill: parent
state: "inspectorShown"
WebView {
objectName: "webView"
id: webview
anchors.fill: parent
/*
anchors {
left: parent.left
right: parent.right
bottom: sizeGrip.top
top: parent.top
}
*/
onTitleChanged: { window.title = title }
experimental.preferences.javascriptEnabled: true
experimental.preferences.navigatorQtObjectEnabled: true
experimental.preferences.developerExtrasEnabled: true
experimental.userScripts: [ui.assetPath("ext/pre.js"), ui.assetPath("ext/big.js"), ui.assetPath("ext/string.js"), ui.assetPath("ext/ethereum.js")]
experimental.onMessageReceived: {
console.log("[onMessageReceived]: ", message.data)
// TODO move to messaging.js
var data = JSON.parse(message.data)
try {
switch(data.call) {
case "getCoinBase":
postData(data._seed, eth.getCoinBase())
break
case "getIsListening":
postData(data._seed, eth.getIsListening())
break
case "getIsMining":
postData(data._seed, eth.getIsMining())
break
case "getPeerCount":
postData(data._seed, eth.getPeerCount())
break
case "getTxCountAt":
require(1)
postData(data._seed, eth.getTxCountAt(data.args[0]))
break
case "getBlockByNumber":
var block = eth.getBlock(data.args[0])
postData(data._seed, block)
break
case "getBlockByHash":
var block = eth.getBlock(data.args[0])
postData(data._seed, block)
break
case "transact":
require(5)
var tx = eth.transact(data.args[0], data.args[1], data.args[2],data.args[3],data.args[4],data.args[5])
postData(data._seed, tx)
break
case "create":
postData(data._seed, null)
break
case "getStorage":
require(2);
var stateObject = eth.getStateObject(data.args[0])
var storage = stateObject.getStorage(data.args[1])
postData(data._seed, storage)
break
case "getBalance":
require(1);
postData(data._seed, eth.getStateObject(data.args[0]).value());
break
case "getKey":
var key = eth.getKey().privateKey;
postData(data._seed, key)
break
case "watch":
require(1)
eth.watch(data.args[0], data.args[1]);
break
case "disconnect":
require(1)
postData(data._seed, null)
break;
case "set":
console.log("'Set' has been depcrecated")
/*
for(var key in data.args) {
if(webview.hasOwnProperty(key)) {
window[key] = data.args[key];
}
}
*/
break;
case "getSecretToAddress":
require(1)
postData(data._seed, eth.secretToAddress(data.args[0]))
break;
case "debug":
console.log(data.args[0]);
break;
}
} catch(e) {
console.log(data.call + ": " + e)
postData(data._seed, null);
}
}
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, _seed: seed}))
}
function postEvent(event, data) {
webview.experimental.postMessage(JSON.stringify({data: data, _event: event}))
}
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
url: webview.experimental.remoteInspectorUrl
anchors {
left: root.left
right: root.right
top: sizeGrip.bottom
bottom: root.bottom
}
}
states: [
State {
name: "inspectorShown"
PropertyChanges {
target: inspector
url: webview.experimental.remoteInspectorUrl
}
}
]
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -0,0 +1,34 @@
/* Space out content a bit */
body {
padding-top: 20px;
padding-bottom: 20px;
}
/* Everything but the jumbotron gets side spacing for mobile first
* views */
.header,
.marketing,
.footer {
padding-right: 15px;
padding-left: 15px;
}
/* Custom page header */
.header {
border-bottom: 1px solid #e5e5e5;
}
/* Make the masthead heading the same height as the navigation */
.header h3 {
padding-bottom: 19px;
margin-top: 0;
margin-bottom: 0;
line-height: 40px;
}
.jumbotron {
text-align: center;
border-bottom: 1px solid #e5e5e5;
margin: 0 auto;
width: 300px;
}

View File

@ -0,0 +1,68 @@
<html>
<head>
<title>jeffcoin</title>
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="bootstrap-theme.min.css">
<link rel="stylesheet" href="samplecoin.css">
<meta name="viewport" content="minimum-scale=1; maximum-scale=1; initial-scale=1;">
<script type="text/javascript">
var jefcoinAddr = "518546ffa883dcc838a64bc2dabada0fd64af459"
var mAddr = ""
function createTransaction() {
var addr = ("0x" + document.querySelector("#addr").value).pad(32);
var amount = document.querySelector("#amount").value.pad(32);
var data = (addr + amount).unbin();
eth.transact(mAddr, jefcoinAddr, 0, "10000000", "250", data, function(receipt) {
debug("received tx hash:", reciept.address)
})
}
function init() {
eth.getKey(function(sec) {
mAddr = sec;
eth.getSecretToAddress(sec, function(addr) {
eth.getStorageAt(jefcoinAddr, addr, function(storage) {
document.querySelector("#current-amount").innerHTML = storage;
});
eth.watch(jefcoinAddr, addr, function(addr, value) {
document.querySelector("#current-amount").innerHTML = value
});
});
});
}
</script>
</head>
<body onload="init();">
<div class="container">
<div class="header">
<h3 class="text-muted">JeffCoin</h3>
</div>
<div class="jumbotron ">
<img src="icon.png">
<div>Amount: <strong id="current-amount"></strong></div>
<div id="transactions">
<div class="form-group">
<input id="addr" class="form-control" type="text" placeholder="Receiver address"></input><br>
<input id="amount" class="form-control" type="text" placeholder="Amount"></input><br>
</div>
<button class="btn btn-default" onclick="createTransaction();">Send Tx</button>
</div>
</div>
</div>
<div id="debug" style="border: 1px solid black; min-height: 30px;"></div>
</body>
</html>

BIN
ethereal/assets/tx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,43 @@
<html>
<head>
<title>Utils</title>
</head>
<body onload="init();">
<label>Nonce for 2ef47100e0787b915105fd5e3f4ff6752079d5cb</label>
<p id="nonce"></p>
<label>Connected peers</label>
<p id="peers"></p>
<label>Is mining</label>
<p id="isMining"></p>
<label>Is listening</label>
<p id="isListen"></p>
<label>Coinbase</label>
<p id="coinbase"></p>
<script type="text/javascript">
function init() {
eth.getTxCountAt("2ef47100e0787b915105fd5e3f4ff6752079d5cb", function(nonce){
document.querySelector("#nonce").innerHTML = nonce;
})
eth.getPeerCount(function(peerLength){
document.querySelector("#peers").innerHTML = peerLength;
})
eth.getIsMining(function(mining){
document.querySelector("#isMining").innerHTML = mining;
})
eth.getIsListening(function(listen){
document.querySelector("#isListen").innerHTML = listen;
})
eth.getCoinBase(function(address){
document.querySelector("#coinbase").innerHTML = address;
})
}
</script>
</body>
</html>

42
ethereal/config.go Normal file
View File

@ -0,0 +1,42 @@
package main
import (
"flag"
)
var Identifier string
var StartConsole bool
var StartMining bool
var StartRpc bool
var RpcPort int
var UseUPnP bool
var OutboundPort string
var ShowGenesis bool
var AddPeer string
var MaxPeer int
var GenAddr bool
var UseSeed bool
var ImportKey string
var ExportKey bool
var DataDir string
var AssetPath string
func Init() {
flag.StringVar(&Identifier, "i", "", "Custom client identifier")
flag.BoolVar(&StartConsole, "c", false, "debug and testing console")
flag.BoolVar(&StartMining, "m", false, "start dagger mining")
flag.BoolVar(&StartRpc, "r", false, "start rpc server")
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.StringVar(&OutboundPort, "p", "30303", "listening port")
flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
flag.IntVar(&MaxPeer, "x", 10, "maximum desired peers")
flag.StringVar(&AssetPath, "asset_path", "", "absolute path to GUI assets directory")
flag.Parse()
}

132
ethereal/ethereum.go Normal file
View File

@ -0,0 +1,132 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/ethereal/ui"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"log"
"os"
"os/signal"
"runtime"
)
const Debug = true
// Register interrupt handlers so we can stop the ethereum
func RegisterInterupts(s *eth.Ethereum) {
// Buffered chan of one is enough
c := make(chan os.Signal, 1)
// Notify about interrupts for now
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
fmt.Printf("Shutting down (%v) ... \n", sig)
s.Stop()
}
}()
}
func main() {
Init()
qml.Init(nil)
runtime.GOMAXPROCS(runtime.NumCPU())
ethchain.InitFees()
ethutil.ReadConfig(DataDir, ethutil.LogFile|ethutil.LogStd, Identifier)
// Instantiated a eth stack
ethereum, err := eth.New(eth.CapDefault, UseUPnP)
if err != nil {
log.Println("eth start err:", err)
return
}
ethereum.Port = OutboundPort
if GenAddr {
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
if r == "y" {
utils.CreateKeyPair(true)
}
os.Exit(0)
} else {
if len(ImportKey) > 0 {
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
if r == "y" {
utils.ImportPrivateKey(ImportKey)
os.Exit(0)
}
}
}
if ExportKey {
keyPair := ethutil.GetKeyRing().Get(0)
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey)
os.Exit(0)
}
if ShowGenesis {
fmt.Println(ethereum.BlockChain().Genesis())
os.Exit(0)
}
if StartMining {
utils.DoMining(ethereum)
}
if StartRpc {
utils.DoRpc(ethereum, RpcPort)
}
log.Printf("Starting Ethereum GUI v%s\n", ethutil.Config.Ver)
// Set the max peers
ethereum.MaxPeers = MaxPeer
gui := ethui.New(ethereum)
ethereum.Start(UseSeed)
gui.Start(AssetPath)
// Wait for shutdown
ethereum.WaitForShutdown()
}

177
ethereal/ui/debugger.go Normal file
View File

@ -0,0 +1,177 @@
package ethui
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"math/big"
"strings"
)
type DebuggerWindow struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
Db *Debugger
}
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
engine := qml.NewEngine()
component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
if err != nil {
fmt.Println(err)
return nil
}
win := component.CreateWindow(nil)
db := &Debugger{win, make(chan bool), make(chan bool), true}
return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
}
func (self *DebuggerWindow) Show() {
context := self.engine.Context()
context.SetVar("dbg", self)
go func() {
self.win.Show()
self.win.Wait()
}()
}
func formatData(data string) []byte {
if len(data) == 0 {
return nil
}
// Simple stupid
d := new(big.Int)
if data[0:1] == "\"" && data[len(data)-1:] == "\"" {
d.SetBytes([]byte(data[1 : len(data)-1]))
} else if data[:2] == "0x" {
d.SetBytes(ethutil.FromHex(data[2:]))
} else {
d.SetString(data, 0)
}
return ethutil.BigToBytes(d, 256)
}
func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
if !self.Db.done {
self.Db.Q <- true
}
dataSlice := strings.Split(dataStr, "\n")
var data []byte
for _, dataItem := range dataSlice {
d := formatData(dataItem)
data = append(data, d...)
}
state := self.lib.eth.BlockChain().CurrentBlock.State()
defer func() {
if r := recover(); r != nil {
fmt.Println(r)
}
}()
script, err := ethutil.Compile(scriptStr)
if err != nil {
ethutil.Config.Log.Debugln(err)
return
}
dis := ethchain.Disassemble(script)
self.win.Root().Call("clearAsm")
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
// Contract addr as test address
keyPair := ethutil.GetKeyRing().Get(0)
callerTx := ethchain.NewContractCreationTx(ethutil.Big(valueStr), ethutil.Big(gasStr), ethutil.Big(gasPriceStr), script)
callerTx.Sign(keyPair.PrivateKey)
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethchain.MakeContract(callerTx, state)
callerClosure := ethchain.NewClosure(account, contract, script, state, ethutil.Big(gasStr), ethutil.Big(gasPriceStr))
block := self.lib.eth.BlockChain().CurrentBlock
vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
Origin: account.Address(),
BlockNumber: block.BlockInfo().Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
})
self.Db.done = false
go func() {
callerClosure.Call(vm, data, self.Db.halting)
state.Reset()
self.Db.done = true
}()
}
func (self *DebuggerWindow) Next() {
self.Db.Next()
}
type Debugger struct {
win *qml.Window
N chan bool
Q chan bool
done bool
}
type storeVal struct {
Key, Value string
}
func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, stack *ethchain.Stack, stateObject *ethchain.StateObject) bool {
d.win.Root().Call("setInstruction", pc)
d.win.Root().Call("clearMem")
d.win.Root().Call("clearStack")
d.win.Root().Call("clearStorage")
addr := 0
for i := 0; i+32 <= mem.Len(); i += 32 {
d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
addr++
}
for _, val := range stack.Data() {
d.win.Root().Call("setStack", val.String())
}
stateObject.State().EachStorage(func(key string, node *ethutil.Value) {
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
})
out:
for {
select {
case <-d.N:
break out
case <-d.Q:
d.done = true
return false
}
}
return true
}
func (d *Debugger) Next() {
if !d.done {
d.N <- true
}
}

132
ethereal/ui/ext_app.go Normal file
View File

@ -0,0 +1,132 @@
package ethui
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
)
type AppContainer interface {
Create() error
Destroy()
Window() *qml.Window
Engine() *qml.Engine
NewBlock(*ethchain.Block)
ObjectChanged(*ethchain.StateObject)
StorageChanged(*ethchain.StorageState)
NewWatcher(chan bool)
}
type ExtApplication struct {
*ethpub.PEthereum
blockChan chan ethutil.React
changeChan chan ethutil.React
quitChan chan bool
watcherQuitChan chan bool
container AppContainer
lib *UiLib
registeredEvents []string
}
func NewExtApplication(container AppContainer, lib *UiLib) *ExtApplication {
app := &ExtApplication{
ethpub.NewPEthereum(lib.eth),
make(chan ethutil.React, 1),
make(chan ethutil.React, 1),
make(chan bool),
make(chan bool),
container,
lib,
nil,
}
return app
}
func (app *ExtApplication) run() {
// Set the "eth" api on to the containers context
context := app.container.Engine().Context()
context.SetVar("eth", app)
context.SetVar("ui", app.lib)
err := app.container.Create()
if err != nil {
fmt.Println(err)
return
}
// Call the main loop
go app.mainLoop()
// Subscribe to events
reactor := app.lib.eth.Reactor()
reactor.Subscribe("newBlock", app.blockChan)
app.container.NewWatcher(app.watcherQuitChan)
win := app.container.Window()
win.Show()
win.Wait()
app.stop()
}
func (app *ExtApplication) stop() {
// Clean up
reactor := app.lib.eth.Reactor()
reactor.Unsubscribe("newBlock", app.blockChan)
for _, event := range app.registeredEvents {
reactor.Unsubscribe(event, app.changeChan)
}
// Kill the main loop
app.quitChan <- true
app.watcherQuitChan <- true
close(app.blockChan)
close(app.quitChan)
close(app.changeChan)
app.container.Destroy()
}
func (app *ExtApplication) mainLoop() {
out:
for {
select {
case <-app.quitChan:
break out
case block := <-app.blockChan:
if block, ok := block.Resource.(*ethchain.Block); ok {
app.container.NewBlock(block)
}
case object := <-app.changeChan:
if stateObject, ok := object.Resource.(*ethchain.StateObject); ok {
app.container.ObjectChanged(stateObject)
} else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok {
app.container.StorageChanged(storageObject)
}
}
}
}
func (app *ExtApplication) Watch(addr, storageAddr string) {
var event string
if len(storageAddr) == 0 {
event = "object:" + string(ethutil.FromHex(addr))
app.lib.eth.Reactor().Subscribe(event, app.changeChan)
} else {
event = "storage:" + string(ethutil.FromHex(addr)) + ":" + string(ethutil.FromHex(storageAddr))
app.lib.eth.Reactor().Subscribe(event, app.changeChan)
}
app.registeredEvents = append(app.registeredEvents, event)
}

273
ethereal/ui/gui.go Normal file
View File

@ -0,0 +1,273 @@
package ethui
import (
"bytes"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"math/big"
"strings"
)
type Gui struct {
// The main application window
win *qml.Window
// QML Engine
engine *qml.Engine
component *qml.Common
// The ethereum interface
eth *eth.Ethereum
// The public Ethereum library
lib *EthLib
uiLib *UiLib
txDb *ethdb.LDBDatabase
addr []byte
pub *ethpub.PEthereum
}
// Create GUI, but doesn't start it
func New(ethereum *eth.Ethereum) *Gui {
lib := &EthLib{stateManager: ethereum.StateManager(), blockChain: ethereum.BlockChain(), txPool: ethereum.TxPool()}
db, err := ethdb.NewLDBDatabase("tx_database")
if err != nil {
panic(err)
}
// On first run we won't have any keys yet, so this would crash.
// Therefor we check if we are ready to actually start this process
var addr []byte
if ethutil.GetKeyRing().Len() != 0 {
addr = ethutil.GetKeyRing().Get(0).Address()
}
pub := ethpub.NewPEthereum(ethereum)
return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr, pub: pub}
}
func (gui *Gui) Start(assetPath string) {
const version = "0.5.0 RC10"
defer gui.txDb.Close()
// Register ethereum functions
qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{
Init: func(p *ethpub.PBlock, obj qml.Object) { p.Number = 0; p.Hash = "" },
}, {
Init: func(p *ethpub.PTx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}})
ethutil.Config.SetClientString(fmt.Sprintf("/Ethereal v%s", version))
ethutil.Config.Log.Infoln("[GUI] Starting GUI")
// Create a new QML engine
gui.engine = qml.NewEngine()
context := gui.engine.Context()
// Expose the eth library and the ui library to QML
context.SetVar("eth", gui)
context.SetVar("pub", gui.pub)
gui.uiLib = NewUiLib(gui.engine, gui.eth, assetPath)
context.SetVar("ui", gui.uiLib)
// Load the main QML interface
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
var win *qml.Window
var err error
if len(data) == 0 {
win, err = gui.showKeyImport(context)
} else {
win, err = gui.showWallet(context)
}
if err != nil {
ethutil.Config.Log.Infoln("FATAL: asset not found: you can set an alternative asset path on on the command line using option 'asset_path'")
panic(err)
}
win.Show()
win.Wait()
gui.eth.Stop()
}
func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/wallet.qml"))
if err != nil {
return nil, err
}
win := gui.createWindow(component)
go gui.setInitialBlockChain()
go gui.readPreviousTransactions()
go gui.update()
return win, nil
}
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
context.SetVar("lib", gui.lib)
component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml"))
if err != nil {
return nil, err
}
return gui.createWindow(component), nil
}
func (gui *Gui) createWindow(comp qml.Object) *qml.Window {
win := comp.CreateWindow(nil)
gui.win = win
gui.uiLib.win = win
db := &Debugger{gui.win, make(chan bool), make(chan bool), true}
gui.lib.Db = db
gui.uiLib.Db = db
return gui.win
}
func (gui *Gui) setInitialBlockChain() {
sBlk := gui.eth.BlockChain().LastBlockHash
blk := gui.eth.BlockChain().GetBlock(sBlk)
for ; blk != nil; blk = gui.eth.BlockChain().GetBlock(sBlk) {
sBlk = blk.PrevHash
gui.processBlock(blk, true)
}
}
func (gui *Gui) readPreviousTransactions() {
it := gui.txDb.Db().NewIterator(nil, nil)
for it.Next() {
tx := ethchain.NewTransactionFromBytes(it.Value())
var inout string
if bytes.Compare(tx.Sender(), gui.addr) == 0 {
inout = "send"
} else {
inout = "recv"
}
gui.win.Root().Call("addTx", ethpub.NewPTx(tx), inout)
}
it.Release()
}
func (gui *Gui) processBlock(block *ethchain.Block, initial bool) {
gui.win.Root().Call("addBlock", ethpub.NewPBlock(block), initial)
}
func (gui *Gui) setWalletValue(amount, unconfirmedFunds *big.Int) {
var str string
if unconfirmedFunds != nil {
pos := "+"
if unconfirmedFunds.Cmp(big.NewInt(0)) < 0 {
pos = "-"
}
val := ethutil.CurrencyToString(new(big.Int).Abs(ethutil.BigCopy(unconfirmedFunds)))
str = fmt.Sprintf("%v (%s %v)", ethutil.CurrencyToString(amount), pos, val)
} else {
str = fmt.Sprintf("%v", ethutil.CurrencyToString(amount))
}
gui.win.Root().Call("setWalletValue", str)
}
// Simple go routine function that updates the list of peers in the GUI
func (gui *Gui) update() {
reactor := gui.eth.Reactor()
blockChan := make(chan ethutil.React, 1)
txChan := make(chan ethutil.React, 1)
reactor.Subscribe("newBlock", blockChan)
reactor.Subscribe("newTx:pre", txChan)
reactor.Subscribe("newTx:post", txChan)
state := gui.eth.StateManager().TransState()
unconfirmedFunds := new(big.Int)
gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.addr).Amount)))
for {
select {
case b := <-blockChan:
block := b.Resource.(*ethchain.Block)
gui.processBlock(block, false)
if bytes.Compare(block.Coinbase, gui.addr) == 0 {
gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.addr).Amount, nil)
}
case txMsg := <-txChan:
tx := txMsg.Resource.(*ethchain.Transaction)
if txMsg.Event == "newTx:pre" {
object := state.GetAccount(gui.addr)
if bytes.Compare(tx.Sender(), gui.addr) == 0 {
gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "send")
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
} else if bytes.Compare(tx.Recipient, gui.addr) == 0 {
gui.win.Root().Call("addTx", ethpub.NewPTx(tx), "recv")
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
}
gui.setWalletValue(object.Amount, unconfirmedFunds)
} else {
object := state.GetAccount(gui.addr)
if bytes.Compare(tx.Sender(), gui.addr) == 0 {
object.SubAmount(tx.Value)
} else if bytes.Compare(tx.Recipient, gui.addr) == 0 {
object.AddAmount(tx.Value)
}
gui.setWalletValue(object.Amount, nil)
state.UpdateStateObject(object)
}
}
}
}
// Logging functions that log directly to the GUI interface
func (gui *Gui) Println(v ...interface{}) {
str := strings.TrimRight(fmt.Sprintln(v...), "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
gui.win.Root().Call("addLog", line)
}
}
func (gui *Gui) Printf(format string, v ...interface{}) {
str := strings.TrimRight(fmt.Sprintf(format, v...), "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
gui.win.Root().Call("addLog", line)
}
}
func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
keyPair := ethutil.GetKeyRing().Get(0)
return gui.pub.Transact(ethutil.Hex(keyPair.PrivateKey), recipient, value, gas, gasPrice, data)
}
func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
keyPair := ethutil.GetKeyRing().Get(0)
return gui.pub.Create(ethutil.Hex(keyPair.PrivateKey), value, gas, gasPrice, data)
}

View File

@ -0,0 +1,133 @@
package ethui
import (
"errors"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"github.com/howeyc/fsnotify"
"io/ioutil"
"log"
"net/url"
"os"
"path"
"path/filepath"
)
type HtmlApplication struct {
win *qml.Window
webView qml.Object
engine *qml.Engine
lib *UiLib
path string
watcher *fsnotify.Watcher
}
func NewHtmlApplication(path string, lib *UiLib) *HtmlApplication {
engine := qml.NewEngine()
return &HtmlApplication{engine: engine, lib: lib, path: path}
}
func (app *HtmlApplication) Create() error {
component, err := app.engine.LoadFile(app.lib.AssetPath("qml/webapp.qml"))
if err != nil {
return err
}
if filepath.Ext(app.path) == "eth" {
return errors.New("Ethereum package not yet supported")
// TODO
ethutil.OpenPackage(app.path)
}
win := component.CreateWindow(nil)
win.Set("url", app.path)
webView := win.ObjectByName("webView")
app.win = win
app.webView = webView
return nil
}
func (app *HtmlApplication) RootFolder() string {
folder, err := url.Parse(app.path)
if err != nil {
return ""
}
return path.Dir(folder.RequestURI())
}
func (app *HtmlApplication) RecursiveFolders() []os.FileInfo {
files, _ := ioutil.ReadDir(app.RootFolder())
var folders []os.FileInfo
for _, file := range files {
if file.IsDir() {
folders = append(folders, file)
}
}
return folders
}
func (app *HtmlApplication) NewWatcher(quitChan chan bool) {
var err error
app.watcher, err = fsnotify.NewWatcher()
if err != nil {
return
}
err = app.watcher.Watch(app.RootFolder())
if err != nil {
log.Fatal(err)
}
for _, folder := range app.RecursiveFolders() {
fullPath := app.RootFolder() + "/" + folder.Name()
app.watcher.Watch(fullPath)
}
go func() {
out:
for {
select {
case <-quitChan:
app.watcher.Close()
break out
case <-app.watcher.Event:
//ethutil.Config.Log.Debugln("Got event:", ev)
app.webView.Call("reload")
case err := <-app.watcher.Error:
// TODO: Do something here
ethutil.Config.Log.Infoln("Watcher error:", err)
}
}
}()
}
func (app *HtmlApplication) Engine() *qml.Engine {
return app.engine
}
func (app *HtmlApplication) Window() *qml.Window {
return app.win
}
func (app *HtmlApplication) NewBlock(block *ethchain.Block) {
b := &ethpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())}
app.webView.Call("onNewBlockCb", b)
}
func (app *HtmlApplication) ObjectChanged(stateObject *ethchain.StateObject) {
app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
}
func (app *HtmlApplication) StorageChanged(storageObject *ethchain.StorageState) {
app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}
func (app *HtmlApplication) Destroy() {
app.engine.Destroy()
}

46
ethereal/ui/library.go Normal file
View File

@ -0,0 +1,46 @@
package ethui
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/obscuren/secp256k1-go"
"strings"
)
type EthLib struct {
stateManager *ethchain.StateManager
blockChain *ethchain.BlockChain
txPool *ethchain.TxPool
Db *Debugger
}
func (lib *EthLib) ImportAndSetPrivKey(privKey string) bool {
fmt.Println(privKey)
mnemonic := strings.Split(privKey, " ")
if len(mnemonic) == 24 {
fmt.Println("Got mnemonic key, importing.")
key := ethutil.MnemonicDecode(mnemonic)
utils.ImportPrivateKey(key)
} else if len(mnemonic) == 1 {
fmt.Println("Got hex key, importing.")
utils.ImportPrivateKey(privKey)
} else {
fmt.Println("Did not recognise format, exiting.")
return false
}
return true
}
func (lib *EthLib) CreateAndSetPrivKey() (string, string, string, string) {
_, prv := secp256k1.GenerateKeyPair()
keyPair, err := ethutil.GetKeyRing().NewKeyPair(prv)
if err != nil {
panic(err)
}
mne := ethutil.MnemonicEncode(ethutil.Hex(keyPair.PrivateKey))
mnemonicString := strings.Join(mne, " ")
return mnemonicString, fmt.Sprintf("%x", keyPair.Address()), ethutil.Hex(keyPair.PrivateKey), ethutil.Hex(keyPair.PublicKey)
}

172
ethereal/ui/ui_lib.go Normal file
View File

@ -0,0 +1,172 @@
package ethui
import (
"bitbucket.org/kardianos/osext"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"os"
"path"
"path/filepath"
"runtime"
)
type memAddr struct {
Num string
Value string
}
// UI Library that has some basic functionality exposed
type UiLib struct {
engine *qml.Engine
eth *eth.Ethereum
connected bool
assetPath string
// The main application window
win *qml.Window
Db *Debugger
}
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
if assetPath == "" {
assetPath = DefaultAssetPath()
}
return &UiLib{engine: engine, eth: eth, assetPath: assetPath}
}
// Opens a QML file (external application)
func (ui *UiLib) Open(path string) {
component, err := ui.engine.LoadFile(path[7:])
if err != nil {
ethutil.Config.Log.Debugln(err)
}
win := component.CreateWindow(nil)
go func() {
win.Show()
win.Wait()
}()
}
func (ui *UiLib) OpenHtml(path string) {
container := NewHtmlApplication(path, ui)
app := NewExtApplication(container, ui)
go app.run()
}
func (ui *UiLib) Muted(content string) {
component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
if err != nil {
ethutil.Config.Log.Debugln(err)
return
}
win := component.CreateWindow(nil)
go func() {
path := "file://" + ui.AssetPath("muted/index.html")
win.Set("url", path)
win.Show()
win.Wait()
}()
}
func (ui *UiLib) Connect(button qml.Object) {
if !ui.connected {
ui.eth.Start(true)
ui.connected = true
button.Set("enabled", false)
}
}
func (ui *UiLib) ConnectToPeer(addr string) {
ui.eth.ConnectToPeer(addr)
}
func (ui *UiLib) AssetPath(p string) string {
return path.Join(ui.assetPath, p)
}
func (self *UiLib) StartDebugger() {
dbWindow := NewDebuggerWindow(self)
dbWindow.Show()
}
func DefaultAssetPath() string {
var base string
// If the current working directory is the go-ethereum dir
// assume a debug build and use the source directory as
// asset directory.
pwd, _ := os.Getwd()
if pwd == path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal") {
base = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
base = filepath.Join(exedir, "../Resources")
case "linux":
base = "/usr/share/ethereal"
case "window":
fallthrough
default:
base = "."
}
}
return base
}
func (ui *UiLib) DebugTx(recipient, valueStr, gasStr, gasPriceStr, data string) {
state := ui.eth.BlockChain().CurrentBlock.State()
script, err := ethutil.Compile(data)
if err != nil {
ethutil.Config.Log.Debugln(err)
return
}
dis := ethchain.Disassemble(script)
ui.win.Root().Call("clearAsm")
for _, str := range dis {
ui.win.Root().Call("setAsm", str)
}
// Contract addr as test address
keyPair := ethutil.GetKeyRing().Get(0)
callerTx :=
ethchain.NewContractCreationTx(ethutil.Big(valueStr), ethutil.Big(gasStr), ethutil.Big(gasPriceStr), script)
callerTx.Sign(keyPair.PrivateKey)
account := ui.eth.StateManager().TransState().GetStateObject(keyPair.Address())
contract := ethchain.MakeContract(callerTx, state)
callerClosure := ethchain.NewClosure(account, contract, contract.Init(), state, ethutil.Big(gasStr), ethutil.Big(gasPriceStr))
block := ui.eth.BlockChain().CurrentBlock
vm := ethchain.NewVm(state, ui.eth.StateManager(), ethchain.RuntimeVars{
Origin: account.Address(),
BlockNumber: block.BlockInfo().Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
})
ui.Db.done = false
go func() {
callerClosure.Call(vm, contract.Init(), ui.Db.halting)
state.Reset()
ui.Db.done = true
}()
}
func (ui *UiLib) Next() {
ui.Db.Next()
}

View File

@ -1,151 +0,0 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
"log"
"os"
"os/signal"
"runtime"
)
const Debug = true
// Register interrupt handlers so we can stop the ethereum
func RegisterInterupts(s *eth.Ethereum) {
// Buffered chan of one is enough
c := make(chan os.Signal, 1)
// Notify about interrupts for now
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
fmt.Printf("Shutting down (%v) ... \n", sig)
s.Stop()
}
}()
}
func CreateKeyPair(force bool) {
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
if len(data) == 0 || force {
pub, prv := secp256k1.GenerateKeyPair()
addr := ethutil.Sha3Bin(pub[1:])[12:]
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
Currently Ethereum(G) does not support
exporting keys.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
`, addr, prv, pub)
keyRing := ethutil.NewValue([]interface{}{prv, addr, pub[1:]})
ethutil.Config.Db.Put([]byte("KeyRing"), keyRing.Encode())
}
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
Init()
ethchain.InitFees()
ethutil.ReadConfig(".ethereum")
ethutil.Config.Seed = UseSeed
// Instantiated a eth stack
ethereum, err := eth.New(eth.CapDefault, UseUPnP)
if err != nil {
log.Println("eth start err:", err)
return
}
if GenAddr {
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
if r == "y" {
CreateKeyPair(true)
}
os.Exit(0)
} else {
CreateKeyPair(false)
}
if ShowGenesis {
fmt.Println(ethereum.BlockManager.BlockChain().Genesis())
os.Exit(0)
}
log.Printf("Starting Ethereum v%s\n", ethutil.Config.Ver)
// Set the max peers
ethereum.MaxPeers = MaxPeer
if StartConsole {
err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm)
// Error is OK if the error is ErrExist
if err != nil && !os.IsExist(err) {
log.Panic("Unable to create EXECPATH:", err)
}
console := NewConsole(ethereum)
go console.Start()
}
RegisterInterupts(ethereum)
ethereum.Start()
if StartMining {
log.Printf("Miner started\n")
// Fake block mining. It broadcasts a new block every 5 seconds
go func() {
pow := &ethchain.EasyPow{}
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
keyRing := ethutil.NewValueFromBytes(data)
addr := keyRing.Get(1).Bytes()
for {
txs := ethereum.TxPool.Flush()
// Create a new block which we're going to mine
block := ethereum.BlockManager.BlockChain().NewBlock(addr, txs)
// Apply all transactions to the block
ethereum.BlockManager.ApplyTransactions(block, block.Transactions())
ethereum.BlockManager.AccumelateRewards(block, block)
// Search the nonce
block.Nonce = pow.Search(block)
err := ethereum.BlockManager.ProcessBlock(block)
if err != nil {
log.Println(err)
} else {
log.Println("\n+++++++ MINED BLK +++++++\n", ethereum.BlockManager.BlockChain().CurrentBlock)
}
}
}()
}
// Wait for shutdown
ethereum.WaitForShutdown()
}

54
ethereum/config.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"flag"
"fmt"
"os"
)
var Identifier string
var StartMining bool
var StartRpc bool
var RpcPort int
var UseUPnP bool
var OutboundPort string
var ShowGenesis bool
var AddPeer string
var MaxPeer int
var GenAddr bool
var UseSeed bool
var ImportKey string
var ExportKey bool
var LogFile string
var DataDir string
var NonInteractive bool
var StartJsConsole bool
var InputFile string
func Init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s [options] [filename]:\n", os.Args[0])
flag.PrintDefaults()
}
flag.StringVar(&Identifier, "i", "", "custom client identifier")
flag.BoolVar(&StartMining, "m", false, "start dagger mining")
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits")
flag.BoolVar(&StartRpc, "r", false, "start rpc server")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.BoolVar(&ExportKey, "export", false, "export private key")
flag.StringVar(&OutboundPort, "p", "30303", "listening port")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&DataDir, "dir", ".ethereum", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
flag.IntVar(&MaxPeer, "x", 10, "maximum desired peers")
flag.BoolVar(&StartJsConsole, "js", false, "exp")
flag.Parse()
InputFile = flag.Arg(0)
}

186
ethereum/ethereum.go Normal file
View File

@ -0,0 +1,186 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"io/ioutil"
"log"
"os"
"os/signal"
"runtime"
"strings"
)
const Debug = true
func RegisterInterrupt(cb func(os.Signal)) {
go func() {
// Buffered chan of one is enough
c := make(chan os.Signal, 1)
// Notify about interrupts for now
signal.Notify(c, os.Interrupt)
for sig := range c {
cb(sig)
}
}()
}
func confirm(message string) bool {
fmt.Println(message, "Are you sure? (y/n)")
var r string
fmt.Scanln(&r)
for ; ; fmt.Scanln(&r) {
if r == "n" || r == "y" {
break
} else {
fmt.Printf("Yes or no?", r)
}
}
return r == "y"
}
func main() {
Init()
runtime.GOMAXPROCS(runtime.NumCPU())
// set logger
var logSys *log.Logger
flags := log.LstdFlags
var lt ethutil.LoggerType
if StartJsConsole || len(InputFile) > 0 {
lt = ethutil.LogFile
} else {
lt = ethutil.LogFile | ethutil.LogStd
}
ethutil.ReadConfig(DataDir, lt, Identifier)
logger := ethutil.Config.Log
if LogFile != "" {
logfile, err := os.OpenFile(LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
panic(fmt.Sprintf("error opening log file '%s': %v", LogFile, err))
}
defer logfile.Close()
log.SetOutput(logfile)
logSys = log.New(logfile, "", flags)
logger.AddLogSystem(logSys)
} else {
logSys = log.New(os.Stdout, "", flags)
}
ethchain.InitFees()
// Instantiated a eth stack
ethereum, err := eth.New(eth.CapDefault, UseUPnP)
if err != nil {
log.Println("eth start err:", err)
return
}
ethereum.Port = OutboundPort
// bookkeeping tasks
switch {
case GenAddr:
if NonInteractive || confirm("This action overwrites your old private key.") {
utils.CreateKeyPair(true)
}
os.Exit(0)
case len(ImportKey) > 0:
if NonInteractive || confirm("This action overwrites your old private key.") {
mnemonic := strings.Split(ImportKey, " ")
if len(mnemonic) == 24 {
logSys.Println("Got mnemonic key, importing.")
key := ethutil.MnemonicDecode(mnemonic)
utils.ImportPrivateKey(key)
} else if len(mnemonic) == 1 {
logSys.Println("Got hex key, importing.")
utils.ImportPrivateKey(ImportKey)
} else {
logSys.Println("Did not recognise format, exiting.")
}
}
os.Exit(0)
case ExportKey:
keyPair := ethutil.GetKeyRing().Get(0)
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey)
os.Exit(0)
case ShowGenesis:
logSys.Println(ethereum.BlockChain().Genesis())
os.Exit(0)
default:
// Creates a keypair if non exists
utils.CreateKeyPair(false)
}
// client
logger.Infoln(fmt.Sprintf("Starting Ethereum v%s", ethutil.Config.Ver))
// Set the max peers
ethereum.MaxPeers = MaxPeer
// Set Mining status
ethereum.Mining = StartMining
if StartMining {
utils.DoMining(ethereum)
}
if StartJsConsole {
repl := NewJSRepl(ethereum)
go repl.Start()
RegisterInterrupt(func(os.Signal) {
repl.Stop()
})
} else if len(InputFile) > 0 {
file, err := os.Open(InputFile)
if err != nil {
ethutil.Config.Log.Fatal(err)
}
content, err := ioutil.ReadAll(file)
if err != nil {
ethutil.Config.Log.Fatal(err)
}
re := NewJSRE(ethereum)
RegisterInterrupt(func(os.Signal) {
re.Stop()
})
re.Run(string(content))
}
if StartRpc {
utils.DoRpc(ethereum, RpcPort)
}
RegisterInterrupt(func(sig os.Signal) {
fmt.Printf("Shutting down (%v) ... \n", sig)
ethereum.Stop()
})
ethereum.Start(UseSeed)
// Wait for shutdown
ethereum.WaitForShutdown()
}

View File

@ -0,0 +1,190 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/obscuren/otto"
"io/ioutil"
"os"
"path/filepath"
)
type JSRE struct {
ethereum *eth.Ethereum
vm *otto.Otto
lib *ethpub.PEthereum
blockChan chan ethutil.React
changeChan chan ethutil.React
quitChan chan bool
objectCb map[string][]otto.Value
}
func NewJSRE(ethereum *eth.Ethereum) *JSRE {
re := &JSRE{
ethereum,
otto.New(),
ethpub.NewPEthereum(ethereum),
make(chan ethutil.React, 1),
make(chan ethutil.React, 1),
make(chan bool),
make(map[string][]otto.Value),
}
// Init the JS lib
re.vm.Run(jsLib)
// We have to make sure that, whoever calls this, calls "Stop"
go re.mainLoop()
re.Bind("eth", &JSEthereum{re.lib, re.vm})
re.initStdFuncs()
return re
}
func (self *JSRE) Bind(name string, v interface{}) {
self.vm.Set(name, v)
}
func (self *JSRE) Run(code string) (otto.Value, error) {
return self.vm.Run(code)
}
func (self *JSRE) Require(file string) error {
if len(filepath.Ext(file)) == 0 {
file += ".js"
}
fh, err := os.Open(file)
if err != nil {
return err
}
content, _ := ioutil.ReadAll(fh)
self.Run("exports = {};(function() {" + string(content) + "})();")
return nil
}
func (self *JSRE) Stop() {
// Kill the main loop
self.quitChan <- true
close(self.blockChan)
close(self.quitChan)
close(self.changeChan)
}
func (self *JSRE) mainLoop() {
// Subscribe to events
reactor := self.ethereum.Reactor()
reactor.Subscribe("newBlock", self.blockChan)
out:
for {
select {
case <-self.quitChan:
break out
case block := <-self.blockChan:
if _, ok := block.Resource.(*ethchain.Block); ok {
}
case object := <-self.changeChan:
if stateObject, ok := object.Resource.(*ethchain.StateObject); ok {
for _, cb := range self.objectCb[ethutil.Hex(stateObject.Address())] {
val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject))
cb.Call(cb, val)
}
} else if storageObject, ok := object.Resource.(*ethchain.StorageState); ok {
for _, cb := range self.objectCb[ethutil.Hex(storageObject.StateAddress)+ethutil.Hex(storageObject.Address)] {
val, _ := self.vm.ToValue(ethpub.NewPStorageState(storageObject))
cb.Call(cb, val)
}
}
}
}
}
func (self *JSRE) initStdFuncs() {
t, _ := self.vm.Get("eth")
eth := t.Object()
eth.Set("watch", self.watch)
eth.Set("addPeer", self.addPeer)
eth.Set("require", self.require)
eth.Set("stopMining", self.stopMining)
eth.Set("startMining", self.startMining)
}
/*
* The following methods are natively implemented javascript functions
*/
func (self *JSRE) stopMining(call otto.FunctionCall) otto.Value {
v, _ := self.vm.ToValue(utils.StopMining(self.ethereum))
return v
}
func (self *JSRE) startMining(call otto.FunctionCall) otto.Value {
v, _ := self.vm.ToValue(utils.StartMining(self.ethereum))
return v
}
// eth.watch
func (self *JSRE) watch(call otto.FunctionCall) otto.Value {
addr, _ := call.Argument(0).ToString()
var storageAddr string
var cb otto.Value
var storageCallback bool
if len(call.ArgumentList) > 2 {
storageCallback = true
storageAddr, _ = call.Argument(1).ToString()
cb = call.Argument(2)
} else {
cb = call.Argument(1)
}
if storageCallback {
self.objectCb[addr+storageAddr] = append(self.objectCb[addr+storageAddr], cb)
event := "storage:" + string(ethutil.FromHex(addr)) + ":" + string(ethutil.FromHex(storageAddr))
self.ethereum.Reactor().Subscribe(event, self.changeChan)
} else {
self.objectCb[addr] = append(self.objectCb[addr], cb)
event := "object:" + string(ethutil.FromHex(addr))
self.ethereum.Reactor().Subscribe(event, self.changeChan)
}
return otto.UndefinedValue()
}
func (self *JSRE) addPeer(call otto.FunctionCall) otto.Value {
host, err := call.Argument(0).ToString()
if err != nil {
return otto.FalseValue()
}
self.ethereum.ConnectToPeer(host)
return otto.TrueValue()
}
func (self *JSRE) require(call otto.FunctionCall) otto.Value {
file, err := call.Argument(0).ToString()
if err != nil {
return otto.UndefinedValue()
}
if err := self.Require(file); err != nil {
fmt.Println("err:", err)
return otto.UndefinedValue()
}
t, _ := self.vm.Get("exports")
return t
}

53
ethereum/js_lib.go Normal file
View File

@ -0,0 +1,53 @@
package main
const jsLib = `
function pp(object) {
var str = "";
if(object instanceof Array) {
str += "[ ";
for(var i = 0, l = object.length; i < l; i++) {
str += pp(object[i]);
if(i < l-1) {
str += ", ";
}
}
str += " ]";
} else if(typeof(object) === "object") {
str += "{ ";
var last = Object.keys(object).sort().pop()
for(var k in object) {
str += k + ": " + pp(object[k]);
if(k !== last) {
str += ", ";
}
}
str += " }";
} else if(typeof(object) === "string") {
str += "\033[32m'" + object + "'";
} else if(typeof(object) === "undefined") {
str += "\033[1m\033[30m" + object;
} else if(typeof(object) === "number") {
str += "\033[31m" + object;
} else if(typeof(object) === "function") {
str += "\033[35m[Function]";
} else {
str += object;
}
str += "\033[0m";
return str;
}
function prettyPrint(/* */) {
var args = arguments;
for(var i = 0, l = args.length; i < l; i++) {
console.log(pp(args[i]))
}
}
var print = prettyPrint;
`

110
ethereum/repl.go Normal file
View File

@ -0,0 +1,110 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethpub"
"github.com/obscuren/otto"
)
type Repl interface {
Start()
Stop()
}
type JSRepl struct {
re *JSRE
prompt string
}
func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
return &JSRepl{re: NewJSRE(ethereum), prompt: "> "}
}
func (self *JSRepl) Start() {
self.read()
}
func (self *JSRepl) Stop() {
self.re.Stop()
}
func (self *JSRepl) parseInput(code string) {
defer func() {
if r := recover(); r != nil {
fmt.Println("[native] error", r)
}
}()
value, err := self.re.Run(code)
if err != nil {
fmt.Println(err)
return
}
self.PrintValue(value)
}
// The JSEthereum object attempts to wrap the PEthereum object and returns
// meaningful javascript objects
type JSBlock struct {
*ethpub.PBlock
eth *JSEthereum
}
func (self *JSBlock) GetTransaction(hash string) otto.Value {
return self.eth.toVal(self.PBlock.GetTransaction(hash))
}
type JSEthereum struct {
*ethpub.PEthereum
vm *otto.Otto
}
func (self *JSEthereum) GetBlock(hash string) otto.Value {
return self.toVal(&JSBlock{self.PEthereum.GetBlock(hash), self})
}
func (self *JSEthereum) GetKey() otto.Value {
return self.toVal(self.PEthereum.GetKey())
}
func (self *JSEthereum) GetStateObject(addr string) otto.Value {
return self.toVal(self.PEthereum.GetStateObject(addr))
}
func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
r, err := self.PEthereum.Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
return self.toVal(r)
}
func (self *JSEthereum) Create(key, valueStr, gasStr, gasPriceStr, scriptStr string) otto.Value {
r, err := self.PEthereum.Create(key, valueStr, gasStr, gasPriceStr, scriptStr)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
return self.toVal(r)
}
func (self *JSEthereum) toVal(v interface{}) otto.Value {
result, err := self.vm.ToValue(v)
if err != nil {
fmt.Println(err)
return otto.UndefinedValue()
}
return result
}

121
ethereum/repl_darwin.go Normal file
View File

@ -0,0 +1,121 @@
package main
// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include
// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib
// #cgo LDFLAGS: -lreadline
// #include <stdio.h>
// #include <stdlib.h>
// #include <readline/readline.h>
// #include <readline/history.h>
import "C"
import (
"os"
"os/signal"
"strings"
"syscall"
"unsafe"
)
func initReadLine() {
C.rl_catch_sigwinch = 0
C.rl_catch_signals = 0
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGWINCH)
signal.Notify(c, os.Interrupt)
go func() {
for sig := range c {
switch sig {
case syscall.SIGWINCH:
C.rl_resize_terminal()
case os.Interrupt:
C.rl_cleanup_after_signal()
default:
}
}
}()
}
func readLine(prompt *string) *string {
var p *C.char
//readline allows an empty prompt(NULL)
if prompt != nil {
p = C.CString(*prompt)
}
ret := C.readline(p)
if p != nil {
C.free(unsafe.Pointer(p))
}
if ret == nil {
return nil
} //EOF
s := C.GoString(ret)
C.free(unsafe.Pointer(ret))
return &s
}
func addHistory(s string) {
p := C.CString(s)
C.add_history(p)
C.free(unsafe.Pointer(p))
}
var indentCount = 0
var str = ""
func (self *JSRepl) setIndent() {
open := strings.Count(str, "{")
open += strings.Count(str, "(")
closed := strings.Count(str, "}")
closed += strings.Count(str, ")")
indentCount = open - closed
if indentCount <= 0 {
self.prompt = "> "
} else {
self.prompt = strings.Join(make([]string, indentCount*2), "..")
self.prompt += " "
}
}
func (self *JSRepl) read() {
initReadLine()
L:
for {
switch result := readLine(&self.prompt); true {
case result == nil:
break L
case *result != "":
str += *result + "\n"
self.setIndent()
if indentCount <= 0 {
if *result == "exit" {
self.Stop()
break L
}
addHistory(str[:len(str)-1]) //allow user to recall this line
self.parseInput(str)
str = ""
}
}
}
}
func (self *JSRepl) PrintValue(v interface{}) {
method, _ := self.re.vm.Get("prettyPrint")
v, err := self.re.vm.ToValue(v)
if err == nil {
method.Call(method, v)
}
}

1
ethereum/repl_linux.go Symbolic link
View File

@ -0,0 +1 @@
repl_darwin.go

24
ethereum/repl_windows.go Normal file
View File

@ -0,0 +1,24 @@
package main
import (
"bufio"
"fmt"
"os"
)
func (self *JSRepl) read() {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Printf(self.prompt)
str, _, err := reader.ReadLine()
if err != nil {
fmt.Println("Error reading input", err)
} else {
self.parseInput(string(str))
}
}
}
func (self *JSRepl) PrintValue(value otto.Value) {
fmt.Println(value)
}

View File

@ -1,35 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"testing"
)
type TestSource struct {
Inputs map[string]string
Expectation string
}
func NewTestSource(source string) *TestSource {
s := &TestSource{}
err := json.Unmarshal([]byte(source), s)
if err != nil {
fmt.Println(err)
}
return s
}
type TestRunner struct {
source *TestSource
}
func NewTestRunner(t *testing.T) *TestRunner {
return &TestRunner{}
}
func (runner *TestRunner) RunFromString(input string, Cb func(*TestSource)) {
source := NewTestSource(input)
Cb(source)
}

View File

@ -1,36 +0,0 @@
package main
/*
import (
"encoding/hex"
_ "fmt"
"github.com/ethereum/ethdb-go"
"github.com/ethereum/ethutil-go"
"testing"
)
var testsource = `
{
"inputs":{
"doe": "reindeer",
"dog": "puppy",
"dogglesworth": "cat"
},
"expectation":"e378927bfc1bd4f01a2e8d9f59bd18db8a208bb493ac0b00f93ce51d4d2af76c"
}`
func TestTestRunner(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
trie := ethutil.NewTrie(db, "")
runner := NewTestRunner(t)
runner.RunFromString(testsource, func(source *TestSource) {
for key, value := range source.Inputs {
trie.Update(key, value)
}
if hex.EncodeToString(trie.Root.([]byte)) != source.Expectation {
t.Error("trie root did not match")
}
})
}
*/

View File

@ -1,33 +0,0 @@
package main
/*
import (
_"fmt"
)
// This will eventually go away
var Db *MemDatabase
func Testing() {
db, _ := NewMemDatabase()
Db = db
bm := NewBlockManager()
tx := NewTransaction("\x00", 20, []string{"PUSH"})
txData := tx.RlpEncode()
//fmt.Printf("%q\n", txData)
copyTx := &Transaction{}
copyTx.RlpDecode(txData)
//fmt.Println(tx)
//fmt.Println(copyTx)
tx2 := NewTransaction("\x00", 20, []string{"SET 10 6", "LD 10 10"})
blck := CreateTestBlock([]*Transaction{tx2, tx})
bm.ProcessBlock( blck )
}
*/

76
utils/cmd.go Normal file
View File

@ -0,0 +1,76 @@
package utils
import (
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethminer"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil"
"time"
)
func DoRpc(ethereum *eth.Ethereum, RpcPort int) {
var err error
ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
if err != nil {
ethutil.Config.Log.Infoln("Could not start RPC interface:", err)
} else {
go ethereum.RpcServer.Start()
}
}
var miner ethminer.Miner
func DoMining(ethereum *eth.Ethereum) {
// Set Mining status
ethereum.Mining = true
if ethutil.GetKeyRing().Len() == 0 {
ethutil.Config.Log.Infoln("No address found, can't start mining")
return
}
keyPair := ethutil.GetKeyRing().Get(0)
addr := keyPair.Address()
go func() {
ethutil.Config.Log.Infoln("Miner started")
miner = ethminer.NewDefaultMiner(addr, ethereum)
// Give it some time to connect with peers
time.Sleep(3 * time.Second)
for ethereum.IsUpToDate() == false {
time.Sleep(5 * time.Second)
}
ethutil.Config.Log.Infoln("Miner started")
miner := ethminer.NewDefaultMiner(addr, ethereum)
miner.Start()
}()
}
func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining {
miner.Stop()
ethutil.Config.Log.Infoln("Miner stopped")
ethereum.Mining = false
return true
}
return false
}
func StartMining(ethereum *eth.Ethereum) bool {
if !ethereum.Mining {
DoMining(ethereum)
return true
}
return false
}

41
utils/compile.go Normal file
View File

@ -0,0 +1,41 @@
package utils
import (
"fmt"
"github.com/obscuren/mutan"
"strings"
)
// General compile function
func Compile(script string) ([]byte, error) {
byteCode, errors := mutan.Compile(strings.NewReader(script), false)
if len(errors) > 0 {
var errs string
for _, er := range errors {
if er != nil {
errs += er.Error()
}
}
return nil, fmt.Errorf("%v", errs)
}
return byteCode, nil
}
func CompileScript(script string) ([]byte, []byte, error) {
// Preprocess
mainInput, initInput := mutan.PreParse(script)
// Compile main script
mainScript, err := Compile(mainInput)
if err != nil {
return nil, nil, err
}
// Compile init script
initScript, err := Compile(initInput)
if err != nil {
return nil, nil, err
}
return mainScript, initScript, nil
}

108
utils/keys.go Normal file
View File

@ -0,0 +1,108 @@
package utils
import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
)
func CreateKeyPair(force bool) {
if force {
ethutil.GetKeyRing().Reset()
fmt.Println("resetting")
}
if ethutil.GetKeyRing().Get(0) == nil {
_, prv := secp256k1.GenerateKeyPair()
keyPair, err := ethutil.GetKeyRing().NewKeyPair(prv)
if err != nil {
panic(err)
}
mne := ethutil.MnemonicEncode(ethutil.Hex(keyPair.PrivateKey))
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey, mne)
}
}
func ImportPrivateKey(sec string) {
ethutil.GetKeyRing().Reset()
keyPair, err := ethutil.GetKeyRing().NewKeyPair(ethutil.FromHex(sec))
if err != nil {
panic(err)
}
mne := ethutil.MnemonicEncode(ethutil.Hex(keyPair.PrivateKey))
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, keyPair.Address(), keyPair.PrivateKey, keyPair.PublicKey, mne)
}
/*
func CreateKeyPair(force bool) {
data, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
if len(data) == 0 || force {
pub, prv := secp256k1.GenerateKeyPair()
pair := &ethutil.Key{PrivateKey: prv, PublicKey: pub}
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode())
mne := ethutil.MnemonicEncode(ethutil.Hex(prv))
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
save these words so you can restore your account later: %s
`, pair.Address(), prv, pub, mne)
}
}
*/
/*
func ImportPrivateKey(prvKey string) {
key := ethutil.FromHex(prvKey)
msg := []byte("tmp")
// Couldn't think of a better way to get the pub key
sig, _ := secp256k1.Sign(msg, key)
pub, _ := secp256k1.RecoverPubkey(msg, sig)
pair := &ethutil.Key{PrivateKey: key, PublicKey: pub}
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode())
fmt.Printf(`
Importing private key
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
`, pair.Address(), key, pub)
}
*/