Compare commits

..

428 Commits

Author SHA1 Message Date
b3f25a6ade Merge branch 'release/0.6.0' 2014-07-25 10:42:14 +02:00
44da1801d8 Fixed strange issue where qml will crash first run after go install 2014-07-24 14:34:22 +02:00
82a84dca80 Move to goroutine for faster startup time 2014-07-24 14:16:43 +02:00
0ca776a6b8 Merge branch 'feature/new_vm' into develop 2014-07-24 14:16:25 +02:00
2e39efbe7c New State object 2014-07-24 12:34:48 +02:00
a06a84d19b Refactored to reflect the new VM and State 2014-07-24 12:30:41 +02:00
e7a80ec681 set asm 2014-07-22 19:54:33 +02:00
15960a5c04 changed iterator 2014-07-21 11:55:50 +02:00
f702e27485 Fixed miner stopping / starting:wq 2014-07-18 13:49:52 +02:00
0c5a747ef1 Add mining hash to GUI 2014-07-18 12:29:14 +02:00
75df148ba2 Fixed miner channel 2014-07-18 12:21:34 +02:00
4572d4940c Windows don't like dem flags 2014-07-18 12:02:45 +02:00
2b9f16802d WIP to expose hashrate to gui 2014-07-18 12:01:26 +02:00
34e2ab9f9f Added block update 2014-07-18 11:57:58 +02:00
44296c0b33 html tags not allowed 2014-07-17 23:17:10 +02:00
01d9107bce Add namecoin name if available to block 2014-07-17 22:30:17 +02:00
ba3fabda77 Added a catch up indicator 2014-07-17 22:01:39 +02:00
edf10ef8c5 Fixed name reg 2014-07-17 17:10:35 +02:00
6c565eae74 bump 2014-07-17 15:36:16 +02:00
c951702423 Merge branch 'develop' 2014-07-17 15:32:44 +02:00
7d64b589b4 h scroll 2014-07-17 15:02:25 +02:00
c302afd411 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-07-15 20:36:45 +02:00
28948d061c Moved the repl to a new package 2014-07-15 20:34:25 +02:00
223432fa1e Work around crash issues when building OSX binary 2014-07-15 16:21:16 +02:00
c0ae5c58a6 Rewrote mnemonic word loading to facilitate deployable builds. 2014-07-15 12:52:30 +02:00
e53acdc2ac Work around race condition with qt webinspector for windows builds 2014-07-14 16:46:00 +02:00
dce0ccf490 Don't silently fail on watcher creation 2014-07-14 15:29:02 +02:00
e6a428f85f Make the reload watcher use windows-safe paths 2014-07-14 15:25:01 +02:00
288f1c5387 Removed timer 2014-07-12 11:02:50 +02:00
d3e31a4a6d Special diff output + debugger changes 2014-07-11 16:04:27 +02:00
fc8bd7229e Merge branch 'develop' 2014-07-10 21:54:46 +02:00
c2bca5939d Added path check for Windows when loading external QML windows/components 2014-07-09 14:01:53 +02:00
05c1899895 Windos case for assetPath had a typo 2014-07-08 14:58:33 +02:00
7e88dd4e6b Setup default asset path for windows 2014-07-08 14:58:23 +02:00
61d5d107b6 Make script inclusion via QML also relative to asset path 2014-07-08 14:27:22 +02:00
7f9e614b5d Forgot two images 2014-07-08 14:25:30 +02:00
79259c916d Use relative image paths to help with windows builds 2014-07-08 14:05:42 +02:00
685aebc72e Merge branch 'develop' 2014-07-07 22:15:35 +02:00
0360e60dd5 Merge pull request #101 from ethereum/revert-100-feature/ethutil-refactor
Revert "ethreact - Feature/ethutil refactor"
2014-07-07 10:59:30 +02:00
0c132e4c9e Revert "ethreact - Feature/ethutil refactor" 2014-07-07 10:58:42 +02:00
f9e2e5276f Merge pull request #100 from ethersphere/feature/ethutil-refactor
ethreact - Feature/ethutil refactor
2014-07-07 10:55:39 +02:00
8e5117444e New type of debugger 2014-07-05 13:25:16 +02:00
1e4ae24126 use ethreact.Event, unbuffered event channels, subscribe after loop reading from channel starts 2014-07-04 19:48:37 +01:00
0ae3bbc3f5 deleted 2014-07-04 15:53:16 +02:00
b9fa4dada8 Merge branch 'develop' 2014-07-04 15:53:03 +02:00
9754c01f56 Added sample coin as a submodule 2014-07-04 15:49:51 +02:00
043920d157 Removed sample coin 2014-07-04 15:49:32 +02:00
3ebcd36667 Merge branch 'develop' 2014-07-04 15:32:25 +02:00
9e38ca555d Visual updates 2014-07-04 15:31:13 +02:00
de183e80db Silent compiler errors when continues compiling 2014-07-04 13:42:43 +02:00
ca395306e3 Updated debugger
* Compile on the go. Continues compilation in order to update the ASM
  view
* Short cuts commands
2014-07-04 13:04:25 +02:00
24ff81d14e Merge branch 'ethersphere-feature/clientid' into develop 2014-07-04 00:14:17 +02:00
9de30d96f0 Modify main wrappers
- clientIdentifier now set in main wrappers
- version handled within wrapper
- modify InitConfig now returning *ethutil.ConfigManager (passed to gui)
- added NewClientIdentity returning *ethwire.SimpleClientIdentiy (passed to ethereum)
2014-07-03 17:36:24 +01:00
a3c4823511 Gui saves custom client id and loglevel
- gui NewWindow takes SimpleClientIdentity as argument
- gui NewWindow takes ethutil.ConfigManager as argument to manage flag persistence
- gui now saves loglevel and custom client id via config.Save
- rename custom client id methods consistently also in wallet.qml
- clientIdentifier now set in main wrappers
- version handled within wrapper
- modify InitConfig now returning *ethutil.ConfigManager (passed to gui)
2014-07-03 17:35:48 +01:00
0076fa583c Merge branch 'develop' 2014-07-02 17:48:35 +02:00
a0dd1ebb6d . 2014-07-02 13:44:59 +02:00
50c0938226 Break points and debugger commands 2014-07-02 13:08:18 +02:00
98f21669c7 Merge branch 'develop' 2014-07-02 11:30:37 +02:00
7d0004f058 For namreg only show items starting without leading zeros. 2014-07-02 11:29:59 +02:00
e5b45d1c86 VM Update 2014-07-02 01:04:32 +02:00
677de48f6c Listen for namereg changes 2014-07-02 00:28:45 +02:00
c4f9151c67 Moved files 2014-07-02 00:13:50 +02:00
4918531dd5 Merge branch 'develop' 2014-07-01 20:10:49 +02:00
2835321377 Fixed namereg 2014-07-01 20:10:38 +02:00
74ef489fe2 Merge branch 'release/0.5.16' into develop 2014-07-01 16:24:54 +02:00
cb595fb63c Merge branch 'release/0.5.16' 2014-07-01 16:24:35 +02:00
5d3259587f bump 2014-07-01 16:24:34 +02:00
5e02d2b586 Merge pull request #96 from ethersphere/feature/keys
Feature/keys
2014-07-01 16:15:59 +02:00
ce88a73aa6 Merge branch 'develop' of github.com:ethereum/go-ethereum into feature/keys 2014-07-01 15:01:28 +01:00
41a03b29ab Merge branch 'ebuchman-miner_up_to_date' into develop 2014-07-01 11:28:11 +02:00
0ed9528d76 fix: miner wait untill UpToDate 2014-07-01 04:25:42 -04:00
098f7f23ce changed name for ethutil hex functions; and access to keyring via keyManager 2014-06-29 20:39:45 +01:00
8aea468744 gui changes
- remove lib   *EthLib, expose gui itself to initial import window
- remove addr []byte instead use dynamic adress()
- use ethereum.KeyManager to retrieve address and privateKey
- add Session string (keyRing identifier)
- add and reimplement ImportAndSetPrivKey and CreateAndSetPrivKey
2014-06-29 20:38:26 +01:00
29cc1af2bc remove ui/library; instead expose gui itself for initial window 2014-06-29 20:34:07 +01:00
e43e4ff2c1 main loop uses new flags and common methods in util: db, keymanager set up; passes KeyRing/Session string to gui 2014-06-29 20:32:31 +01:00
12fbb7ae5c new command line options
- keyring: keyring/session identifier used by key manager
- keystore: choice of db/file key storage
- import message updated
- export: name of directory to export keys to (was bool)
2014-06-29 20:31:00 +01:00
ce4080faa7 Merge branch 'develop' of github.com:ethereum/go-ethereum into feature/keys 2014-06-29 18:39:31 +01:00
cf7fcadeca added utility functions to set up db, keymanager, ethereum init and simplify key tasks 2014-06-29 18:39:13 +01:00
9bd67de671 remove keys file, now subsumed under ethcrypto/key_manager 2014-06-29 18:38:17 +01:00
27e1352c85 main loop uses new flags and common methods in util: db, keymanager set up 2014-06-29 18:37:22 +01:00
0ea9595d41 new command line options
- keyring: keyring/session identifier used by key manager
- keystore: choice of db/file key storage
- import message updated
- export: name of directory to export keys to (was bool)
2014-06-29 18:33:22 +01:00
e38b016547 changed name for ethutil hex functions 2014-06-29 18:32:48 +01:00
2d48fc1113 fix logmessage if data directory doesn't exist 2014-06-29 13:43:27 +01:00
328ee9a3ec Merge branch 'master' into develop 2014-06-29 10:44:03 +02:00
4fc60f340f Wait for catchup when starting the miner 2014-06-29 10:43:56 +02:00
1b74b98f90 Check if go install succeed 2014-06-26 23:31:07 +02:00
d57b7e8d5f Fix for installer 2014-06-26 23:25:17 +02:00
2d274003b8 Merge branch 'develop'
Conflicts:
	install.sh
2014-06-26 23:14:50 +02:00
52ddf044ae Initialization of Qt should happen before anything else 2014-06-26 23:14:17 +02:00
214721ca01 update 2014-06-26 23:07:20 +02:00
cad98dc4d5 update 2014-06-26 23:06:04 +02:00
e46e7e7a9c Added install script 2014-06-26 23:04:46 +02:00
bf2ac5acc5 Added install script 2014-06-26 23:01:35 +02:00
42414cadaa Merge branch 'release/0.5.15' into develop 2014-06-26 19:54:23 +02:00
3777ead25e Merge branch 'release/0.5.15' 2014-06-26 19:54:09 +02:00
a68bfd215f bump 2014-06-26 19:54:00 +02:00
fd89df4d38 Merge branch 'develop' into release/0.5.15 2014-06-26 19:53:03 +02:00
91bdf9e801 Merge branch 'ethersphere-feature/logging' into develop 2014-06-26 19:52:23 +02:00
ae5ace1619 go fmt 2014-06-26 18:48:08 +01:00
b57ee87485 bump 2014-06-26 19:04:53 +02:00
8100903d92 Increase width of asm instruction 2014-06-26 18:58:37 +02:00
648c418fcd Merge branch 'develop' of github.com:ethereum/go-ethereum into feature/logging 2014-06-26 16:33:40 +01:00
21d86ca486 gui stop
- introduce gui.Stop()
- remember state with open
- stopping ethereum stack is not gui concern, moved to main
- stopping mining, gui and ethereum handled via interrupt callbacks
- ^C triggers exactly the same behaviour as quit via menu
2014-06-26 16:26:14 +01:00
c0a05fcf89 log slider
- only add the gui logger after window is shown otherwise slider wont be shown
- need to silence gui logger after window closed otherwise logsystem hangs
- gui.GetLogLevelInt() extra function needed to give correcty int typecast value to gui widget that sets initial loglevel to default
2014-06-26 12:13:31 +01:00
b89076faa2 Added amount to contract during debugging 2014-06-26 12:10:11 +02:00
2f96652bb4 interrupt handlers now ordered 2014-06-26 10:47:45 +01:00
b3367ec0e3 Added option to not break eachline 2014-06-26 10:37:48 +02:00
9a06efd080 new logger API for upstream merge 2014-06-25 18:28:38 +01:00
6763d28a17 repl.Stop() to only if running, fixes panic after js> exit followed by interrupt 2014-06-25 18:18:22 +01:00
bf57e9603b add newline to help usage msg 2014-06-25 18:09:42 +01:00
096427c3b1 Merge remote-tracking branch 'upstream/develop' into feature/logging 2014-06-25 16:56:03 +01:00
8ee1abecb9 update log levels to include DebugDetail; correct default datadir for ethereal 2014-06-25 16:54:29 +01:00
39c0f7f386 fix logSlider: now has 5 levels, initialized to gui.GetLogLevel which is set through command line flag (defaults to InfoLevel) 2014-06-25 16:53:19 +01:00
1268413ba7 Removed old compile methods 2014-06-25 17:26:16 +02:00
08de13a57b merge upstream 2014-06-25 16:20:26 +01:00
9654b80912 Implemented TX History for ethjs 2014-06-25 16:12:53 +02:00
1e965cb8f5 Moved BlockDo to utils 2014-06-25 09:47:11 +02:00
fd1ddbce68 Save repl history to file and recall on next session 2014-06-24 10:09:02 +02:00
a13aa873c2 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-06-24 09:39:25 +02:00
17e8d7519b Renamed execBlock 2014-06-24 09:36:05 +02:00
bcb88e7352 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-06-23 16:26:01 +02:00
f6aabb7a90 Implements QML Apps. Implements #47
You are welcome Stephan.
2014-06-23 16:25:57 +02:00
6f09a3e820 fix imports in ui_lib and flags cos of defaultAssetPath move; fix logLevel type for gui 2014-06-23 12:38:23 +01:00
34284b7532 merge upstream 2014-06-23 12:30:30 +01:00
1024766514 refactor cli and gui wrapper code. Details:
- all cli functions shared between ethereum and ethereal abstracted to utils/ cmd.go (should be ethcommon or shared or sth)
- simplify main() now readable stepwise
- rename main wrapper files to main.go
- rename commmand line args definition file from config.go to flags.go
- rename Do -> Start to parallel option names
- register interrupt for rpc server stop
- fix interrupt stopping js repl and ethereum
- register interrupt for mining stop
- custom config file option from command line
- debug option from command line
- loglevel option from command line
- changed ethutil.Config API
- default datadir and default config file set together with other flag defaults in wrappers
- default assetpath set together with other command line flags defaults in gui wrapper (not in ethutil.Config or ui/ui_lib)
- options precedence: default < config file < environment variables < command line
2014-06-23 12:25:55 +01:00
456167aca0 fix gitignore to ignore executables 2014-06-23 12:13:06 +01:00
c67cdab221 merge upstream 2014-06-23 12:06:45 +01:00
d060ae6a36 changed logger API, functions that allow Gui to implement ethlog.LogSystem for gui logging 2014-06-23 11:57:00 +01:00
7bcf875c57 add logging for jsre 2014-06-23 11:39:09 +01:00
f90001e938 add logging start/exit to js console 2014-06-23 11:38:14 +01:00
176b780251 Added a execBlock method which replays the given block 2014-06-23 11:28:05 +02:00
2408e38218 Merge branch 'release/0.5.14' into develop 2014-06-20 00:49:00 +02:00
cba4796311 Merge branch 'release/0.5.14' 2014-06-20 00:48:53 +02:00
65cbea2b6a bump 2014-06-20 00:48:48 +02:00
c89566a42f Removed old debugger code 2014-06-20 00:42:53 +02:00
3ec0c719b9 Verbose logging 2014-06-19 13:47:18 +02:00
a32a15ad93 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-06-18 18:12:31 +01:00
e517fb5f9d Merge branch 'release/0.5.13' into develop 2014-06-16 18:25:07 +02:00
98335d2040 Merge branch 'release/0.5.13' 2014-06-16 18:24:57 +02:00
c1220e8729 bump 2014-06-16 18:24:24 +02:00
3744151359 Removed init fees 2014-06-16 11:15:08 +02:00
7ab735eb02 Max 250 log 2014-06-15 00:02:41 +02:00
ef1b923b31 Added a log level slider which can change the log level 2014-06-14 15:44:32 +02:00
50fdfb127a Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-06-14 13:53:55 +01:00
e7a22af0e6 Minor UI adjustments 2014-06-12 10:06:02 +02:00
1d300bbc10 Toggle inspector / reload using magic rectangle 2014-06-11 15:55:47 +02:00
e36badd744 Reimplement -datadir flag. Implements #79
The config file is actually loaded from the folder that datadir points at
2014-06-11 12:33:11 +02:00
57e3b1b093 Implemented usedGas to the explorer 2014-06-11 11:40:13 +02:00
0ee258bb75 Add GasLimit to the block explorer 2014-06-11 10:27:58 +02:00
66199497a0 Merge branch 'release/poc5-rc12' into develop 2014-06-09 22:24:30 +02:00
aa8a86f0a6 Merge branch 'release/poc5-rc12' 2014-06-09 22:24:24 +02:00
d929c63474 bump 2014-06-09 22:23:33 +02:00
ba3623d0cc Fixed debugger hang 2014-06-09 22:04:16 +02:00
cc20b0e3a0 debugger output 2014-06-06 12:13:13 +02:00
a107a5db05 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-06-05 09:01:10 +02:00
964587b14a Added more debugger output 2014-06-05 09:00:57 +02:00
7843390ecd Implement getStateKeyVal for JS bindings.
Gives JS the option to 'loop' over contract key/val storage
2014-06-04 15:54:33 +02:00
307fe4a3cd Add loading of extra build in js files to JS-Repl. Implements #67 2014-06-04 12:19:50 +02:00
3755616a29 Added namereg register option to qml wallet 2014-06-03 14:30:26 +02:00
cc1d043423 Implemented transaction catching up. Implements #73 2014-06-03 11:48:44 +02:00
9e411d785b Tweaks and latency added to peeroverview 2014-06-03 10:42:36 +02:00
a6f4eef1da Added Peer Window 2014-06-02 15:16:37 +02:00
98811f11e5 ethereum instead of ethereal. Fixes #69 2014-05-31 11:43:08 +02:00
d6acb74ac9 fixed logging issue that would otherwise crash the client. Fixes #68 2014-05-31 11:34:37 +02:00
397e99fcc6 Merge branch 'develop' 2014-05-30 20:35:44 +02:00
be27309dbb show first? 2014-05-30 20:35:37 +02:00
4dfce5d347 Merge branch 'develop' 2014-05-30 19:36:21 +02:00
0bdb0a9d58 Added ini file for ethereum. fixes #66 2014-05-30 19:36:05 +02:00
5f28013f79 Merge branch 'develop' 2014-05-30 16:58:17 +02:00
65c5a20e1c Added config file setup. Fixes #59
* Also fixes asset path problems
2014-05-30 16:56:56 +02:00
1020d7ff67 Unified the contract interface and tx interface. Fixes #62 2014-05-30 16:14:46 +02:00
e7c9b86a5a Improved UI
* Added mining button
2014-05-30 13:28:31 +02:00
0938b56829 Update peer info 2014-05-30 13:04:23 +02:00
fcbf99a30a Minor GUI updates
* IceCream => IceCREAM
* Added coin base to block info
2014-05-30 11:50:30 +02:00
40d72ff40b . 2014-05-29 12:24:56 +02:00
efadfbfb17 Minor UI changes
* Moved log from block view
* Prepend instead of append for logs
2014-05-29 12:24:14 +02:00
8ee6574d12 Minimal fee for sending transactions 2014-05-29 12:14:25 +02:00
efb3ee044b Removed regexp for namereg 2014-05-29 11:49:59 +02:00
0b4c42d756 Disabled instruction selection 2014-05-29 02:05:06 +02:00
f0f205004c Merge branch 'develop' 2014-05-28 23:23:52 +02:00
f802e17626 merge 2014-05-28 23:16:15 +02:00
8fab7ce37d Fixes and improved debugger 2014-05-28 23:14:23 +02:00
44db1a1eb2 Add 0x when feeding data to debugger 2014-05-28 18:11:27 +02:00
0aee830bde Fix merge conflict 2014-05-28 16:20:36 +02:00
06d41794f9 Merge branch 'release/poc5-rc11' into develop 2014-05-28 16:20:05 +02:00
2114218ed8 Merge branch 'release/poc5-rc11' 2014-05-28 16:19:58 +02:00
58032d60e7 Bump to RC11 2014-05-28 16:17:57 +02:00
d4f9daa631 Refactor hex encode and remove coupling of popup to main window 2014-05-28 16:14:24 +02:00
1eda1d25b0 Hooked up the Block Explorer to the Debugger so we can instantly debug made transactions 2014-05-28 15:48:17 +02:00
aaeb268522 Merge branch 'develop' of github.com-obscure:ethereum/go-ethereum into develop 2014-05-28 13:01:04 +02:00
540d39220d Merge branch 'master' into develop 2014-05-28 13:00:51 +02:00
09728bf43c Debugger script&data now accept "0x" values 2014-05-28 13:00:45 +02:00
090447c664 Data and script in the debugger accept "0x" values and regular scripting 2014-05-28 12:59:10 +02:00
d4af5a5763 Merge branch 'hotfix/2' into develop 2014-05-28 11:53:31 +02:00
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
72df038d25 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2014-05-23 18:25:49 +01: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
64 changed files with 13684 additions and 1373 deletions

2
.gitignore vendored
View File

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

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "ethereal/assets/samplecoin"]
path = ethereal/assets/samplecoin
url = git@github.com:obscuren/SampleCoin.git

View File

@ -3,67 +3,72 @@ Ethereum
[![Build Status](https://travis-ci.org/ethereum/go-ethereum.png?branch=master)](https://travis-ci.org/ethereum/go-ethereum)
Ethereum Go Client (c) Jeffrey Wilcke
Ethereum Go Client © 2014 Jeffrey Wilcke.
The current state is "Proof of Concept 3". For build instructions see
the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Edge).
Current state: Proof of Concept 0.6.0.
For the development Go Package please see [eth-go package](https://github.com/ethereum/eth-go).
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):
Command line options
`go get github.com/ethereum/go-ethereum/ethereal`
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
-m Start mining blocks
Shared between ethereum and ethereal
-id Set the custom identifier of the client (shows up on other clients)
-port Port on which the server will accept incomming connections
-upnp Enable UPnP
-maxpeer Desired amount of peers
-rpc Start JSON RPC
-dir Data directory used to store configs and databases
-import Import a private key
-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
-gui Launch with GUI (= true)
-dir Data directory used to store configs and databases (=".ethereum")
-import Import a private key (hex)
```
-h This
Developer console commands
==========================
Ethereum only
ethereum [options] [filename]
-js Start the JavaScript REPL
filename Load the given file and interpret as JavaScript
-m Start mining blocks
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*
@ -74,12 +79,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,36 +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
var ImportKey string
var ExportKey bool
var UseGui bool
var DataDir string
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(&UseGui, "gui", true, "use the gui")
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(&DataDir, "dir", ".ethereum", "ethereum data directory")
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)")
flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers")
flag.Parse()
}

View File

@ -1,253 +0,0 @@
package main
import (
"bufio"
"bytes"
"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) Editor() []string {
var buff bytes.Buffer
for {
reader := bufio.NewReader(os.Stdin)
str, _, err := reader.ReadLine()
if len(str) > 0 {
buff.Write(str)
buff.WriteString("\n")
}
if err != nil && err.Error() == "EOF" {
break
}
}
scanner := bufio.NewScanner(strings.NewReader(buff.String()))
scanner.Split(bufio.ScanLines)
var lines []string
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines
}
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)
info := block.BlockInfo()
fmt.Printf("++++++++++ #%d ++++++++++\n%v\n", info.Number, 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{""})
key := ethutil.Config.Db.GetKeys()[0]
tx.Sign(key.PrivateKey)
i.ethereum.TxPool.QueueTransaction(tx)
fmt.Printf("%x\n", tx.Hash())
}
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":
fmt.Println("Contract editor (Ctrl-D = done)")
code := ethchain.Compile(i.Editor())
contract := ethchain.NewTransaction(ethchain.ContractAddr, ethutil.Big(tokens[1]), code)
key := ethutil.Config.Db.GetKeys()[0]
contract.Sign(key.PrivateKey)
i.ethereum.TxPool.QueueTransaction(contract)
fmt.Printf("%x\n", contract.Hash()[12:])
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
}
}
}
}

View File

@ -0,0 +1,377 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
ApplicationWindow {
id: win
visible: false
title: "IceCREAM"
minimumWidth: 1280
minimumHeight: 700
width: 1290
height: 750
property alias codeText: codeEditor.text
property alias dataText: rawDataField.text
onClosing: {
//compileTimer.stop()
}
MenuBar {
Menu {
title: "Debugger"
MenuItem {
text: "Run"
shortcut: "Ctrl+r"
onTriggered: debugCurrent()
}
MenuItem {
text: "Next"
shortcut: "Ctrl+n"
onTriggered: dbg.next()
}
MenuItem {
text: "Continue"
shortcut: "Ctrl+g"
onTriggered: dbg.continue()
}
MenuItem {
text: "Command"
shortcut: "Ctrl+l"
onTriggered: {
dbgCommand.focus = true
}
}
MenuItem {
text: "Focus code"
shortcut: "Ctrl+1"
onTriggered: {
codeEditor.focus = true
}
}
MenuItem {
text: "Focus data"
shortcut: "Ctrl+2"
onTriggered: {
rawDataField.focus = true
}
}
/*
MenuItem {
text: "Close window"
shortcut: "Ctrl+w"
onTriggered: {
win.close()
}
}
*/
}
}
SplitView {
anchors.fill: parent
property var asmModel: ListModel {
id: asmModel
}
TableView {
id: asmTableView
width: 200
TableViewColumn{ role: "value" ; title: "" ; width: asmTableView.width - 2 }
model: asmModel
}
Rectangle {
color: "#00000000"
anchors.left: asmTableView.right
anchors.right: parent.right
SplitView {
orientation: Qt.Vertical
anchors.fill: parent
Rectangle {
color: "#00000000"
height: 330
anchors.left: parent.left
anchors.right: parent.right
TextArea {
id: codeEditor
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: settings.left
focus: true
/*
Timer {
id: compileTimer
interval: 500 ; running: true ; repeat: true
onTriggered: {
dbg.autoComp(codeEditor.text)
}
}
*/
}
Column {
id: settings
spacing: 5
width: 300
height: parent.height
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
Label {
text: "Arbitrary data"
}
TextArea {
id: rawDataField
anchors.left: parent.left
anchors.right: parent.right
height: 150
}
Label {
text: "Amount"
}
TextField {
id: txValue
width: 200
placeholderText: "Amount"
validator: RegExpValidator { regExp: /\d*/ }
}
Label {
text: "Amount of gas"
}
TextField {
id: txGas
width: 200
validator: RegExpValidator { regExp: /\d*/ }
text: "10000"
placeholderText: "Gas"
}
Label {
text: "Gas price"
}
TextField {
id: txGasPrice
width: 200
placeholderText: "Gas price"
text: "1000000000000"
validator: RegExpValidator { regExp: /\d*/ }
}
}
}
SplitView {
orientation: Qt.Vertical
id: inspectorPane
height: 500
SplitView {
orientation: Qt.Horizontal
height: 150
TableView {
id: stackTableView
property var stackModel: ListModel {
id: stackModel
}
height: parent.height
width: 300
TableViewColumn{ role: "value" ; title: "Temp" ; 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
}
}
Rectangle {
height: 100
width: parent.width
TableView {
id: storageTableView
property var memModel: ListModel {
id: storageModel
}
height: parent.height
width: parent.width
TableViewColumn{ id: key ; role: "key" ; title: "#" ; width: storageTableView.width / 2}
TableViewColumn{ role: "value" ; title: "Storage" ; width: storageTableView.width / 2}
model: storageModel
}
}
Rectangle {
height: 200
width: parent.width
TableView {
id: logTableView
property var logModel: ListModel {
id: logModel
}
height: parent.height
width: parent.width
TableViewColumn{ id: message ; role: "message" ; title: "log" ; width: logTableView.width - 2 }
model: logModel
}
}
}
}
}
}
function exec() {
dbg.execCommand(dbgCommand.text);
dbgCommand.text = "";
}
statusBar: StatusBar {
height: 30
TextField {
id: dbgCommand
y: 1
x: asmTableView.width
width: 500
placeholderText: "Debugger (type 'help')"
Keys.onReturnPressed: {
exec()
}
}
}
toolBar: ToolBar {
height: 30
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"
}
Button {
id: debugContinueButton
onClicked: {
dbg.continue()
}
text: "Continue"
}
}
ComboBox {
id: snippets
anchors.right: parent.right
model: ListModel {
ListElement { text: "Snippets" ; value: "" }
ListElement { text: "Call Contract" ; value: "var[2] in;\nvar ret;\n\nin[0] = \"arg1\"\nin[1] = 0xdeadbeef\n\nvar success = call(0x0c542ddea93dae0c2fcb2cf175f03ad80d6be9a0, 0, 7000, in, ret)\n\nreturn ret" }
}
onCurrentIndexChanged: {
if(currentIndex != 0) {
var code = snippets.model.get(currentIndex).value;
codeEditor.insert(codeEditor.cursorPosition, code)
}
}
}
}
function debugCurrent() {
dbg.debug(txValue.text, txGas.text, txGasPrice.text, codeEditor.text, rawDataField.text)
}
function setAsm(asm) {
asmModel.append({asm: asm})
}
function clearAsm() {
asmModel.clear()
}
function setInstruction(num) {
asmTableView.selection.clear()
asmTableView.selection.select(num)
}
function setMem(mem) {
memModel.append({num: mem.num, value: mem.value})
}
function clearMem(){
memModel.clear()
}
function setStack(stack) {
stackModel.append({value: stack})
}
function addDebugMessage(message){
debuggerLog.append({value: message})
}
function clearStack() {
stackModel.clear()
}
function clearStorage() {
storageModel.clear()
}
function setStorage(storage) {
storageModel.append({key: storage.key, value: storage.value})
}
function setLog(msg) {
// Remove first item once we've reached max log items
if(logModel.count > 250) {
logModel.remove(0)
}
if(msg.len != 0) {
if(logTableView.flickableItem.atYEnd) {
logModel.append({message: msg})
logTableView.positionViewAtRow(logTableView.rowCount - 1, ListView.Contain)
} else {
logModel.append({message: msg})
}
}
}
function clearLog() {
logModel.clear()
}
}

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,145 @@
// 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);
},
getStateKeyVals: function(address, cb){
postData({call: "getStateKeyVals", args: [address]}, 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);
},
getTransactionsFor: function(address, cb) {
postData({call: "getTransactionsFor", 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()
}

View File

Before

Width:  |  Height:  |  Size: 27 KiB

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];
}
}
}
}

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

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

View File

@ -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,70 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import Ethereum 1.0
QmlApp {
minimumWidth: 350
maximumWidth: 350
maximumHeight: 80
minimumHeight: 80
title: "Generic Coin"
property string contractAddr: "f299f6c74515620e4c4cd8fe3d205b5c4f2e25c8"
property string addr: "2ef47100e0787b915105fd5e3f4ff6752079d5cb"
Component.onCompleted: {
eth.watch(contractAddr, addr)
eth.watch(addr, contractAddr)
setAmount()
}
function onStorageChangeCb(storageObject) {
setAmount()
}
function setAmount(){
var state = eth.getStateObject(contractAddr)
var storage = state.getStorage(addr)
amountLabel.text = storage
}
Column {
spacing: 5
Row {
spacing: 20
Label {
id: genLabel
text: "Generic coin balance:"
}
Label {
id: amountLabel
}
}
Row {
spacing: 20
TextField {
id: address
placeholderText: "Address"
}
TextField {
id: amount
placeholderText: "Amount"
}
}
Button {
text: "Send coins"
onClicked: {
var privKey = eth.getKey().privateKey
if(privKey){
var result = eth.transact(privKey, contractAddr, 0,"100000","250", "0x" + address.text + "\n" + amount.text)
resultTx.text = result.hash
}
}
}
Label {
id: resultTx
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,245 @@
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: ["../ext/pre.js", "../ext/big.js", "../ext/string.js", "../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 "getStateKeyVals":
require(1);
var stateObject = eth.getStateObject(data.args[0]).stateKeyVal(true)
postData(data._seed,stateObject)
break
case "getTransactionsFor":
require(1);
var txs = eth.getTransactionsFor(data.args[0], true)
postData(data._seed, txs)
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: toggleInspector
color: "#bcbcbc"
visible: true
height: 12
width: 12
anchors {
right: root.right
}
MouseArea {
onClicked: {
if(inspector.visible == true){
inspector.visible = false
}else{
inspector.visible = true
inspector.url = webview.experimental.remoteInspectorUrl
}
}
onDoubleClicked: {
console.log('refreshing')
webView.reload()
}
anchors.fill: parent
}
}
Rectangle {
id: sizeGrip
color: "gray"
visible: false
height: 10
anchors {
left: root.left
right: root.right
}
y: Math.round(root.height * 2 / 3)
MouseArea {
anchors.fill: parent
drag.target: sizeGrip
drag.minimumY: 0
drag.maximumY: root.height
drag.axis: Drag.YAxis
}
}
WebView {
id: inspector
visible: false
anchors {
left: root.left
right: root.right
top: sizeGrip.bottom
bottom: root.bottom
}
}
states: [
State {
name: "inspectorShown"
PropertyChanges {
target: inspector
}
}
]
}
}

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

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>

339
ethereal/debugger.go Normal file
View File

@ -0,0 +1,339 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethvm"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"math/big"
"strconv"
"strings"
)
type DebuggerWindow struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
vm *ethvm.Vm
Db *Debugger
state *ethstate.State
}
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)
w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &ethvm.Vm{}}
w.Db = NewDebugger(w)
return w
}
func (self *DebuggerWindow) Show() {
context := self.engine.Context()
context.SetVar("dbg", self)
go func() {
self.win.Show()
self.win.Wait()
}()
}
func (self *DebuggerWindow) SetCode(code string) {
self.win.Set("codeText", code)
}
func (self *DebuggerWindow) SetData(data string) {
self.win.Set("dataText", data)
}
func (self *DebuggerWindow) SetAsm(data []byte) {
self.win.Root().Call("clearAsm")
dis := ethchain.Disassemble(data)
for _, str := range dis {
self.win.Root().Call("setAsm", str)
}
}
func (self *DebuggerWindow) Compile(code string) {
var err error
script := ethutil.StringToByteFunc(code, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s, true)
return
})
if err == nil {
self.SetAsm(script)
}
}
// Used by QML
func (self *DebuggerWindow) AutoComp(code string) {
if self.Db.done {
self.Compile(code)
}
}
func (self *DebuggerWindow) ClearLog() {
self.win.Root().Call("clearLog")
}
func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
if !self.Db.done {
self.Db.Q <- true
}
defer func() {
if r := recover(); r != nil {
self.Logf("compile FAULT: %v", r)
}
}()
data := ethutil.StringToByteFunc(dataStr, func(s string) (ret []byte) {
slice := strings.Split(dataStr, "\n")
for _, dataItem := range slice {
d := ethutil.FormatData(dataItem)
ret = append(ret, d...)
}
return
})
var err error
script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
ret, err = ethutil.Compile(s, false)
return
})
if err != nil {
self.Logln(err)
return
}
var (
gas = ethutil.Big(gasStr)
gasPrice = ethutil.Big(gasPriceStr)
value = ethutil.Big(valueStr)
// Contract addr as test address
keyPair = self.lib.eth.KeyManager().KeyPair()
)
state := self.lib.eth.StateManager().TransState()
account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
contract := ethstate.NewStateObject([]byte{0})
contract.Amount = value
self.SetAsm(script)
callerClosure := ethvm.NewClosure(account, contract, script, gas, gasPrice)
block := self.lib.eth.BlockChain().CurrentBlock
/*
vm := ethchain.NewVm(state, self.lib.eth.StateManager(), ethchain.RuntimeVars{
Block: block,
Origin: account.Address(),
BlockNumber: block.Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: ethutil.Big(valueStr),
})
*/
env := utils.NewEnv(state, block, account.Address(), value)
vm := ethvm.New(env)
vm.Verbose = true
vm.Dbg = self.Db
self.vm = vm
self.Db.done = false
self.Logf("callsize %d", len(script))
go func() {
ret, g, err := callerClosure.Call(vm, data)
tot := new(big.Int).Mul(g, gasPrice)
self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
if err != nil {
self.Logln("exited with errors:", err)
} else {
if len(ret) > 0 {
self.Logf("exited: % x", ret)
} else {
self.Logf("exited: nil")
}
}
state.Reset()
if !self.Db.interrupt {
self.Db.done = true
} else {
self.Db.interrupt = false
}
}()
}
func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}
func (self *DebuggerWindow) Logln(v ...interface{}) {
str := fmt.Sprintln(v...)
self.Logf("%s", str[:len(str)-1])
}
func (self *DebuggerWindow) Next() {
self.Db.Next()
}
func (self *DebuggerWindow) Continue() {
self.vm.Stepping = false
self.Next()
}
func (self *DebuggerWindow) ExecCommand(command string) {
if len(command) > 0 {
cmd := strings.Split(command, " ")
switch cmd[0] {
case "help":
self.Logln("Debugger commands:")
self.Logln("break, bp Set breakpoint on instruction")
self.Logln("clear [log, break, bp] Clears previous set sub-command(s)")
case "break", "bp":
if len(cmd) > 1 {
lineNo, err := strconv.Atoi(cmd[1])
if err != nil {
self.Logln(err)
break
}
self.Db.breakPoints = append(self.Db.breakPoints, int64(lineNo))
self.Logf("break point set on instruction %d", lineNo)
} else {
self.Logf("'%s' requires line number", cmd[0])
}
case "clear":
if len(cmd) > 1 {
switch cmd[1] {
case "break", "bp":
self.Db.breakPoints = nil
self.Logln("Breakpoints cleared")
case "log":
self.ClearLog()
default:
self.Logf("clear '%s' is not valid", cmd[1])
}
} else {
self.Logln("'clear' requires sub command")
}
default:
self.Logf("Unknown command %s", cmd[0])
}
}
}
type Debugger struct {
N chan bool
Q chan bool
done, interrupt bool
breakPoints []int64
main *DebuggerWindow
win *qml.Window
}
func NewDebugger(main *DebuggerWindow) *Debugger {
db := &Debugger{make(chan bool), make(chan bool), true, false, nil, main, main.win}
return db
}
type storeVal struct {
Key, Value string
}
func (self *Debugger) BreakHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
self.main.Logln("break on instr:", pc)
return self.halting(pc, op, mem, stack, stateObject)
}
func (self *Debugger) StepHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
return self.halting(pc, op, mem, stack, stateObject)
}
func (self *Debugger) SetCode(byteCode []byte) {
self.main.SetAsm(byteCode)
}
func (self *Debugger) BreakPoints() []int64 {
return self.breakPoints
}
func (d *Debugger) halting(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.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.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.interrupt = true
d.clearBuffers()
return false
}
}
return true
}
func (d *Debugger) clearBuffers() {
out:
// drain
for {
select {
case <-d.N:
case <-d.Q:
default:
break out
}
}
}
func (d *Debugger) Next() {
if !d.done {
d.N <- true
}
}

133
ethereal/ext_app.go Normal file
View File

@ -0,0 +1,133 @@
package main
import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"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(*ethstate.StateObject)
StorageChanged(*ethstate.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.(*ethstate.StateObject); ok {
app.container.ObjectChanged(stateObject)
} else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok {
app.container.StorageChanged(storageObject)
}
}
}
}
func (app *ExtApplication) Watch(addr, storageAddr string) {
var event string
if len(storageAddr) == 0 {
event = "object:" + string(ethutil.Hex2Bytes(addr))
app.lib.eth.Reactor().Subscribe(event, app.changeChan)
} else {
event = "storage:" + string(ethutil.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr))
app.lib.eth.Reactor().Subscribe(event, app.changeChan)
}
app.registeredEvents = append(app.registeredEvents, event)
}

99
ethereal/flags.go Normal file
View File

@ -0,0 +1,99 @@
package main
import (
"bitbucket.org/kardianos/osext"
"flag"
"fmt"
"github.com/ethereum/eth-go/ethlog"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
)
var Identifier string
var KeyRing string
var KeyStore string
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 SecretFile string
var ExportDir string
var NonInteractive bool
var Datadir string
var LogFile string
var ConfigFile string
var DebugFile string
var LogLevel int
// flags specific to gui client
var AssetPath string
//TODO: If we re-use the one defined in cmd.go the binary osx image crashes. If somebody finds out why we can dry this up.
func defaultAssetPath() string {
var assetPath 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") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/ethereal"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereal")
}
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
func Init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0])
flag.PrintDefaults()
}
flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
flag.StringVar(&OutboundPort, "port", "30303", "listening port")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)")
flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use")
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.StringVar(&AssetPath, "asset_path", defaultAssetPath(), "absolute path to GUI assets directory")
flag.Parse()
}

459
ethereal/gui.go Normal file
View File

@ -0,0 +1,459 @@
package main
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/ethlog"
"github.com/ethereum/eth-go/ethminer"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"math/big"
"strconv"
"strings"
"time"
)
var logger = ethlog.NewLogger("GUI")
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
uiLib *UiLib
txDb *ethdb.LDBDatabase
pub *ethpub.PEthereum
logLevel ethlog.LogLevel
open bool
Session string
clientIdentity *ethwire.SimpleClientIdentity
config *ethutil.ConfigManager
miner *ethminer.Miner
}
// Create GUI, but doesn't start it
func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, clientIdentity *ethwire.SimpleClientIdentity, session string, logLevel int) *Gui {
db, err := ethdb.NewLDBDatabase("tx_database")
if err != nil {
panic(err)
}
pub := ethpub.NewPEthereum(ethereum)
return &Gui{eth: ethereum, txDb: db, pub: pub, logLevel: ethlog.LogLevel(logLevel), Session: session, open: false, clientIdentity: clientIdentity, config: config}
}
func (gui *Gui) Start(assetPath string) {
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 = "" },
}, {
Init: func(p *ethpub.KeyVal, obj qml.Object) { p.Key = ""; p.Value = "" },
}})
// 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
var addlog = false
if len(data) == 0 {
win, err = gui.showKeyImport(context)
} else {
win, err = gui.showWallet(context)
addlog = true
}
if err != nil {
logger.Errorln("asset not found: you can set an alternative asset path on the command line using option 'asset_path'", err)
panic(err)
}
logger.Infoln("Starting GUI")
gui.open = true
win.Show()
// only add the gui logger after window is shown otherwise slider wont be shown
if addlog {
ethlog.AddLogSystem(gui)
}
win.Wait()
// need to silence gui logger after window closed otherwise logsystem hangs (but do not save loglevel)
gui.logLevel = ethlog.Silence
gui.open = false
}
func (gui *Gui) Stop() {
if gui.open {
gui.logLevel = ethlog.Silence
gui.open = false
gui.win.Hide()
}
logger.Infoln("Stopped")
}
func (gui *Gui) ToggleMining() {
var txt string
if gui.eth.Mining {
utils.StopMining(gui.eth)
txt = "Start mining"
} else {
utils.StartMining(gui.eth)
gui.miner = utils.GetMiner()
txt = "Stop mining"
}
gui.win.Root().Set("miningButtonText", txt)
}
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 func() {
gui.setInitialBlockChain()
gui.loadAddressBook()
gui.readPreviousTransactions()
gui.setPeerInfo()
}()
go gui.update()
return win, nil
}
func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
context.SetVar("lib", gui)
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
return gui.win
}
func (gui *Gui) ImportAndSetPrivKey(secret string) bool {
err := gui.eth.KeyManager().InitFromString(gui.Session, 0, secret)
if err != nil {
logger.Errorln("unable to import: ", err)
return false
}
logger.Errorln("successfully imported: ", err)
return true
}
func (gui *Gui) CreateAndSetPrivKey() (string, string, string, string) {
err := gui.eth.KeyManager().Init(gui.Session, 0, true)
if err != nil {
logger.Errorln("unable to create key: ", err)
return "", "", "", ""
}
return gui.eth.KeyManager().KeyPair().AsStrings()
}
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
addr := gui.address()
// Loop through all transactions to see if we missed any while being offline
for _, tx := range blk.Transactions() {
if bytes.Compare(tx.Sender(), addr) == 0 || bytes.Compare(tx.Recipient, addr) == 0 {
if ok, _ := gui.txDb.Get(tx.Hash()); ok == nil {
gui.txDb.Put(tx.Hash(), tx.RlpEncode())
}
}
}
gui.processBlock(blk, true)
}
}
type address struct {
Name, Address string
}
func (gui *Gui) loadAddressBook() {
gui.win.Root().Call("clearAddress")
nameReg := ethpub.EthereumConfig(gui.eth.StateManager()).NameReg()
if nameReg != nil {
nameReg.EachStorage(func(name string, value *ethutil.Value) {
if name[0] != 0 {
value.Decode()
gui.win.Root().Call("addAddress", struct{ Name, Address string }{name, ethutil.Bytes2Hex(value.Bytes())})
}
})
}
}
func (gui *Gui) readPreviousTransactions() {
it := gui.txDb.Db().NewIterator(nil, nil)
addr := gui.address()
for it.Next() {
tx := ethchain.NewTransactionFromBytes(it.Value())
var inout string
if bytes.Compare(tx.Sender(), 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) {
name := ethpub.FindNameInNameReg(gui.eth.StateManager(), block.Coinbase)
b := ethpub.NewPBlock(block)
b.Name = name
gui.win.Root().Call("addBlock", b, 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)
}
func (self *Gui) getObjectByName(objectName string) qml.Object {
return self.win.Root().ObjectByName(objectName)
}
// Simple go routine function that updates the list of peers in the GUI
func (gui *Gui) update() {
reactor := gui.eth.Reactor()
var (
blockChan = make(chan ethutil.React, 1)
txChan = make(chan ethutil.React, 1)
objectChan = make(chan ethutil.React, 1)
peerChan = make(chan ethutil.React, 1)
chainSyncChan = make(chan ethutil.React, 1)
miningChan = make(chan ethutil.React, 1)
)
reactor.Subscribe("newBlock", blockChan)
reactor.Subscribe("newTx:pre", txChan)
reactor.Subscribe("newTx:post", txChan)
reactor.Subscribe("chainSync", chainSyncChan)
reactor.Subscribe("miner:start", miningChan)
reactor.Subscribe("miner:stop", miningChan)
nameReg := ethpub.EthereumConfig(gui.eth.StateManager()).NameReg()
if nameReg != nil {
reactor.Subscribe("object:"+string(nameReg.Address()), objectChan)
}
reactor.Subscribe("peerList", peerChan)
peerUpdateTicker := time.NewTicker(5 * time.Second)
generalUpdateTicker := time.NewTicker(1 * time.Second)
state := gui.eth.StateManager().TransState()
unconfirmedFunds := new(big.Int)
gui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(state.GetAccount(gui.address()).Amount)))
gui.getObjectByName("syncProgressIndicator").Set("visible", !gui.eth.IsUpToDate())
lastBlockLabel := gui.getObjectByName("lastBlockLabel")
for {
select {
case b := <-blockChan:
block := b.Resource.(*ethchain.Block)
gui.processBlock(block, false)
if bytes.Compare(block.Coinbase, gui.address()) == 0 {
gui.setWalletValue(gui.eth.StateManager().CurrentState().GetAccount(gui.address()).Amount, nil)
}
case txMsg := <-txChan:
tx := txMsg.Resource.(*ethchain.Transaction)
if txMsg.Event == "newTx:pre" {
object := state.GetAccount(gui.address())
if bytes.Compare(tx.Sender(), gui.address()) == 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.address()) == 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.address())
if bytes.Compare(tx.Sender(), gui.address()) == 0 {
object.SubAmount(tx.Value)
} else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
object.AddAmount(tx.Value)
}
gui.setWalletValue(object.Amount, nil)
state.UpdateStateObject(object)
}
case msg := <-chainSyncChan:
sync := msg.Resource.(bool)
gui.win.Root().ObjectByName("syncProgressIndicator").Set("visible", sync)
case <-objectChan:
gui.loadAddressBook()
case <-peerChan:
gui.setPeerInfo()
case <-peerUpdateTicker.C:
gui.setPeerInfo()
case msg := <-miningChan:
if msg.Event == "miner:start" {
gui.miner = msg.Resource.(*ethminer.Miner)
} else {
gui.miner = nil
}
case <-generalUpdateTicker.C:
statusText := "#" + gui.eth.BlockChain().CurrentBlock.Number.String()
if gui.miner != nil {
pow := gui.miner.GetPow()
if pow.GetHashrate() != 0 {
statusText = "Mining @ " + strconv.FormatInt(pow.GetHashrate(), 10) + "Khash - " + statusText
}
}
lastBlockLabel.Set("text", statusText)
}
}
}
func (gui *Gui) setPeerInfo() {
gui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", gui.eth.PeerCount(), gui.eth.MaxPeers))
gui.win.Root().Call("resetPeers")
for _, peer := range gui.pub.GetPeers() {
gui.win.Root().Call("addPeer", peer)
}
}
func (gui *Gui) privateKey() string {
return ethutil.Bytes2Hex(gui.eth.KeyManager().PrivateKey())
}
func (gui *Gui) address() []byte {
return gui.eth.KeyManager().Address()
}
func (gui *Gui) RegisterName(name string) {
name = fmt.Sprintf("\"register\"\n\"%s\"", name)
gui.pub.Transact(gui.privateKey(), "NameReg", "", "10000", "10000000000000", name)
}
func (gui *Gui) Transact(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
}
func (gui *Gui) Create(recipient, value, gas, gasPrice, data string) (*ethpub.PReceipt, error) {
return gui.pub.Transact(gui.privateKey(), recipient, value, gas, gasPrice, data)
}
func (gui *Gui) SetCustomIdentifier(customIdentifier string) {
gui.clientIdentity.SetCustomIdentifier(customIdentifier)
gui.config.Save("id", customIdentifier)
}
func (gui *Gui) GetCustomIdentifier() string {
return gui.clientIdentity.GetCustomIdentifier()
}
// functions that allow Gui to implement interface ethlog.LogSystem
func (gui *Gui) SetLogLevel(level ethlog.LogLevel) {
gui.logLevel = level
gui.config.Save("loglevel", level)
}
func (gui *Gui) GetLogLevel() ethlog.LogLevel {
return gui.logLevel
}
// this extra function needed to give int typecast value to gui widget
// that sets initial loglevel to default
func (gui *Gui) GetLogLevelInt() int {
return int(gui.logLevel)
}
func (gui *Gui) Println(v ...interface{}) {
gui.printLog(fmt.Sprintln(v...))
}
func (gui *Gui) Printf(format string, v ...interface{}) {
gui.printLog(fmt.Sprintf(format, v...))
}
// Print function that logs directly to the GUI
func (gui *Gui) printLog(s string) {
str := strings.TrimRight(s, "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
gui.win.Root().Call("addLog", line)
}
}

135
ethereal/html_container.go Normal file
View File

@ -0,0 +1,135 @@
package main
import (
"errors"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"github.com/howeyc/fsnotify"
"io/ioutil"
"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(ethutil.WindonizePath(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 {
logger.Infoln("Could not create new auto-reload watcher:", err)
return
}
err = app.watcher.Watch(app.RootFolder())
if err != nil {
logger.Infoln("Could not start auto-reload watcher:", err)
return
}
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:
//logger.Debugln("Got event:", ev)
app.webView.Call("reload")
case err := <-app.watcher.Error:
// TODO: Do something here
logger.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.Bytes2Hex(block.Hash())}
app.webView.Call("onNewBlockCb", b)
}
func (app *HtmlApplication) ObjectChanged(stateObject *ethstate.StateObject) {
app.webView.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
}
func (app *HtmlApplication) StorageChanged(storageObject *ethstate.StorageState) {
app.webView.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}
func (app *HtmlApplication) Destroy() {
app.engine.Destroy()
}

72
ethereal/main.go Normal file
View File

@ -0,0 +1,72 @@
package main
import (
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/go-ethereum/utils"
"github.com/go-qml/qml"
"os"
"runtime"
)
const (
ClientIdentifier = "Ethereal"
Version = "0.6.0"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
qml.Init(nil)
var interrupted = false
utils.RegisterInterrupt(func(os.Signal) {
interrupted = true
})
utils.HandleInterrupt()
// precedence: code-internal flag default < config file < environment variables < command line
Init() // parsing command line
config := utils.InitConfig(ConfigFile, Datadir, "ETH")
utils.InitDataDir(Datadir)
utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
db := utils.NewDatabase()
keyManager := utils.NewKeyManager(KeyStore, Datadir, db)
// create, import, export keys
utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier)
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer)
if ShowGenesis {
utils.ShowGenesis(ethereum)
}
if StartRpc {
utils.StartRpc(ethereum, RpcPort)
}
gui := NewWindow(ethereum, config, clientIdentity, KeyRing, LogLevel)
utils.RegisterInterrupt(func(os.Signal) {
gui.Stop()
})
utils.StartEthereum(ethereum, UseSeed)
// gui blocks the main thread
gui.Start(AssetPath)
// we need to run the interrupt callbacks in case gui is closed
// this skips if we got here by actual interrupt stopping the GUI
if !interrupted {
utils.RunInterruptCallbacks(os.Interrupt)
}
// this blocks the thread
ethereum.WaitForShutdown()
ethlog.Flush()
}

68
ethereal/qml_container.go Normal file
View File

@ -0,0 +1,68 @@
package main
import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"runtime"
)
type QmlApplication struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
path string
}
func NewQmlApplication(path string, lib *UiLib) *QmlApplication {
engine := qml.NewEngine()
return &QmlApplication{engine: engine, path: path, lib: lib}
}
func (app *QmlApplication) Create() error {
path := string(app.path)
// For some reason for windows we get /c:/path/to/something, windows doesn't like the first slash but is fine with the others so we are removing it
if string(app.path[0]) == "/" && runtime.GOOS == "windows" {
path = app.path[1:]
}
component, err := app.engine.LoadFile(path)
if err != nil {
logger.Warnln(err)
}
app.win = component.CreateWindow(nil)
return nil
}
func (app *QmlApplication) Destroy() {
app.engine.Destroy()
}
func (app *QmlApplication) NewWatcher(quitChan chan bool) {
}
// Events
func (app *QmlApplication) NewBlock(block *ethchain.Block) {
pblock := &ethpub.PBlock{Number: int(block.BlockInfo().Number), Hash: ethutil.Bytes2Hex(block.Hash())}
app.win.Call("onNewBlockCb", pblock)
}
func (app *QmlApplication) ObjectChanged(stateObject *ethstate.StateObject) {
app.win.Call("onObjectChangeCb", ethpub.NewPStateObject(stateObject))
}
func (app *QmlApplication) StorageChanged(storageObject *ethstate.StorageState) {
app.win.Call("onStorageChangeCb", ethpub.NewPStorageState(storageObject))
}
// Getters
func (app *QmlApplication) Engine() *qml.Engine {
return app.engine
}
func (app *QmlApplication) Window() *qml.Window {
return app.win
}

100
ethereal/ui_lib.go Normal file
View File

@ -0,0 +1,100 @@
package main
import (
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"path"
)
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
DbWindow *DebuggerWindow
}
func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath string) *UiLib {
return &UiLib{engine: engine, eth: eth, assetPath: assetPath}
}
func (ui *UiLib) OpenQml(path string) {
container := NewQmlApplication(path[7:], ui)
app := NewExtApplication(container, ui)
go app.run()
}
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 {
logger.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) StartDbWithContractAndData(contractHash, data string) {
dbWindow := NewDebuggerWindow(self)
object := self.eth.StateManager().CurrentState().GetStateObject(ethutil.Hex2Bytes(contractHash))
if len(object.Code) > 0 {
dbWindow.SetCode("0x" + ethutil.Bytes2Hex(object.Code))
}
dbWindow.SetData("0x" + data)
dbWindow.Show()
}
func (self *UiLib) StartDbWithCode(code string) {
dbWindow := NewDebuggerWindow(self)
dbWindow.SetCode("0x" + code)
dbWindow.Show()
}
func (self *UiLib) StartDebugger() {
dbWindow := NewDebuggerWindow(self)
//self.DbWindow = dbWindow
dbWindow.Show()
}

View File

@ -1,210 +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/ethereum/eth-go/ethwire"
"github.com/ethereum/go-ethereum/ui"
"github.com/niemeyer/qml"
"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()
pair := &ethutil.Key{PrivateKey: prv, PublicKey: pub}
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode())
fmt.Printf(`
Generating new address and keypair.
Please keep your keys somewhere save.
++++++++++++++++ KeyRing +++++++++++++++++++
addr: %x
prvk: %x
pubk: %x
++++++++++++++++++++++++++++++++++++++++++++
`, pair.Address(), prv, pub)
}
}
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)
}
func main() {
Init()
// Qt has to be initialized in the main thread or it will throw errors
// It has to be called BEFORE setting the maximum procs.
if UseGui {
qml.Init(nil)
}
runtime.GOMAXPROCS(runtime.NumCPU())
ethchain.InitFees()
ethutil.ReadConfig(DataDir)
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
}
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" {
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" {
ImportPrivateKey(ImportKey)
os.Exit(0)
}
} else {
CreateKeyPair(false)
}
}
if ExportKey {
key := ethutil.Config.Db.GetKeys()[0]
fmt.Printf("%x\n", key.PrivateKey)
os.Exit(0)
}
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()
}
if UseGui {
gui := ethui.New(ethereum)
gui.Start()
//ethereum.Stop()
} else {
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)
ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})
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()
}
}

33
ethereum/cmd.go Normal file
View File

@ -0,0 +1,33 @@
package main
import (
"github.com/ethereum/eth-go"
"github.com/ethereum/go-ethereum/ethereum/repl"
"github.com/ethereum/go-ethereum/utils"
"io/ioutil"
"os"
)
func InitJsConsole(ethereum *eth.Ethereum) {
repl := ethrepl.NewJSRepl(ethereum)
go repl.Start()
utils.RegisterInterrupt(func(os.Signal) {
repl.Stop()
})
}
func ExecJsFile(ethereum *eth.Ethereum, InputFile string) {
file, err := os.Open(InputFile)
if err != nil {
logger.Fatalln(err)
}
content, err := ioutil.ReadAll(file)
if err != nil {
logger.Fatalln(err)
}
re := ethrepl.NewJSRE(ethereum)
utils.RegisterInterrupt(func(os.Signal) {
re.Stop()
})
re.Run(string(content))
}

80
ethereum/flags.go Normal file
View File

@ -0,0 +1,80 @@
package main
import (
"flag"
"fmt"
"github.com/ethereum/eth-go/ethlog"
"os"
"os/user"
"path"
)
var Identifier string
var KeyRing string
var DiffTool bool
var DiffType string
var KeyStore string
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 SecretFile string
var ExportDir string
var NonInteractive bool
var Datadir string
var LogFile string
var ConfigFile string
var DebugFile string
var LogLevel int
// flags specific to cli client
var StartMining bool
var StartJsConsole bool
var InputFile string
func defaultDataDir() string {
usr, _ := user.Current()
return path.Join(usr.HomeDir, ".ethereum")
}
var defaultConfigFile = path.Join(defaultDataDir(), "conf.ini")
func Init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0])
flag.PrintDefaults()
}
flag.StringVar(&Identifier, "id", "", "Custom client identifier")
flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use")
flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file (db)")
flag.StringVar(&OutboundPort, "port", "30303", "listening port")
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support")
flag.IntVar(&MaxPeer, "maxpeer", 10, "maximum desired peers")
flag.IntVar(&RpcPort, "rpcport", 8080, "port to start json-rpc server on")
flag.BoolVar(&StartRpc, "rpc", false, "start rpc server")
flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)")
flag.BoolVar(&UseSeed, "seed", true, "seed peers")
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)")
flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)")
flag.StringVar(&Datadir, "datadir", defaultDataDir(), "specifies the datadir to use")
flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)")
flag.IntVar(&LogLevel, "loglevel", int(ethlog.InfoLevel), "loglevel: 0-5: silent,error,warn,info,debug,debug detail)")
flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
flag.BoolVar(&StartMining, "mine", false, "start dagger mining")
flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console")
flag.Parse()
InputFile = flag.Arg(0)
}

73
ethereum/main.go Normal file
View File

@ -0,0 +1,73 @@
package main
import (
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"runtime"
)
const (
ClientIdentifier = "Ethereum(G)"
Version = "0.6.0"
)
var logger = ethlog.NewLogger("CLI")
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
utils.HandleInterrupt()
// precedence: code-internal flag default < config file < environment variables < command line
Init() // parsing command line
// If the difftool option is selected ignore all other log output
if DiffTool {
LogLevel = 0
}
utils.InitConfig(ConfigFile, Datadir, "ETH")
ethutil.Config.Diff = DiffTool
ethutil.Config.DiffType = DiffType
utils.InitDataDir(Datadir)
utils.InitLogging(Datadir, LogFile, LogLevel, DebugFile)
db := utils.NewDatabase()
keyManager := utils.NewKeyManager(KeyStore, Datadir, db)
// create, import, export keys
utils.KeyTasks(keyManager, KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive)
clientIdentity := utils.NewClientIdentity(ClientIdentifier, Version, Identifier)
ethereum := utils.NewEthereum(db, clientIdentity, keyManager, UseUPnP, OutboundPort, MaxPeer)
if ShowGenesis {
utils.ShowGenesis(ethereum)
}
if StartMining {
utils.StartMining(ethereum)
}
// better reworked as cases
if StartJsConsole {
InitJsConsole(ethereum)
} else if len(InputFile) > 0 {
ExecJsFile(ethereum, InputFile)
}
if StartRpc {
utils.StartRpc(ethereum, RpcPort)
}
utils.StartEthereum(ethereum, UseSeed)
// this blocks the thread
ethereum.WaitForShutdown()
ethlog.Flush()
}

View File

@ -0,0 +1,232 @@
package ethrepl
import (
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/go-ethereum/utils"
"github.com/obscuren/otto"
"io/ioutil"
"os"
"path"
"path/filepath"
)
var jsrelogger = ethlog.NewLogger("JSRE")
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 (jsre *JSRE) LoadExtFile(path string) {
result, err := ioutil.ReadFile(path)
if err == nil {
jsre.vm.Run(result)
} else {
jsrelogger.Debugln("Could not load file:", path)
}
}
func (jsre *JSRE) LoadIntFile(file string) {
assetPath := path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "ethereal", "assets", "ext")
jsre.LoadExtFile(path.Join(assetPath, file))
}
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)
// Load extra javascript files
re.LoadIntFile("string.js")
re.LoadIntFile("big.js")
// We have to make sure that, whoever calls this, calls "Stop"
go re.mainLoop()
re.Bind("eth", &JSEthereum{re.lib, re.vm})
re.initStdFuncs()
jsrelogger.Infoln("started")
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)
jsrelogger.Infoln("stopped")
}
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.(*ethstate.StateObject); ok {
for _, cb := range self.objectCb[ethutil.Bytes2Hex(stateObject.Address())] {
val, _ := self.vm.ToValue(ethpub.NewPStateObject(stateObject))
cb.Call(cb, val)
}
} else if storageObject, ok := object.Resource.(*ethstate.StorageState); ok {
for _, cb := range self.objectCb[ethutil.Bytes2Hex(storageObject.StateAddress)+ethutil.Bytes2Hex(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)
eth.Set("execBlock", self.execBlock)
}
/*
* 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.Hex2Bytes(addr)) + ":" + string(ethutil.Hex2Bytes(storageAddr))
self.ethereum.Reactor().Subscribe(event, self.changeChan)
} else {
self.objectCb[addr] = append(self.objectCb[addr], cb)
event := "object:" + string(ethutil.Hex2Bytes(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
}
func (self *JSRE) execBlock(call otto.FunctionCall) otto.Value {
hash, err := call.Argument(0).ToString()
if err != nil {
return otto.UndefinedValue()
}
err = utils.BlockDo(self.ethereum, ethutil.Hex2Bytes(hash))
if err != nil {
fmt.Println(err)
return otto.FalseValue()
}
return otto.TrueValue()
}

53
ethereum/repl/js_lib.go Normal file
View File

@ -0,0 +1,53 @@
package ethrepl
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;
`

83
ethereum/repl/repl.go Normal file
View File

@ -0,0 +1,83 @@
package ethrepl
import (
"bufio"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"io"
"os"
"path"
)
var logger = ethlog.NewLogger("REPL")
type Repl interface {
Start()
Stop()
}
type JSRepl struct {
re *JSRE
prompt string
history *os.File
running bool
}
func NewJSRepl(ethereum *eth.Ethereum) *JSRepl {
hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
panic(err)
}
return &JSRepl{re: NewJSRE(ethereum), prompt: "> ", history: hist}
}
func (self *JSRepl) Start() {
if !self.running {
self.running = true
logger.Infoln("init JS Console")
reader := bufio.NewReader(self.history)
for {
line, err := reader.ReadString('\n')
if err != nil && err == io.EOF {
break
} else if err != nil {
fmt.Println("error reading history", err)
break
}
addHistory(line[:len(line)-1])
}
self.read()
}
}
func (self *JSRepl) Stop() {
if self.running {
self.running = false
self.re.Stop()
logger.Infoln("exit JS Console")
self.history.Close()
}
}
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)
}

View File

@ -0,0 +1,123 @@
package ethrepl
// #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
}
hist := str[:len(str)-1]
addHistory(hist) //allow user to recall this line
self.history.WriteString(str)
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/repl_linux.go Symbolic link
View File

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

View File

@ -0,0 +1,24 @@
package ethrepl
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)
}

95
ethereum/repl/types.go Normal file
View File

@ -0,0 +1,95 @@
package ethrepl
import (
"fmt"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/otto"
)
type JSStateObject struct {
*ethpub.PStateObject
eth *JSEthereum
}
func (self *JSStateObject) EachStorage(call otto.FunctionCall) otto.Value {
cb := call.Argument(0)
self.PStateObject.EachStorage(func(key string, value *ethutil.Value) {
value.Decode()
cb.Call(self.eth.toVal(self), self.eth.toVal(key), self.eth.toVal(ethutil.Bytes2Hex(value.Bytes())))
})
return otto.UndefinedValue()
}
// 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) GetPeers() otto.Value {
return self.toVal(self.PEthereum.GetPeers())
}
func (self *JSEthereum) GetKey() otto.Value {
return self.toVal(self.PEthereum.GetKey())
}
func (self *JSEthereum) GetStateObject(addr string) otto.Value {
return self.toVal(&JSStateObject{self.PEthereum.GetStateObject(addr), self})
}
func (self *JSEthereum) GetStateKeyVals(addr string) otto.Value {
return self.toVal(self.PEthereum.GetStateObject(addr).StateKeyVal(false))
}
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("Value unknown:", err)
return otto.UndefinedValue()
}
return result
}

57
install.sh Executable file
View File

@ -0,0 +1,57 @@
#!/bin/sh
if [ "$1" == "" ]; then
echo "Usage $0 executable branch ethereum develop"
echo "executable ethereum or ethereal"
echo "branch develop or master"
exit
fi
exe=$1
branch=$2
# Test if go is installed
command -v go >/dev/null 2>&1 || { echo >&2 "Unable to find 'go'. This script requires go."; exit 1; }
# Test if $GOPATH is set
if [ "$GOPATH" == "" ]; then
echo "\$GOPATH not set"
exit
fi
echo "go get -u -d github.com/ethereum/go-ethereum/$exe"
go get -v -u -d github.com/ethereum/go-ethereum/$exe
if [ $? != 0 ]; then
echo "go get failed"
exit
fi
echo "serpent-go"
cd $GOPATH/src/github.com/obscuren/serpent-go
echo "init submodule"
git submodule init
git submodule update
echo "eth-go"
cd $GOPATH/src/github.com/ethereum/eth-go
git checkout $branch
echo "go-ethereum"
cd $GOPATH/src/github.com/ethereum/go-ethereum/$exe
git checkout $branch
if [ "$exe" == "ethereal" ]; then
echo "Building ethereal GUI. Assuming Qt is installed. If this step"
echo "fails; please refer to: https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)"
else
echo "Building ethereum CLI."
fi
go install
if [ $? == 0 ]; then
echo "go install failed"
exit
fi
echo "done. Please run $exe :-)"

BIN
net.pxm

Binary file not shown.

View File

@ -1,35 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import Ethereum 1.0
ApplicationWindow {
minimumWidth: 500
maximumWidth: 500
maximumHeight: 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

@ -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 )
}
*/

BIN
tx.pxm

Binary file not shown.

223
ui/gui.go
View File

@ -1,223 +0,0 @@
package ethui
import (
"bytes"
"encoding/hex"
"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/niemeyer/qml"
"bitbucket.org/kardianos/osext"
"path/filepath"
"math/big"
"strings"
)
// Block interface exposed to QML
type Block struct {
Number int
Hash string
}
type Tx struct {
Value, Hash, Address string
}
func NewTxFromTransaction(tx *ethchain.Transaction) *Tx {
hash := hex.EncodeToString(tx.Hash())
sender := hex.EncodeToString(tx.Recipient)
return &Tx{Hash: hash, Value: ethutil.CurrencyToString(tx.Value), Address: sender}
}
// Creates a new QML Block from a chain block
func NewBlockFromBlock(block *ethchain.Block) *Block {
info := block.BlockInfo()
hash := hex.EncodeToString(block.Hash())
return &Block{Number: int(info.Number), Hash: hash}
}
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
txDb *ethdb.LDBDatabase
addr []byte
}
// Create GUI, but doesn't start it
func New(ethereum *eth.Ethereum) *Gui {
lib := &EthLib{blockManager: ethereum.BlockManager, blockChain: ethereum.BlockManager.BlockChain(), txPool: ethereum.TxPool}
db, err := ethdb.NewLDBDatabase("tx_database")
if err != nil {
panic(err)
}
key := ethutil.Config.Db.GetKeys()[0]
addr := key.Address()
ethereum.BlockManager.WatchAddr(addr)
return &Gui{eth: ethereum, lib: lib, txDb: db, addr: addr}
}
func (ui *Gui) Start() {
defer ui.txDb.Close()
// Register ethereum functions
qml.RegisterTypes("Ethereum", 1, 0, []qml.TypeSpec{{
Init: func(p *Block, obj qml.Object) { p.Number = 0; p.Hash = "" },
}, {
Init: func(p *Tx, obj qml.Object) { p.Value = ""; p.Hash = ""; p.Address = "" },
}})
ethutil.Config.Log.Infoln("[GUI] Starting GUI")
// Create a new QML engine
ui.engine = qml.NewEngine()
// Get Binary Directory
exedir , _ := osext.ExecutableFolder()
// Load the main QML interface
component, err := ui.engine.LoadFile(filepath.Join(exedir, "wallet.qml"))
if err != nil {
panic(err)
}
ui.engine.LoadFile(filepath.Join(exedir, "transactions.qml"))
ui.win = component.CreateWindow(nil)
context := ui.engine.Context()
// Expose the eth library and the ui library to QML
context.SetVar("eth", ui.lib)
context.SetVar("ui", &UiLib{engine: ui.engine, eth: ui.eth})
// Register the ui as a block processor
ui.eth.BlockManager.SecondaryBlockProcessor = ui
//ui.eth.TxPool.SecondaryProcessor = ui
// Add the ui as a log system so we can log directly to the UGI
ethutil.Config.Log.AddLogSystem(ui)
// Loads previous blocks
go ui.setInitialBlockChain()
go ui.readPreviousTransactions()
go ui.update()
ui.win.Show()
ui.win.Wait()
ui.eth.Stop()
}
func (ui *Gui) setInitialBlockChain() {
// Load previous 10 blocks
chain := ui.eth.BlockManager.BlockChain().GetChain(ui.eth.BlockManager.BlockChain().CurrentBlock.Hash(), 10)
for _, block := range chain {
ui.ProcessBlock(block)
}
}
func (ui *Gui) readPreviousTransactions() {
it := ui.txDb.Db().NewIterator(nil, nil)
for it.Next() {
tx := ethchain.NewTransactionFromBytes(it.Value())
ui.win.Root().Call("addTx", NewTxFromTransaction(tx))
}
it.Release()
}
func (ui *Gui) ProcessBlock(block *ethchain.Block) {
ui.win.Root().Call("addBlock", NewBlockFromBlock(block))
}
// Simple go routine function that updates the list of peers in the GUI
func (ui *Gui) update() {
txChan := make(chan ethchain.TxMsg, 1)
ui.eth.TxPool.Subscribe(txChan)
account := ui.eth.BlockManager.GetAddrState(ui.addr).Account
unconfirmedFunds := new(big.Int)
ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(account.Amount)))
for {
select {
case txMsg := <-txChan:
tx := txMsg.Tx
if txMsg.Type == ethchain.TxPre {
if bytes.Compare(tx.Sender(), ui.addr) == 0 {
ui.win.Root().Call("addTx", NewTxFromTransaction(tx))
ui.txDb.Put(tx.Hash(), tx.RlpEncode())
ui.eth.BlockManager.GetAddrState(ui.addr).Nonce += 1
unconfirmedFunds.Sub(unconfirmedFunds, tx.Value)
} else if bytes.Compare(tx.Recipient, ui.addr) == 0 {
ui.win.Root().Call("addTx", NewTxFromTransaction(tx))
ui.txDb.Put(tx.Hash(), tx.RlpEncode())
unconfirmedFunds.Add(unconfirmedFunds, tx.Value)
}
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(account.Amount), pos, val)
ui.win.Root().Call("setWalletValue", str)
} else {
amount := account.Amount
if bytes.Compare(tx.Sender(), ui.addr) == 0 {
amount.Sub(account.Amount, tx.Value)
} else if bytes.Compare(tx.Recipient, ui.addr) == 0 {
amount.Add(account.Amount, tx.Value)
}
ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", ethutil.CurrencyToString(amount)))
}
}
/*
accountAmount := ui.eth.BlockManager.GetAddrState(ui.addr).Account.Amount
ui.win.Root().Call("setWalletValue", fmt.Sprintf("%v", accountAmount))
ui.win.Root().Call("setPeers", fmt.Sprintf("%d / %d", ui.eth.Peers().Len(), ui.eth.MaxPeers))
time.Sleep(1 * time.Second)
*/
}
}
// Logging functions that log directly to the GUI interface
func (ui *Gui) Println(v ...interface{}) {
str := strings.TrimRight(fmt.Sprintln(v...), "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
ui.win.Root().Call("addLog", line)
}
}
func (ui *Gui) Printf(format string, v ...interface{}) {
str := strings.TrimRight(fmt.Sprintf(format, v...), "\n")
lines := strings.Split(str, "\n")
for _, line := range lines {
ui.win.Root().Call("addLog", line)
}
}

View File

@ -1,60 +0,0 @@
package ethui
import (
"encoding/hex"
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"strings"
)
type EthLib struct {
blockManager *ethchain.BlockManager
blockChain *ethchain.BlockChain
txPool *ethchain.TxPool
}
func (lib *EthLib) CreateTx(receiver, a, data string) string {
var hash []byte
if len(receiver) == 0 {
hash = ethchain.ContractAddr
} else {
var err error
hash, err = hex.DecodeString(receiver)
if err != nil {
return err.Error()
}
}
k, _ := ethutil.Config.Db.Get([]byte("KeyRing"))
keyRing := ethutil.NewValueFromBytes(k)
amount := ethutil.Big(a)
code := ethchain.Compile(strings.Split(data, "\n"))
tx := ethchain.NewTransaction(hash, amount, code)
tx.Nonce = lib.blockManager.GetAddrState(keyRing.Get(1).Bytes()).Nonce
tx.Sign(keyRing.Get(0).Bytes())
lib.txPool.QueueTransaction(tx)
if len(receiver) == 0 {
ethutil.Config.Log.Infof("Contract addr %x", tx.Hash()[12:])
} else {
ethutil.Config.Log.Infof("Tx hash %x", tx.Hash())
}
return ethutil.Hex(tx.Hash())
}
func (lib *EthLib) GetBlock(hexHash string) *Block {
hash, err := hex.DecodeString(hexHash)
if err != nil {
return nil
}
block := lib.blockChain.GetBlock(hash)
fmt.Println(block)
return &Block{Number: int(block.BlockInfo().Number), Hash: ethutil.Hex(block.Hash())}
}

View File

@ -1,40 +0,0 @@
package ethui
import (
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethutil"
"github.com/niemeyer/qml"
)
// UI Library that has some basic functionality exposed
type UiLib struct {
engine *qml.Engine
eth *eth.Ethereum
connected bool
}
// 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) Connect(button qml.Object) {
if !ui.connected {
ui.eth.Start()
ui.connected = true
button.Set("enabled", false)
}
}
func (ui *UiLib) ConnectToPeer(addr string) {
ui.eth.ConnectToPeer(addr)
}

301
utils/cmd.go Normal file
View File

@ -0,0 +1,301 @@
package utils
import (
"bitbucket.org/kardianos/osext"
"fmt"
"github.com/ethereum/eth-go"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethminer"
"github.com/ethereum/eth-go/ethpub"
"github.com/ethereum/eth-go/ethrpc"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"io"
"log"
"os"
"os/signal"
"path"
"path/filepath"
"runtime"
"time"
)
var logger = ethlog.NewLogger("CLI")
var interruptCallbacks = []func(os.Signal){}
// Register interrupt handlers callbacks
func RegisterInterrupt(cb func(os.Signal)) {
interruptCallbacks = append(interruptCallbacks, cb)
}
// go routine that call interrupt handlers in order of registering
func HandleInterrupt() {
c := make(chan os.Signal, 1)
go func() {
signal.Notify(c, os.Interrupt)
for sig := range c {
logger.Errorf("Shutting down (%v) ... \n", sig)
RunInterruptCallbacks(sig)
}
}()
}
func RunInterruptCallbacks(sig os.Signal) {
for _, cb := range interruptCallbacks {
cb(sig)
}
}
func AbsolutePath(Datadir string, filename string) string {
if path.IsAbs(filename) {
return filename
}
return path.Join(Datadir, filename)
}
func openLogFile(Datadir string, filename string) *os.File {
path := AbsolutePath(Datadir, filename)
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
}
return file
}
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 InitDataDir(Datadir string) {
_, err := os.Stat(Datadir)
if err != nil {
if os.IsNotExist(err) {
fmt.Printf("Data directory '%s' doesn't exist, creating it\n", Datadir)
os.Mkdir(Datadir, 0777)
}
}
}
func InitLogging(Datadir string, LogFile string, LogLevel int, DebugFile string) {
var writer io.Writer
if LogFile == "" {
writer = os.Stdout
} else {
writer = openLogFile(Datadir, LogFile)
}
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.LogLevel(LogLevel)))
if DebugFile != "" {
writer = openLogFile(Datadir, DebugFile)
ethlog.AddLogSystem(ethlog.NewStdLogSystem(writer, log.LstdFlags, ethlog.DebugLevel))
}
}
func InitConfig(ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
InitDataDir(Datadir)
return ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
}
func exit(err error) {
status := 0
if err != nil {
fmt.Println(err)
logger.Errorln("Fatal: ", err)
status = 1
}
ethlog.Flush()
os.Exit(status)
}
func NewDatabase() ethutil.Database {
db, err := ethdb.NewLDBDatabase("database")
if err != nil {
exit(err)
}
return db
}
func NewClientIdentity(clientIdentifier, version, customIdentifier string) *ethwire.SimpleClientIdentity {
return ethwire.NewSimpleClientIdentity(clientIdentifier, version, customIdentifier)
}
func NewEthereum(db ethutil.Database, clientIdentity ethwire.ClientIdentity, keyManager *ethcrypto.KeyManager, usePnp bool, OutboundPort string, MaxPeer int) *eth.Ethereum {
ethereum, err := eth.New(db, clientIdentity, keyManager, eth.CapDefault, usePnp)
if err != nil {
logger.Fatalln("eth start err:", err)
}
ethereum.Port = OutboundPort
ethereum.MaxPeers = MaxPeer
return ethereum
}
func StartEthereum(ethereum *eth.Ethereum, UseSeed bool) {
logger.Infof("Starting %s", ethereum.ClientIdentity())
ethereum.Start(UseSeed)
RegisterInterrupt(func(sig os.Signal) {
ethereum.Stop()
ethlog.Flush()
})
}
func ShowGenesis(ethereum *eth.Ethereum) {
logger.Infoln(ethereum.BlockChain().Genesis())
exit(nil)
}
func NewKeyManager(KeyStore string, Datadir string, db ethutil.Database) *ethcrypto.KeyManager {
var keyManager *ethcrypto.KeyManager
switch {
case KeyStore == "db":
keyManager = ethcrypto.NewDBKeyManager(db)
case KeyStore == "file":
keyManager = ethcrypto.NewFileKeyManager(Datadir)
default:
exit(fmt.Errorf("unknown keystore type: %s", KeyStore))
}
return keyManager
}
func DefaultAssetPath() string {
var assetPath 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") {
assetPath = path.Join(pwd, "assets")
} else {
switch runtime.GOOS {
case "darwin":
// Get Binary Directory
exedir, _ := osext.ExecutableFolder()
assetPath = filepath.Join(exedir, "../Resources")
case "linux":
assetPath = "/usr/share/ethereal"
case "windows":
assetPath = "./assets"
default:
assetPath = "."
}
}
return assetPath
}
func KeyTasks(keyManager *ethcrypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
ethcrypto.InitWords(DefaultAssetPath()) // Init mnemonic word list
var err error
switch {
case GenAddr:
if NonInteractive || confirm("This action overwrites your old private key.") {
err = keyManager.Init(KeyRing, 0, true)
}
exit(err)
case len(SecretFile) > 0:
SecretFile = ethutil.ExpandHomePath(SecretFile)
if NonInteractive || confirm("This action overwrites your old private key.") {
err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
}
exit(err)
case len(ExportDir) > 0:
err = keyManager.Init(KeyRing, 0, false)
if err == nil {
err = keyManager.Export(ExportDir)
}
exit(err)
default:
// Creates a keypair if none exists
err = keyManager.Init(KeyRing, 0, false)
if err != nil {
exit(err)
}
}
}
func StartRpc(ethereum *eth.Ethereum, RpcPort int) {
var err error
ethereum.RpcServer, err = ethrpc.NewJsonRpcServer(ethpub.NewPEthereum(ethereum), RpcPort)
if err != nil {
logger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
} else {
go ethereum.RpcServer.Start()
}
}
var miner *ethminer.Miner
func GetMiner() *ethminer.Miner {
return miner
}
func StartMining(ethereum *eth.Ethereum) bool {
if !ethereum.Mining {
ethereum.Mining = true
addr := ethereum.KeyManager().Address()
go func() {
if miner == nil {
miner = ethminer.NewDefaultMiner(addr, ethereum)
}
// Give it some time to connect with peers
time.Sleep(3 * time.Second)
for !ethereum.IsUpToDate() {
time.Sleep(5 * time.Second)
}
logger.Infoln("Miner started")
miner.Start()
}()
RegisterInterrupt(func(os.Signal) {
StopMining(ethereum)
})
return true
}
return false
}
func StopMining(ethereum *eth.Ethereum) bool {
if ethereum.Mining && miner != nil {
miner.Stop()
logger.Infoln("Miner stopped")
ethereum.Mining = false
return true
}
return false
}
// Replay block
func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
block := ethereum.BlockChain().GetBlock(hash)
if block == nil {
return fmt.Errorf("unknown block %x", hash)
}
parent := ethereum.BlockChain().GetBlock(block.PrevHash)
_, err := ethereum.StateManager().ApplyDiff(parent.State(), parent, block)
if err != nil {
return err
}
return nil
}

33
utils/vm_env.go Normal file
View File

@ -0,0 +1,33 @@
package utils
import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethstate"
"math/big"
)
type VMEnv struct {
state *ethstate.State
block *ethchain.Block
transactor []byte
value *big.Int
}
func NewEnv(state *ethstate.State, block *ethchain.Block, transactor []byte, value *big.Int) *VMEnv {
return &VMEnv{
state: state,
block: block,
transactor: transactor,
value: value,
}
}
func (self *VMEnv) Origin() []byte { return self.transactor }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
func (self *VMEnv) Time() int64 { return self.block.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
func (self *VMEnv) Value() *big.Int { return self.value }
func (self *VMEnv) State() *ethstate.State { return self.state }

View File

@ -1,370 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 1.0;
import QtQuick.Layouts 1.0;
import QtQuick.Dialogs 1.0;
import QtQuick.Window 2.1;
import QtQuick.Controls.Styles 1.1
import Ethereum 1.0
ApplicationWindow {
id: 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: "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
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: "tx.png"
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onClicked: {
setView(historyView)
}
}
}
Image {
source: "new.png"
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onClicked: {
setView(newTxView)
}
}
}
Image {
source: "net.png"
anchors.horizontalCenter: parent.horizontalCenter
MouseArea {
anchors.fill: parent
onClicked: {
setView(networkView)
}
}
}
}
}
property var txModel: ListModel {
id: txModel
}
Rectangle {
id: historyView
property var title: "Transactions"
anchors.right: parent.right
anchors.left: menu.right
anchors.bottom: parent.bottom
anchors.top: parent.top
TableView {
id: txTableView
anchors.fill: parent
TableViewColumn{ role: "value" ; title: "Value" ; width: 100 }
TableViewColumn{ role: "address" ; title: "Address" ; width: 430 }
model: txModel
}
}
Rectangle {
id: newTxView
property var title: "New transaction"
visible: false
anchors.right: parent.right
anchors.left: menu.right
anchors.bottom: parent.bottom
anchors.top: parent.top
color: "#00000000"
ColumnLayout {
width: 400
anchors.left: parent.left
anchors.top: parent.top
anchors.leftMargin: 5
anchors.topMargin: 5
TextField {
id: txAmount
width: 200
placeholderText: "Amount"
}
TextField {
id: txReceiver
placeholderText: "Receiver Address (or empty for contract)"
Layout.fillWidth: true
}
Label {
text: "Transaction data"
}
TextArea {
id: codeView
anchors.topMargin: 5
Layout.fillWidth: true
width: parent.width /2
}
Button {
text: "Send"
onClicked: {
console.log(eth.createTx(txReceiver.text, txAmount.text, codeView.text))
}
}
}
}
Rectangle {
id: networkView
property var title: "Network"
visible: false
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.top: parent.top
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 }
model: blockModel
onDoubleClicked: {
popup.visible = true
popup.block = eth.getBlock(blockModel.get(row).hash)
popup.hashLabel.text = popup.block.hash
}
}
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
}
}
}
FileDialog {
id: openAppDialog
title: "Open QML Application"
onAccepted: {
ui.open(openAppDialog.fileUrl.toString())
}
}
statusBar: StatusBar {
RowLayout {
anchors.fill: parent
Button {
property var enabled: true
id: connectButton
onClicked: {
if(this.enabled) {
ui.connect(this)
}
}
text: "Connect"
}
Button {
id: importAppButton
anchors.left: connectButton.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: "network.png"
}
}
}
Window {
id: popup
visible: false
property var block
Label {
id: hashLabel
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
}
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"
}
Button {
anchors.left: addrField.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 5
text: "Add"
onClicked: {
ui.connectToPeer(addrField.text)
addPeerWin.visible = false
}
}
}
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: "facet.png"
x: 10
y: 10
}
Text {
anchors.left: aboutIcon.right
anchors.leftMargin: 10
font.pointSize: 12
text: "<h2>Ethereum(Go)</h2><br><h3>Development</h3>Jeffrey Wilcke<br><h3>Binary Distribution</h3>Jarrad Hope<br>"
}
}
function setWalletValue(value) {
walletValueLabel.text = value
}
function addTx(tx) {
txModel.insert(0, {hash: tx.hash, address: tx.address, value: tx.value})
}
function addBlock(block) {
blockModel.insert(0, {number: block.number, hash: block.hash})
}
function addLog(str) {
if(str.len != 0) {
logModel.append({description: str})
}
}
function setPeers(text) {
peerLabel.text = text
}
}