Compare commits

...

1242 Commits

Author SHA1 Message Date
f75becc264 cmd/geth, VERSION: bumped version 1.3.1 2015-10-31 20:00:58 +01:00
c841e39476 Merge pull request #1954 from obscuren/regression-miner
miner: synchronise start / stop
2015-10-31 20:00:34 +01:00
8c38f8d815 miner: synchronise start / stop
This PR fixes an issue where the remote worker was stopped twice and not
properly handled. This adds a synchronised running check to the start
and stop methods preventing closing of a channel more than once.
2015-10-31 02:18:41 +01:00
016ad3e962 Merge pull request #1952 from obscuren/testnet-peers
eth: added new testnet peers
2015-10-30 11:00:31 +01:00
98b036ddb6 Merge pull request #1949 from karalabe/update-command-usage
cmd/geth, cmd/utils, eth: group CLI flags by purpose
2015-10-30 10:59:36 +01:00
3c6e285d3b cmd/geth, cmd/utils, eth: group CLI flags by purpose 2015-10-30 11:33:12 +02:00
1bc789553a eth: added new testnet peers 2015-10-30 10:01:19 +01:00
1abbe05e93 Merge pull request #1951 from fjl/godeps-upgrade-goupnp
Godeps: upgrade github.com/huin/goupnp
2015-10-30 00:14:15 +01:00
f570b68ed1 p2p/nat: add docs for discover 2015-10-29 22:54:44 +01:00
bf11a47f22 Godeps: upgrade github.com/huin/goupnp to 90f71cb5 2015-10-29 22:53:59 +01:00
fc46cf337a Merge pull request #1946 from fjl/xeth-oom
Fix for xeth OOM issue
2015-10-29 17:42:55 +01:00
fbdb44dcc1 cmd/utils, rpc/comms: stop XEth when IPC connection ends
There are a bunch of changes required to make this work:

- in miner: allow unregistering agents, fix RemoteAgent.Stop
- in eth/filters: make FilterSystem.Stop not crash
- in rpc/comms: move listen loop to platform-independent code

Fixes #1930. I ran the shell loop there for a few minutes and didn't see
any changes in the memory profile.
2015-10-29 17:26:26 +01:00
fd27f074fe Merge pull request #1945 from bas-vk/rpcparsing
Argument parsing can lead to panic in rpc channel
2015-10-29 16:55:51 +01:00
8202bae070 Merge pull request #1939 from karalabe/fix-blocked-sync-goroutines
eth: don't block sync goroutines that short circuit
2015-10-29 16:54:43 +01:00
c3c5f8b654 rpc: fixed params parsing problem which could lead to a panic
check argument type before parsing params
 recover from panic in ipc channel
2015-10-29 09:23:03 +01:00
56f8699a6c Merge pull request #1940 from wildfjre/lightkdfflag
cmd/utils, crypto: add --lightkdf flag for lighter KDF
2015-10-28 18:54:50 +01:00
05ea8926c3 cmd/utils, crypto: add --lightkdf flag for lighter KDF 2015-10-28 18:46:39 +01:00
667987e7d0 core: only reset head header/fastblock if stale 2015-10-28 17:40:24 +02:00
2019ed71b4 eth: don't block sync goroutines that short circuit 2015-10-28 16:41:01 +02:00
6b5a42a15c Merge pull request #1937 from karalabe/make-ldflags
makefile: fix evm ld flags, pass them to xgo too
2015-10-28 11:46:23 +01:00
e655626268 makefile: dump mist leftover, add phony targets 2015-10-28 12:34:40 +02:00
04f8d05bd4 makefile: fix evm ld flags, pass them to xgo too 2015-10-28 12:31:20 +02:00
05f74077fb Merge pull request #1919 from ethersphere/getnatspec
rpc api: eth_getNatSpec
2015-10-28 10:49:53 +01:00
2e4fdce743 Merge pull request #1932 from fjl/gpo-defootgunize
eth, xeth: fix GasPriceOracle goroutine leak
2015-10-28 10:32:35 +01:00
ae1b5b3ff2 eth, xeth: fix GasPriceOracle goroutine leak
XEth.gpo was being initialized as needed. WithState copies the XEth
struct including the gpo field. If gpo was nil at the time of the copy
and Call or Transact were invoked on it, an additional GPO listenLoop
would be spawned.

Move the lazy initialization to GasPriceOracle instead so the same GPO
instance is shared among all created XEths.

Fixes #1317
Might help with #1930
2015-10-27 18:43:47 +01:00
57ab147388 update Dockerfile, remove supervisord and unattended-upgrades 2015-10-26 18:06:19 -04:00
4d005a2c1d rpc api: eth_getNatSpec
* xeth, rpc: implement eth_getNatSpec for tx confirmations
* rename silly docserver -> httpclient
* eth/backend: httpclient now accessible via eth.Ethereum init-d via config.DocRoot
* cmd: introduce separate CLI flag for DocRoot (defaults to homedir)
* common/path: delete unused assetpath func, separate HomeDir func
2015-10-26 22:24:09 +01:00
3b4ffacd0c bump VERSION to 1.3.0 2015-10-25 17:49:01 -04:00
491dd49419 Merge pull request #1928 from Gustav-Simonsson/common_tests
tests: update JSON files, add new wrappers
2015-10-25 06:17:19 -07:00
c43db8a2ee Merge pull request #1924 from fjl/eth-status-timeout
eth: time out status message exchange after 5s
2015-10-23 16:43:10 -07:00
0aeab5fd83 Merge pull request #1929 from ethersphere/develop
fix console history, lines with leadning whitespace NOT included
2015-10-23 16:18:52 -07:00
6b5d077c09 fix console history, lines with leadning whitespace NOT included 2015-10-23 20:37:12 +02:00
145366c07e tests: update JSON files, add new wrappers 2015-10-23 14:25:18 +02:00
3cf74336c9 eth: time out status message exchange after 5s 2015-10-22 22:22:04 +02:00
77878f76a9 Merge pull request #1922 from karalabe/fix-receipt-storage-regression
core: fix #1921, decode all receipt field, not just consensus
2015-10-22 10:17:15 -07:00
dce503779b Merge pull request #1840 from ethersphere/console
console, cli, api fixes
2015-10-22 09:27:05 -07:00
28c7b54d68 core: fix #1921, decode all receipt field, not just consensus 2015-10-22 13:09:30 +03:00
8b81ad1fc4 console:
* lines with leading space are ommitted from history
* exit processed even with whitespace around
* all whitespace lines (not only empty ones) are ignored

add 7 missing commands to admin api autocomplete

registrar: methods now return proper error if reg addresses are not set. fixes #1457

rpc/console: fix personal.newAccount() regression. Now all comms accept interactive password

registrar: add registrar tests for errors

crypto: catch AES decryption error on presale wallet import + fix error msg format. fixes #1580

CLI: improve error message when starting a second instance of geth. fixes #1564

cli/accounts: unlock multiple accounts. fixes #1785
* make unlocking multiple accounts work with inline <() fd
* passwdfile now correctly read only once
* improve logs
* fix CLI help text for unlocking

fix regression with docRoot / admin API
* docRoot/jspath passed to rpc/api ParseApis, which passes onto adminApi
* docRoot field for JS console in order to pass when RPC is (re)started
* improve flag desc for jspath

common/docserver: catch http errors from response

fix rpc/api tests

common/natspec: fix end to end test (skipped because takes 8s)

registrar: fix major regression:
* deploy registrars on frontier
* register HashsReg and UrlHint in GlobalRegistrar.
* set all 3 contract addresses in code
* zero out addresses first in tests
2015-10-22 00:22:39 +02:00
58d0752fdd Merge pull request #1883 from obscuren/jit-vm-optimisations
core/vm: JIT segmentation
2015-10-21 12:34:32 -07:00
0467a6ceec Merge pull request #1889 from karalabe/fast-sync-rebase
eth/63 fast synchronization algorithm
2015-10-21 11:44:22 -07:00
5b0ee8ec30 core, eth, trie: fix data races and merge/review issues 2015-10-21 16:49:55 +03:00
dba15d9c36 Merge pull request #1918 from obscuren/get-hash-fix
core, tests: get_hash fix
2015-10-21 03:54:59 -07:00
80f26086ee core, tests: get_hash fix
Make sure that we're fetching the hash from the current chain and not
the canonical chain.
2015-10-21 02:31:46 +02:00
796952a49a Merge pull request #1758 from fjl/coinbase
core, core/state: move gas tracking out of core/state
2015-10-20 03:31:36 -07:00
aa0538db0b eth: clean out light node notions from eth 2015-10-19 10:03:10 +03:00
a9d8dfc8e7 core, eth: roll back uncertain headers in failed fast syncs 2015-10-19 10:03:10 +03:00
b97e34a8e4 eth/downloader: concurrent receipt and state processing 2015-10-19 10:03:10 +03:00
ab27bee25a core, eth, trie: direct state trie synchronization 2015-10-19 10:03:09 +03:00
832b37c822 core, eth: receipt chain reconstruction 2015-10-19 10:03:09 +03:00
42c8afd440 core: differentiate receipt concensus and storage decoding 2015-10-19 10:03:09 +03:00
b99fe27f8b core: fix block canonical mark / content write race 2015-10-19 10:03:09 +03:00
f186b39018 eth/downloader: add fast and light sync strategies 2015-10-19 10:03:09 +03:00
c33cc382b3 core: support inserting pure header chains 2015-10-19 10:03:09 +03:00
92f9a3e5fa cmd, eth: support switching client modes of operation 2015-10-19 10:03:09 +03:00
de8d5aaa92 core, core/state: move gas tracking out of core/state
The amount of gas available for tx execution was tracked in the
StateObject representing the coinbase account. This commit makes the gas
counter a separate type in package core, which avoids unintended
consequences of intertwining the counter with state logic.
2015-10-17 10:24:34 +02:00
8c85532412 core/vm: added parsing utilities 2015-10-16 22:30:42 +02:00
b196278044 core/vm: added JIT segmenting / optimisations
* multi-push segments
* static jumps segments
2015-10-16 22:30:42 +02:00
9d61d78de6 core/vm: abstracted instruction execution away from JIT
Moved the execution of instructions to the instruction it self. This
will allow for specialised instructions (e.g. segments) to be execution
in the same manner as regular instructions.
2015-10-16 22:17:35 +02:00
10ed107ba2 Merge pull request #1899 from obscuren/mipmap-bloom
core, eth/filters, miner, xeth: Optimised log filtering
2015-10-16 12:35:24 -07:00
6dc14788a2 core, eth/filters, miner, xeth: Optimised log filtering
Log filtering is now using a MIPmap like approach where addresses of
logs are added to a mapped bloom bin. The current levels for the MIP are
in ranges of 1.000.000, 500.000, 100.000, 50.000, 1.000. Logs are
therefor filtered in batches of 1.000.
2015-10-16 21:28:59 +02:00
c5ef2afda5 Merge pull request #1907 from Gustav-Simonsson/ethash_godep
godeps: update ethash following GPU miner merge
2015-10-16 07:39:42 -07:00
d5f56ad5c5 godeps: update ethash following GPU miner merge 2015-10-16 16:27:51 +02:00
d5327ddc5f Merge pull request #1869 from Gustav-Simonsson/gpu_miner
all: Add GPU mining, disabled by default
2015-10-16 06:25:33 -07:00
b747754009 Merge pull request #1881 from Gustav-Simonsson/state_new_error
core/state, core, miner: handle missing root error from state.New
2015-10-16 06:18:41 -07:00
1b1f293082 core/state, core, miner: handle missing root error from state.New 2015-10-16 02:22:06 +02:00
f466243417 Merge pull request #1853 from Gustav-Simonsson/libsecp256k1_update
Update libsecp256k1, Go wrapper and tests
2015-10-15 10:46:57 -07:00
30f057aaf9 eth/filters: added benchmark 2015-10-15 19:45:44 +02:00
cefe5c80b1 Merge pull request #1898 from karalabe/eventmux-post-race
core, eth, event, miner, xeth: fix event post / subscription race
2015-10-15 10:44:30 -07:00
2f1f2e4811 Merge pull request #1887 from Gustav-Simonsson/icap
common, crypto: add ICAP functions
2015-10-15 10:32:05 -07:00
2db9798646 common, crypto: add ICAP functions 2015-10-13 17:44:14 +02:00
402fd6e8c6 core, eth, event, miner, xeth: fix event post / subscription race 2015-10-12 16:22:03 +03:00
0de9b16b11 Merge pull request #1896 from karalabe/fix-vm-stack-logs
core/vm: copy stack element to prevent overwrites
2015-10-12 05:32:45 -07:00
af9afb686b core/vm: copy stack element to prevent overwrites 2015-10-12 00:14:35 +03:00
f32fa075f1 core/secp256k1: update libsecp256k1 Go wrapper and tests 2015-10-09 14:47:55 +02:00
315a422ba7 Merge pull request #1888 from obscuren/testnet
cmd, core, eth: added official testnet
2015-10-09 01:31:37 -07:00
1de796f101 cmd, core, eth: added official testnet 2015-10-08 22:01:39 +02:00
9e91579105 Merge pull request #1885 from karalabe/olympic-fix
cmd: properly initialize Olympic for all subcommands
2015-10-08 11:33:28 -07:00
bba4dcb72f Merge pull request #1880 from Gustav-Simonsson/core_transfer
core, core/vm, cmd/evm: remove redundant balance check
2015-10-08 11:32:30 -07:00
37abbcb54b Merge pull request #1833 from Gustav-Simonsson/crypto_tests
crypto: correct sig validation, add missing unit tests of exported functions
2015-10-08 11:31:12 -07:00
2547c9c9b7 cmd: properly initialize Olympic for all subcommands 2015-10-07 18:25:33 +03:00
ec6a548ee3 all: Add GPU mining, disabled by default 2015-10-07 13:19:30 +02:00
27528ad3d2 Merge pull request #1851 from bas-vk/historyfile
console/history respect datadir
2015-10-07 01:51:13 -07:00
f8786defd0 Merge pull request #1850 from karalabe/genesis-block-receipts
core: fix #1848, block receipts db entry for the genesis too
2015-10-07 01:50:37 -07:00
e1616f77c7 core, core/vm, cmd/evm: remove redundant balance check 2015-10-06 12:42:34 +02:00
44fd395141 Merge pull request #1879 from obscuren/versioning
cmd/geth: dev version number
2015-10-05 12:35:42 -07:00
7b44b8aece cmd/geth: dev version number 2015-10-05 21:11:39 +02:00
13699e2dd9 Merge pull request #1877 from obscuren/head-write
core: fixed head write on block insertion
2015-10-05 11:00:57 -07:00
20ab29f885 core: fixed head write on block insertion
Due to a rebase this probably got overlooked / ignored. This fixes the
issue of a block insertion never writing the last block.
2015-10-05 17:00:59 +02:00
5b34fa538e Merge pull request #1756 from obscuren/core-refactor
core, core/vm: refactor
2015-10-05 07:14:01 -07:00
7c7692933c cmd/geth, cmd/utils, core, rpc: renamed to blockchain
* Renamed ChainManager to BlockChain
* Checkpointing is no longer required and never really properly worked
when the state was corrupted.
2015-10-04 01:13:56 +02:00
361082ec4b cmd/evm, core/vm, test: refactored VM and core
* Moved `vm.Transfer` to `core` package and changed execution to call
`env.Transfer` instead of `core.Transfer` directly.
* core/vm: byte code VM moved to jump table instead of switch
* Moved `vm.Transfer` to `core` package and changed execution to call
  `env.Transfer` instead of `core.Transfer` directly.
* Byte code VM now shares the same code as the JITVM
* Renamed Context to Contract
* Changed initialiser of state transition & unexported methods
* Removed the Execution object and refactor `Call`, `CallCode` &
  `Create` in to their own functions instead of being methods.
* Removed the hard dep on the state for the VM. The VM now
  depends on a Database interface returned by the environment. In the
  process the core now depends less on the statedb by usage of the env
* Moved `Log` from package `core/state` to package `core/vm`.
2015-10-04 01:13:54 +02:00
f7a71996fb core, event/filter, xeth: refactored filter system
Moved the filtering system from `event` to `eth/filters` package and
removed the `core.Filter` object. The `filters.Filter` object now
requires a `common.Database` rather than a `eth.Backend` and invokes the
`core.GetBlockByX` directly rather than thru a "manager".
2015-10-02 22:47:43 +02:00
8b865fa9bf Merge pull request #1866 from karalabe/honor-eth-capabilities
eth/downloader: match capabilities when querying idle peers
2015-10-02 03:49:56 -07:00
0d78f96205 Merge pull request #1865 from obscuren/deadlock-chainmanager-fix
core: deadlock in chainmanager after posting RemovedTransactionEvent
2015-10-02 03:39:43 -07:00
47f62a67aa eth/downloader: match capabilities when querying idle peers 2015-10-02 13:20:41 +03:00
a6cc02f68f core: deadlock in chainmanager after posting RemovedTransactionEvent
This PR solves an issue with the chain manager posting a
`RemovedTransactionEvent`, the tx pool will try to
acquire the chainmanager lock which has previously been locked prior to
posting `RemovedTransactionEvent`. This results in a deadlock in the
core.
2015-10-02 12:20:18 +02:00
49ae538506 Merge pull request #1405 from fjl/lean-trie
core, trie: new trie
2015-10-01 04:34:38 -07:00
581c0901af Merge pull request #1856 from karalabe/andorid-path-fix
common: fix #1818, secondary datadir paths to fall back to
2015-10-01 04:03:04 -07:00
74578ab22b common: fix #1818, secondary datadir paths to fall back to 2015-10-01 12:26:19 +03:00
e3ac56d502 Merge pull request #1859 from fjl/fix-discover-refresh-race
p2p/discover: fix race involving the seed node iterator
2015-09-30 08:21:40 -07:00
32dda97602 p2p/discover: ignore packet version numbers
The strict matching can get in the way of protocol upgrades.
2015-09-30 16:23:03 +02:00
631bf36102 p2p/discover: remove unused lastLookup field 2015-09-30 16:23:03 +02:00
b4374436f3 p2p/discover: fix race involving the seed node iterator
nodeDB.querySeeds was not safe for concurrent use but could be called
concurrenty on multiple goroutines in the following case:

- the table was empty
- a timed refresh started
- a lookup was started and initiated refresh

These conditions are unlikely to coincide during normal use, but are
much more likely to occur all at once when the user's machine just woke
from sleep. The root cause of the issue is that querySeeds reused the
same leveldb iterator until it was exhausted.

This commit moves the refresh scheduling logic into its own goroutine
(so only one refresh is ever active) and changes querySeeds to not use
a persistent iterator. The seed node selection is now more random and
ignores nodes that have not been contacted in the last 5 days.
2015-09-30 16:23:03 +02:00
46ad5a5f5b Merge pull request #1852 from obscuren/filter-nil-fix
xeth: fixed nil pointer of filter retrieval
2015-09-30 03:06:36 -07:00
9b94076717 Merge pull request #1854 from karalabe/badhasherror-formatting-loop
core: fix a formatting loop in BadHashError
2015-09-29 02:26:01 -07:00
b8b996be74 core: fix a formatting loop in BadHashError 2015-09-29 09:11:38 +03:00
1d20b0247c Update libsecp256k1 2015-09-28 17:46:38 +02:00
b9359981f4 xeth: fixed nil pointer of filter retrieval
This fix addresses an issue with filters that were (possibly) not yet
added to the filter queues but were expected. I've added additional nil
checks making sure it doesn't crash and swapped the installation of the
filter around so it's installed before use.

Closes #1665
2015-09-25 13:56:53 +02:00
7977e87ce1 Merge pull request #1843 from karalabe/cleanup-downloader-channel
eth/downloader: always send termination wakes, clean leftover
2015-09-25 04:34:59 -07:00
8636f0e1c3 console/history respect datadir 2015-09-25 13:08:48 +02:00
830ddcee60 core: fix #1848, block receipts db entry for the genesis too 2015-09-24 19:38:59 +03:00
69d86442a5 Merge pull request #1803 from Gustav-Simonsson/badhashes
core: Add BadHashErr and test for BadHashes handling
2015-09-23 11:10:25 -07:00
36f46a61a7 Merge pull request #1844 from obscuren/version-file
VERSION: added version
2015-09-23 05:48:00 -07:00
6e1dc321f4 VERSION: added version 2015-09-23 14:47:20 +02:00
7a2a918067 Merge pull request #1842 from fjl/rpc-fix-unknown-block
rpc/api: don't crash for unknown blocks
2015-09-23 12:57:33 +02:00
f459a3f0ae eth/downloader: always send termination wakes, clean leftover 2015-09-23 12:39:17 +03:00
e456f27795 Merge pull request #1827 from Gustav-Simonsson/common_tests
tests: add test for StateTests/stCallCodes.json
2015-09-23 02:12:59 -07:00
90cd8ae9f2 rpc/api: don't crash for unknown blocks
Most eth RPC calls that work with blocks crashed when the block was not
found because they called Hash on a nil block. This is a regression
introduced in cdc2662c40 (#1779).

While here, remove the insane conversions in get*CountBy*. There is no
need to construct a complete BlockRes and converting
int->int64->*big.Int->[]byte->hexnum->string to format the length of a
slice as hex.
2015-09-22 23:59:26 +02:00
70b6174748 cmd/geth, core: make "geth blocktest" work again
The test genesis block was not written properly, block insertion failed
immediately.

While here, fix the panic when shutting down "geth blocktest" with
Ctrl+C. The signal handler is now installed automatically, causing
ethereum.Stop to crash because everything is already stopped.
2015-09-22 23:55:31 +02:00
c1a352c108 trie: add merkle proof functions 2015-09-22 22:57:37 +02:00
a2d5a60418 core, core/state: batch-based state sync 2015-09-22 22:57:37 +02:00
565d9f2306 core, trie: new trie 2015-09-22 22:53:49 +02:00
6b91a4abe5 trie: improve benchmarks 2015-09-22 22:49:27 +02:00
bfde1a4305 core: Add BadHashErr and test for BadHashes handling 2015-09-22 18:02:26 +02:00
3340b56593 crypto: correct sig validation, add more unit tests 2015-09-22 17:33:39 +02:00
e56cbc225e Merge pull request #1835 from karalabe/make-cross
makefile: built in cross compilation targets
2015-09-21 11:47:10 -07:00
7bf8e949e7 Merge pull request #1669 from obscuren/tx-pool-auto-resend
core, xeth: chain reorg move missing transactions to transaction pool
2015-09-21 11:45:59 -07:00
6a05c569f2 makefile: built in cross compilation targets 2015-09-21 21:36:01 +03:00
eaa4473dbd core, core/types: readd transactions after chain re-org
Added a `Difference` method to `types.Transactions` which sets the
receiver to the difference of a to b (NOTE: not a **and** b).

Transaction pool subscribes to RemovedTransactionEvent adding back to
those potential missing from the chain.

When a chain re-org occurs remove any transactions that were removed
from the canonical chain during the re-org as well as the receipts that
were generated in the process.

Closes #1746
2015-09-21 20:33:28 +02:00
be76a68aea cmd/geth: changed version number to 1.2.0
Changed the version number of geth to 1.2.0 so that dev builds are now properly build (instead of master). Note to self; increase version number to 1.2.1 for our next actual release.
2015-09-21 16:13:07 +02:00
12c0afe4fe Merge pull request #1822 from karalabe/contain-pow
core: separate and contain POW verifier, extensive tests
2015-09-21 06:52:11 -07:00
5621308949 tests: add test for StateTests/stCallCodes.json 2015-09-21 11:34:02 +02:00
399c920380 core: separate and contain POW verifier, extensive tests 2015-09-21 10:24:49 +03:00
e40b447fea Merge pull request #1814 from Gustav-Simonsson/common_tests
tests: update common test wrappers and test files
2015-09-18 16:34:54 -07:00
b94b9b0158 Merge pull request #1817 from obscuren/nonce-fix
core: transaction nonce recovery
2015-09-18 15:56:10 -07:00
47ca6904b3 tests: use lastblockhash field to validate reorgs and block headers 2015-09-18 17:48:31 +02:00
075815e5ff tests: update common test wrappers and test files 2015-09-18 13:08:36 +02:00
b60a27627b core: transaction nonce recovery fix
When the transaction state recovery kicked in it assigned the last
(incorrect) nonce to the pending state which caused transactions with
the same nonce to occur.

Added test for nonce recovery
2015-09-18 11:59:21 +02:00
216c486a3a Merge pull request #1815 from karalabe/chain-maker-timer
core: allow modifying test-chain block times
2015-09-18 11:23:31 +02:00
ac6248ed7a Merge pull request #1793 from jeffallen/typo
common: Update README.md for the current package name
2015-09-17 19:26:49 +02:00
bdf4fd6091 Merge pull request #1813 from kobigurk/develop
cmd/geth: extradata is correcly initialized with console
2015-09-17 19:25:32 +02:00
69f48e4689 Merge pull request #1811 from bas-vk/timer-clearinterval
timer bugfix when clearInterval was called from within the callback
2015-09-17 19:21:49 +02:00
6f3cb12924 core: allow modifying test-chain block times 2015-09-17 13:43:52 +03:00
58fbcaa750 Merge pull request #1810 from karalabe/pure-header-verifications-2
core, eth, miner: use pure header validation
2015-09-16 14:21:12 -07:00
1a1a1ee4ff cmd/geth: extradata is correcly initialized with console 2015-09-16 21:01:21 +03:00
985b5f29ed Merge pull request #1801 from fjl/ethdb
all: move common.Database to ethdb and add NewBatch
2015-09-16 07:50:14 -07:00
2f65ddc501 jsre: timer bugfix when clearInterval was called from within the callback 2015-09-16 11:57:33 +02:00
1cc2f08041 Merge pull request #1784 from karalabe/standard-sync-stats
eth, rpc: standardize the chain sync progress counters
2015-09-16 02:31:58 -07:00
821619e1c3 core, eth, miner: use pure header validation 2015-09-16 10:46:28 +03:00
e9a80518c7 Merge pull request #1744 from kobigurk/develop
adds extradata flag
2015-09-15 13:56:10 -07:00
321733ab23 cmd/geth: adds extradata flag 2015-09-15 23:35:36 +03:00
d4d3fc6a70 jsre, rpc/api: pull in new web3 and use hex numbers 2015-09-15 17:05:12 +03:00
99b62f36b6 eth/downloader: header-chain order and ancestry check 2015-09-15 14:45:53 +03:00
0a7d059b6a eth, rpc: standardize the chain sync progress counters 2015-09-15 14:45:53 +03:00
55bdcfaeac Merge pull request #1806 from ethersphere/solc2
new solc api - late fixes
2015-09-15 01:08:30 -07:00
3a5e7ed9a6 new solc api:
* use legacy version matcher
* optimise just a boolean flag
* skipf for messages in tests
2015-09-15 00:35:22 +02:00
b252589960 ethdb: remove Flush 2015-09-14 23:36:30 +02:00
d581dfee5f ethdb: copy stored memdb values
Storing a value in LevelDB copies the bytes, modifying the value
afterwards does not affect the content of the database. This commit
ensures that MemDatabase satisfies the same property.
2015-09-14 23:36:30 +02:00
8b32f10f16 ethdb: add NewBatch 2015-09-14 23:36:30 +02:00
8c4dab77ba all: move common.Database to package ethdb 2015-09-14 23:36:30 +02:00
071e2cd08e Merge pull request #1786 from ethersphere/solc
common/compiler: new solc API
2015-09-14 23:32:40 +02:00
47b9c640f5 Merge pull request #1797 from karalabe/ensure-ipcpath-exists
rpc/comms: fix #1795, ensure IPC path exists before binding
2015-09-14 14:45:11 +02:00
a9c809b441 Merge pull request #1792 from jeffallen/uuid
Change go-uuid to use the current supported repository.
2015-09-14 12:06:59 +02:00
0d40727775 Change go-uuid to use the current supported repository. 2015-09-12 16:49:24 +06:00
17b729759b Solidity Compiler - solc new API
* adapt to new compiler versioning
* use compiler version as language version
* implement new solc API for versions >= 0.1.[2-9][0-9]* fixes #1770
* add optimize=1 to options
* backward compatibility (for now) for <= 0.1.1, and old versions (0.[2-9][0-9]*.[0-9]+)
* introduce compilerOptions to ContractInfo
* clean up flair, include full version string to version line and ContractInfo
2015-09-12 10:52:52 +02:00
55ed8d108d Merge pull request #1789 from Gustav-Simonsson/core_remove_unused_functions
core, core/vm, core/state: remove unused functions
2015-09-11 15:29:27 -07:00
f1a4b330dd Merge pull request #1796 from karalabe/ethash-android-support
godeps: pull in ethash android fix
2015-09-11 15:26:01 -07:00
0eac601b5b Merge pull request #1779 from karalabe/split-block-storage-3000
core: split the db blocks into components, move TD out top level
2015-09-11 08:10:37 -07:00
cdc2662c40 core: split out TD from database and all internals 2015-09-11 17:42:25 +03:00
2b339cbbd8 core, eth: split the db blocks into headers and bodies 2015-09-11 17:42:25 +03:00
3e6964b841 rpc/comms: fix #1795, ensure IPC path exists before binding 2015-09-11 17:03:31 +03:00
c6013725a8 godeps: pull in ethash android fix 2015-09-11 15:53:23 +03:00
4e075e4013 Merge pull request #1773 from obscuren/dev-mode
cmd/geth, cmd/utils, eth: added dev mode flag
2015-09-10 21:15:33 +02:00
b81a6e6ab8 core, core/vm, core/state: remove unused functions 2015-09-10 21:10:58 +02:00
62bbf8a09e Merge pull request #1778 from fjl/rlp-trie-changes
rlp: precursor changes for trie, p2p
2015-09-10 12:02:16 -07:00
4ce3dfe9c8 common: Update README.md for the current package name 2015-09-10 23:59:38 +06:00
fc8b246109 rlp: move ListSize to raw.go 2015-09-10 19:41:51 +02:00
24bb68e7cf rlp: add RawValue 2015-09-10 19:41:51 +02:00
bc17dba8fb rlp: add Split functions
These functions allow destructuring of raw rlp-encoded bytes
without the overhead of reflection or copying.
2015-09-10 19:41:51 +02:00
ac32f52ca6 rlp: fix encReader returning nil buffers to the pool
The bug can cause crashes if Read is called after EOF has been returned.
No code performs such calls right now, but hitting the bug gets more
likely as rlp.EncodeToReader gets used in more places.
2015-09-10 19:12:32 +02:00
90f1fe0ed2 Merge pull request #1781 from Gustav-Simonsson/state_object_copy
core/state: deleted field in StateObject Copy() and unit test
2015-09-09 18:42:36 +02:00
28b13a4d1e Merge pull request #1780 from bas-vk/miner-crash
agent/miner Prevent the CpuAgent to be started multiple times
2015-09-09 04:49:28 -07:00
f04b3a6f29 cmd/geth, cmd/utils, eth: added dev mode flag
Dev mode enabled some debugging flags such as:

* VM debugging mode
* Simpler proof of work
* Whisper enabled by default
* Datadir to a tmp datadir
* Maxpeers set to 0
* Gas price of 0
* Random listen port
2015-09-09 08:53:05 +02:00
bf879ef230 core/state: test formatting adhering to Go convention 2015-09-09 00:26:18 +02:00
004ed786b4 core/state: deleted field in StateObject Copy() and unit test 2015-09-08 15:56:11 +02:00
652eea71fe put unlock after lock 2015-09-08 12:42:29 +02:00
618065895b agent/miner Prevent the CpuAgent to be started multiple times 2015-09-08 11:27:55 +02:00
edaea69817 Merge pull request #1777 from hectorchu/develop
rpc/comms: fix bug attaching the console over http
2015-09-08 11:02:09 +03:00
6fe46cc743 Merge pull request #1774 from bas-vk/console-crash
cmd/geth Autocompletion bugfix which let the console crash
2015-09-08 10:33:09 +03:00
4ea81f170a rpc/comms: fix bug attaching the console over http 2015-09-07 15:09:59 +01:00
f69121357d cmd/geth Autocompletion bugfix which let the console crash 2015-09-06 16:25:55 +02:00
e2d7c1a523 Merge pull request #1752 from karalabe/fix-eth61-test
eth/downloader: fix race causing occasional test failure
2015-09-03 15:52:18 +02:00
ebbe25ee71 Merge pull request #1764 from kobigurk/honor_ipc_datadir
honors datadir when attaching
2015-09-03 10:48:23 +03:00
1a86adc5a2 cmd/geth: honor datadir when attaching 2015-09-03 10:28:30 +03:00
e98854588b Merge pull request #1761 from CJentzsch/patch-3
fix block time issue
2015-09-02 15:13:14 -07:00
0fda4c4e15 fix block time issue
currently, under normal circumstances, you always set the timestamp to previous.Time() + 1.
credits to https://www.reddit.com/r/ethereum/comments/3jcs5r/code_avg_block_time_vs_difficulty_adjustment/cuoi4op

style
2015-09-03 00:05:05 +02:00
b2c17a5a63 Merge pull request #1726 from Gustav-Simonsson/update_tests
Add TestBcForkUncle tests & update JSON files
2015-09-02 22:02:44 +02:00
e9b031b88b Merge pull request #1755 from fjl/coinbase
core: improve block gas tracking
2015-09-01 23:36:05 +02:00
00b45acb9e core: improve block gas tracking 2015-09-01 23:11:03 +02:00
1ffc5b0cfd Merge pull request #1751 from maran/fix_filters
core: Filter on addresses should work as an OR not an AND.
2015-09-01 20:10:27 +02:00
5e4cd599eb Merge pull request #1745 from mrdomino/obsd-build-master
Pull in ethash and go-isatty updates
2015-09-01 20:06:13 +02:00
1f1d73ab74 eth/downloader: fix race causing occasional test failure 2015-09-01 16:11:14 +03:00
67225de255 Filter on addresses should work as an OR not an AND. 2015-09-01 09:19:45 +02:00
540eb3d02d Pull in ethash and go-isatty updates
Fixes build on OpenBSD.
2015-08-31 12:14:32 -04:00
fe8093b71f Add TestBcForkUncleTests and update JSON files 2015-08-31 16:45:00 +02:00
9dc23ce284 Merge pull request #1742 from fjl/rpc-receipt-root
rpc: add receiptRoot to getBlock* responses
2015-08-31 14:50:21 +02:00
1801748ccd Merge pull request #1734 from fjl/ldflags-warning-go1.5
build: avoid -X separator warning with Go >= 1.5
2015-08-31 14:49:50 +02:00
8b12bcc0ac rpc: add receiptRoot to getBlock* responses
Fixes #1679
2015-08-29 11:12:01 +02:00
e1037bd0cf Merge pull request #1724 from Gustav-Simonsson/get_work
rpc: return error code for eth_getWork when no work ready
2015-08-29 10:54:10 +02:00
2d1ced8759 Merge pull request #1739 from bas-vk/empty-password
rpc/api allow empty password
2015-08-28 13:14:51 +02:00
39e9560600 rpc/api allow empty password 2015-08-28 12:49:41 +02:00
d9addf79fa Improve error string and remove unneeded else clause 2015-08-28 03:42:01 +02:00
cfd84a6ad9 build: avoid -X separator warning with Go >= 1.5 2015-08-27 13:26:13 +02:00
6ec13e7e2b Merge pull request #1701 from karalabe/eth62-sync-rebase
eth: implement eth/62 synchronization logic
2015-08-27 00:03:59 +02:00
79b644c7a3 Merge pull request #1717 from karalabe/forward-solidity-errors
common/compiler: fix #1598, expose solidity errors
2015-08-26 19:00:11 +02:00
14370a2260 Merge pull request #1718 from caktux/develop
add missing shh_getMessages to RPC mappings
2015-08-26 18:55:51 +02:00
3df6f3fc14 Merge pull request #1721 from bas-vk/console-error-parsing
Improved console error handling
2015-08-26 18:55:31 +02:00
847794a321 Merge pull request #1722 from bas-vk/remote-deleteaccount
Remove personal.deleteAccount from RPC interface
2015-08-26 18:02:51 +02:00
829201382b rpc: return error code for eth_getWork when no work ready 2015-08-26 12:46:50 +02:00
5dd2462816 rpc/api - remove personal.deleteAccount from RPC interface 2015-08-26 11:39:43 +02:00
f448310eef bugfix console error handling 2015-08-26 11:33:02 +02:00
101418b275 common/compiler: fix #1598, expose solidity errors 2015-08-26 10:04:23 +03:00
a1d8015817 add missing shh_getMessages to RPC mappings 2015-08-25 14:42:57 -04:00
17f65cd1e5 eth: update metrics collection to handle eth/62 algos 2015-08-25 17:48:47 +03:00
47a7fe5d22 eth: port the synchronisation algo to eth/62 2015-08-25 17:48:47 +03:00
abce09954b Merge pull request #1711 from Gustav-Simonsson/timestamp_big_int
Add tests for uncle timestamps and refactor timestamp type
2015-08-25 15:49:36 +02:00
a219159e7e Merge pull request #1710 from bas-vk/useragent
user agent messages were dumped in some cases
2015-08-25 12:23:25 +02:00
7324176f70 Add tests for uncle timestamps and refactor timestamp type 2015-08-25 04:46:11 +02:00
ca88e18f59 eth: kill off protocol eth/60 in preparation for eth/62 2015-08-24 17:57:28 +03:00
42f44dda54 eth, eth/downloader: handle header requests, table driven proto tests 2015-08-24 17:57:28 +03:00
d910148a96 Set ipc channel as user agent client 2015-08-24 12:41:34 +02:00
c51e153b5c eth, metrics, p2p: prepare metrics and net packets to eth/62 2015-08-21 10:30:57 +03:00
d51d0022ce cmd/geth: bumped version 1.1.0 2015-08-20 21:43:36 +02:00
3793991c0e remove 0x 2015-08-20 18:50:47 +02:00
b884d6ebaa canary update 2015-08-20 18:38:21 +02:00
36f7fe61c3 core, tests: Double SUICIDE fix 2015-08-20 18:22:50 +02:00
54088b0b8b cmd/geth: bumped version 1.0.3 2015-08-20 13:08:08 +02:00
9fb7bc7443 geth: bumped version 1.0.2 2015-08-19 23:05:39 +02:00
e2d44814a5 Merge pull request #1694 from obscuren/hide-fdtrack
fdtrack: hide message
2015-08-19 13:50:54 -07:00
bd3a44cac9 Merge pull request #1652 from bas-vk/autoreconnect
rpc/comms: reconnect ipc client after write error
2015-08-19 13:29:51 -07:00
61a6911eeb Merge pull request #1689 from fjl/discover-ignore-temp-errors
p2p, p2p/discover: small fixes
2015-08-19 12:55:40 -07:00
9bf17eb05a rpc/comms reconnect ipc client after write error 2015-08-19 21:48:56 +02:00
269c5c7107 Revert "fdtrack: temporary hack for tracking file descriptor usage"
This reverts commit 5c949d3b3b.
2015-08-19 21:46:01 +02:00
382d35bf40 Merge pull request #1688 from karalabe/fix-double-imports
eth: fix an issue with pulling and inserting blocks twice
2015-08-19 08:19:37 -07:00
dd54fef898 p2p/discover: don't attempt to replace nodes that are being replaced
PR #1621 changed Table locking so the mutex is not held while a
contested node is being pinged. If multiple nodes ping the local node
during this time window, multiple ping packets will be sent to the
contested node. The changes in this commit prevent multiple packets by
tracking whether the node is being replaced.
2015-08-19 14:57:16 +02:00
edccc7ae34 p2p: continue listening after temporary errors 2015-08-19 14:39:04 +02:00
7d5ff770e2 p2p/discover: continue reading after temporary errors
Might solve #1579
2015-08-19 14:38:55 +02:00
c6a11fe372 Merge pull request #1680 from maran/fix_removedb
cmd/geth: Fix chain purging from cmd line
2015-08-19 05:17:22 -07:00
941920f2aa eth: fix an issue with pulling and inserting blocks twice 2015-08-19 15:14:26 +03:00
3b997c3e16 Merge pull request #1454 from ethersphere/frozen-cryptoclean
crypto: remove obsolete code
2015-08-19 02:39:02 -07:00
0737cbc5c1 Merge pull request #1683 from ethereum/travis
Switch from Coveralls to Codecov code coverage service
2015-08-18 14:26:14 -07:00
227ff4d2d6 Merge pull request #1682 from obscuren/readme-improvements
Updated README, Added CONTRIBUTING
2015-08-18 14:16:42 -07:00
18d450b2d0 Updated README, Added CONTRIBUTING 2015-08-18 23:00:15 +02:00
cc87551edc Codecov integration 2015-08-18 22:46:48 +02:00
d0dc1b4a60 Merge pull request #1681 from obscuren/miner-receipt-fix
core, miner: write miner receipts
2015-08-18 12:53:26 -07:00
b4369e1015 core, miner: write miner receipts 2015-08-18 21:46:26 +02:00
4d5501c46a cmd/geth: Fix chain purging from cmd line 2015-08-18 15:56:37 +02:00
d4da2f630e crypto: remove obsolete key files 2015-08-18 01:25:04 +02:00
e1da124415 Merge pull request #1675 from obscuren/submithashrate-change
rpc/api: return boolean value for eth_submitHashrate
2015-08-17 11:49:15 -07:00
36081505c4 Merge pull request #1673 from karalabe/fix-api-xeth-responses
rpc: update the xeth over RPC API to use the success/failure messages
2015-08-17 11:47:55 -07:00
2497f28aa9 Merge pull request #1627 from zsfelfoldi/gpo
GPO update
2015-08-17 06:37:58 -07:00
49ece3155c GPO update 2015-08-17 15:20:33 +02:00
8839fee415 rpc/api: return boolean value for eth_submitHashrate 2015-08-17 15:09:30 +02:00
ff1f6fa09d Merge pull request #1649 from maran/pending_tx_response
rpc/api: format pendingTx response. Fixes #1648
2015-08-17 06:02:08 -07:00
7ea30f18f9 Merge pull request #1674 from tgerring/bootnodes
Added SG bootnode
2015-08-17 05:56:38 -07:00
12805c738c Merge pull request #1667 from fjl/pretty-printer-improvements
jsre: pretty printer improvements
2015-08-17 05:55:09 -07:00
80b294c3c7 Update CPP pubkey 2015-08-17 14:51:27 +02:00
8884f856ef Added SG bootnode 2015-08-17 14:36:57 +02:00
309788de37 rpc: update the xeth over RPC API to use the success/failure messages 2015-08-17 14:04:20 +03:00
f6367548e4 Merge pull request #1654 from obscuren/call-gas
xeth: call fix when doing 'create'-like calls
2015-08-16 16:33:29 -07:00
1c3ca3ce6a xeth: max gas limit 2015-08-16 15:27:30 +02:00
8603ec7055 rpc/api: format pendingTx response. Fixes #1648 2015-08-16 11:12:22 +02:00
1086e2f298 jsre: fix annoying indentation when printing arrays of objects
The pretty printer, dumb as it is, printed arrays of objects as

  [{
    ...
    }]

With this change, they now print as:

  [{
    ...
  }]
2015-08-16 00:35:00 +01:00
49703bea0a jsre: bind the pretty printer to "inspect" in JS 2015-08-15 23:55:42 +01:00
59b28cfa31 Merge pull request #1663 from obscuren/issue-1662
xeth: added a transact mu
2015-08-15 14:55:04 -07:00
5c5c3930b7 Merge pull request #1659 from bas-vk/exec-output
Javascript --exec output
2015-08-15 06:23:29 -07:00
7bb5ac045e xeth: added a transact mu
Added a transact mutex. The transact mutex will fix an issue where
transactions were created with the same nonce resulting in some
transactions being dropped. This happened when two concurrent calls
would call the `Transact` method (which is OK) which would both call
`GetNonce`. While the managed is thread safe it does not help us in this
case.
2015-08-15 00:33:52 +02:00
cd81356ace Merge pull request #1658 from bas-vk/liner-ctrl-c
Clear current line on ctrl-C
2015-08-14 04:36:15 -07:00
c472b8f725 main clear current line on ctrl-C 2015-08-14 13:23:41 +02:00
3a66c4ed47 Merge pull request #1642 from ethereum/fix-js-console-windows
cmd/geth, jsre: restore command line editing on windows
2015-08-14 04:14:11 -07:00
29181003d4 Merge pull request #1655 from obscuren/db-merge-fix
eth, trie: removed key prefixing from state entries & merge db fix
2015-08-14 04:12:33 -07:00
87d1cde7e4 main print console output for js statement given by the exec argument 2015-08-14 13:06:34 +02:00
28b14d3e6d Merge pull request #1635 from bas-vk/useragent
support for user agents
2015-08-13 16:25:33 -07:00
73c4e6005c Merge pull request #1638 from obscuren/jit-fixes
core/vm: fixed jit error & added inline docs
2015-08-13 11:49:01 -07:00
b8ca0a830e eth, trie: removed key prefixing from state entries & merge db fix
Fixed database merge strategy to use the correct database. Due to a copy
paste fail when doing type evaluation the same database was being
iterated (chain), all others were ignored.

Removed state prefixing because {H(code): code} is stored in the same
database as the rest of the state.
2015-08-13 20:44:03 +02:00
a89cfe92cc Merge pull request #1470 from ebuchman/encHandshake
p2p: validate recovered ephemeral pubkey
2015-08-13 11:59:27 +02:00
0b0b31c7d2 Merge pull request #1651 from karalabe/rlp-boolean-support
rlp: boolean support
2015-08-13 11:10:26 +02:00
1d2420323c rlp: add support for boolean encoding/decoding 2015-08-13 12:05:39 +03:00
0dd6911c62 Merge pull request #1647 from fjl/fix-disc-reason
p2p: fix value of DiscSubprotocolError
2015-08-12 21:20:21 +02:00
28feafe7af Merge pull request #1646 from fjl/fix-client-identifier
cmd/geth: remove spaces in client identifier
2015-08-12 14:38:48 +02:00
0d10d5a0a5 p2p: fix value of DiscSubprotocolError
We had the wrong value (12) since forever.
2015-08-12 14:15:54 +02:00
31a2793662 cmd/geth: remove spaces in client identifier 2015-08-12 13:32:52 +02:00
f9cbd16f27 support for user agents 2015-08-12 12:22:16 +02:00
0ef80bb3d0 cmd/geth, jsre: restore command line editing on windows
PR #856 broke command line editing by wrapping stdout with a filter that
interprets ANSI escape sequences to fix colored printing on windows.
Implement the printer in Go instead so it can do its own
platform-dependent coloring.

As a nice side effect, the JS console is now noticeably more responsive
when printing results.

Fixes #1608
Fixes #1612
2015-08-12 12:04:00 +02:00
05c66529b2 Merge pull request #1621 from ethereum/fix-discover-hangs
p2p/discover: fix two major bugs in reply packet handling
2015-08-11 12:17:13 -07:00
9cacec70f9 cmd/evm, core/vm, tests: changed DisableVm to EnableVm 2015-08-11 18:43:22 +02:00
94b6f38869 Merge pull request #1641 from obscuren/web3-update
web3: updated
2015-08-11 08:55:55 -07:00
bf6ea2919d web3: updated 2015-08-11 17:17:20 +02:00
c32d6fdf74 Merge pull request #1640 from obscuren/trace-flag-ethtest
cmd/ethtest: added trace flag for debugging
2015-08-11 02:53:02 -07:00
67c8ccc309 cmd/ethtest: added trace flag for debugging 2015-08-11 11:46:52 +02:00
590c99a98f p2p/discover: fix UDP reply packet timeout handling
If the timeout fired (even just nanoseconds) before the deadline of the
next pending reply, the timer was not rescheduled. The timer would've
been rescheduled anyway once the next packet was sent, but there were
cases where no next packet could ever be sent due to the locking issue
fixed in the previous commit.

As timing-related bugs go, this issue had been present for a long time
and I could never reproduce it. The test added in this commit did
reproduce the issue on about one out of 15 runs.
2015-08-11 11:42:17 +02:00
01ed3fa1a9 p2p/discover: unlock the table during ping replacement
Table.mutex was being held while waiting for a reply packet, which
effectively made many parts of the whole stack block on that packet,
including the net_peerCount RPC call.
2015-08-11 11:42:17 +02:00
32395ddb89 core/vm: fixed jit error & added inline docs
opNumber did not create a new big int which could lead to the block's
number being modified.
2015-08-11 00:16:38 +02:00
2fcf7f1241 Merge pull request #1604 from obscuren/db-merge
core, eth, trie, xeth: merged state, chain, extra databases in one
2015-08-09 05:16:37 -07:00
07cb8092e7 Merge pull request #1611 from obscuren/expdiff-olympic-fix
cmd/utils, core: disable exp diff for olympic net
2015-08-09 05:15:13 -07:00
1cbd53add8 Merge pull request #1626 from obscuren/defaults-fix
cmd/geth, core/vm: setup vm settings and defaulted JIT disabled
2015-08-08 17:11:28 -07:00
eec38c5853 cmd/geth, core/vm: setup vm settings and defaulted JIT disabled 2015-08-09 02:06:16 +02:00
c93f0b9f4b Merge pull request #1490 from obscuren/jit-vm
core/vm: jit vm
2015-08-08 06:36:26 -07:00
a23478c0be core, eth, trie, xeth: merged state, chain, extra databases in one 2015-08-07 22:29:02 +02:00
312128384b Merge pull request #1620 from caktux/develop
string version for build server
2015-08-07 11:41:41 -07:00
3ccab5a1e8 string version for build server 2015-08-07 14:13:33 -04:00
dcb23bc3ab Merge pull request #1615 from obscuren/contract-addr-fix
xeth: fixed contract addr check
2015-08-07 05:38:02 -07:00
b6c5b3b4a7 xeth: fixed contract addr check 2015-08-07 14:32:06 +02:00
d7580f21f6 Merge pull request #1595 from obscuren/extra-data
cmd/geth, eth: added canonical extra data
2015-08-07 05:00:36 -07:00
b1fac4270d Merge pull request #1614 from obscuren/web3-finite-fix
web3: regression. Fixes #1613
2015-08-07 04:59:15 -07:00
ac697326a6 core/vm: reduced big int allocations
Reduced big int allocation by making stack items modifiable. Instead of
adding items such as `common.Big0` to the stack, `new(big.Int)` is
added instead. One must expect that any item that is added to the stack
might change.
2015-08-07 12:52:23 +02:00
184e9ae9a8 core, tests: reduced state copy by N calls
Reduced the amount of state copied that are required by N calls by doing
a balance check prior to any state modifications.
2015-08-07 12:52:23 +02:00
846f34f78b core/vm, tests: implemented semi-jit vm
* changed stack and removed stack ptr. Let go decide on slice reuse.
2015-08-07 12:52:17 +02:00
a33726b7db web3: regression. Fixes #1613 2015-08-07 12:33:12 +02:00
132df860d9 miner, rpc: added length check for extra data 2015-08-07 12:24:44 +02:00
785b3e7a57 cmd/geth, eth: added canonical extra data
Implemented canonical extra data according to
https://github.com/ethereum/wiki/wiki/Extra-Data
2015-08-07 12:24:32 +02:00
e89536ca0b Merge pull request #1596 from obscuren/submit-hashrate
miner, rpc: added submit hashrate for remote agents
2015-08-07 03:08:48 -07:00
ac10c9352e Merge pull request #1610 from obscuren/address-check
xeth: added address hex check and length check
2015-08-07 02:05:54 -07:00
cf7cef4293 xeth: added address hex check and length check 2015-08-07 09:52:12 +02:00
698e98d981 Merge pull request #1600 from ethereum/fix-tests-windows
Fix tests on windows
2015-08-06 12:39:29 -07:00
a3b8169938 Merge pull request #1603 from ebuchman/trie_hex_fix
trie: hex fix
2015-08-06 12:02:55 -07:00
46c9594081 trie: run codec tests, add benchmarks, faster 2015-08-06 14:04:16 -04:00
7baa5977c8 Merge pull request #1594 from ebuchman/trie_hex_fix
faster hex-prefix codec and string -> []byte
2015-08-06 08:44:19 -07:00
803096ca0f .gitattributes: add 2015-08-06 17:18:59 +02:00
6ee908848c p2p/nat: disable UPnP test on windows 2015-08-06 17:18:59 +02:00
3832019964 common/compiler, common/docserver, jsre: fix tests on windows 2015-08-06 17:18:59 +02:00
eae1191904 cmd/utils: fix path expansion on windows 2015-08-06 17:18:59 +02:00
78b101e15d common: remove windows path functions
They were unused and their tests failed on Windows.
2015-08-06 16:43:43 +02:00
74f6d90153 cmd/utils, core: disable exp diff for olympic net 2015-08-06 13:29:06 +02:00
c32073b11f miner, rpc: added submit hashrate for remote agents 2015-08-06 12:58:54 +02:00
b23b4dbd79 p2p/discover: close Table during testing
Not closing the table used to be fine, but now the table has a database.
2015-08-06 12:27:59 +02:00
c1d516546d faster hex-prefix codec and string -> []byte 2015-08-06 03:17:59 -04:00
82ef26f600 Merge branch 'develop' 2015-08-05 18:41:08 +02:00
ee5728ec03 fake commit for build server :( 2015-08-05 18:41:00 +02:00
9a02f53726 Merge branch 'develop' 2015-08-05 18:35:28 +02:00
98100f472c cmd/geth: bumped version number 2015-08-05 18:35:23 +02:00
80e5f50713 Merge branch 'develop' 2015-08-05 18:08:52 +02:00
26f838796b Merge pull request #1583 from obscuren/miner-price-order
miner, core: sort txs by price, nonce
2015-08-05 09:03:18 -07:00
35f271b264 miner, core: sort txs by price, nonce 2015-08-05 17:44:19 +02:00
f12e0161ca Merge pull request #1588 from obscuren/diff-bomb
core, miner: added difficulty bomb
2015-08-05 04:26:57 -07:00
71d32f54f7 core, miner: added difficulty bomb 2015-08-05 13:09:09 +02:00
1f4ac6b05a Merge pull request #1587 from obscuren/miner-race
miner: fixed worker race condition
2015-08-05 01:50:49 -07:00
d8590d9790 miner: fixed worker race condition 2015-08-04 20:54:21 +02:00
56219a5e7a Merge pull request #1578 from Gustav-Simonsson/frontier_thawing
miner: gas limit strategy, target 3141592 & def gas price 50 Shannon
2015-08-04 11:53:39 -07:00
26c6e3b206 miner: gas limit strategy, target 3141592 & def gas price 50 Shannon 2015-08-04 15:20:28 +02:00
b01f2c29ae Merge pull request #1574 from fjl/fdtrack
fdtrack: hack to track file descriptor usage
2015-08-04 03:51:16 -07:00
ff66e8fa29 Merge pull request #1562 from ethersphere/blankpasswd
jsre: leave out lines from history possibly containing passwords
2015-08-04 03:10:59 -07:00
17b481e3c3 Merge pull request #1581 from obscuren/olympic
cmd, core, eth: support for the olympic network
2015-08-04 00:54:07 -07:00
5c949d3b3b fdtrack: temporary hack for tracking file descriptor usage
Package fdtrack logs statistics about open file descriptors.
This should help identify the source of #1549.
2015-08-04 03:10:27 +02:00
dcdb7059cc cmd, core, eth: support for the olympic network
Added a --olympic flag which initialiser the olympic protocol settings
2015-08-03 18:15:48 +02:00
bf48ed32dd metrics: fix file descriptor leak when reading disk stats on linux
The disk stats file was not closed after reading.
2015-08-03 16:27:36 +02:00
ba14957cf3 rpc/comms: use ConnState to track HTTP connections
The JSON-RPC server wraps TCP connections in order to be able to shut
down them down when RPC is stopped. This is rather scary code. Go 1.3
introduced the http.Server.ConnState hook for such purposes. We can use
this facility now that we depend on Go 1.4.

There are multiple reasons for the switch apart from making the code
less scary:

* the TCP listener no longer ticks every second to check a channel
* pending requests are allowed to finish after stopping the server
* we can time out idle keep-alive connections
2015-08-03 16:27:36 +02:00
97cdf84899 Merge pull request #1479 from tgerring/ethtest
Update ethtest default path for BlockTests
2015-08-03 07:18:48 -07:00
98db08c42f Merge pull request #1548 from fjl/accounts-test-deflake
accounts: bump timeout in TestSignRace
2015-08-03 07:16:36 -07:00
cc6c5846e5 Merge pull request #1568 from obscuren/issue-1559
core: added a running flag to prevent panics in the chainmanager
2015-08-03 07:15:19 -07:00
db988a46dd Merge pull request #1569 from obscuren/default-genesis
core: added default genesis block
2015-08-03 04:49:30 -07:00
7a75da63c6 core: added default genesis block
When a user runs a freshly setup geth w/o a database initialised the
default genesis block is decoded and inserted in to the database.
2015-08-02 01:23:02 +02:00
33efb3381c Merge pull request #1461 from bas-vk/eth_resend
Old transaction after resend was not removed from pool
2015-08-01 16:18:54 -07:00
5aec1d94ad accounts: bump timeout and spin less in TestSignRace
This should fix the flakeyness.
2015-08-02 00:49:53 +02:00
a8b39b5cc0 Merge pull request #1541 from bas-vk/issue1518
Improved error handling for NewTransactionFromBytes
2015-08-01 08:47:32 -07:00
acd2c4e520 core: added a running flag to prevent panics in the chainmanager
The running flag will determine whether the chain manager is still
running or not. This will prevent the quit channel from being closed
twice resulting in a panic. This PR should fix this issue.

Closes #1559
2015-08-01 12:32:28 +02:00
ab85a3593a Merge pull request #1545 from obscuren/log-index
core/state: Set log index. Closes #1226
2015-07-31 10:36:42 -07:00
c1c06fffcb Merge pull request #1561 from karalabe/add-missing-autocompletes
rpc/api: add missing autocomplete commands
2015-07-31 03:09:08 -07:00
6628eeb6ca jsre: leave out lines from history containing methods of the personal module 2015-07-31 11:51:18 +02:00
0d3a8ad6dd rpc/api: add missing autocomplete commands 2015-07-31 12:46:16 +03:00
4231de3914 Merge pull request #1553 from prusnak/develop
remove elliptic.P224 usage
2015-07-30 03:59:25 -07:00
3f07afbbd2 remove elliptic.P224 usage
Fedora/RedHat distros comply with US patent law and remove this curve,
which makes it impossible to run ethereum with distro provided Golang.

File crypto/ecies/README claims it is unsupported anyway.
2015-07-30 12:47:45 +02:00
64e2f52c2e Merge pull request #1534 from obscuren/issue-1040
rpc: to in eth_call no longer required. Fixed eth_estimateGas
2015-07-30 03:25:47 -07:00
d261c3f455 rpc: to in Call no longer required. Fixed eth_estimateGas 2015-07-29 15:12:12 +02:00
e7f4232b10 Merge pull request #1544 from karalabe/fix-stall-detector
eth, eth/downloader: don't report stall if fetcher filled the block
2015-07-29 06:11:43 -07:00
f715547fc7 core/state: Set log index. Closes #1226 2015-07-29 15:08:59 +02:00
fa286688ab Merge pull request #1546 from obscuren/tests-update
tests: updated
2015-07-29 06:07:19 -07:00
03c39d4fc0 tests: updated 2015-07-29 15:01:42 +02:00
6adbaabc65 eth, eth/downloader: don't report stall if fetcher filled the block 2015-07-29 15:39:08 +03:00
81e2124ea2 improved error detection and handling for NewTransactionFromBytes
integrated review comments
2015-07-29 10:30:00 +02:00
cc27be9d44 Merge pull request #1543 from enriquefynn/develop
FreeBSD support
2015-07-28 16:20:13 -07:00
7065ebd2ed FreeBSD support 2015-07-28 19:16:16 -03:00
a281df783d Merge pull request #1533 from ethersphere/frontier/etherbase
Etherbase defaults to first account even if it is created during the session
2015-07-28 05:11:43 -07:00
1fad8798ec Merge pull request #1515 from fjl/license-fixes
all: fix license headers one more time
2015-07-28 04:29:42 -07:00
7e31df3987 bugfix, pending transaction was resend with new gas price/limit but not removed from transaction pool 2015-07-28 10:42:31 +02:00
572e78cee0 Merge pull request #1536 from fjl/fix-go1.5-build
crypto: fix build with Go 1.5
2015-07-28 00:59:52 +02:00
453d2c9ce1 crypto: fix build with Go 1.5 2015-07-27 19:13:45 +02:00
1356daad27 etherbase defaults to first account even if created during the session 2015-07-27 10:50:29 +02:00
d18d256442 Merge pull request #1529 from obscuren/extra-data-fix
core: genesis extra data field fix
2015-07-26 15:15:36 -07:00
3530acb9e2 core: genesis extra data field fix 2015-07-26 14:44:54 +02:00
8a5ea466e4 Merge pull request #1528 from obscuren/reduce-extra-data
params: reduce extra data to 32 bytes & target block time
2015-07-26 04:04:10 -07:00
1e241e84f7 params: reduce extra data to 32 bytes 2015-07-26 12:47:57 +02:00
e86233abc9 Merge pull request #1525 from obscuren/genesis-write-fix
core: fixed genesis write out to write only canon number
2015-07-25 13:13:27 -07:00
c1c895a36b core: fixed genesis write out to write only canon number 2015-07-25 21:48:53 +02:00
73a576c9af Merge pull request #1524 from obscuren/default-extra
eth: set default miner extra to client name
2015-07-25 08:58:08 -07:00
665eaff9b9 Merge pull request #1520 from obscuren/reward-5eth
core: 5 ether block reward
2015-07-25 08:57:33 -07:00
9afda6ab8c core: 5 ether block reward 2015-07-25 17:47:20 +02:00
3adaeb1dbc eth: set default miner extra to client name 2015-07-25 17:36:56 +02:00
0efcd7ed05 Merge pull request #1521 from obscuren/client-update
cmd/geth, core, eth: Version 1.0.0
2015-07-25 08:36:04 -07:00
4019e2a6f2 Merge pull request #1497 from obscuren/remove-rle
ethdb, trie: removed RLE compression
2015-07-25 08:35:40 -07:00
f6097f4a0a Merge pull request #1522 from obscuren/genesis-block-check
core: check genesis block before writeout
2015-07-25 08:10:08 -07:00
d4428cc77f Merge pull request #1523 from obscuren/lower-gasprice
cmd/util: lowered default gas price
2015-07-25 08:09:55 -07:00
ba15f9d282 cmd/util: lowered default gas price 2015-07-25 17:03:10 +02:00
0c718afe90 core: check genesis block before writeout 2015-07-25 16:53:35 +02:00
036e6301af cmd/geth, core, eth: Version 1.0.0
Genesis release. Closes #1402

Conflicts:
	cmd/geth/main.go
2015-07-25 13:55:56 +02:00
6cffa743ee Merge pull request #1519 from obscuren/develop
web3: updated 0.9.1
2015-07-25 04:06:43 -07:00
5001f778aa web3: updated 0.9.1 2015-07-25 12:22:39 +02:00
cd657b9878 Godeps: use BSD-licensed version of gopkg.in/karalabe/cookiejar.v2 2015-07-24 14:23:02 +02:00
67598d9d08 crypto/sha3: add full license headers 2015-07-24 12:32:58 +02:00
fd2356c620 common: remove config.go
The code in config.go is unused. The main reason for removing it is to
get rid github.com/rakyll/goini in Godeps (it has no license).
2015-07-24 11:43:32 +02:00
bfbcfbe4a9 all: fix license headers one more time
I forgot to update one instance of "go-ethereum" in commit 3f047be5a.
2015-07-23 18:35:11 +02:00
adc7ab0dd6 Merge pull request #1507 from obscuren/batch-write
cmd/core,xeth: removed unneeded states & added batch writes
2015-07-23 07:50:07 -07:00
8f56eea77d ethdb, trie: removed RLE compression 2015-07-23 12:57:33 +02:00
8fc9830971 cmd/core,xeth: removed unneeded states & added batch writes 2015-07-23 10:45:31 +02:00
0cff61beda Merge pull request #1510 from fjl/license-fixes
all: license fixes
2015-07-23 01:43:11 -07:00
b403b9e4c3 Merge pull request #1508 from karalabe/database-caching
cmd, core, eth, ethdb: cache flag to allocate memory for db internal use
2015-07-23 01:17:18 -07:00
26a269ea09 Merge pull request #1511 from karalabe/rlp-data-race
core: fix an RLP encoding data race due to deep struct copy
2015-07-22 20:10:41 +02:00
04bb89604e core: fix an RLP encoding data race due to deep struct copy 2015-07-22 20:54:53 +03:00
0428cae226 remove LICENSE files 2015-07-22 18:54:45 +02:00
3f047be5aa all: update license headers to distiguish GPL/LGPL
All code outside of cmd/ is licensed as LGPL. The headers
now reflect this by calling the whole work "the go-ethereum library".
2015-07-22 18:51:45 +02:00
f4acdea402 crypto: fix license of curve.go
crypto/curve.go is not our code and has its own license. This commit
excludes it in update-license.go and removes our GPL header.
2015-07-22 18:50:31 +02:00
c7e7778f2a cmd, core, eth, ethdb: cache flag to allocate memory for db internal use 2015-07-22 14:00:52 +03:00
d1d45aa839 Merge pull request #1503 from fjl/fix-accounts-race
accounts: fix data race when key is locked after the unlock timeout
2015-07-22 13:00:09 +02:00
d103af5dd4 Disassociate test directory from test name 2015-07-22 11:39:36 +01:00
ed1d2f858e Merge pull request #1481 from tgerring/legalese
Legalese updates
2015-07-22 03:35:33 -07:00
482cc4957d Merge pull request #1500 from karalabe/fix-miner-race
miner: fix current work data race
2015-07-22 03:16:13 -07:00
f1daed65b1 Merge pull request #1502 from ethereum/canaryFix
Fixed canary to require 2+ nonzero, not sum 2+
2015-07-20 16:17:48 -07:00
cf5313f13e Update disclaimer 2015-07-20 18:49:25 +02:00
06d5898d6a crypto: remove debug print call after decrypting a key from disk 2015-07-20 18:04:23 +02:00
7662dd9bbb accounts: fix data race when key is locked after the unlock timeout
While here, also improve the docs and speed up the tests.
The tests used the scrypt keystore with ridiculous settins and took 20s
each.
2015-07-20 18:04:23 +02:00
8160b8618d Fixed canary to require 2+ nonzero, not sum 2+ 2015-07-20 16:28:28 +02:00
3029349761 miner: fix current work data race 2015-07-20 14:37:43 +03:00
02c5022742 Merge pull request #1496 from karalabe/fix-xeth-races
xeth: fix #1485, data race in fiilter creation and event firing
2015-07-20 04:27:10 -07:00
3642441ca3 xeth: fix #1485, data race in fiilter creation and event firing 2015-07-20 14:02:02 +03:00
12bb743b35 Merge pull request #1484 from fjl/rlp-json-tests
cmd/ethtest, tests: add support for RLP JSON tests
2015-07-19 05:05:16 -07:00
26c0fa1cb0 Merge pull request #1480 from obscuren/miner-state-sync
miner: moved state sync
2015-07-19 05:03:59 -07:00
a38f3740d6 Merge pull request #1488 from ethereum/travis
Travis container support
2015-07-18 09:05:29 -07:00
345590f27f rlp: fix check for canonical byte array size
Decoding did not reject byte arrays of length one with a single element
b where 55 < b < 128. Such byte arrays must be rejected because
they must be encoded as the single byte b instead.
2015-07-18 16:23:35 +02:00
5a41326521 Travis container support 2015-07-18 16:12:48 +02:00
cefd948267 rlp: reject trailing data when using DecodeBytes 2015-07-18 01:47:17 +02:00
593b1b65e7 tests: document RLP tests 2015-07-17 15:42:23 +02:00
5da82077d1 cmd/ethtest, tests: add support for RLP JSON tests 2015-07-17 15:13:24 +02:00
1b9ef0e52d miner: moved state sync
Moved the state sync so it only syncs the state when the block mining yield a possitive result
2015-07-16 14:19:27 +02:00
a75b95b876 Merge pull request #1477 from tgerring/legalese
Prompt user to accept legalese when datadir doesn't exist
2015-07-16 04:40:15 -07:00
e954375109 Merge pull request #1469 from obscuren/smart-mining
miner: smart mining
2015-07-16 04:39:07 -07:00
618991f136 Move text to separate file 2015-07-16 13:34:34 +02:00
bc6b6932d0 Merge pull request #1476 from obscuren/deadlock-logs
xeth: removed mutex lock
2015-07-16 03:35:43 -07:00
1909d26fe2 Prompt user to accept legalese when datadir doesn't exist 2015-07-16 12:27:42 +02:00
b1d0d3c0ed xeth: removed unneeded mutex lock 2015-07-16 11:04:53 +02:00
9addb3df3a Merge pull request #1475 from obscuren/issue1473
core: during chain reorg rewrite receipts and transactions
2015-07-15 13:17:07 -07:00
e870e61bc9 miner: smart mining
Work is now handled and carried over multiple sessions. Previously one
session only was assumed, potentially resulting in invalid (outdated)
work

* Larger work / result queue
* Full validation option
2015-07-15 20:37:12 +02:00
cecc9cdd2f Merge pull request #1468 from Gustav-Simonsson/xeth_transact_logging
xeth: log signed tx hash
2015-07-15 11:35:51 -07:00
e17d8ddbeb core: during chain reorg rewrite receipts and transactions
Added PutBlockReceipts; storing receipts by blocks. Eventually this will
require pruning during some cleanup cycle. During forks the receipts by
block are used to get the new canonical receipts and transactions.

This PR fixes #1473 by rewriting transactions and receipts from the point
of where the fork occured.
2015-07-14 18:40:03 +02:00
37efd08b42 p2p: validate recovered ephemeral pubkey against checksum in decodeAuthMsg 2015-07-14 03:06:44 +00:00
afba798357 xeth: log signed tx hash 2015-07-13 03:09:02 +02:00
796c18db93 Merge pull request #1462 from obscuren/genesis
core: genesis preparation
2015-07-12 03:45:45 -07:00
a32c51effd cmd, core, eth, common: genesis preparation
Implemented the --genesis flag thru which we can set a custom genesis
block, including the official Ethereum genesis block.
2015-07-10 17:37:41 +02:00
5a810758db cmd/geth: bump version 0.9.39 2015-07-09 18:07:52 +02:00
6f9377475c Merge branch 'release/0.9.38' into develop 2015-07-09 18:06:49 +02:00
98f4c936f2 Merge branch 'release/0.9.38' 2015-07-09 18:06:39 +02:00
344277d026 cmd/geth: version bump 0.9.38 2015-07-09 17:43:45 +02:00
3add8cfdb0 Merge pull request #1452 from obscuren/develop
core/vm: added str to op
2015-07-09 08:42:38 -07:00
8b5a65c14a core/vm: added str to op 2015-07-09 17:08:33 +02:00
0646cc8d14 Merge pull request #1453 from ethersphere/frozen-accounts
accounts, crypto: fixed file naming for windows
2015-07-09 08:08:09 -07:00
97d22be318 Merge pull request #1441 from obscuren/logs-return-fix
miner, xeth: fire log event during mining. Fix return raw tx
2015-07-09 07:24:35 -07:00
4c62ce831b Merge pull request #1451 from karalabe/handle-potential-TD-forge-attack
eth/downloader: drop peer if advertised TD but won't delvier
2015-07-09 07:23:50 -07:00
b041aed660 Merge pull request #1450 from karalabe/fix-propagation-td
eth: calculate the correct TD, only update if better
2015-07-09 07:23:16 -07:00
cd6d703e94 Merge pull request #1447 from karalabe/fix-database-metrics-race-3
eth, ethdb: fix a data race during startup/shutdown
2015-07-09 07:22:54 -07:00
dd140beb73 Merge pull request #1443 from Gustav-Simonsson/core_uint64_ts
Core uint64 ts
2015-07-09 07:22:38 -07:00
06afabb631 Merge pull request #1436 from bas-vk/net_version
added net.version
2015-07-09 07:22:20 -07:00
505b77a0d5 Merge pull request #1432 from tgerring/develop
Adjust .mailmap
2015-07-09 07:21:41 -07:00
c3f5403b64 fix wallet key duplicate write - how did it get there? mystery. fixes #1411 2015-07-09 14:07:35 +01:00
589f1c85b9 : colon => dash - in keyfile name - slight deviation from ISO8601 for WIN FS compatibility 2015-07-09 13:55:09 +01:00
492d5454b1 eth/downloader: drop peer if advertised TD but won't delvier 2015-07-09 14:40:18 +03:00
4f95e2f9ec eth: calculate the correct TD, only update if better 2015-07-09 13:55:06 +03:00
eb2d168710 eth, ethdb: fix a data race during startup/shutdown 2015-07-09 12:44:07 +03:00
d25634662b web3: updated 2015-07-08 15:47:33 +02:00
819ecd4508 miner, xeth: fire log event during mining. Fix return raw tx 2015-07-08 15:34:11 +02:00
5d6d40f329 Use uint64 on ts in chain_manager, block_processor 2015-07-08 13:21:06 +02:00
b08abe64e4 Unskip SimpleTx3, check err in pre/post state validations 2015-07-08 13:09:22 +02:00
0b53a5c673 Update Ethereum JSON test files and wrappers 2015-07-08 13:08:42 +02:00
e84f3ec1d4 added net.version 2015-07-08 08:03:20 +02:00
b1af5af30e Adjust .mailmap 2015-07-07 11:50:49 -05:00
423c2f499c Merge branch 'release/0.9.36' 2015-07-07 15:33:55 +02:00
a2333bcbb4 Merge pull request #1430 from obscuren/web3-0.8.0
web3 update
2015-07-07 06:33:38 -07:00
c6578d2336 Merge branch 'release/0.9.36' 2015-07-07 15:32:04 +02:00
c5972b4ac7 web3 update 2015-07-07 15:21:24 +02:00
0c9c5439d4 Merge branch 'release/0.9.36' into develop 2015-07-07 15:13:11 +02:00
193c62fdba Merge branch 'release/0.9.36' 2015-07-07 15:12:56 +02:00
d673c34c8d Merge branch 'release/0.9.36' of github.com-obscure:ethereum/go-ethereum into release/0.9.36 2015-07-07 14:55:39 +02:00
df54510e3e common/natspec: fixed test 2015-07-07 14:55:27 +02:00
ee04b71887 cmd/geth, cmd/utils: changed ParamsToAddress to return error
ParamsToAddress no longer aborts the process, it now returns an error
instead so that the caller can handle the error properly.
2015-07-07 14:55:27 +02:00
4b5c99d97f cmd/geth: version number 0.9.36 2015-07-07 14:55:27 +02:00
9e7d5d9d3b Merge pull request #1426 from fjl/license
all: update license information and godoc comments
2015-07-07 05:55:06 -07:00
b2d18393c4 README.md: update copyright 2015-07-07 14:12:45 +02:00
335d7f4855 LICENSE, cmd/LICENSE: the go-ethereum authors have copyright 2015-07-07 14:12:45 +02:00
4fb28e0dab all: goimports -w 2015-07-07 14:12:45 +02:00
bdae4fd573 all: add some godoc synopsis comments 2015-07-07 14:12:45 +02:00
e813626ee1 all: remove @author comments 2015-07-07 14:12:44 +02:00
7bb77c02da build: change license regexp for // comments 2015-07-07 14:12:44 +02:00
ea54283b30 all: update license information 2015-07-07 14:12:44 +02:00
46fbd34c70 .mailmap: update 2015-07-07 14:01:33 +02:00
3ff5cfd028 build: new update-license.go
This version is less clever. All names are listed in a single file,
AUTHORS. All source files have the same header. This is an improvement
over the previous version, which attempted to list copyright holders in
each source file.
2015-07-07 14:01:33 +02:00
922f881c3d common/natspec: fixed test 2015-07-07 13:01:39 +02:00
bfcac89881 cmd/geth, cmd/utils: changed ParamsToAddress to return error
ParamsToAddress no longer aborts the process, it now returns an error
instead so that the caller can handle the error properly.
2015-07-07 12:53:36 +02:00
db06906c4f cmd/geth: version number 0.9.36 2015-07-07 12:21:36 +02:00
3016f23864 cmd/geth: fixed test 2015-07-07 12:18:05 +02:00
e5fba8fd70 Merge pull request #1428 from obscuren/coinbase-fixes
cmd,eth,rpc,tests: default coinbase
2015-07-07 02:55:33 -07:00
916d155467 Merge pull request #1429 from obscuren/rebase-registrar
Rebase registrar
2015-07-07 02:55:23 -07:00
c5cb6e8e70 fix/skip tests, adapt registrar to no contract address
registry initialisers now return the txhash which caller can use to retrieve receipt
2015-07-07 11:30:55 +02:00
3791831081 rebase with zelig/frontier/registrar 2015-07-07 11:30:45 +02:00
7e6c1f8024 corrected input formatters as suggested during review 2015-07-07 11:30:23 +02:00
ceb0739ba1 fixed web3 formatters mismatch 2015-07-07 11:30:11 +02:00
37c1a8f69d eth,miner,rpc: set coinbase 2015-07-07 10:58:47 +02:00
6ea28f93b9 output BigNumbers objects in console as strings 2015-07-07 10:43:49 +02:00
1208ac83d5 fix natspec test
* registar url string retrieval chop leading zeros now
* rewrite test using test mining
* remove temporary applyTxs from xeth
2015-07-07 10:43:49 +02:00
aa22cf323e fix js arguments and TestContract passes 2015-07-07 10:43:49 +02:00
492e5049d7 rename js methods in js_test for new console API
+ rebase fixes
2015-07-07 10:43:49 +02:00
042c3290b3 fix GPO missing flags 2015-07-07 10:43:49 +02:00
518dc87db3 fix sleepBlocks, implement sleep 2015-07-07 10:43:49 +02:00
6391ec0c8f add missing method to api/admin 2015-07-07 10:43:31 +02:00
2739233719 Registrar and contractInfo handling
* resolver -> common/registrar
  * global registrar name registry interface
  * add Call to resolver backend interface
  * the hashReg and UrlHing contracts now initialised from global registry
  * initialization of contracts uniform
  * improve errors and more econsistent method names
* common/registrar/ethreg: versioned registrar
* integrate new naming and registrar in natspec
* js console api: setGlobalRegistrar, setHashReg, setUrlHint
* js test TestContract uses mining - tests fixed all pass
* eth/backend: allow PoW test mode (small ethash DAG)
* console jsre refers to resolver.abi/addr,
* cmd/geth/contracts.go moved to common/registrar
2015-07-07 10:43:31 +02:00
83ee39448e Registrar and contractInfo handling
* resolver -> common/registrar
  * global registrar name registry interface
  * add Call to resolver backend interface
  * the hashReg and UrlHing contracts now initialised from global registry
  * initialization of contracts uniform
  * improve errors and more econsistent method names
* common/registrar/ethreg: versioned registrar
* integrate new naming and registrar in natspec
* js console api: setGlobalRegistrar, setHashReg, setUrlHint
* js test TestContract uses mining - tests fixed all pass
* eth/backend: allow PoW test mode (small ethash DAG)
* console jsre refers to resolver.abi/addr,
* cmd/geth/contracts.go moved to common/registrar
2015-07-07 10:43:31 +02:00
35cd355c14 cmd,eth,rpc,tests: default coinbase 2015-07-07 10:32:05 +02:00
d764bd0584 Merge pull request #1423 from obscuren/gasused-receipt-fix
core, eth, rpc: proper gas used. Closes #1422
2015-07-06 12:41:55 -07:00
666a7dda36 core, eth, rpc: proper gas used. Closes #1417
Added some additional backward compatibility code for old receipts
2015-07-06 21:18:24 +02:00
45618d5f6b Merge pull request #1418 from fjl/one-interrupt
cmd/utils: fix interrupt handling to actually see subsequent interrupts
2015-07-06 11:05:54 -07:00
d4c2e9de32 cmd/utils: fix interrupt handling to actually see subsequent interrupts 2015-07-06 16:48:34 +02:00
6220707e03 Merge pull request #1414 from Gustav-Simonsson/update_tests
Add TestBcGasPricer, comments and unskip tests
2015-07-06 06:39:19 -07:00
4c30f0f9ac Merge pull request #1416 from fjl/one-interrupt
cmd/geth, cmd/utils: improve interrupt handling
2015-07-06 06:32:24 -07:00
5615fc4714 cmd/geth, cmd/utils: improve interrupt handling
The new strategy for interrupts is to handle them explicitly.
Ethereum.Stop is now only called once, even if multiple interrupts
are sent. Interrupting ten times in a row forces a panic.

Fixes #869
Fixes #1359
2015-07-06 15:06:11 +02:00
fa7b3b7276 Merge pull request #1415 from obscuren/web3-update
web3: updated
2015-07-06 05:01:39 -07:00
b0aec6402a web3: updated 2015-07-06 14:01:03 +02:00
cc29b4bc27 Merge pull request #1413 from obscuren/receipt-fix
rpc, xeth: fixed returned tx hash & receipt logs
2015-07-06 05:00:17 -07:00
b7e8d954ef Add TestBcGasPricer, comments and unskip tests 2015-07-06 13:56:56 +02:00
4f7fc7b23f rpc, xeth: fixed returned tx hash & receipt logs 2015-07-06 13:43:02 +02:00
457a3c8f76 Merge pull request #1410 from obscuren/newerrors-fix
core, miner: adopted new style errors
2015-07-06 04:00:37 -07:00
e6bb9c1cad core, miner: removed vm errors from consensus err checking
Removed VM errors from the consensus errors. They now used for output
only.
2015-07-06 12:43:05 +02:00
aa4502060b Merge pull request #1400 from obscuren/badblock-reporting
core, miner, tests: added test, implemented bad block reporting
2015-07-06 02:03:50 -07:00
b533aaa765 Merge pull request #1409 from fjl/fix-tx-hash
core/types, xeth: separate tx hash and tx signature hash
2015-07-06 01:59:41 -07:00
35add89c87 Merge pull request #1397 from tgerring/rpcreceipt
getTransactionReceipt RPC support
2015-07-06 01:53:21 -07:00
46e7c8512e Merge pull request #1395 from Gustav-Simonsson/fix_core_errors_in_apply_txs
Fix core errors in apply txs
2015-07-06 01:51:14 -07:00
ec9620fb2f core/types, xeth: separate tx hash and tx signature hash 2015-07-06 10:45:45 +02:00
6c7f5e3d0e Add autocomplete support for console 2015-07-05 15:42:04 -05:00
dd521ece3f Always return transaction hash 2015-07-05 12:25:44 -05:00
bcc1660abc core, miner, tests: added test, implemented bad block reporting 2015-07-05 15:14:31 +02:00
62559ac330 Cleanup 2015-07-04 12:14:06 -05:00
30afd37604 Compose additional fields 2015-07-04 12:03:37 -05:00
cd4cc309ae Remove redundant function 2015-07-04 11:28:30 -05:00
3be9046c21 Rename local variable for clarity 2015-07-04 10:24:52 -05:00
9c3db1be1d Merge pull request #1369 from obscuren/statedb-update-cleanup
core, core/state: throw out intermediate state
2015-07-04 03:42:13 -07:00
9bb575be7d Merge pull request #1283 from ethersphere/frontier/accounts
Account management improvements
2015-07-04 03:40:23 -07:00
0f04af5916 Fix core error forwarding, unify OOG VM err 2015-07-04 09:27:42 +02:00
481b221279 Decode full receipt storage 2015-07-04 00:00:23 -05:00
80eb8f46b7 Fix hex conversion 2015-07-03 23:46:59 -05:00
3a983d2419 Initial getTransactionReceipt support 2015-07-03 23:03:11 -05:00
47460b3b4a trie: removed shallow copies (thanks to @fjl) 2015-07-04 02:51:37 +02:00
0a1ff68c11 trie: dirty tracking 2015-07-04 02:51:36 +02:00
ab16ce70fc core, miner, tests: renamed state methods
* Update => SyncIntermediate
* Added SyncObjects

SyncIntermediate only updates whatever has changed, but, as a side
effect, requires much more disk space.

SyncObjects will only sync whatever is required for a block and will not
save intermediate state to disk. As drawback this requires more time
when more txs come in.
2015-07-04 02:51:36 +02:00
08caeedd84 core, core/state: only write necessary state. Skip intermediate 2015-07-04 02:51:36 +02:00
6f69b4d61f Merge pull request #1399 from obscuren/receipts-storing-fix
core, eth, miner, xeth: receipt storage fix
2015-07-03 17:50:46 -07:00
2feb23c1da core, eth, miner, xeth: receipt storage fix
* Added GetReceiptsFromBlock, GetReceipt, PutReceipts
* Added ContractAddress to receipt. See #1042
2015-07-04 02:32:10 +02:00
efd7da0ce8 Merge pull request #1385 from Gustav-Simonsson/update_tests
Update Ethereum JSON test files, skip failing tests
2015-07-03 09:20:21 -07:00
acd85fe95f Merge pull request #1393 from bas-vk/issue1377
Upgrade web3 to version 0.7.1
2015-07-03 08:27:04 -07:00
4dfcd6012b Merge pull request #1392 from bas-vk/ipcpipelining
Several bugfixes to IPC channel
2015-07-03 08:26:57 -07:00
546c0f631c Merge pull request #1394 from obscuren/develop
miner: ignore future errors
2015-07-03 08:22:30 -07:00
0e33fbdcb9 miner: ignore future errors 2015-07-03 17:21:23 +02:00
8150c0a726 upgrade web3 to version 0.7.1 2015-07-03 17:08:41 +02:00
e8c1399bbf fixed unittest after new implementation 2015-07-03 16:57:40 +02:00
1cbab291a9 Merge pull request #1389 from obscuren/txpool-issues
core, miner: miner header validation, transaction & receipt writing
2015-07-03 07:50:30 -07:00
8181929c9a Merge pull request #1391 from tgerring/consolefalse
Prevent false from printing on console
2015-07-03 07:46:49 -07:00
d9efaf754c simplified implementation and improved performance 2015-07-03 15:44:35 +02:00
6afdc52483 Prevent debug value from printing on console 2015-07-03 07:40:47 -05:00
29e2fb38f8 core, miner: miner header validation, transaction & receipt writing
* Miners do now verify their own header, not their state.
* Changed old putTx and putReceipts to be exported
* Moved writing of transactions and receipts out of the block processer
  in to the chain manager. Closes #1386
* Miner post ChainHeadEvent & ChainEvent. Closes #1388
2015-07-03 13:56:50 +02:00
03129e7c93 Merge pull request #1390 from karalabe/fix-downloader-test-race
eth/downloader: fix a rare test race on the OSX CI
2015-07-03 04:22:14 -07:00
f0e94b4d71 display rpc error in console 2015-07-03 12:22:20 +02:00
f857fb7600 eth/downloader: fix a rare test race on the OSX CI 2015-07-03 13:01:22 +03:00
ff97059a99 Update Ethereum JSON tests, skip failing 2015-07-03 09:40:07 +02:00
1959346793 account update: migrate or change password
* account.Update
* KeyStore.Cleanup
* fix dir rm for old format deleteKey
2015-07-03 07:52:37 +01:00
fc17a527bc fix account ordering
* chronological order of creation
* new naming scheme keystore/UTC--<created_at UTC ISO8601>-<address hex>
* KeyStore2 -> KeyStore
* backward compatibility
* refactor keyStore methods
2015-07-03 03:19:32 +01:00
a4df9d74ea accounts order by keyfile ctime 2015-07-02 23:29:07 +01:00
eb82ca4563 rpc/js coinbase returns null if no etherbase set 2015-07-02 23:28:12 +01:00
09b6983175 no primary when listing accounts 2015-07-02 23:28:12 +01:00
65a26e40a8 require explicit etherbase address for mining. Falling back to primary is risky given it is inconsistent if keys are imported/merged/created or copied/transfered 2015-07-02 23:28:12 +01:00
fc2e33c594 unlock multiple passes and obsolete primary
* multiple passwords allowed in password file
* split on "\n", sideeffect: chop trailing slashes. fixes common mistake <(echo 'pass')
* remove accounts.Primary method
* do not fall back to primary account for mining
2015-07-02 23:28:11 +01:00
1d72aaa0cd simplify account unlocking 2015-07-02 23:28:11 +01:00
cf66826223 merge conflict 2015-07-02 17:33:21 +02:00
56ed408436 ipcpath issue fix 2015-07-02 17:25:11 +02:00
6be527dd52 prevent discarding requests when parsing fails 2015-07-02 17:25:11 +02:00
effe9cc2cf added pipelining support 2015-07-02 17:25:11 +02:00
89525fcb4e ipcpath issue fix 2015-07-02 17:20:58 +02:00
c2590af7fd prevent discarding requests when parsing fails 2015-07-02 15:26:55 +02:00
9f6016e877 Merge branch 'develop' of github.com:ethereum/go-ethereum into develop 2015-07-02 05:27:31 -04:00
75f41dedca Merge pull request #1378 from obscuren/issue1367
core, xeth: core.AddressFromMessage removed => crypto.CreateAddress
2015-07-02 02:27:20 -07:00
744af9f497 Switched canary addresses 2015-07-02 05:27:19 -04:00
529fb7a7d7 core, xeth: core.AddressFromMessage removed => crypto.CreateAddress 2015-07-02 11:19:10 +02:00
5caff3bc24 Merge pull request #1351 from karalabe/eth61
Implement eth/61
2015-07-01 08:16:44 -07:00
507869bff1 Merge pull request #1373 from obscuren/recovery-tools
core, cmd/geth: improved recover functionality
2015-07-01 08:09:33 -07:00
70d5d791cc core, cmd/geth: improved recover functionality
`geth recover` now accepts both hashes and numbers using "#" and no
longer requires the ethereum instance.
2015-07-01 16:34:35 +02:00
d6f2c0a76f eth, eth/downloader: fix #1231, DOS vulnerability in hash queueing 2015-07-01 15:21:35 +03:00
bb418a43c1 Merge pull request #1370 from obscuren/force-checkpoint
core, cmd/geth: recover by number
2015-07-01 03:57:13 -07:00
2e5242f9bb Merge pull request #1355 from Gustav-Simonsson/block_header_ts_uint64
Use uint64 for block header timestamp
2015-07-01 03:57:02 -07:00
1ae80aaf64 eth: fix #1371, double lock during block/txn known set limitation 2015-07-01 11:12:05 +03:00
41de1cb723 added pipelining support 2015-07-01 08:23:17 +02:00
29ab1fa8a5 core, cmd/geth: recover by number 2015-07-01 00:52:44 +02:00
60454da650 eth/downloader: reduce hash fetches in prep for eth/61 2015-07-01 01:20:49 +03:00
cb2c10d862 Merge pull request #1366 from ethers/rpcRequest
fix logging jsonrpc request #1365
2015-06-30 12:17:59 -07:00
d05305473e fix logging jsonrpc request #1365 2015-06-30 12:14:16 -07:00
be935bff84 Merge pull request #1363 from obscuren/safeguard
core: added checkpoint for last block
2015-06-30 09:25:10 -07:00
f43c07cb3c eth, eth/downloader: transition to eth 61 2015-06-30 19:05:06 +03:00
af51dc4d63 eth, eth/downloader: pass the eth protocol version through 2015-06-30 19:00:01 +03:00
aac2b6ae4c eth: add the blocks from numbers protocol message 2015-06-30 19:00:01 +03:00
5db8f447d5 eth: fix #1319, put an upper limit on the known txns and blocks 2015-06-30 19:00:01 +03:00
6fc85f1ec2 eth: clean up peer struct a bit, fix double txn bcast 2015-06-30 19:00:01 +03:00
2c8ed76e01 eth: start cleaning up old protocol implementation, add metrics 2015-06-30 19:00:00 +03:00
393d675690 cmd/geth, cmd/utils, eth: advertise both eth/60 and eth/61 2015-06-30 19:00:00 +03:00
a748afce03 core: txpool listen for ChainHeadEvent instead of ChainEvent
Changed the transaction pool to listen for ChainHeadEvent when resetting
the state instead of ChainEvent. It makes very little sense to burst
through transactions while we are catching up (e.g., have more than one
block to process)
2015-06-30 17:27:47 +02:00
c14f0a4471 core: added checkpoint for last block
* Add a checkpoint every X blocks
* Removed queued write
2015-06-30 17:27:47 +02:00
ba95e445e1 Merge pull request #1328 from bas-vk/issue1327
Add pendingTransactions and resend
2015-06-30 08:27:03 -07:00
8c4d493c66 solved merge conflicts 2015-06-30 15:32:02 +02:00
a5d5387dee rebase with develop 2015-06-30 15:27:27 +02:00
130f3b270a Merge pull request #1362 from obscuren/txpool-cleanup
core: reduce CPU load by reducing calls to checkQueue
2015-06-30 05:18:51 -07:00
61ca780f3b core: reduce CPU load by reducing calls to checkQueue
* Reduced maxQueue count
* Added proper deletion past maxQueue limit
* Added cheap stats method to txpool

queueCheck was called for **every** transaction instead of:
1. add all txs
2. check queue

previously

1. add txs[i]
2. check queue
3. if i < len(txs) goto 1.
2015-06-30 14:01:12 +02:00
57dff6f1d7 initialize fields to prevent nil pointer exception 2015-06-30 11:20:31 +02:00
7ffabf1d39 add json parsing method for resend transaction 2015-06-30 11:20:31 +02:00
6fdddc5ac9 improved error handling in parsing request 2015-06-30 11:20:31 +02:00
02c6af66bf fixed unittest compilation issue 2015-06-30 11:20:31 +02:00
ec866b066a added eth.resend 2015-06-30 11:20:31 +02:00
056e9dd393 added eth.pendingTransactions 2015-06-30 11:20:31 +02:00
9226369b5d Merge branch 'hotfix/0.9.34-1' into develop 2015-06-30 11:15:08 +02:00
a2ce7b9950 Merge branch 'hotfix/0.9.34-1' 2015-06-30 11:14:59 +02:00
d8fe64acaa core, miner: added queued write to WriteBlock
This fixes an issue with the lru cache not being available when calling
WriteBlock. WriteBlock previously always assumed to be called from the
InsertChain where the lru cache was always created prior to calling
WriteBlock. When being called from the worker this could lead in to a
nil pointer exception being thrown and causing database corruption.
2015-06-30 11:14:43 +02:00
4c490db6af Use uint64 for block header timestamp 2015-06-30 10:52:11 +02:00
b047f05e7e cmd/geth: version bump 0.9.35 2015-06-30 02:30:26 +02:00
8d016ced6b Merge branch 'release/0.9.34' into develop 2015-06-30 02:22:40 +02:00
7625b07dd9 Merge branch 'release/0.9.34' 2015-06-30 02:22:19 +02:00
8f504063f4 cmd/geth: version bump 0.9.34 2015-06-30 02:11:54 +02:00
e896cab82c Merge pull request #1360 from obscuren/peter-metrics
Rebased peter's PR
2015-06-29 16:58:49 -07:00
5f3792c2a7 cmd/geth: decent error message if metrics are disabled 2015-06-30 00:57:55 +02:00
01fe972113 cmd, core, eth, metrics, p2p: require enabling metrics 2015-06-30 00:51:46 +02:00
ccbb56b4f2 cmd/geth, eth, ethdb: monitor database compactions 2015-06-30 00:51:29 +02:00
2aeeb72fa5 cmd/geth, metrics: separate process metric collection, add disk 2015-06-30 00:51:02 +02:00
7c4ed8055c Merge pull request #1357 from obscuren/core-optimisations-2
core: optimisations
2015-06-29 15:44:23 -07:00
992e4f83cb core: replaced BlockCache with lru.Cache 2015-06-30 00:36:25 +02:00
a8ebf756c7 Merge branch 'miner-broadcast' into core-optimisations-2
Conflicts:
	core/chain_manager.go
	miner/worker.go
2015-06-29 18:55:49 +02:00
5d9df7348d gpo non-existent block checks 2015-06-29 18:53:04 +02:00
ac80ec59dc miner: update root only when mining 2015-06-29 18:51:49 +02:00
e349fac97d core: fixed tests 2015-06-29 18:51:49 +02:00
aba901e13c core: removed write's go routine 2015-06-29 18:51:49 +02:00
07db098ccf core: renamed next to pending & fixed tests 2015-06-29 18:51:49 +02:00
855e76fddd core: reduced cache limit to 256 2015-06-29 18:51:49 +02:00
4d11747836 deps: Added golang-lru 2015-06-29 18:51:49 +02:00
6ca3a44638 core: switched to proper LRU 2015-06-29 18:51:49 +02:00
4460dc9d1a core: added LRU caching and added batch writing when LDB is used 2015-06-29 18:51:49 +02:00
2a5a55efaf ethdb: accessor for LDB. TODO remove this interface 2015-06-29 18:51:48 +02:00
c850c41ec1 trie: Implemented a batch write approach for flushing 2015-06-29 18:51:48 +02:00
76821d167a core, eth, rpc: avoid unnecessary block header copying 2015-06-29 18:51:48 +02:00
fccc7d71eb core: remove superfluous big.Int allocations
With blocks now being immutable, use big.Int values from
accessor functions instead of copying their results.
2015-06-29 18:51:48 +02:00
d0bb90c69e core: generate benchmark keys only once 2015-06-29 18:51:48 +02:00
992dc74efd core: avoid duplicate calls to Transaction.Data 2015-06-29 18:51:48 +02:00
0b22ad99c1 core: optimize IntrinsicGas 2015-06-29 18:51:48 +02:00
a8889b092b core/types: cache computed block values 2015-06-29 18:51:48 +02:00
11b8d1df59 core/types: cache computed transaction values 2015-06-29 18:51:48 +02:00
8743cc1c1c rlp: add ListSize 2015-06-29 18:51:48 +02:00
a0566c1058 rlp: remove Flat 2015-06-29 18:51:47 +02:00
3d0c6a8345 rlp: pool encoder allocations 2015-06-29 18:51:47 +02:00
c3d6228023 core: add InsertChain benchmarks 2015-06-29 18:51:47 +02:00
7098ec691c rpc: unmask pending block fields
This pleases the RPC tests.
2015-06-29 18:51:47 +02:00
e0e5f74776 eth/downloader, eth/fetcher: use core.GenerateChain in tests
TestMadeupParentBlockChainAttack has been deleted because it was too
hard to port and the attack that it checks the prevention of is being
averted in a different way (through a protocol change).
2015-06-29 18:51:47 +02:00
ceaf1c080b core: add GenerateChain, GenesisBlockForTesting 2015-06-29 18:51:47 +02:00
1d42888d30 core/types: make blocks immutable 2015-06-29 18:51:47 +02:00
654564e164 core/types: make transactions immutable 2015-06-29 18:51:47 +02:00
9d8b512b27 Merge pull request #1356 from Gustav-Simonsson/debug_develop
Debug develop
2015-06-29 09:33:19 -07:00
b39042db56 core, miner: implemented canary 2015-06-29 13:31:49 +02:00
d1e93db3eb core, miner: added write block method & changed mining propagation 2015-06-29 13:31:49 +02:00
059a1e9e4e miner: broadcast block before insertion/validation 2015-06-29 13:31:49 +02:00
5e7db8f5cd Merge pull request #1353 from karalabe/fix-double-fetch
eth/fetcher: don't double filter/fetch the same block
2015-06-29 04:31:13 -07:00
a7d22658ad eth/fetcher: don't drop on future blocks, just not propagate 2015-06-29 14:20:13 +03:00
29d53b2073 eth/fetcher: don't double filter/fetch the same block 2015-06-29 13:49:04 +03:00
61ccc39b56 initialize fields to prevent nil pointer exception 2015-06-29 12:42:47 +02:00
f9264e87ec add json parsing method for resend transaction 2015-06-29 12:32:01 +02:00
a355777ff8 improved error handling in parsing request 2015-06-29 11:13:28 +02:00
a0191910fc Merge pull request #1341 from karalabe/proto-version-negotiation
p2p: support protocol version negotiation
2015-06-28 13:52:37 +02:00
b9ebdffd83 Merge pull request #1335 from tgerring/mistcleanup
Travis and README cleanup
2015-06-27 02:17:35 -07:00
1169ec7681 Merge pull request #1344 from karalabe/monitor-fixes
Monitor fixes
2015-06-27 02:16:12 -07:00
d099a42c85 cmd/geth: fix monitor panic, don't pre-fill with dummy data 2015-06-26 22:05:49 +03:00
7e69392249 cmd/geth: re-scale charts when changing unit magnitudes 2015-06-26 21:48:21 +03:00
216fc267fa p2p: fix local/remote cap/protocol mixup 2015-06-26 20:45:13 +03:00
d84638bd31 p2p: support protocol version negotiation 2015-06-26 15:48:50 +03:00
b0a5be4495 Merge pull request #1321 from karalabe/cut-it-open-3000
Metrics collecting and reporting support
2015-06-25 08:18:42 -07:00
e64625aa82 Merge pull request #1332 from bas-vk/ipcbatch
IPC interface improvements
2015-06-25 08:06:19 -07:00
c6dbe9dc07 Travis and README cleanup 2015-06-25 16:46:54 +02:00
662285074e improved logging for IPC connection lifetime management 2015-06-25 15:54:16 +02:00
e9c0b5431c cmd/geth: finalize mem stats 2015-06-25 16:19:42 +03:00
fdbf8be735 cmd/geth, rpc/api: fix reported metrics issues 2015-06-25 15:33:26 +03:00
5757a0edb5 added IPC timeout support 2015-06-25 14:32:22 +02:00
04910c902a support for large request/response on windows 2015-06-25 04:53:41 -07:00
ffbe5656ff support for large requests/responses 2015-06-25 13:18:10 +02:00
c0343c8f17 cmd/geth: add memory stat collection too 2015-06-25 13:47:06 +03:00
6d92fdc0df added support for batch requests 2015-06-25 12:01:28 +02:00
6b2a03faa2 Merge pull request #1085 from Gustav-Simonsson/key_store_v3
crypto: key store v3
2015-06-25 02:16:54 -07:00
c6e2af14c0 cmd/geth: limit the maximum chart colums to 6 2015-06-25 12:12:11 +03:00
8774fdcd64 Merge pull request #1329 from Gustav-Simonsson/ethash_input_validations
Update Ethash Godeps
2015-06-25 02:06:06 -07:00
3ea6b5ae32 cmd/geth: list the available metrics if none specified 2015-06-25 11:42:45 +03:00
d02f07a983 cmd/geth: polish monitor visuals, add footer, refresh flag 2015-06-25 11:32:21 +03:00
b98b444179 cmd/geth: add attach and rows flags to the monitor command 2015-06-25 10:36:47 +03:00
1ce40d7581 Godeps: remove mist remnants, add termui deps 2015-06-24 18:40:18 +03:00
92ef33d97a rpc/api, cmd/geth: retrievel all percentiles, add time units 2015-06-24 18:34:05 +03:00
302187ae39 cmd/geth: allow branching metric patterns 2015-06-24 18:34:05 +03:00
bf99d5b33c cmd/geth: polish the monitoring charts a bit 2015-06-24 18:34:05 +03:00
e5b820c47b cmd/geth, rpc/api: extend metrics API, add a basic monitor command 2015-06-24 18:34:05 +03:00
bde2ff0343 cmd/geth, rpc/api: move the metrics into the new console 2015-06-24 18:34:05 +03:00
803b3c4a82 eth, ethdb: measure database operation latencies too 2015-06-24 18:34:05 +03:00
0609fcf030 eth: make sure dbs are lvldb before instrumenting 2015-06-24 18:34:04 +03:00
792b0ddccd core, eth, eth/fetcher, ethdb: polish metrics gathering a bit 2015-06-24 18:34:04 +03:00
6260b86c15 eth/fetcher: fix failed merge 2015-06-24 18:34:04 +03:00
43e4a6501b core, ethdb: instrument the block and state db
Conflicts:
	ethdb/database.go
2015-06-24 18:34:04 +03:00
7bd71fa800 godeps: pull in go-metrics 2015-06-24 18:34:04 +03:00
7f92e708c5 cmd/geth, core: impl. percentile reporting, instrument insertions 2015-06-24 18:34:04 +03:00
b426301467 cmd/geth, eth/fetcher: polish metrics reporting, add some more 2015-06-24 18:34:04 +03:00
6994a3daaa p2p: instrument P2P networking layer 2015-06-24 18:33:33 +03:00
821e01b013 cmd/geth, eth/fetcher: initial metrics support
Conflicts:
	cmd/geth/admin.go
2015-06-24 18:33:33 +03:00
ee73f09727 fixed unittest compilation issue 2015-06-24 16:07:44 +02:00
dc58568a25 added eth.resend 2015-06-24 14:56:53 +02:00
f1a4a6e563 added eth.pendingTransactions 2015-06-24 13:53:37 +02:00
8363aba7ac Update Ethash Godeps 2015-06-24 07:17:21 +02:00
d23ec6c419 Change keystore to version 3
* Change password protection crypto in keystore to version 3
* Update KeyStoreTests/basic_tests.json
* Add support for PBKDF2 with HMAC-SHA256
* Change MAC and encryption key to avoid unnecessary hashing
* Add tests for test vectors in new wiki page defining version 3
* Add tests for new keystore tests in ethereum/tests repo
* Move JSON loading util to common for use in both tests and
  crypto packages
* Add backwards compatibility with key store version 1
2015-06-24 06:03:23 +02:00
22c7ce0162 cmd/geth: version bump 0.9.33 2015-06-23 19:20:20 +02:00
983a33cf11 Merge branch 'release/0.9.32' into develop 2015-06-23 19:19:49 +02:00
72e2613a9f Merge branch 'release/0.9.32' 2015-06-23 19:19:33 +02:00
67e6f74e9a cmd/geth: bump 2015-06-23 19:11:20 +02:00
d21c2bfb68 Merge pull request #1314 from karalabe/handle-fetcher-attacks-2
eth/fetcher: handle and test various DOS attacks
2015-06-23 10:04:44 -07:00
6b5532ab0d Merge pull request #1279 from bas-vk/rpc-http
Integrate console and remove old rpc package structure
2015-06-23 07:44:03 -07:00
139439dcdc Merge pull request #1309 from fjl/p2p-fix-lookup-spin
p2p: throttle all discovery lookups
2015-06-23 05:36:58 -07:00
2b3957f373 fixed relative path issue with javascript files 2015-06-23 09:38:30 +02:00
55424a11af improved action description 2015-06-23 09:11:57 +02:00
57c911c398 bugfix in startRPC error handling 2015-06-23 08:26:17 +02:00
3ce17d2862 eth/fetcher: fix a closure data race 2015-06-22 20:13:18 +03:00
99ca4b619b eth/fetcher: clean up test assertions 2015-06-22 18:28:38 +03:00
b53f701c27 eth/fetcher: remove test sleeps (15s -> 2.8s) 2015-06-22 18:08:28 +03:00
1989d1491a eth/fetcher: handle and (crude) test block memory DOS 2015-06-22 16:49:47 +03:00
4ee7f6fc88 added missing change for sign test 2015-06-22 13:54:13 +02:00
6d596b1ad1 fixed eth sign unittest 2015-06-22 13:19:59 +02:00
d36c25bcbc eth/fetcher: handle and test block announce DOS attacks 2015-06-22 14:07:08 +03:00
2e0b56a72b added RPC start/stop support 2015-06-22 12:47:32 +02:00
2737baa657 fixed unittests 2015-06-22 09:17:09 +02:00
f87501b1c5 added batch support to console and attach actions 2015-06-22 09:17:09 +02:00
3ff272b618 moved solidity test to new rpc structure 2015-06-22 09:17:09 +02:00
29297d3b82 fixed bug where history file was create in cwd 2015-06-22 09:17:09 +02:00
ce5c94e471 added attach over http/rpc support 2015-06-22 09:17:09 +02:00
f202563777 added attach over ipc command 2015-06-22 09:17:09 +02:00
36a6b16a3b removed console command 2015-06-22 09:17:09 +02:00
603192cfa7 cleanup comments/code 2015-06-22 09:17:09 +02:00
a4a4e9fcf8 removed old rpc structure and added new inproc api client 2015-06-22 09:17:09 +02:00
3e1d635f8d fixed rpc test failure in eth.blockNumber 2015-06-22 08:54:21 +02:00
9ac1b4e59e fixed rpc test failure in net_peerCount 2015-06-22 08:54:21 +02:00
5fdf72b1ab fixed web3 rpc test failures 2015-06-22 08:54:21 +02:00
c3f6c322c0 added DB api 2015-06-22 08:54:21 +02:00
5c25403b13 refactored old rpc structure to new 2015-06-22 08:54:21 +02:00
fd764d4ff7 added comms http 2015-06-22 08:54:21 +02:00
60c2ccd99c made ipc handler generic and reusable 2015-06-22 08:54:21 +02:00
9cf7913c61 Merge pull request #1304 from obscuren/state-renames
core, miner, xeth: renamed gas methods
2015-06-21 16:49:47 -07:00
7633dfdc08 Merge pull request #1305 from obscuren/database-error-check
core, ethdb, trie: validate database errors
2015-06-21 16:49:14 -07:00
6fb810adaa p2p: throttle all discovery lookups
Lookup calls would spin out of control when network connectivity was
lost. The throttling that was in place only took effect when the table
returned zero results, which doesn't happen very often.

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

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

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

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

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

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

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

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

Why not just check the coinbase? This log is useful if you're running
multiple miners and want to know if *this* miner is performing well.
2015-05-22 12:53:32 -07:00
b2b9b3b567 Merge pull request #1077 from obscuren/disasm
core/vm, rpc: added disasm to `ext_` RPC
2015-05-22 06:51:38 -07:00
7381be8edb core/vm, rpc: added disasm to ext_ RPC 2015-05-22 15:38:46 +02:00
f7415c0bbc Merge pull request #1076 from obscuren/rpc_sign
core: added RPC sign back in
2015-05-22 04:08:51 -07:00
6539ccae7c core: added RPC sign back in 2015-05-22 13:00:04 +02:00
01ddaf5670 Merge pull request #1072 from Gustav-Simonsson/add_random_tests
Add StateTests/RandomTests and VMTests/RandomTests
2015-05-22 02:34:48 -07:00
f5e112ae5a Merge pull request #1074 from bas-vk/issue1068
make registrar available in console
2015-05-22 02:22:49 -07:00
821b578f7e make registrar available in console 2015-05-22 09:13:45 +02:00
6ad817e17b Add StateTests/RandomTests and VMTests/RandomTests 2015-05-21 23:04:46 +02:00
13e662f6de Merge branch 'develop' 2015-05-21 19:53:35 +02:00
054abe20b8 miner: moved break INSIDE the switch ... 2015-05-21 19:53:27 +02:00
8c25a83708 Merge branch 'release/0.9.23' into develop 2015-05-21 18:59:26 +02:00
cbd3ae6906 p2p/discover: fix #838, evacuate self entries from the node db 2015-05-21 19:41:46 +03:00
af24c271c7 p2p/discover: fix database presistency test folder 2015-05-21 19:28:10 +03:00
1229 changed files with 180794 additions and 414083 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@ -11,4 +11,51 @@ Nick Savers <nicksavers@gmail.com>
Maran Hidskes <maran.hidskes@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com> <taylor.gerring@ethereum.org>
Bas van Kervel <bas@ethdev.com>
Bas van Kervel <bas@ethdev.com> <basvankervel@ziggo.nl>
Bas van Kervel <bas@ethdev.com> <basvankervel@gmail.com>
Sven Ehlert <sven@ethdev.com>
Vitalik Buterin <v@buterin.com>
Marian Oancea <contact@siteshop.ro>
Christoph Jentzsch <jentzsch.software@gmail.com>
Heiko Hees <heiko@heiko.org>
Alex Leverington <alex@ethdev.com>
Alex Leverington <alex@ethdev.com> <subtly@users.noreply.github.com>
Zsolt Felföldi <zsfelfoldi@gmail.com>
Gavin Wood <i@gavwood.com>
Martin Becze <mjbecze@gmail.com>
Martin Becze <mjbecze@gmail.com> <wanderer@users.noreply.github.com>
Dimitry Khokhlov <winsvega@mail.ru>
Roman Mandeleil <roman.mandeleil@gmail.com>
Alec Perseghin <aperseghin@gmail.com>
Alon Muroch <alonmuroch@gmail.com>
Arkadiy Paronyan <arkadiy@ethdev.com>
Jae Kwon <jkwon.work@gmail.com>
Aaron Kumavis <kumavis@users.noreply.github.com>
Nick Dodson <silentcicero@outlook.com>
Jason Carver <jacarver@linkedin.com>
Jason Carver <jacarver@linkedin.com> <ut96caarrs@snkmail.com>
Joseph Chow <ethereum@outlook.com>
Joseph Chow <ethereum@outlook.com> ethers <TODO>

View File

@ -1,15 +1,11 @@
language: go
go:
- 1.4.2
before_install:
- sudo add-apt-repository ppa:beineri/opt-qt541 -y
- sudo apt-get update -qq
- sudo apt-get install -yqq libgmp3-dev qt54quickcontrols qt54webengine
install:
# - go get code.google.com/p/go.tools/cmd/goimports
# - go get github.com/golang/lint/golint
# - go get golang.org/x/tools/cmd/vet
- go get golang.org/x/tools/cmd/cover github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
before_script:
# - gofmt -l -w .
# - goimports -l -w .
@ -19,17 +15,19 @@ before_script:
script:
- make travis-test-with-coverage
after_success:
- if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
- bash <(curl -s https://codecov.io/bash)
env:
global:
- PKG_CONFIG_PATH=/opt/qt54/lib/pkgconfig
- LD_LIBRARY_PATH=/opt/qt54/lib
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
sudo: false
addons:
apt:
packages:
- libgmp3-dev
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false
on_success: change
on_failure: always
on_start: false

24
AUTHORS Normal file
View File

@ -0,0 +1,24 @@
# This is the official list of go-ethereum authors for copyright purposes.
Alex Leverington <alex@ethdev.com>
Alexandre Van de Sande <alex.vandesande@ethdev.com>
Bas van Kervel <bas@ethdev.com>
Daniel A. Nagy <nagy.da@gmail.com>
Ethan Buchman <ethan@coinculture.info>
Fabian Vogelsteller <fabian@frozeman.de>
Felix Lange <fjl@twurst.com>
Gustav Simonsson <gustav.simonsson@gmail.com>
Jae Kwon <jkwon.work@gmail.com>
Jason Carver <jacarver@linkedin.com>
Jeffrey Wilcke <jeffrey@ethereum.org>
Joseph Chow <ethereum@outlook.com>
Kobi Gurkan <kobigurk@gmail.com>
Maran Hidskes <maran.hidskes@gmail.com>
Marek Kotewicz <marek.kotewicz@gmail.com>
Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
Nick Dodson <silentcicero@outlook.com>
Péter Szilágyi <peterke@gmail.com>
Taylor Gerring <taylor.gerring@gmail.com>
Viktor Trón <viktor.tron@gmail.com>
Vitalik Buterin <v@buterin.com>
Zsolt Felföldi <zsfelfoldi@gmail.com>

9
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,9 @@
If you'd like to contribute to go-ethereum please fork, fix, commit and
send a pull request. Commits who do not comply with the coding standards
are ignored (use gofmt!). 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.
See [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
for more details on configuring your environment, testing, and
dependency management.

619
COPYING Normal file
View File

@ -0,0 +1,619 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2014 The go-ethereum Authors.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

View File

@ -1,23 +1,3 @@
This software is licensed under the LGPLv3, included below.
As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.
Except as stated in this special exception, the provisions of LGPL3 will
continue to comply in full to this Library. If you modify this Library, you
may apply this exception to your version of this Library, but you are not
obliged to do so. If you do not wish to do so, delete this exception
statement from your version. This exception does not (and cannot) modify any
license terms which apply to the Application, with which you must still
comply.
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

74
Godeps/Godeps.json generated
View File

@ -1,33 +1,40 @@
{
"ImportPath": "github.com/ethereum/go-ethereum",
"GoVersion": "go1.4.2",
"GoVersion": "go1.4",
"Packages": [
"./..."
],
"Deps": [
{
"ImportPath": "code.google.com/p/go-uuid/uuid",
"Comment": "null-12",
"Rev": "7dda39b2e7d5e265014674c5af696ba4186679e9"
"ImportPath": "github.com/codegangsta/cli",
"Comment": "1.2.0-161-gf445c89",
"Rev": "f445c894402839580d30de47551cedc152dad814"
},
{
"ImportPath": "github.com/codegangsta/cli",
"Comment": "1.2.0-95-g9b2bd2b",
"Rev": "9b2bd2b3489748d4d0a204fa4eb2ee9e89e0ebc6"
"ImportPath": "github.com/davecgh/go-spew/spew",
"Rev": "3e6e67c4dcea3ac2f25fd4731abc0e1deaf36216"
},
{
"ImportPath": "github.com/ethereum/ethash",
"Comment": "v23.1-206-gf0e6321",
"Rev": "f0e63218b721dc2f696920a92d5de1f6364e9bf7"
"Comment": "v23.1-238-g9401881",
"Rev": "9401881ab040d1a3b0ae9e4780a115bc284a8a1a"
},
{
"ImportPath": "github.com/howeyc/fsnotify",
"Comment": "v0.9.0-11-g6b1ef89",
"Rev": "6b1ef893dc11e0447abda6da20a5203481878dda"
"ImportPath": "github.com/fatih/color",
"Comment": "v0.1-5-gf773d4c",
"Rev": "f773d4c806cc8e4a5749d6a35e2a4bbcd71443d6"
},
{
"ImportPath": "github.com/gizak/termui",
"Rev": "bab8dce01c193d82bc04888a0a9a7814d505f532"
},
{
"ImportPath": "github.com/hashicorp/golang-lru",
"Rev": "7f9ef20a0256f494e24126014135cf893ab71e9e"
},
{
"ImportPath": "github.com/huin/goupnp",
"Rev": "c57ae84388ab59076fd547f1abeab71c2edb0a21"
"Rev": "90f71cb5dd6d4606388666d2cda4ce2f563d2185"
},
{
"ImportPath": "github.com/jackpal/go-nat-pmp",
@ -37,29 +44,30 @@
"ImportPath": "github.com/kardianos/osext",
"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a"
},
{
"ImportPath": "github.com/mattn/go-colorable",
"Rev": "043ae16291351db8465272edf465c9f388161627"
},
{
"ImportPath": "github.com/mattn/go-isatty",
"Rev": "fdbe02a1b44e75977b2690062b83cf507d70c013"
"Rev": "7fcbc72f853b92b5720db4a6b8482be612daef24"
},
{
"ImportPath": "github.com/obscuren/qml",
"Rev": "c288002b52e905973b131089a8a7c761d4a2c36a"
"ImportPath": "github.com/mattn/go-runewidth",
"Comment": "travisish-33-g5890272",
"Rev": "5890272cd41c5103531cd7b79e428d99c9e97f76"
},
{
"ImportPath": "github.com/nsf/termbox-go",
"Rev": "675ffd907b7401b8a709a5ef2249978af5616bb2"
},
{
"ImportPath": "github.com/pborman/uuid",
"Rev": "cccd189d45f7ac3368a0d127efb7f4d08ae0b655"
},
{
"ImportPath": "github.com/peterh/liner",
"Rev": "29f6a646557d83e2b6e9ba05c45fbea9c006dbe8"
},
{
"ImportPath": "github.com/rakyll/globalconf",
"Rev": "415abc325023f1a00cd2d9fa512e0e71745791a2"
},
{
"ImportPath": "github.com/rakyll/goini",
"Rev": "907cca0f578a5316fb864ec6992dc3d9730ec58c"
"ImportPath": "github.com/rcrowley/go-metrics",
"Rev": "a5cfc242a56ba7fa70b785f678d6214837bf93b9"
},
{
"ImportPath": "github.com/robertkrimen/otto",
@ -69,6 +77,10 @@
"ImportPath": "github.com/rs/cors",
"Rev": "6e0c3cb65fc0fdb064c743d176a620e3ca446dfb"
},
{
"ImportPath": "github.com/shiena/ansicolor",
"Rev": "a5e2b567a4dd6cc74545b8a4f27c9d63b9e7735b"
},
{
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
"Rev": "4875955338b0a434238a31165cb87255ab6e9e4a"
@ -112,15 +124,7 @@
},
{
"ImportPath": "gopkg.in/karalabe/cookiejar.v2/collections/prque",
"Rev": "0b2e270613f5d7ba262a5749b9e32270131497a2"
},
{
"ImportPath": "gopkg.in/qml.v1/cdata",
"Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
},
{
"ImportPath": "gopkg.in/qml.v1/gl/glbase",
"Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
"Rev": "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57"
}
]
}

View File

@ -0,0 +1,26 @@
/*
Package cl provides a binding to the OpenCL api. It's mostly a low-level
wrapper that avoids adding functionality while still making the interface
a little more friendly and easy to use.
Resource life-cycle management:
For any CL object that gets created (buffer, queue, kernel, etc..) you should
call object.Release() when finished with it to free the CL resources. This
explicitely calls the related clXXXRelease method for the type. However,
as a fallback there is a finalizer set for every resource item that takes
care of it (eventually) if Release isn't called. In this way you can have
better control over the life cycle of resources while having a fall back
to avoid leaks. This is similar to how file handles and such are handled
in the Go standard packages.
*/
package cl
// #include "headers/1.2/opencl.h"
// #cgo CFLAGS: -Iheaders/1.2
// #cgo darwin LDFLAGS: -framework OpenCL
// #cgo linux LDFLAGS: -lOpenCL
import "C"
import "errors"
var ErrUnsupported = errors.New("cl: unsupported")

View File

@ -0,0 +1,254 @@
package cl
import (
"math/rand"
"reflect"
"strings"
"testing"
)
var kernelSource = `
__kernel void square(
__global float* input,
__global float* output,
const unsigned int count)
{
int i = get_global_id(0);
if(i < count)
output[i] = input[i] * input[i];
}
`
func getObjectStrings(object interface{}) map[string]string {
v := reflect.ValueOf(object)
t := reflect.TypeOf(object)
strs := make(map[string]string)
numMethods := t.NumMethod()
for i := 0; i < numMethods; i++ {
method := t.Method(i)
if method.Type.NumIn() == 1 && method.Type.NumOut() == 1 && method.Type.Out(0).Kind() == reflect.String {
// this is a string-returning method with (presumably) only a pointer receiver parameter
// call it
outs := v.Method(i).Call([]reflect.Value{})
// put the result in our map
strs[method.Name] = (outs[0].Interface()).(string)
}
}
return strs
}
func TestPlatformStringsContainNoNULs(t *testing.T) {
platforms, err := GetPlatforms()
if err != nil {
t.Fatalf("Failed to get platforms: %+v", err)
}
for _, p := range platforms {
for key, value := range getObjectStrings(p) {
if strings.Contains(value, "\x00") {
t.Fatalf("platform string %q = %+q contains NUL", key, value)
}
}
}
}
func TestDeviceStringsContainNoNULs(t *testing.T) {
platforms, err := GetPlatforms()
if err != nil {
t.Fatalf("Failed to get platforms: %+v", err)
}
for _, p := range platforms {
devs, err := p.GetDevices(DeviceTypeAll)
if err != nil {
t.Fatalf("Failed to get devices for platform %q: %+v", p.Name(), err)
}
for _, d := range devs {
for key, value := range getObjectStrings(d) {
if strings.Contains(value, "\x00") {
t.Fatalf("device string %q = %+q contains NUL", key, value)
}
}
}
}
}
func TestHello(t *testing.T) {
var data [1024]float32
for i := 0; i < len(data); i++ {
data[i] = rand.Float32()
}
platforms, err := GetPlatforms()
if err != nil {
t.Fatalf("Failed to get platforms: %+v", err)
}
for i, p := range platforms {
t.Logf("Platform %d:", i)
t.Logf(" Name: %s", p.Name())
t.Logf(" Vendor: %s", p.Vendor())
t.Logf(" Profile: %s", p.Profile())
t.Logf(" Version: %s", p.Version())
t.Logf(" Extensions: %s", p.Extensions())
}
platform := platforms[0]
devices, err := platform.GetDevices(DeviceTypeAll)
if err != nil {
t.Fatalf("Failed to get devices: %+v", err)
}
if len(devices) == 0 {
t.Fatalf("GetDevices returned no devices")
}
deviceIndex := -1
for i, d := range devices {
if deviceIndex < 0 && d.Type() == DeviceTypeGPU {
deviceIndex = i
}
t.Logf("Device %d (%s): %s", i, d.Type(), d.Name())
t.Logf(" Address Bits: %d", d.AddressBits())
t.Logf(" Available: %+v", d.Available())
// t.Logf(" Built-In Kernels: %s", d.BuiltInKernels())
t.Logf(" Compiler Available: %+v", d.CompilerAvailable())
t.Logf(" Double FP Config: %s", d.DoubleFPConfig())
t.Logf(" Driver Version: %s", d.DriverVersion())
t.Logf(" Error Correction Supported: %+v", d.ErrorCorrectionSupport())
t.Logf(" Execution Capabilities: %s", d.ExecutionCapabilities())
t.Logf(" Extensions: %s", d.Extensions())
t.Logf(" Global Memory Cache Type: %s", d.GlobalMemCacheType())
t.Logf(" Global Memory Cacheline Size: %d KB", d.GlobalMemCachelineSize()/1024)
t.Logf(" Global Memory Size: %d MB", d.GlobalMemSize()/(1024*1024))
t.Logf(" Half FP Config: %s", d.HalfFPConfig())
t.Logf(" Host Unified Memory: %+v", d.HostUnifiedMemory())
t.Logf(" Image Support: %+v", d.ImageSupport())
t.Logf(" Image2D Max Dimensions: %d x %d", d.Image2DMaxWidth(), d.Image2DMaxHeight())
t.Logf(" Image3D Max Dimenionns: %d x %d x %d", d.Image3DMaxWidth(), d.Image3DMaxHeight(), d.Image3DMaxDepth())
// t.Logf(" Image Max Buffer Size: %d", d.ImageMaxBufferSize())
// t.Logf(" Image Max Array Size: %d", d.ImageMaxArraySize())
// t.Logf(" Linker Available: %+v", d.LinkerAvailable())
t.Logf(" Little Endian: %+v", d.EndianLittle())
t.Logf(" Local Mem Size Size: %d KB", d.LocalMemSize()/1024)
t.Logf(" Local Mem Type: %s", d.LocalMemType())
t.Logf(" Max Clock Frequency: %d", d.MaxClockFrequency())
t.Logf(" Max Compute Units: %d", d.MaxComputeUnits())
t.Logf(" Max Constant Args: %d", d.MaxConstantArgs())
t.Logf(" Max Constant Buffer Size: %d KB", d.MaxConstantBufferSize()/1024)
t.Logf(" Max Mem Alloc Size: %d KB", d.MaxMemAllocSize()/1024)
t.Logf(" Max Parameter Size: %d", d.MaxParameterSize())
t.Logf(" Max Read-Image Args: %d", d.MaxReadImageArgs())
t.Logf(" Max Samplers: %d", d.MaxSamplers())
t.Logf(" Max Work Group Size: %d", d.MaxWorkGroupSize())
t.Logf(" Max Work Item Dimensions: %d", d.MaxWorkItemDimensions())
t.Logf(" Max Work Item Sizes: %d", d.MaxWorkItemSizes())
t.Logf(" Max Write-Image Args: %d", d.MaxWriteImageArgs())
t.Logf(" Memory Base Address Alignment: %d", d.MemBaseAddrAlign())
t.Logf(" Native Vector Width Char: %d", d.NativeVectorWidthChar())
t.Logf(" Native Vector Width Short: %d", d.NativeVectorWidthShort())
t.Logf(" Native Vector Width Int: %d", d.NativeVectorWidthInt())
t.Logf(" Native Vector Width Long: %d", d.NativeVectorWidthLong())
t.Logf(" Native Vector Width Float: %d", d.NativeVectorWidthFloat())
t.Logf(" Native Vector Width Double: %d", d.NativeVectorWidthDouble())
t.Logf(" Native Vector Width Half: %d", d.NativeVectorWidthHalf())
t.Logf(" OpenCL C Version: %s", d.OpenCLCVersion())
// t.Logf(" Parent Device: %+v", d.ParentDevice())
t.Logf(" Profile: %s", d.Profile())
t.Logf(" Profiling Timer Resolution: %d", d.ProfilingTimerResolution())
t.Logf(" Vendor: %s", d.Vendor())
t.Logf(" Version: %s", d.Version())
}
if deviceIndex < 0 {
deviceIndex = 0
}
device := devices[deviceIndex]
t.Logf("Using device %d", deviceIndex)
context, err := CreateContext([]*Device{device})
if err != nil {
t.Fatalf("CreateContext failed: %+v", err)
}
// imageFormats, err := context.GetSupportedImageFormats(0, MemObjectTypeImage2D)
// if err != nil {
// t.Fatalf("GetSupportedImageFormats failed: %+v", err)
// }
// t.Logf("Supported image formats: %+v", imageFormats)
queue, err := context.CreateCommandQueue(device, 0)
if err != nil {
t.Fatalf("CreateCommandQueue failed: %+v", err)
}
program, err := context.CreateProgramWithSource([]string{kernelSource})
if err != nil {
t.Fatalf("CreateProgramWithSource failed: %+v", err)
}
if err := program.BuildProgram(nil, ""); err != nil {
t.Fatalf("BuildProgram failed: %+v", err)
}
kernel, err := program.CreateKernel("square")
if err != nil {
t.Fatalf("CreateKernel failed: %+v", err)
}
for i := 0; i < 3; i++ {
name, err := kernel.ArgName(i)
if err == ErrUnsupported {
break
} else if err != nil {
t.Errorf("GetKernelArgInfo for name failed: %+v", err)
break
} else {
t.Logf("Kernel arg %d: %s", i, name)
}
}
input, err := context.CreateEmptyBuffer(MemReadOnly, 4*len(data))
if err != nil {
t.Fatalf("CreateBuffer failed for input: %+v", err)
}
output, err := context.CreateEmptyBuffer(MemReadOnly, 4*len(data))
if err != nil {
t.Fatalf("CreateBuffer failed for output: %+v", err)
}
if _, err := queue.EnqueueWriteBufferFloat32(input, true, 0, data[:], nil); err != nil {
t.Fatalf("EnqueueWriteBufferFloat32 failed: %+v", err)
}
if err := kernel.SetArgs(input, output, uint32(len(data))); err != nil {
t.Fatalf("SetKernelArgs failed: %+v", err)
}
local, err := kernel.WorkGroupSize(device)
if err != nil {
t.Fatalf("WorkGroupSize failed: %+v", err)
}
t.Logf("Work group size: %d", local)
size, _ := kernel.PreferredWorkGroupSizeMultiple(nil)
t.Logf("Preferred Work Group Size Multiple: %d", size)
global := len(data)
d := len(data) % local
if d != 0 {
global += local - d
}
if _, err := queue.EnqueueNDRangeKernel(kernel, nil, []int{global}, []int{local}, nil); err != nil {
t.Fatalf("EnqueueNDRangeKernel failed: %+v", err)
}
if err := queue.Finish(); err != nil {
t.Fatalf("Finish failed: %+v", err)
}
results := make([]float32, len(data))
if _, err := queue.EnqueueReadBufferFloat32(output, true, 0, results, nil); err != nil {
t.Fatalf("EnqueueReadBufferFloat32 failed: %+v", err)
}
correct := 0
for i, v := range data {
if results[i] == v*v {
correct++
}
}
if correct != len(data) {
t.Fatalf("%d/%d correct values", correct, len(data))
}
}

View File

@ -0,0 +1,161 @@
package cl
// #include <stdlib.h>
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import (
"runtime"
"unsafe"
)
const maxImageFormats = 256
type Context struct {
clContext C.cl_context
devices []*Device
}
type MemObject struct {
clMem C.cl_mem
size int
}
func releaseContext(c *Context) {
if c.clContext != nil {
C.clReleaseContext(c.clContext)
c.clContext = nil
}
}
func releaseMemObject(b *MemObject) {
if b.clMem != nil {
C.clReleaseMemObject(b.clMem)
b.clMem = nil
}
}
func newMemObject(mo C.cl_mem, size int) *MemObject {
memObject := &MemObject{clMem: mo, size: size}
runtime.SetFinalizer(memObject, releaseMemObject)
return memObject
}
func (b *MemObject) Release() {
releaseMemObject(b)
}
// TODO: properties
func CreateContext(devices []*Device) (*Context, error) {
deviceIds := buildDeviceIdList(devices)
var err C.cl_int
clContext := C.clCreateContext(nil, C.cl_uint(len(devices)), &deviceIds[0], nil, nil, &err)
if err != C.CL_SUCCESS {
return nil, toError(err)
}
if clContext == nil {
return nil, ErrUnknown
}
context := &Context{clContext: clContext, devices: devices}
runtime.SetFinalizer(context, releaseContext)
return context, nil
}
func (ctx *Context) GetSupportedImageFormats(flags MemFlag, imageType MemObjectType) ([]ImageFormat, error) {
var formats [maxImageFormats]C.cl_image_format
var nFormats C.cl_uint
if err := C.clGetSupportedImageFormats(ctx.clContext, C.cl_mem_flags(flags), C.cl_mem_object_type(imageType), maxImageFormats, &formats[0], &nFormats); err != C.CL_SUCCESS {
return nil, toError(err)
}
fmts := make([]ImageFormat, nFormats)
for i, f := range formats[:nFormats] {
fmts[i] = ImageFormat{
ChannelOrder: ChannelOrder(f.image_channel_order),
ChannelDataType: ChannelDataType(f.image_channel_data_type),
}
}
return fmts, nil
}
func (ctx *Context) CreateCommandQueue(device *Device, properties CommandQueueProperty) (*CommandQueue, error) {
var err C.cl_int
clQueue := C.clCreateCommandQueue(ctx.clContext, device.id, C.cl_command_queue_properties(properties), &err)
if err != C.CL_SUCCESS {
return nil, toError(err)
}
if clQueue == nil {
return nil, ErrUnknown
}
commandQueue := &CommandQueue{clQueue: clQueue, device: device}
runtime.SetFinalizer(commandQueue, releaseCommandQueue)
return commandQueue, nil
}
func (ctx *Context) CreateProgramWithSource(sources []string) (*Program, error) {
cSources := make([]*C.char, len(sources))
for i, s := range sources {
cs := C.CString(s)
cSources[i] = cs
defer C.free(unsafe.Pointer(cs))
}
var err C.cl_int
clProgram := C.clCreateProgramWithSource(ctx.clContext, C.cl_uint(len(sources)), &cSources[0], nil, &err)
if err != C.CL_SUCCESS {
return nil, toError(err)
}
if clProgram == nil {
return nil, ErrUnknown
}
program := &Program{clProgram: clProgram, devices: ctx.devices}
runtime.SetFinalizer(program, releaseProgram)
return program, nil
}
func (ctx *Context) CreateBufferUnsafe(flags MemFlag, size int, dataPtr unsafe.Pointer) (*MemObject, error) {
var err C.cl_int
clBuffer := C.clCreateBuffer(ctx.clContext, C.cl_mem_flags(flags), C.size_t(size), dataPtr, &err)
if err != C.CL_SUCCESS {
return nil, toError(err)
}
if clBuffer == nil {
return nil, ErrUnknown
}
return newMemObject(clBuffer, size), nil
}
func (ctx *Context) CreateEmptyBuffer(flags MemFlag, size int) (*MemObject, error) {
return ctx.CreateBufferUnsafe(flags, size, nil)
}
func (ctx *Context) CreateEmptyBufferFloat32(flags MemFlag, size int) (*MemObject, error) {
return ctx.CreateBufferUnsafe(flags, 4*size, nil)
}
func (ctx *Context) CreateBuffer(flags MemFlag, data []byte) (*MemObject, error) {
return ctx.CreateBufferUnsafe(flags, len(data), unsafe.Pointer(&data[0]))
}
//float64
func (ctx *Context) CreateBufferFloat32(flags MemFlag, data []float32) (*MemObject, error) {
return ctx.CreateBufferUnsafe(flags, 4*len(data), unsafe.Pointer(&data[0]))
}
func (ctx *Context) CreateUserEvent() (*Event, error) {
var err C.cl_int
clEvent := C.clCreateUserEvent(ctx.clContext, &err)
if err != C.CL_SUCCESS {
return nil, toError(err)
}
return newEvent(clEvent), nil
}
func (ctx *Context) Release() {
releaseContext(ctx)
}
// http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateSubBuffer.html
// func (memObject *MemObject) CreateSubBuffer(flags MemFlag, bufferCreateType BufferCreateType, )

View File

@ -0,0 +1,510 @@
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #include "cl_ext.h"
// #endif
import "C"
import (
"strings"
"unsafe"
)
const maxDeviceCount = 64
type DeviceType uint
const (
DeviceTypeCPU DeviceType = C.CL_DEVICE_TYPE_CPU
DeviceTypeGPU DeviceType = C.CL_DEVICE_TYPE_GPU
DeviceTypeAccelerator DeviceType = C.CL_DEVICE_TYPE_ACCELERATOR
DeviceTypeDefault DeviceType = C.CL_DEVICE_TYPE_DEFAULT
DeviceTypeAll DeviceType = C.CL_DEVICE_TYPE_ALL
)
type FPConfig int
const (
FPConfigDenorm FPConfig = C.CL_FP_DENORM // denorms are supported
FPConfigInfNaN FPConfig = C.CL_FP_INF_NAN // INF and NaNs are supported
FPConfigRoundToNearest FPConfig = C.CL_FP_ROUND_TO_NEAREST // round to nearest even rounding mode supported
FPConfigRoundToZero FPConfig = C.CL_FP_ROUND_TO_ZERO // round to zero rounding mode supported
FPConfigRoundToInf FPConfig = C.CL_FP_ROUND_TO_INF // round to positive and negative infinity rounding modes supported
FPConfigFMA FPConfig = C.CL_FP_FMA // IEEE754-2008 fused multiply-add is supported
FPConfigSoftFloat FPConfig = C.CL_FP_SOFT_FLOAT // Basic floating-point operations (such as addition, subtraction, multiplication) are implemented in software
)
var fpConfigNameMap = map[FPConfig]string{
FPConfigDenorm: "Denorm",
FPConfigInfNaN: "InfNaN",
FPConfigRoundToNearest: "RoundToNearest",
FPConfigRoundToZero: "RoundToZero",
FPConfigRoundToInf: "RoundToInf",
FPConfigFMA: "FMA",
FPConfigSoftFloat: "SoftFloat",
}
func (c FPConfig) String() string {
var parts []string
for bit, name := range fpConfigNameMap {
if c&bit != 0 {
parts = append(parts, name)
}
}
if parts == nil {
return ""
}
return strings.Join(parts, "|")
}
func (dt DeviceType) String() string {
var parts []string
if dt&DeviceTypeCPU != 0 {
parts = append(parts, "CPU")
}
if dt&DeviceTypeGPU != 0 {
parts = append(parts, "GPU")
}
if dt&DeviceTypeAccelerator != 0 {
parts = append(parts, "Accelerator")
}
if dt&DeviceTypeDefault != 0 {
parts = append(parts, "Default")
}
if parts == nil {
parts = append(parts, "None")
}
return strings.Join(parts, "|")
}
type Device struct {
id C.cl_device_id
}
func buildDeviceIdList(devices []*Device) []C.cl_device_id {
deviceIds := make([]C.cl_device_id, len(devices))
for i, d := range devices {
deviceIds[i] = d.id
}
return deviceIds
}
// Obtain the list of devices available on a platform. 'platform' refers
// to the platform returned by GetPlatforms or can be nil. If platform
// is nil, the behavior is implementation-defined.
func GetDevices(platform *Platform, deviceType DeviceType) ([]*Device, error) {
var deviceIds [maxDeviceCount]C.cl_device_id
var numDevices C.cl_uint
var platformId C.cl_platform_id
if platform != nil {
platformId = platform.id
}
if err := C.clGetDeviceIDs(platformId, C.cl_device_type(deviceType), C.cl_uint(maxDeviceCount), &deviceIds[0], &numDevices); err != C.CL_SUCCESS {
return nil, toError(err)
}
if numDevices > maxDeviceCount {
numDevices = maxDeviceCount
}
devices := make([]*Device, numDevices)
for i := 0; i < int(numDevices); i++ {
devices[i] = &Device{id: deviceIds[i]}
}
return devices, nil
}
func (d *Device) nullableId() C.cl_device_id {
if d == nil {
return nil
}
return d.id
}
func (d *Device) GetInfoString(param C.cl_device_info, panicOnError bool) (string, error) {
var strC [1024]C.char
var strN C.size_t
if err := C.clGetDeviceInfo(d.id, param, 1024, unsafe.Pointer(&strC), &strN); err != C.CL_SUCCESS {
if panicOnError {
panic("Should never fail")
}
return "", toError(err)
}
// OpenCL strings are NUL-terminated, and the terminator is included in strN
// Go strings aren't NUL-terminated, so subtract 1 from the length
return C.GoStringN((*C.char)(unsafe.Pointer(&strC)), C.int(strN-1)), nil
}
func (d *Device) getInfoUint(param C.cl_device_info, panicOnError bool) (uint, error) {
var val C.cl_uint
if err := C.clGetDeviceInfo(d.id, param, C.size_t(unsafe.Sizeof(val)), unsafe.Pointer(&val), nil); err != C.CL_SUCCESS {
if panicOnError {
panic("Should never fail")
}
return 0, toError(err)
}
return uint(val), nil
}
func (d *Device) getInfoSize(param C.cl_device_info, panicOnError bool) (int, error) {
var val C.size_t
if err := C.clGetDeviceInfo(d.id, param, C.size_t(unsafe.Sizeof(val)), unsafe.Pointer(&val), nil); err != C.CL_SUCCESS {
if panicOnError {
panic("Should never fail")
}
return 0, toError(err)
}
return int(val), nil
}
func (d *Device) getInfoUlong(param C.cl_device_info, panicOnError bool) (int64, error) {
var val C.cl_ulong
if err := C.clGetDeviceInfo(d.id, param, C.size_t(unsafe.Sizeof(val)), unsafe.Pointer(&val), nil); err != C.CL_SUCCESS {
if panicOnError {
panic("Should never fail")
}
return 0, toError(err)
}
return int64(val), nil
}
func (d *Device) getInfoBool(param C.cl_device_info, panicOnError bool) (bool, error) {
var val C.cl_bool
if err := C.clGetDeviceInfo(d.id, param, C.size_t(unsafe.Sizeof(val)), unsafe.Pointer(&val), nil); err != C.CL_SUCCESS {
if panicOnError {
panic("Should never fail")
}
return false, toError(err)
}
return val == C.CL_TRUE, nil
}
func (d *Device) Name() string {
str, _ := d.GetInfoString(C.CL_DEVICE_NAME, true)
return str
}
func (d *Device) Vendor() string {
str, _ := d.GetInfoString(C.CL_DEVICE_VENDOR, true)
return str
}
func (d *Device) Extensions() string {
str, _ := d.GetInfoString(C.CL_DEVICE_EXTENSIONS, true)
return str
}
func (d *Device) OpenCLCVersion() string {
str, _ := d.GetInfoString(C.CL_DEVICE_OPENCL_C_VERSION, true)
return str
}
func (d *Device) Profile() string {
str, _ := d.GetInfoString(C.CL_DEVICE_PROFILE, true)
return str
}
func (d *Device) Version() string {
str, _ := d.GetInfoString(C.CL_DEVICE_VERSION, true)
return str
}
func (d *Device) DriverVersion() string {
str, _ := d.GetInfoString(C.CL_DRIVER_VERSION, true)
return str
}
// The default compute device address space size specified as an
// unsigned integer value in bits. Currently supported values are 32 or 64 bits.
func (d *Device) AddressBits() int {
val, _ := d.getInfoUint(C.CL_DEVICE_ADDRESS_BITS, true)
return int(val)
}
// Size of global memory cache line in bytes.
func (d *Device) GlobalMemCachelineSize() int {
val, _ := d.getInfoUint(C.CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, true)
return int(val)
}
// Maximum configured clock frequency of the device in MHz.
func (d *Device) MaxClockFrequency() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MAX_CLOCK_FREQUENCY, true)
return int(val)
}
// The number of parallel compute units on the OpenCL device.
// A work-group executes on a single compute unit. The minimum value is 1.
func (d *Device) MaxComputeUnits() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MAX_COMPUTE_UNITS, true)
return int(val)
}
// Max number of arguments declared with the __constant qualifier in a kernel.
// The minimum value is 8 for devices that are not of type CL_DEVICE_TYPE_CUSTOM.
func (d *Device) MaxConstantArgs() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MAX_CONSTANT_ARGS, true)
return int(val)
}
// Max number of simultaneous image objects that can be read by a kernel.
// The minimum value is 128 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) MaxReadImageArgs() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MAX_READ_IMAGE_ARGS, true)
return int(val)
}
// Maximum number of samplers that can be used in a kernel. The minimum
// value is 16 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE. (Also see sampler_t.)
func (d *Device) MaxSamplers() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MAX_SAMPLERS, true)
return int(val)
}
// Maximum dimensions that specify the global and local work-item IDs used
// by the data parallel execution model. (Refer to clEnqueueNDRangeKernel).
// The minimum value is 3 for devices that are not of type CL_DEVICE_TYPE_CUSTOM.
func (d *Device) MaxWorkItemDimensions() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, true)
return int(val)
}
// Max number of simultaneous image objects that can be written to by a
// kernel. The minimum value is 8 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) MaxWriteImageArgs() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MAX_WRITE_IMAGE_ARGS, true)
return int(val)
}
// The minimum value is the size (in bits) of the largest OpenCL built-in
// data type supported by the device (long16 in FULL profile, long16 or
// int16 in EMBEDDED profile) for devices that are not of type CL_DEVICE_TYPE_CUSTOM.
func (d *Device) MemBaseAddrAlign() int {
val, _ := d.getInfoUint(C.CL_DEVICE_MEM_BASE_ADDR_ALIGN, true)
return int(val)
}
func (d *Device) NativeVectorWidthChar() int {
val, _ := d.getInfoUint(C.CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, true)
return int(val)
}
func (d *Device) NativeVectorWidthShort() int {
val, _ := d.getInfoUint(C.CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, true)
return int(val)
}
func (d *Device) NativeVectorWidthInt() int {
val, _ := d.getInfoUint(C.CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, true)
return int(val)
}
func (d *Device) NativeVectorWidthLong() int {
val, _ := d.getInfoUint(C.CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, true)
return int(val)
}
func (d *Device) NativeVectorWidthFloat() int {
val, _ := d.getInfoUint(C.CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, true)
return int(val)
}
func (d *Device) NativeVectorWidthDouble() int {
val, _ := d.getInfoUint(C.CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, true)
return int(val)
}
func (d *Device) NativeVectorWidthHalf() int {
val, _ := d.getInfoUint(C.CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, true)
return int(val)
}
// Max height of 2D image in pixels. The minimum value is 8192
// if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) Image2DMaxHeight() int {
val, _ := d.getInfoSize(C.CL_DEVICE_IMAGE2D_MAX_HEIGHT, true)
return int(val)
}
// Max width of 2D image or 1D image not created from a buffer object in
// pixels. The minimum value is 8192 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) Image2DMaxWidth() int {
val, _ := d.getInfoSize(C.CL_DEVICE_IMAGE2D_MAX_WIDTH, true)
return int(val)
}
// Max depth of 3D image in pixels. The minimum value is 2048 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) Image3DMaxDepth() int {
val, _ := d.getInfoSize(C.CL_DEVICE_IMAGE3D_MAX_DEPTH, true)
return int(val)
}
// Max height of 3D image in pixels. The minimum value is 2048 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) Image3DMaxHeight() int {
val, _ := d.getInfoSize(C.CL_DEVICE_IMAGE3D_MAX_HEIGHT, true)
return int(val)
}
// Max width of 3D image in pixels. The minimum value is 2048 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) Image3DMaxWidth() int {
val, _ := d.getInfoSize(C.CL_DEVICE_IMAGE3D_MAX_WIDTH, true)
return int(val)
}
// Max size in bytes of the arguments that can be passed to a kernel. The
// minimum value is 1024 for devices that are not of type CL_DEVICE_TYPE_CUSTOM.
// For this minimum value, only a maximum of 128 arguments can be passed to a kernel.
func (d *Device) MaxParameterSize() int {
val, _ := d.getInfoSize(C.CL_DEVICE_MAX_PARAMETER_SIZE, true)
return int(val)
}
// Maximum number of work-items in a work-group executing a kernel on a
// single compute unit, using the data parallel execution model. (Refer
// to clEnqueueNDRangeKernel). The minimum value is 1.
func (d *Device) MaxWorkGroupSize() int {
val, _ := d.getInfoSize(C.CL_DEVICE_MAX_WORK_GROUP_SIZE, true)
return int(val)
}
// Describes the resolution of device timer. This is measured in nanoseconds.
func (d *Device) ProfilingTimerResolution() int {
val, _ := d.getInfoSize(C.CL_DEVICE_PROFILING_TIMER_RESOLUTION, true)
return int(val)
}
// Size of local memory arena in bytes. The minimum value is 32 KB for
// devices that are not of type CL_DEVICE_TYPE_CUSTOM.
func (d *Device) LocalMemSize() int64 {
val, _ := d.getInfoUlong(C.CL_DEVICE_LOCAL_MEM_SIZE, true)
return val
}
// Max size in bytes of a constant buffer allocation. The minimum value is
// 64 KB for devices that are not of type CL_DEVICE_TYPE_CUSTOM.
func (d *Device) MaxConstantBufferSize() int64 {
val, _ := d.getInfoUlong(C.CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, true)
return val
}
// Max size of memory object allocation in bytes. The minimum value is max
// (1/4th of CL_DEVICE_GLOBAL_MEM_SIZE, 128*1024*1024) for devices that are
// not of type CL_DEVICE_TYPE_CUSTOM.
func (d *Device) MaxMemAllocSize() int64 {
val, _ := d.getInfoUlong(C.CL_DEVICE_MAX_MEM_ALLOC_SIZE, true)
return val
}
// Size of global device memory in bytes.
func (d *Device) GlobalMemSize() int64 {
val, _ := d.getInfoUlong(C.CL_DEVICE_GLOBAL_MEM_SIZE, true)
return val
}
func (d *Device) Available() bool {
val, _ := d.getInfoBool(C.CL_DEVICE_AVAILABLE, true)
return val
}
func (d *Device) CompilerAvailable() bool {
val, _ := d.getInfoBool(C.CL_DEVICE_COMPILER_AVAILABLE, true)
return val
}
func (d *Device) EndianLittle() bool {
val, _ := d.getInfoBool(C.CL_DEVICE_ENDIAN_LITTLE, true)
return val
}
// Is CL_TRUE if the device implements error correction for all
// accesses to compute device memory (global and constant). Is
// CL_FALSE if the device does not implement such error correction.
func (d *Device) ErrorCorrectionSupport() bool {
val, _ := d.getInfoBool(C.CL_DEVICE_ERROR_CORRECTION_SUPPORT, true)
return val
}
func (d *Device) HostUnifiedMemory() bool {
val, _ := d.getInfoBool(C.CL_DEVICE_HOST_UNIFIED_MEMORY, true)
return val
}
func (d *Device) ImageSupport() bool {
val, _ := d.getInfoBool(C.CL_DEVICE_IMAGE_SUPPORT, true)
return val
}
func (d *Device) Type() DeviceType {
var deviceType C.cl_device_type
if err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_TYPE, C.size_t(unsafe.Sizeof(deviceType)), unsafe.Pointer(&deviceType), nil); err != C.CL_SUCCESS {
panic("Failed to get device type")
}
return DeviceType(deviceType)
}
// Describes double precision floating-point capability of the OpenCL device
func (d *Device) DoubleFPConfig() FPConfig {
var fpConfig C.cl_device_fp_config
if err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_DOUBLE_FP_CONFIG, C.size_t(unsafe.Sizeof(fpConfig)), unsafe.Pointer(&fpConfig), nil); err != C.CL_SUCCESS {
panic("Failed to get double FP config")
}
return FPConfig(fpConfig)
}
// Describes the OPTIONAL half precision floating-point capability of the OpenCL device
func (d *Device) HalfFPConfig() FPConfig {
var fpConfig C.cl_device_fp_config
err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_HALF_FP_CONFIG, C.size_t(unsafe.Sizeof(fpConfig)), unsafe.Pointer(&fpConfig), nil)
if err != C.CL_SUCCESS {
return FPConfig(0)
}
return FPConfig(fpConfig)
}
// Type of local memory supported. This can be set to CL_LOCAL implying dedicated
// local memory storage such as SRAM, or CL_GLOBAL. For custom devices, CL_NONE
// can also be returned indicating no local memory support.
func (d *Device) LocalMemType() LocalMemType {
var memType C.cl_device_local_mem_type
if err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_LOCAL_MEM_TYPE, C.size_t(unsafe.Sizeof(memType)), unsafe.Pointer(&memType), nil); err != C.CL_SUCCESS {
return LocalMemType(C.CL_NONE)
}
return LocalMemType(memType)
}
// Describes the execution capabilities of the device. The mandated minimum capability is CL_EXEC_KERNEL.
func (d *Device) ExecutionCapabilities() ExecCapability {
var execCap C.cl_device_exec_capabilities
if err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_EXECUTION_CAPABILITIES, C.size_t(unsafe.Sizeof(execCap)), unsafe.Pointer(&execCap), nil); err != C.CL_SUCCESS {
panic("Failed to get execution capabilities")
}
return ExecCapability(execCap)
}
func (d *Device) GlobalMemCacheType() MemCacheType {
var memType C.cl_device_mem_cache_type
if err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, C.size_t(unsafe.Sizeof(memType)), unsafe.Pointer(&memType), nil); err != C.CL_SUCCESS {
return MemCacheType(C.CL_NONE)
}
return MemCacheType(memType)
}
// Maximum number of work-items that can be specified in each dimension of the work-group to clEnqueueNDRangeKernel.
//
// Returns n size_t entries, where n is the value returned by the query for CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS.
//
// The minimum value is (1, 1, 1) for devices that are not of type CL_DEVICE_TYPE_CUSTOM.
func (d *Device) MaxWorkItemSizes() []int {
dims := d.MaxWorkItemDimensions()
sizes := make([]C.size_t, dims)
if err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_MAX_WORK_ITEM_SIZES, C.size_t(int(unsafe.Sizeof(sizes[0]))*dims), unsafe.Pointer(&sizes[0]), nil); err != C.CL_SUCCESS {
panic("Failed to get max work item sizes")
}
intSizes := make([]int, dims)
for i, s := range sizes {
intSizes[i] = int(s)
}
return intSizes
}

View File

@ -0,0 +1,51 @@
// +build cl12
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import "unsafe"
const FPConfigCorrectlyRoundedDivideSqrt FPConfig = C.CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT
func init() {
fpConfigNameMap[FPConfigCorrectlyRoundedDivideSqrt] = "CorrectlyRoundedDivideSqrt"
}
func (d *Device) BuiltInKernels() string {
str, _ := d.getInfoString(C.CL_DEVICE_BUILT_IN_KERNELS, true)
return str
}
// Is CL_FALSE if the implementation does not have a linker available. Is CL_TRUE if the linker is available. This can be CL_FALSE for the embedded platform profile only. This must be CL_TRUE if CL_DEVICE_COMPILER_AVAILABLE is CL_TRUE
func (d *Device) LinkerAvailable() bool {
val, _ := d.getInfoBool(C.CL_DEVICE_LINKER_AVAILABLE, true)
return val
}
func (d *Device) ParentDevice() *Device {
var deviceId C.cl_device_id
if err := C.clGetDeviceInfo(d.id, C.CL_DEVICE_PARENT_DEVICE, C.size_t(unsafe.Sizeof(deviceId)), unsafe.Pointer(&deviceId), nil); err != C.CL_SUCCESS {
panic("ParentDevice failed")
}
if deviceId == nil {
return nil
}
return &Device{id: deviceId}
}
// Max number of pixels for a 1D image created from a buffer object. The minimum value is 65536 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE.
func (d *Device) ImageMaxBufferSize() int {
val, _ := d.getInfoSize(C.CL_DEVICE_IMAGE_MAX_BUFFER_SIZE, true)
return int(val)
}
// Max number of images in a 1D or 2D image array. The minimum value is 2048 if CL_DEVICE_IMAGE_SUPPORT is CL_TRUE
func (d *Device) ImageMaxArraySize() int {
val, _ := d.getInfoSize(C.CL_DEVICE_IMAGE_MAX_ARRAY_SIZE, true)
return int(val)
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,315 @@
/*******************************************************************************
* Copyright (c) 2008-2013 The Khronos Group Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and/or associated documentation files (the
* "Materials"), to deal in the Materials without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Materials, and to
* permit persons to whom the Materials are furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Materials.
*
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
******************************************************************************/
/* $Revision: 11928 $ on $Date: 2010-07-13 09:04:56 -0700 (Tue, 13 Jul 2010) $ */
/* cl_ext.h contains OpenCL extensions which don't have external */
/* (OpenGL, D3D) dependencies. */
#ifndef __CL_EXT_H
#define __CL_EXT_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif
#include <cl.h>
/* cl_khr_fp16 extension - no extension #define since it has no functions */
#define CL_DEVICE_HALF_FP_CONFIG 0x1033
/* Memory object destruction
*
* Apple extension for use to manage externally allocated buffers used with cl_mem objects with CL_MEM_USE_HOST_PTR
*
* Registers a user callback function that will be called when the memory object is deleted and its resources
* freed. Each call to clSetMemObjectCallbackFn registers the specified user callback function on a callback
* stack associated with memobj. The registered user callback functions are called in the reverse order in
* which they were registered. The user callback functions are called and then the memory object is deleted
* and its resources freed. This provides a mechanism for the application (and libraries) using memobj to be
* notified when the memory referenced by host_ptr, specified when the memory object is created and used as
* the storage bits for the memory object, can be reused or freed.
*
* The application may not call CL api's with the cl_mem object passed to the pfn_notify.
*
* Please check for the "cl_APPLE_SetMemObjectDestructor" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS)
* before using.
*/
#define cl_APPLE_SetMemObjectDestructor 1
cl_int CL_API_ENTRY clSetMemObjectDestructorAPPLE( cl_mem /* memobj */,
void (* /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/),
void * /*user_data */ ) CL_EXT_SUFFIX__VERSION_1_0;
/* Context Logging Functions
*
* The next three convenience functions are intended to be used as the pfn_notify parameter to clCreateContext().
* Please check for the "cl_APPLE_ContextLoggingFunctions" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS)
* before using.
*
* clLogMessagesToSystemLog fowards on all log messages to the Apple System Logger
*/
#define cl_APPLE_ContextLoggingFunctions 1
extern void CL_API_ENTRY clLogMessagesToSystemLogAPPLE( const char * /* errstr */,
const void * /* private_info */,
size_t /* cb */,
void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0;
/* clLogMessagesToStdout sends all log messages to the file descriptor stdout */
extern void CL_API_ENTRY clLogMessagesToStdoutAPPLE( const char * /* errstr */,
const void * /* private_info */,
size_t /* cb */,
void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0;
/* clLogMessagesToStderr sends all log messages to the file descriptor stderr */
extern void CL_API_ENTRY clLogMessagesToStderrAPPLE( const char * /* errstr */,
const void * /* private_info */,
size_t /* cb */,
void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0;
/************************
* cl_khr_icd extension *
************************/
#define cl_khr_icd 1
/* cl_platform_info */
#define CL_PLATFORM_ICD_SUFFIX_KHR 0x0920
/* Additional Error Codes */
#define CL_PLATFORM_NOT_FOUND_KHR -1001
extern CL_API_ENTRY cl_int CL_API_CALL
clIcdGetPlatformIDsKHR(cl_uint /* num_entries */,
cl_platform_id * /* platforms */,
cl_uint * /* num_platforms */);
typedef CL_API_ENTRY cl_int (CL_API_CALL *clIcdGetPlatformIDsKHR_fn)(
cl_uint /* num_entries */,
cl_platform_id * /* platforms */,
cl_uint * /* num_platforms */);
/* Extension: cl_khr_image2D_buffer
*
* This extension allows a 2D image to be created from a cl_mem buffer without a copy.
* The type associated with a 2D image created from a buffer in an OpenCL program is image2d_t.
* Both the sampler and sampler-less read_image built-in functions are supported for 2D images
* and 2D images created from a buffer. Similarly, the write_image built-ins are also supported
* for 2D images created from a buffer.
*
* When the 2D image from buffer is created, the client must specify the width,
* height, image format (i.e. channel order and channel data type) and optionally the row pitch
*
* The pitch specified must be a multiple of CL_DEVICE_IMAGE_PITCH_ALIGNMENT pixels.
* The base address of the buffer must be aligned to CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT pixels.
*/
/*************************************
* cl_khr_initalize_memory extension *
*************************************/
#define CL_CONTEXT_MEMORY_INITIALIZE_KHR 0x200E
/**************************************
* cl_khr_terminate_context extension *
**************************************/
#define CL_DEVICE_TERMINATE_CAPABILITY_KHR 0x200F
#define CL_CONTEXT_TERMINATE_KHR 0x2010
#define cl_khr_terminate_context 1
extern CL_API_ENTRY cl_int CL_API_CALL clTerminateContextKHR(cl_context /* context */) CL_EXT_SUFFIX__VERSION_1_2;
typedef CL_API_ENTRY cl_int (CL_API_CALL *clTerminateContextKHR_fn)(cl_context /* context */) CL_EXT_SUFFIX__VERSION_1_2;
/*
* Extension: cl_khr_spir
*
* This extension adds support to create an OpenCL program object from a
* Standard Portable Intermediate Representation (SPIR) instance
*/
#define CL_DEVICE_SPIR_VERSIONS 0x40E0
#define CL_PROGRAM_BINARY_TYPE_INTERMEDIATE 0x40E1
/******************************************
* cl_nv_device_attribute_query extension *
******************************************/
/* cl_nv_device_attribute_query extension - no extension #define since it has no functions */
#define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000
#define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001
#define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002
#define CL_DEVICE_WARP_SIZE_NV 0x4003
#define CL_DEVICE_GPU_OVERLAP_NV 0x4004
#define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005
#define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006
/*********************************
* cl_amd_device_attribute_query *
*********************************/
#define CL_DEVICE_PROFILING_TIMER_OFFSET_AMD 0x4036
/*********************************
* cl_arm_printf extension
*********************************/
#define CL_PRINTF_CALLBACK_ARM 0x40B0
#define CL_PRINTF_BUFFERSIZE_ARM 0x40B1
#ifdef CL_VERSION_1_1
/***********************************
* cl_ext_device_fission extension *
***********************************/
#define cl_ext_device_fission 1
extern CL_API_ENTRY cl_int CL_API_CALL
clReleaseDeviceEXT( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1;
typedef CL_API_ENTRY cl_int
(CL_API_CALL *clReleaseDeviceEXT_fn)( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1;
extern CL_API_ENTRY cl_int CL_API_CALL
clRetainDeviceEXT( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1;
typedef CL_API_ENTRY cl_int
(CL_API_CALL *clRetainDeviceEXT_fn)( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1;
typedef cl_ulong cl_device_partition_property_ext;
extern CL_API_ENTRY cl_int CL_API_CALL
clCreateSubDevicesEXT( cl_device_id /*in_device*/,
const cl_device_partition_property_ext * /* properties */,
cl_uint /*num_entries*/,
cl_device_id * /*out_devices*/,
cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1;
typedef CL_API_ENTRY cl_int
( CL_API_CALL * clCreateSubDevicesEXT_fn)( cl_device_id /*in_device*/,
const cl_device_partition_property_ext * /* properties */,
cl_uint /*num_entries*/,
cl_device_id * /*out_devices*/,
cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1;
/* cl_device_partition_property_ext */
#define CL_DEVICE_PARTITION_EQUALLY_EXT 0x4050
#define CL_DEVICE_PARTITION_BY_COUNTS_EXT 0x4051
#define CL_DEVICE_PARTITION_BY_NAMES_EXT 0x4052
#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT 0x4053
/* clDeviceGetInfo selectors */
#define CL_DEVICE_PARENT_DEVICE_EXT 0x4054
#define CL_DEVICE_PARTITION_TYPES_EXT 0x4055
#define CL_DEVICE_AFFINITY_DOMAINS_EXT 0x4056
#define CL_DEVICE_REFERENCE_COUNT_EXT 0x4057
#define CL_DEVICE_PARTITION_STYLE_EXT 0x4058
/* error codes */
#define CL_DEVICE_PARTITION_FAILED_EXT -1057
#define CL_INVALID_PARTITION_COUNT_EXT -1058
#define CL_INVALID_PARTITION_NAME_EXT -1059
/* CL_AFFINITY_DOMAINs */
#define CL_AFFINITY_DOMAIN_L1_CACHE_EXT 0x1
#define CL_AFFINITY_DOMAIN_L2_CACHE_EXT 0x2
#define CL_AFFINITY_DOMAIN_L3_CACHE_EXT 0x3
#define CL_AFFINITY_DOMAIN_L4_CACHE_EXT 0x4
#define CL_AFFINITY_DOMAIN_NUMA_EXT 0x10
#define CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT 0x100
/* cl_device_partition_property_ext list terminators */
#define CL_PROPERTIES_LIST_END_EXT ((cl_device_partition_property_ext) 0)
#define CL_PARTITION_BY_COUNTS_LIST_END_EXT ((cl_device_partition_property_ext) 0)
#define CL_PARTITION_BY_NAMES_LIST_END_EXT ((cl_device_partition_property_ext) 0 - 1)
/*********************************
* cl_qcom_ext_host_ptr extension
*********************************/
#define CL_MEM_EXT_HOST_PTR_QCOM (1 << 29)
#define CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM 0x40A0
#define CL_DEVICE_PAGE_SIZE_QCOM 0x40A1
#define CL_IMAGE_ROW_ALIGNMENT_QCOM 0x40A2
#define CL_IMAGE_SLICE_ALIGNMENT_QCOM 0x40A3
#define CL_MEM_HOST_UNCACHED_QCOM 0x40A4
#define CL_MEM_HOST_WRITEBACK_QCOM 0x40A5
#define CL_MEM_HOST_WRITETHROUGH_QCOM 0x40A6
#define CL_MEM_HOST_WRITE_COMBINING_QCOM 0x40A7
typedef cl_uint cl_image_pitch_info_qcom;
extern CL_API_ENTRY cl_int CL_API_CALL
clGetDeviceImageInfoQCOM(cl_device_id device,
size_t image_width,
size_t image_height,
const cl_image_format *image_format,
cl_image_pitch_info_qcom param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret);
typedef struct _cl_mem_ext_host_ptr
{
/* Type of external memory allocation. */
/* Legal values will be defined in layered extensions. */
cl_uint allocation_type;
/* Host cache policy for this external memory allocation. */
cl_uint host_cache_policy;
} cl_mem_ext_host_ptr;
/*********************************
* cl_qcom_ion_host_ptr extension
*********************************/
#define CL_MEM_ION_HOST_PTR_QCOM 0x40A8
typedef struct _cl_mem_ion_host_ptr
{
/* Type of external memory allocation. */
/* Must be CL_MEM_ION_HOST_PTR_QCOM for ION allocations. */
cl_mem_ext_host_ptr ext_host_ptr;
/* ION file descriptor */
int ion_filedesc;
/* Host pointer to the ION allocated memory */
void* ion_hostptr;
} cl_mem_ion_host_ptr;
#endif /* CL_VERSION_1_1 */
#ifdef __cplusplus
}
#endif
#endif /* __CL_EXT_H */

View File

@ -0,0 +1,158 @@
/**********************************************************************************
* Copyright (c) 2008 - 2012 The Khronos Group Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and/or associated documentation files (the
* "Materials"), to deal in the Materials without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Materials, and to
* permit persons to whom the Materials are furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Materials.
*
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
**********************************************************************************/
#ifndef __OPENCL_CL_GL_H
#define __OPENCL_CL_GL_H
#include <cl.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef cl_uint cl_gl_object_type;
typedef cl_uint cl_gl_texture_info;
typedef cl_uint cl_gl_platform_info;
typedef struct __GLsync *cl_GLsync;
/* cl_gl_object_type = 0x2000 - 0x200F enum values are currently taken */
#define CL_GL_OBJECT_BUFFER 0x2000
#define CL_GL_OBJECT_TEXTURE2D 0x2001
#define CL_GL_OBJECT_TEXTURE3D 0x2002
#define CL_GL_OBJECT_RENDERBUFFER 0x2003
#define CL_GL_OBJECT_TEXTURE2D_ARRAY 0x200E
#define CL_GL_OBJECT_TEXTURE1D 0x200F
#define CL_GL_OBJECT_TEXTURE1D_ARRAY 0x2010
#define CL_GL_OBJECT_TEXTURE_BUFFER 0x2011
/* cl_gl_texture_info */
#define CL_GL_TEXTURE_TARGET 0x2004
#define CL_GL_MIPMAP_LEVEL 0x2005
#define CL_GL_NUM_SAMPLES 0x2012
extern CL_API_ENTRY cl_mem CL_API_CALL
clCreateFromGLBuffer(cl_context /* context */,
cl_mem_flags /* flags */,
cl_GLuint /* bufobj */,
int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0;
extern CL_API_ENTRY cl_mem CL_API_CALL
clCreateFromGLTexture(cl_context /* context */,
cl_mem_flags /* flags */,
cl_GLenum /* target */,
cl_GLint /* miplevel */,
cl_GLuint /* texture */,
cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_2;
extern CL_API_ENTRY cl_mem CL_API_CALL
clCreateFromGLRenderbuffer(cl_context /* context */,
cl_mem_flags /* flags */,
cl_GLuint /* renderbuffer */,
cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0;
extern CL_API_ENTRY cl_int CL_API_CALL
clGetGLObjectInfo(cl_mem /* memobj */,
cl_gl_object_type * /* gl_object_type */,
cl_GLuint * /* gl_object_name */) CL_API_SUFFIX__VERSION_1_0;
extern CL_API_ENTRY cl_int CL_API_CALL
clGetGLTextureInfo(cl_mem /* memobj */,
cl_gl_texture_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0;
extern CL_API_ENTRY cl_int CL_API_CALL
clEnqueueAcquireGLObjects(cl_command_queue /* command_queue */,
cl_uint /* num_objects */,
const cl_mem * /* mem_objects */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0;
extern CL_API_ENTRY cl_int CL_API_CALL
clEnqueueReleaseGLObjects(cl_command_queue /* command_queue */,
cl_uint /* num_objects */,
const cl_mem * /* mem_objects */,
cl_uint /* num_events_in_wait_list */,
const cl_event * /* event_wait_list */,
cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0;
/* Deprecated OpenCL 1.1 APIs */
extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL
clCreateFromGLTexture2D(cl_context /* context */,
cl_mem_flags /* flags */,
cl_GLenum /* target */,
cl_GLint /* miplevel */,
cl_GLuint /* texture */,
cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED;
extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL
clCreateFromGLTexture3D(cl_context /* context */,
cl_mem_flags /* flags */,
cl_GLenum /* target */,
cl_GLint /* miplevel */,
cl_GLuint /* texture */,
cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED;
/* cl_khr_gl_sharing extension */
#define cl_khr_gl_sharing 1
typedef cl_uint cl_gl_context_info;
/* Additional Error Codes */
#define CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR -1000
/* cl_gl_context_info */
#define CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR 0x2006
#define CL_DEVICES_FOR_GL_CONTEXT_KHR 0x2007
/* Additional cl_context_properties */
#define CL_GL_CONTEXT_KHR 0x2008
#define CL_EGL_DISPLAY_KHR 0x2009
#define CL_GLX_DISPLAY_KHR 0x200A
#define CL_WGL_HDC_KHR 0x200B
#define CL_CGL_SHAREGROUP_KHR 0x200C
extern CL_API_ENTRY cl_int CL_API_CALL
clGetGLContextInfoKHR(const cl_context_properties * /* properties */,
cl_gl_context_info /* param_name */,
size_t /* param_value_size */,
void * /* param_value */,
size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0;
typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetGLContextInfoKHR_fn)(
const cl_context_properties * properties,
cl_gl_context_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret);
#ifdef __cplusplus
}
#endif
#endif /* __OPENCL_CL_GL_H */

View File

@ -0,0 +1,65 @@
/**********************************************************************************
* Copyright (c) 2008-2012 The Khronos Group Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and/or associated documentation files (the
* "Materials"), to deal in the Materials without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Materials, and to
* permit persons to whom the Materials are furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Materials.
*
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
**********************************************************************************/
/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */
/* cl_gl_ext.h contains vendor (non-KHR) OpenCL extensions which have */
/* OpenGL dependencies. */
#ifndef __OPENCL_CL_GL_EXT_H
#define __OPENCL_CL_GL_EXT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <cl_gl.h>
/*
* For each extension, follow this template
* cl_VEN_extname extension */
/* #define cl_VEN_extname 1
* ... define new types, if any
* ... define new tokens, if any
* ... define new APIs, if any
*
* If you need GLtypes here, mirror them with a cl_GLtype, rather than including a GL header
* This allows us to avoid having to decide whether to include GL headers or GLES here.
*/
/*
* cl_khr_gl_event extension
* See section 9.9 in the OpenCL 1.1 spec for more information
*/
#define CL_COMMAND_GL_FENCE_SYNC_OBJECT_KHR 0x200D
extern CL_API_ENTRY cl_event CL_API_CALL
clCreateEventFromGLsyncKHR(cl_context /* context */,
cl_GLsync /* cl_GLsync */,
cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1;
#ifdef __cplusplus
}
#endif
#endif /* __OPENCL_CL_GL_EXT_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2008-2012 The Khronos Group Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and/or associated documentation files (the
* "Materials"), to deal in the Materials without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Materials, and to
* permit persons to whom the Materials are furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Materials.
*
* THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
******************************************************************************/
/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */
#ifndef __OPENCL_H
#define __OPENCL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <cl.h>
#include <cl_gl.h>
#include <cl_gl_ext.h>
#include <cl_ext.h>
#ifdef __cplusplus
}
#endif
#endif /* __OPENCL_H */

View File

@ -0,0 +1,83 @@
// +build cl12
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import (
"image"
"unsafe"
)
func (ctx *Context) CreateImage(flags MemFlag, imageFormat ImageFormat, imageDesc ImageDescription, data []byte) (*MemObject, error) {
format := imageFormat.toCl()
desc := imageDesc.toCl()
var dataPtr unsafe.Pointer
if data != nil {
dataPtr = unsafe.Pointer(&data[0])
}
var err C.cl_int
clBuffer := C.clCreateImage(ctx.clContext, C.cl_mem_flags(flags), &format, &desc, dataPtr, &err)
if err != C.CL_SUCCESS {
return nil, toError(err)
}
if clBuffer == nil {
return nil, ErrUnknown
}
return newMemObject(clBuffer, len(data)), nil
}
func (ctx *Context) CreateImageSimple(flags MemFlag, width, height int, channelOrder ChannelOrder, channelDataType ChannelDataType, data []byte) (*MemObject, error) {
format := ImageFormat{channelOrder, channelDataType}
desc := ImageDescription{
Type: MemObjectTypeImage2D,
Width: width,
Height: height,
}
return ctx.CreateImage(flags, format, desc, data)
}
func (ctx *Context) CreateImageFromImage(flags MemFlag, img image.Image) (*MemObject, error) {
switch m := img.(type) {
case *image.Gray:
format := ImageFormat{ChannelOrderIntensity, ChannelDataTypeUNormInt8}
desc := ImageDescription{
Type: MemObjectTypeImage2D,
Width: m.Bounds().Dx(),
Height: m.Bounds().Dy(),
RowPitch: m.Stride,
}
return ctx.CreateImage(flags, format, desc, m.Pix)
case *image.RGBA:
format := ImageFormat{ChannelOrderRGBA, ChannelDataTypeUNormInt8}
desc := ImageDescription{
Type: MemObjectTypeImage2D,
Width: m.Bounds().Dx(),
Height: m.Bounds().Dy(),
RowPitch: m.Stride,
}
return ctx.CreateImage(flags, format, desc, m.Pix)
}
b := img.Bounds()
w := b.Dx()
h := b.Dy()
data := make([]byte, w*h*4)
dataOffset := 0
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
c := img.At(x+b.Min.X, y+b.Min.Y)
r, g, b, a := c.RGBA()
data[dataOffset] = uint8(r >> 8)
data[dataOffset+1] = uint8(g >> 8)
data[dataOffset+2] = uint8(b >> 8)
data[dataOffset+3] = uint8(a >> 8)
dataOffset += 4
}
}
return ctx.CreateImageSimple(flags, w, h, ChannelOrderRGBA, ChannelDataTypeUNormInt8, data)
}

View File

@ -0,0 +1,127 @@
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import (
"fmt"
"unsafe"
)
type ErrUnsupportedArgumentType struct {
Index int
Value interface{}
}
func (e ErrUnsupportedArgumentType) Error() string {
return fmt.Sprintf("cl: unsupported argument type for index %d: %+v", e.Index, e.Value)
}
type Kernel struct {
clKernel C.cl_kernel
name string
}
type LocalBuffer int
func releaseKernel(k *Kernel) {
if k.clKernel != nil {
C.clReleaseKernel(k.clKernel)
k.clKernel = nil
}
}
func (k *Kernel) Release() {
releaseKernel(k)
}
func (k *Kernel) SetArgs(args ...interface{}) error {
for index, arg := range args {
if err := k.SetArg(index, arg); err != nil {
return err
}
}
return nil
}
func (k *Kernel) SetArg(index int, arg interface{}) error {
switch val := arg.(type) {
case uint8:
return k.SetArgUint8(index, val)
case int8:
return k.SetArgInt8(index, val)
case uint32:
return k.SetArgUint32(index, val)
case uint64:
return k.SetArgUint64(index, val)
case int32:
return k.SetArgInt32(index, val)
case float32:
return k.SetArgFloat32(index, val)
case *MemObject:
return k.SetArgBuffer(index, val)
case LocalBuffer:
return k.SetArgLocal(index, int(val))
default:
return ErrUnsupportedArgumentType{Index: index, Value: arg}
}
}
func (k *Kernel) SetArgBuffer(index int, buffer *MemObject) error {
return k.SetArgUnsafe(index, int(unsafe.Sizeof(buffer.clMem)), unsafe.Pointer(&buffer.clMem))
}
func (k *Kernel) SetArgFloat32(index int, val float32) error {
return k.SetArgUnsafe(index, int(unsafe.Sizeof(val)), unsafe.Pointer(&val))
}
func (k *Kernel) SetArgInt8(index int, val int8) error {
return k.SetArgUnsafe(index, int(unsafe.Sizeof(val)), unsafe.Pointer(&val))
}
func (k *Kernel) SetArgUint8(index int, val uint8) error {
return k.SetArgUnsafe(index, int(unsafe.Sizeof(val)), unsafe.Pointer(&val))
}
func (k *Kernel) SetArgInt32(index int, val int32) error {
return k.SetArgUnsafe(index, int(unsafe.Sizeof(val)), unsafe.Pointer(&val))
}
func (k *Kernel) SetArgUint32(index int, val uint32) error {
return k.SetArgUnsafe(index, int(unsafe.Sizeof(val)), unsafe.Pointer(&val))
}
func (k *Kernel) SetArgUint64(index int, val uint64) error {
return k.SetArgUnsafe(index, int(unsafe.Sizeof(val)), unsafe.Pointer(&val))
}
func (k *Kernel) SetArgLocal(index int, size int) error {
return k.SetArgUnsafe(index, size, nil)
}
func (k *Kernel) SetArgUnsafe(index, argSize int, arg unsafe.Pointer) error {
//fmt.Println("FUNKY: ", index, argSize)
return toError(C.clSetKernelArg(k.clKernel, C.cl_uint(index), C.size_t(argSize), arg))
}
func (k *Kernel) PreferredWorkGroupSizeMultiple(device *Device) (int, error) {
var size C.size_t
err := C.clGetKernelWorkGroupInfo(k.clKernel, device.nullableId(), C.CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, C.size_t(unsafe.Sizeof(size)), unsafe.Pointer(&size), nil)
return int(size), toError(err)
}
func (k *Kernel) WorkGroupSize(device *Device) (int, error) {
var size C.size_t
err := C.clGetKernelWorkGroupInfo(k.clKernel, device.nullableId(), C.CL_KERNEL_WORK_GROUP_SIZE, C.size_t(unsafe.Sizeof(size)), unsafe.Pointer(&size), nil)
return int(size), toError(err)
}
func (k *Kernel) NumArgs() (int, error) {
var num C.cl_uint
err := C.clGetKernelInfo(k.clKernel, C.CL_KERNEL_NUM_ARGS, C.size_t(unsafe.Sizeof(num)), unsafe.Pointer(&num), nil)
return int(num), toError(err)
}

View File

@ -0,0 +1,7 @@
// +build !cl12
package cl
func (k *Kernel) ArgName(index int) (string, error) {
return "", ErrUnsupported
}

View File

@ -0,0 +1,20 @@
// +build cl12
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import "unsafe"
func (k *Kernel) ArgName(index int) (string, error) {
var strC [1024]byte
var strN C.size_t
if err := C.clGetKernelArgInfo(k.clKernel, C.cl_uint(index), C.CL_KERNEL_ARG_NAME, 1024, unsafe.Pointer(&strC[0]), &strN); err != C.CL_SUCCESS {
return "", toError(err)
}
return string(strC[:strN]), nil
}

View File

@ -0,0 +1,83 @@
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import "unsafe"
const maxPlatforms = 32
type Platform struct {
id C.cl_platform_id
}
// Obtain the list of platforms available.
func GetPlatforms() ([]*Platform, error) {
var platformIds [maxPlatforms]C.cl_platform_id
var nPlatforms C.cl_uint
if err := C.clGetPlatformIDs(C.cl_uint(maxPlatforms), &platformIds[0], &nPlatforms); err != C.CL_SUCCESS {
return nil, toError(err)
}
platforms := make([]*Platform, nPlatforms)
for i := 0; i < int(nPlatforms); i++ {
platforms[i] = &Platform{id: platformIds[i]}
}
return platforms, nil
}
func (p *Platform) GetDevices(deviceType DeviceType) ([]*Device, error) {
return GetDevices(p, deviceType)
}
func (p *Platform) getInfoString(param C.cl_platform_info) (string, error) {
var strC [2048]byte
var strN C.size_t
if err := C.clGetPlatformInfo(p.id, param, 2048, unsafe.Pointer(&strC[0]), &strN); err != C.CL_SUCCESS {
return "", toError(err)
}
return string(strC[:(strN - 1)]), nil
}
func (p *Platform) Name() string {
if str, err := p.getInfoString(C.CL_PLATFORM_NAME); err != nil {
panic("Platform.Name() should never fail")
} else {
return str
}
}
func (p *Platform) Vendor() string {
if str, err := p.getInfoString(C.CL_PLATFORM_VENDOR); err != nil {
panic("Platform.Vendor() should never fail")
} else {
return str
}
}
func (p *Platform) Profile() string {
if str, err := p.getInfoString(C.CL_PLATFORM_PROFILE); err != nil {
panic("Platform.Profile() should never fail")
} else {
return str
}
}
func (p *Platform) Version() string {
if str, err := p.getInfoString(C.CL_PLATFORM_VERSION); err != nil {
panic("Platform.Version() should never fail")
} else {
return str
}
}
func (p *Platform) Extensions() string {
if str, err := p.getInfoString(C.CL_PLATFORM_EXTENSIONS); err != nil {
panic("Platform.Extensions() should never fail")
} else {
return str
}
}

View File

@ -0,0 +1,105 @@
package cl
// #include <stdlib.h>
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import (
"fmt"
"runtime"
"unsafe"
)
type BuildError struct {
Message string
Device *Device
}
func (e BuildError) Error() string {
if e.Device != nil {
return fmt.Sprintf("cl: build error on %q: %s", e.Device.Name(), e.Message)
} else {
return fmt.Sprintf("cl: build error: %s", e.Message)
}
}
type Program struct {
clProgram C.cl_program
devices []*Device
}
func releaseProgram(p *Program) {
if p.clProgram != nil {
C.clReleaseProgram(p.clProgram)
p.clProgram = nil
}
}
func (p *Program) Release() {
releaseProgram(p)
}
func (p *Program) BuildProgram(devices []*Device, options string) error {
var cOptions *C.char
if options != "" {
cOptions = C.CString(options)
defer C.free(unsafe.Pointer(cOptions))
}
var deviceList []C.cl_device_id
var deviceListPtr *C.cl_device_id
numDevices := C.cl_uint(len(devices))
if devices != nil && len(devices) > 0 {
deviceList = buildDeviceIdList(devices)
deviceListPtr = &deviceList[0]
}
if err := C.clBuildProgram(p.clProgram, numDevices, deviceListPtr, cOptions, nil, nil); err != C.CL_SUCCESS {
buffer := make([]byte, 4096)
var bLen C.size_t
var err C.cl_int
for _, dev := range p.devices {
for i := 2; i >= 0; i-- {
err = C.clGetProgramBuildInfo(p.clProgram, dev.id, C.CL_PROGRAM_BUILD_LOG, C.size_t(len(buffer)), unsafe.Pointer(&buffer[0]), &bLen)
if err == C.CL_INVALID_VALUE && i > 0 && bLen < 1024*1024 {
// INVALID_VALUE probably means our buffer isn't large enough
buffer = make([]byte, bLen)
} else {
break
}
}
if err != C.CL_SUCCESS {
return toError(err)
}
if bLen > 1 {
return BuildError{
Device: dev,
Message: string(buffer[:bLen-1]),
}
}
}
return BuildError{
Device: nil,
Message: "build failed and produced no log entries",
}
}
return nil
}
func (p *Program) CreateKernel(name string) (*Kernel, error) {
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
var err C.cl_int
clKernel := C.clCreateKernel(p.clProgram, cName, &err)
if err != C.CL_SUCCESS {
return nil, toError(err)
}
kernel := &Kernel{clKernel: clKernel, name: name}
runtime.SetFinalizer(kernel, releaseKernel)
return kernel, nil
}

View File

@ -0,0 +1,193 @@
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import "unsafe"
type CommandQueueProperty int
const (
CommandQueueOutOfOrderExecModeEnable CommandQueueProperty = C.CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE
CommandQueueProfilingEnable CommandQueueProperty = C.CL_QUEUE_PROFILING_ENABLE
)
type CommandQueue struct {
clQueue C.cl_command_queue
device *Device
}
func releaseCommandQueue(q *CommandQueue) {
if q.clQueue != nil {
C.clReleaseCommandQueue(q.clQueue)
q.clQueue = nil
}
}
// Call clReleaseCommandQueue on the CommandQueue. Using the CommandQueue after Release will cause a panick.
func (q *CommandQueue) Release() {
releaseCommandQueue(q)
}
// Blocks until all previously queued OpenCL commands in a command-queue are issued to the associated device and have completed.
func (q *CommandQueue) Finish() error {
return toError(C.clFinish(q.clQueue))
}
// Issues all previously queued OpenCL commands in a command-queue to the device associated with the command-queue.
func (q *CommandQueue) Flush() error {
return toError(C.clFlush(q.clQueue))
}
// Enqueues a command to map a region of the buffer object given by buffer into the host address space and returns a pointer to this mapped region.
func (q *CommandQueue) EnqueueMapBuffer(buffer *MemObject, blocking bool, flags MapFlag, offset, size int, eventWaitList []*Event) (*MappedMemObject, *Event, error) {
var event C.cl_event
var err C.cl_int
ptr := C.clEnqueueMapBuffer(q.clQueue, buffer.clMem, clBool(blocking), flags.toCl(), C.size_t(offset), C.size_t(size), C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event, &err)
if err != C.CL_SUCCESS {
return nil, nil, toError(err)
}
ev := newEvent(event)
if ptr == nil {
return nil, ev, ErrUnknown
}
return &MappedMemObject{ptr: ptr, size: size}, ev, nil
}
// Enqueues a command to map a region of an image object into the host address space and returns a pointer to this mapped region.
func (q *CommandQueue) EnqueueMapImage(buffer *MemObject, blocking bool, flags MapFlag, origin, region [3]int, eventWaitList []*Event) (*MappedMemObject, *Event, error) {
cOrigin := sizeT3(origin)
cRegion := sizeT3(region)
var event C.cl_event
var err C.cl_int
var rowPitch, slicePitch C.size_t
ptr := C.clEnqueueMapImage(q.clQueue, buffer.clMem, clBool(blocking), flags.toCl(), &cOrigin[0], &cRegion[0], &rowPitch, &slicePitch, C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event, &err)
if err != C.CL_SUCCESS {
return nil, nil, toError(err)
}
ev := newEvent(event)
if ptr == nil {
return nil, ev, ErrUnknown
}
size := 0 // TODO: could calculate this
return &MappedMemObject{ptr: ptr, size: size, rowPitch: int(rowPitch), slicePitch: int(slicePitch)}, ev, nil
}
// Enqueues a command to unmap a previously mapped region of a memory object.
func (q *CommandQueue) EnqueueUnmapMemObject(buffer *MemObject, mappedObj *MappedMemObject, eventWaitList []*Event) (*Event, error) {
var event C.cl_event
if err := C.clEnqueueUnmapMemObject(q.clQueue, buffer.clMem, mappedObj.ptr, C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event); err != C.CL_SUCCESS {
return nil, toError(err)
}
return newEvent(event), nil
}
// Enqueues a command to copy a buffer object to another buffer object.
func (q *CommandQueue) EnqueueCopyBuffer(srcBuffer, dstBuffer *MemObject, srcOffset, dstOffset, byteCount int, eventWaitList []*Event) (*Event, error) {
var event C.cl_event
err := toError(C.clEnqueueCopyBuffer(q.clQueue, srcBuffer.clMem, dstBuffer.clMem, C.size_t(srcOffset), C.size_t(dstOffset), C.size_t(byteCount), C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
// Enqueue commands to write to a buffer object from host memory.
func (q *CommandQueue) EnqueueWriteBuffer(buffer *MemObject, blocking bool, offset, dataSize int, dataPtr unsafe.Pointer, eventWaitList []*Event) (*Event, error) {
var event C.cl_event
err := toError(C.clEnqueueWriteBuffer(q.clQueue, buffer.clMem, clBool(blocking), C.size_t(offset), C.size_t(dataSize), dataPtr, C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
func (q *CommandQueue) EnqueueWriteBufferFloat32(buffer *MemObject, blocking bool, offset int, data []float32, eventWaitList []*Event) (*Event, error) {
dataPtr := unsafe.Pointer(&data[0])
dataSize := int(unsafe.Sizeof(data[0])) * len(data)
return q.EnqueueWriteBuffer(buffer, blocking, offset, dataSize, dataPtr, eventWaitList)
}
// Enqueue commands to read from a buffer object to host memory.
func (q *CommandQueue) EnqueueReadBuffer(buffer *MemObject, blocking bool, offset, dataSize int, dataPtr unsafe.Pointer, eventWaitList []*Event) (*Event, error) {
var event C.cl_event
err := toError(C.clEnqueueReadBuffer(q.clQueue, buffer.clMem, clBool(blocking), C.size_t(offset), C.size_t(dataSize), dataPtr, C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
func (q *CommandQueue) EnqueueReadBufferFloat32(buffer *MemObject, blocking bool, offset int, data []float32, eventWaitList []*Event) (*Event, error) {
dataPtr := unsafe.Pointer(&data[0])
dataSize := int(unsafe.Sizeof(data[0])) * len(data)
return q.EnqueueReadBuffer(buffer, blocking, offset, dataSize, dataPtr, eventWaitList)
}
// Enqueues a command to execute a kernel on a device.
func (q *CommandQueue) EnqueueNDRangeKernel(kernel *Kernel, globalWorkOffset, globalWorkSize, localWorkSize []int, eventWaitList []*Event) (*Event, error) {
workDim := len(globalWorkSize)
var globalWorkOffsetList []C.size_t
var globalWorkOffsetPtr *C.size_t
if globalWorkOffset != nil {
globalWorkOffsetList = make([]C.size_t, len(globalWorkOffset))
for i, off := range globalWorkOffset {
globalWorkOffsetList[i] = C.size_t(off)
}
globalWorkOffsetPtr = &globalWorkOffsetList[0]
}
var globalWorkSizeList []C.size_t
var globalWorkSizePtr *C.size_t
if globalWorkSize != nil {
globalWorkSizeList = make([]C.size_t, len(globalWorkSize))
for i, off := range globalWorkSize {
globalWorkSizeList[i] = C.size_t(off)
}
globalWorkSizePtr = &globalWorkSizeList[0]
}
var localWorkSizeList []C.size_t
var localWorkSizePtr *C.size_t
if localWorkSize != nil {
localWorkSizeList = make([]C.size_t, len(localWorkSize))
for i, off := range localWorkSize {
localWorkSizeList[i] = C.size_t(off)
}
localWorkSizePtr = &localWorkSizeList[0]
}
var event C.cl_event
err := toError(C.clEnqueueNDRangeKernel(q.clQueue, kernel.clKernel, C.cl_uint(workDim), globalWorkOffsetPtr, globalWorkSizePtr, localWorkSizePtr, C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
// Enqueues a command to read from a 2D or 3D image object to host memory.
func (q *CommandQueue) EnqueueReadImage(image *MemObject, blocking bool, origin, region [3]int, rowPitch, slicePitch int, data []byte, eventWaitList []*Event) (*Event, error) {
cOrigin := sizeT3(origin)
cRegion := sizeT3(region)
var event C.cl_event
err := toError(C.clEnqueueReadImage(q.clQueue, image.clMem, clBool(blocking), &cOrigin[0], &cRegion[0], C.size_t(rowPitch), C.size_t(slicePitch), unsafe.Pointer(&data[0]), C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
// Enqueues a command to write from a 2D or 3D image object to host memory.
func (q *CommandQueue) EnqueueWriteImage(image *MemObject, blocking bool, origin, region [3]int, rowPitch, slicePitch int, data []byte, eventWaitList []*Event) (*Event, error) {
cOrigin := sizeT3(origin)
cRegion := sizeT3(region)
var event C.cl_event
err := toError(C.clEnqueueWriteImage(q.clQueue, image.clMem, clBool(blocking), &cOrigin[0], &cRegion[0], C.size_t(rowPitch), C.size_t(slicePitch), unsafe.Pointer(&data[0]), C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
func (q *CommandQueue) EnqueueFillBuffer(buffer *MemObject, pattern unsafe.Pointer, patternSize, offset, size int, eventWaitList []*Event) (*Event, error) {
var event C.cl_event
err := toError(C.clEnqueueFillBuffer(q.clQueue, buffer.clMem, pattern, C.size_t(patternSize), C.size_t(offset), C.size_t(size), C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
// A synchronization point that enqueues a barrier operation.
func (q *CommandQueue) EnqueueBarrierWithWaitList(eventWaitList []*Event) (*Event, error) {
var event C.cl_event
err := toError(C.clEnqueueBarrierWithWaitList(q.clQueue, C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}
// Enqueues a marker command which waits for either a list of events to complete, or all previously enqueued commands to complete.
func (q *CommandQueue) EnqueueMarkerWithWaitList(eventWaitList []*Event) (*Event, error) {
var event C.cl_event
err := toError(C.clEnqueueMarkerWithWaitList(q.clQueue, C.cl_uint(len(eventWaitList)), eventListPtr(eventWaitList), &event))
return newEvent(event), err
}

View File

@ -0,0 +1,487 @@
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
import (
"errors"
"fmt"
"reflect"
"runtime"
"strings"
"unsafe"
)
var (
ErrUnknown = errors.New("cl: unknown error") // Generally an unexpected result from an OpenCL function (e.g. CL_SUCCESS but null pointer)
)
type ErrOther int
func (e ErrOther) Error() string {
return fmt.Sprintf("cl: error %d", int(e))
}
var (
ErrDeviceNotFound = errors.New("cl: Device Not Found")
ErrDeviceNotAvailable = errors.New("cl: Device Not Available")
ErrCompilerNotAvailable = errors.New("cl: Compiler Not Available")
ErrMemObjectAllocationFailure = errors.New("cl: Mem Object Allocation Failure")
ErrOutOfResources = errors.New("cl: Out Of Resources")
ErrOutOfHostMemory = errors.New("cl: Out Of Host Memory")
ErrProfilingInfoNotAvailable = errors.New("cl: Profiling Info Not Available")
ErrMemCopyOverlap = errors.New("cl: Mem Copy Overlap")
ErrImageFormatMismatch = errors.New("cl: Image Format Mismatch")
ErrImageFormatNotSupported = errors.New("cl: Image Format Not Supported")
ErrBuildProgramFailure = errors.New("cl: Build Program Failure")
ErrMapFailure = errors.New("cl: Map Failure")
ErrMisalignedSubBufferOffset = errors.New("cl: Misaligned Sub Buffer Offset")
ErrExecStatusErrorForEventsInWaitList = errors.New("cl: Exec Status Error For Events In Wait List")
ErrCompileProgramFailure = errors.New("cl: Compile Program Failure")
ErrLinkerNotAvailable = errors.New("cl: Linker Not Available")
ErrLinkProgramFailure = errors.New("cl: Link Program Failure")
ErrDevicePartitionFailed = errors.New("cl: Device Partition Failed")
ErrKernelArgInfoNotAvailable = errors.New("cl: Kernel Arg Info Not Available")
ErrInvalidValue = errors.New("cl: Invalid Value")
ErrInvalidDeviceType = errors.New("cl: Invalid Device Type")
ErrInvalidPlatform = errors.New("cl: Invalid Platform")
ErrInvalidDevice = errors.New("cl: Invalid Device")
ErrInvalidContext = errors.New("cl: Invalid Context")
ErrInvalidQueueProperties = errors.New("cl: Invalid Queue Properties")
ErrInvalidCommandQueue = errors.New("cl: Invalid Command Queue")
ErrInvalidHostPtr = errors.New("cl: Invalid Host Ptr")
ErrInvalidMemObject = errors.New("cl: Invalid Mem Object")
ErrInvalidImageFormatDescriptor = errors.New("cl: Invalid Image Format Descriptor")
ErrInvalidImageSize = errors.New("cl: Invalid Image Size")
ErrInvalidSampler = errors.New("cl: Invalid Sampler")
ErrInvalidBinary = errors.New("cl: Invalid Binary")
ErrInvalidBuildOptions = errors.New("cl: Invalid Build Options")
ErrInvalidProgram = errors.New("cl: Invalid Program")
ErrInvalidProgramExecutable = errors.New("cl: Invalid Program Executable")
ErrInvalidKernelName = errors.New("cl: Invalid Kernel Name")
ErrInvalidKernelDefinition = errors.New("cl: Invalid Kernel Definition")
ErrInvalidKernel = errors.New("cl: Invalid Kernel")
ErrInvalidArgIndex = errors.New("cl: Invalid Arg Index")
ErrInvalidArgValue = errors.New("cl: Invalid Arg Value")
ErrInvalidArgSize = errors.New("cl: Invalid Arg Size")
ErrInvalidKernelArgs = errors.New("cl: Invalid Kernel Args")
ErrInvalidWorkDimension = errors.New("cl: Invalid Work Dimension")
ErrInvalidWorkGroupSize = errors.New("cl: Invalid Work Group Size")
ErrInvalidWorkItemSize = errors.New("cl: Invalid Work Item Size")
ErrInvalidGlobalOffset = errors.New("cl: Invalid Global Offset")
ErrInvalidEventWaitList = errors.New("cl: Invalid Event Wait List")
ErrInvalidEvent = errors.New("cl: Invalid Event")
ErrInvalidOperation = errors.New("cl: Invalid Operation")
ErrInvalidGlObject = errors.New("cl: Invalid Gl Object")
ErrInvalidBufferSize = errors.New("cl: Invalid Buffer Size")
ErrInvalidMipLevel = errors.New("cl: Invalid Mip Level")
ErrInvalidGlobalWorkSize = errors.New("cl: Invalid Global Work Size")
ErrInvalidProperty = errors.New("cl: Invalid Property")
ErrInvalidImageDescriptor = errors.New("cl: Invalid Image Descriptor")
ErrInvalidCompilerOptions = errors.New("cl: Invalid Compiler Options")
ErrInvalidLinkerOptions = errors.New("cl: Invalid Linker Options")
ErrInvalidDevicePartitionCount = errors.New("cl: Invalid Device Partition Count")
)
var errorMap = map[C.cl_int]error{
C.CL_SUCCESS: nil,
C.CL_DEVICE_NOT_FOUND: ErrDeviceNotFound,
C.CL_DEVICE_NOT_AVAILABLE: ErrDeviceNotAvailable,
C.CL_COMPILER_NOT_AVAILABLE: ErrCompilerNotAvailable,
C.CL_MEM_OBJECT_ALLOCATION_FAILURE: ErrMemObjectAllocationFailure,
C.CL_OUT_OF_RESOURCES: ErrOutOfResources,
C.CL_OUT_OF_HOST_MEMORY: ErrOutOfHostMemory,
C.CL_PROFILING_INFO_NOT_AVAILABLE: ErrProfilingInfoNotAvailable,
C.CL_MEM_COPY_OVERLAP: ErrMemCopyOverlap,
C.CL_IMAGE_FORMAT_MISMATCH: ErrImageFormatMismatch,
C.CL_IMAGE_FORMAT_NOT_SUPPORTED: ErrImageFormatNotSupported,
C.CL_BUILD_PROGRAM_FAILURE: ErrBuildProgramFailure,
C.CL_MAP_FAILURE: ErrMapFailure,
C.CL_MISALIGNED_SUB_BUFFER_OFFSET: ErrMisalignedSubBufferOffset,
C.CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST: ErrExecStatusErrorForEventsInWaitList,
C.CL_INVALID_VALUE: ErrInvalidValue,
C.CL_INVALID_DEVICE_TYPE: ErrInvalidDeviceType,
C.CL_INVALID_PLATFORM: ErrInvalidPlatform,
C.CL_INVALID_DEVICE: ErrInvalidDevice,
C.CL_INVALID_CONTEXT: ErrInvalidContext,
C.CL_INVALID_QUEUE_PROPERTIES: ErrInvalidQueueProperties,
C.CL_INVALID_COMMAND_QUEUE: ErrInvalidCommandQueue,
C.CL_INVALID_HOST_PTR: ErrInvalidHostPtr,
C.CL_INVALID_MEM_OBJECT: ErrInvalidMemObject,
C.CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: ErrInvalidImageFormatDescriptor,
C.CL_INVALID_IMAGE_SIZE: ErrInvalidImageSize,
C.CL_INVALID_SAMPLER: ErrInvalidSampler,
C.CL_INVALID_BINARY: ErrInvalidBinary,
C.CL_INVALID_BUILD_OPTIONS: ErrInvalidBuildOptions,
C.CL_INVALID_PROGRAM: ErrInvalidProgram,
C.CL_INVALID_PROGRAM_EXECUTABLE: ErrInvalidProgramExecutable,
C.CL_INVALID_KERNEL_NAME: ErrInvalidKernelName,
C.CL_INVALID_KERNEL_DEFINITION: ErrInvalidKernelDefinition,
C.CL_INVALID_KERNEL: ErrInvalidKernel,
C.CL_INVALID_ARG_INDEX: ErrInvalidArgIndex,
C.CL_INVALID_ARG_VALUE: ErrInvalidArgValue,
C.CL_INVALID_ARG_SIZE: ErrInvalidArgSize,
C.CL_INVALID_KERNEL_ARGS: ErrInvalidKernelArgs,
C.CL_INVALID_WORK_DIMENSION: ErrInvalidWorkDimension,
C.CL_INVALID_WORK_GROUP_SIZE: ErrInvalidWorkGroupSize,
C.CL_INVALID_WORK_ITEM_SIZE: ErrInvalidWorkItemSize,
C.CL_INVALID_GLOBAL_OFFSET: ErrInvalidGlobalOffset,
C.CL_INVALID_EVENT_WAIT_LIST: ErrInvalidEventWaitList,
C.CL_INVALID_EVENT: ErrInvalidEvent,
C.CL_INVALID_OPERATION: ErrInvalidOperation,
C.CL_INVALID_GL_OBJECT: ErrInvalidGlObject,
C.CL_INVALID_BUFFER_SIZE: ErrInvalidBufferSize,
C.CL_INVALID_MIP_LEVEL: ErrInvalidMipLevel,
C.CL_INVALID_GLOBAL_WORK_SIZE: ErrInvalidGlobalWorkSize,
C.CL_INVALID_PROPERTY: ErrInvalidProperty,
}
func toError(code C.cl_int) error {
if err, ok := errorMap[code]; ok {
return err
}
return ErrOther(code)
}
type LocalMemType int
const (
LocalMemTypeNone LocalMemType = C.CL_NONE
LocalMemTypeGlobal LocalMemType = C.CL_GLOBAL
LocalMemTypeLocal LocalMemType = C.CL_LOCAL
)
var localMemTypeMap = map[LocalMemType]string{
LocalMemTypeNone: "None",
LocalMemTypeGlobal: "Global",
LocalMemTypeLocal: "Local",
}
func (t LocalMemType) String() string {
name := localMemTypeMap[t]
if name == "" {
name = "Unknown"
}
return name
}
type ExecCapability int
const (
ExecCapabilityKernel ExecCapability = C.CL_EXEC_KERNEL // The OpenCL device can execute OpenCL kernels.
ExecCapabilityNativeKernel ExecCapability = C.CL_EXEC_NATIVE_KERNEL // The OpenCL device can execute native kernels.
)
func (ec ExecCapability) String() string {
var parts []string
if ec&ExecCapabilityKernel != 0 {
parts = append(parts, "Kernel")
}
if ec&ExecCapabilityNativeKernel != 0 {
parts = append(parts, "NativeKernel")
}
if parts == nil {
return ""
}
return strings.Join(parts, "|")
}
type MemCacheType int
const (
MemCacheTypeNone MemCacheType = C.CL_NONE
MemCacheTypeReadOnlyCache MemCacheType = C.CL_READ_ONLY_CACHE
MemCacheTypeReadWriteCache MemCacheType = C.CL_READ_WRITE_CACHE
)
func (ct MemCacheType) String() string {
switch ct {
case MemCacheTypeNone:
return "None"
case MemCacheTypeReadOnlyCache:
return "ReadOnly"
case MemCacheTypeReadWriteCache:
return "ReadWrite"
}
return fmt.Sprintf("Unknown(%x)", int(ct))
}
type MemFlag int
const (
MemReadWrite MemFlag = C.CL_MEM_READ_WRITE
MemWriteOnly MemFlag = C.CL_MEM_WRITE_ONLY
MemReadOnly MemFlag = C.CL_MEM_READ_ONLY
MemUseHostPtr MemFlag = C.CL_MEM_USE_HOST_PTR
MemAllocHostPtr MemFlag = C.CL_MEM_ALLOC_HOST_PTR
MemCopyHostPtr MemFlag = C.CL_MEM_COPY_HOST_PTR
MemWriteOnlyHost MemFlag = C.CL_MEM_HOST_WRITE_ONLY
MemReadOnlyHost MemFlag = C.CL_MEM_HOST_READ_ONLY
MemNoAccessHost MemFlag = C.CL_MEM_HOST_NO_ACCESS
)
type MemObjectType int
const (
MemObjectTypeBuffer MemObjectType = C.CL_MEM_OBJECT_BUFFER
MemObjectTypeImage2D MemObjectType = C.CL_MEM_OBJECT_IMAGE2D
MemObjectTypeImage3D MemObjectType = C.CL_MEM_OBJECT_IMAGE3D
)
type MapFlag int
const (
// This flag specifies that the region being mapped in the memory object is being mapped for reading.
MapFlagRead MapFlag = C.CL_MAP_READ
MapFlagWrite MapFlag = C.CL_MAP_WRITE
MapFlagWriteInvalidateRegion MapFlag = C.CL_MAP_WRITE_INVALIDATE_REGION
)
func (mf MapFlag) toCl() C.cl_map_flags {
return C.cl_map_flags(mf)
}
type ChannelOrder int
const (
ChannelOrderR ChannelOrder = C.CL_R
ChannelOrderA ChannelOrder = C.CL_A
ChannelOrderRG ChannelOrder = C.CL_RG
ChannelOrderRA ChannelOrder = C.CL_RA
ChannelOrderRGB ChannelOrder = C.CL_RGB
ChannelOrderRGBA ChannelOrder = C.CL_RGBA
ChannelOrderBGRA ChannelOrder = C.CL_BGRA
ChannelOrderARGB ChannelOrder = C.CL_ARGB
ChannelOrderIntensity ChannelOrder = C.CL_INTENSITY
ChannelOrderLuminance ChannelOrder = C.CL_LUMINANCE
ChannelOrderRx ChannelOrder = C.CL_Rx
ChannelOrderRGx ChannelOrder = C.CL_RGx
ChannelOrderRGBx ChannelOrder = C.CL_RGBx
)
var channelOrderNameMap = map[ChannelOrder]string{
ChannelOrderR: "R",
ChannelOrderA: "A",
ChannelOrderRG: "RG",
ChannelOrderRA: "RA",
ChannelOrderRGB: "RGB",
ChannelOrderRGBA: "RGBA",
ChannelOrderBGRA: "BGRA",
ChannelOrderARGB: "ARGB",
ChannelOrderIntensity: "Intensity",
ChannelOrderLuminance: "Luminance",
ChannelOrderRx: "Rx",
ChannelOrderRGx: "RGx",
ChannelOrderRGBx: "RGBx",
}
func (co ChannelOrder) String() string {
name := channelOrderNameMap[co]
if name == "" {
name = fmt.Sprintf("Unknown(%x)", int(co))
}
return name
}
type ChannelDataType int
const (
ChannelDataTypeSNormInt8 ChannelDataType = C.CL_SNORM_INT8
ChannelDataTypeSNormInt16 ChannelDataType = C.CL_SNORM_INT16
ChannelDataTypeUNormInt8 ChannelDataType = C.CL_UNORM_INT8
ChannelDataTypeUNormInt16 ChannelDataType = C.CL_UNORM_INT16
ChannelDataTypeUNormShort565 ChannelDataType = C.CL_UNORM_SHORT_565
ChannelDataTypeUNormShort555 ChannelDataType = C.CL_UNORM_SHORT_555
ChannelDataTypeUNormInt101010 ChannelDataType = C.CL_UNORM_INT_101010
ChannelDataTypeSignedInt8 ChannelDataType = C.CL_SIGNED_INT8
ChannelDataTypeSignedInt16 ChannelDataType = C.CL_SIGNED_INT16
ChannelDataTypeSignedInt32 ChannelDataType = C.CL_SIGNED_INT32
ChannelDataTypeUnsignedInt8 ChannelDataType = C.CL_UNSIGNED_INT8
ChannelDataTypeUnsignedInt16 ChannelDataType = C.CL_UNSIGNED_INT16
ChannelDataTypeUnsignedInt32 ChannelDataType = C.CL_UNSIGNED_INT32
ChannelDataTypeHalfFloat ChannelDataType = C.CL_HALF_FLOAT
ChannelDataTypeFloat ChannelDataType = C.CL_FLOAT
)
var channelDataTypeNameMap = map[ChannelDataType]string{
ChannelDataTypeSNormInt8: "SNormInt8",
ChannelDataTypeSNormInt16: "SNormInt16",
ChannelDataTypeUNormInt8: "UNormInt8",
ChannelDataTypeUNormInt16: "UNormInt16",
ChannelDataTypeUNormShort565: "UNormShort565",
ChannelDataTypeUNormShort555: "UNormShort555",
ChannelDataTypeUNormInt101010: "UNormInt101010",
ChannelDataTypeSignedInt8: "SignedInt8",
ChannelDataTypeSignedInt16: "SignedInt16",
ChannelDataTypeSignedInt32: "SignedInt32",
ChannelDataTypeUnsignedInt8: "UnsignedInt8",
ChannelDataTypeUnsignedInt16: "UnsignedInt16",
ChannelDataTypeUnsignedInt32: "UnsignedInt32",
ChannelDataTypeHalfFloat: "HalfFloat",
ChannelDataTypeFloat: "Float",
}
func (ct ChannelDataType) String() string {
name := channelDataTypeNameMap[ct]
if name == "" {
name = fmt.Sprintf("Unknown(%x)", int(ct))
}
return name
}
type ImageFormat struct {
ChannelOrder ChannelOrder
ChannelDataType ChannelDataType
}
func (f ImageFormat) toCl() C.cl_image_format {
var format C.cl_image_format
format.image_channel_order = C.cl_channel_order(f.ChannelOrder)
format.image_channel_data_type = C.cl_channel_type(f.ChannelDataType)
return format
}
type ProfilingInfo int
const (
// A 64-bit value that describes the current device time counter in
// nanoseconds when the command identified by event is enqueued in
// a command-queue by the host.
ProfilingInfoCommandQueued ProfilingInfo = C.CL_PROFILING_COMMAND_QUEUED
// A 64-bit value that describes the current device time counter in
// nanoseconds when the command identified by event that has been
// enqueued is submitted by the host to the device associated with the command-queue.
ProfilingInfoCommandSubmit ProfilingInfo = C.CL_PROFILING_COMMAND_SUBMIT
// A 64-bit value that describes the current device time counter in
// nanoseconds when the command identified by event starts execution on the device.
ProfilingInfoCommandStart ProfilingInfo = C.CL_PROFILING_COMMAND_START
// A 64-bit value that describes the current device time counter in
// nanoseconds when the command identified by event has finished
// execution on the device.
ProfilingInfoCommandEnd ProfilingInfo = C.CL_PROFILING_COMMAND_END
)
type CommmandExecStatus int
const (
CommmandExecStatusComplete CommmandExecStatus = C.CL_COMPLETE
CommmandExecStatusRunning CommmandExecStatus = C.CL_RUNNING
CommmandExecStatusSubmitted CommmandExecStatus = C.CL_SUBMITTED
CommmandExecStatusQueued CommmandExecStatus = C.CL_QUEUED
)
type Event struct {
clEvent C.cl_event
}
func releaseEvent(ev *Event) {
if ev.clEvent != nil {
C.clReleaseEvent(ev.clEvent)
ev.clEvent = nil
}
}
func (e *Event) Release() {
releaseEvent(e)
}
func (e *Event) GetEventProfilingInfo(paramName ProfilingInfo) (int64, error) {
var paramValue C.cl_ulong
if err := C.clGetEventProfilingInfo(e.clEvent, C.cl_profiling_info(paramName), C.size_t(unsafe.Sizeof(paramValue)), unsafe.Pointer(&paramValue), nil); err != C.CL_SUCCESS {
return 0, toError(err)
}
return int64(paramValue), nil
}
// Sets the execution status of a user event object.
//
// `status` specifies the new execution status to be set and
// can be CL_COMPLETE or a negative integer value to indicate
// an error. A negative integer value causes all enqueued commands
// that wait on this user event to be terminated. clSetUserEventStatus
// can only be called once to change the execution status of event.
func (e *Event) SetUserEventStatus(status int) error {
return toError(C.clSetUserEventStatus(e.clEvent, C.cl_int(status)))
}
// Waits on the host thread for commands identified by event objects in
// events to complete. A command is considered complete if its execution
// status is CL_COMPLETE or a negative value. The events specified in
// event_list act as synchronization points.
//
// If the cl_khr_gl_event extension is enabled, event objects can also be
// used to reflect the status of an OpenGL sync object. The sync object
// in turn refers to a fence command executing in an OpenGL command
// stream. This provides another method of coordinating sharing of buffers
// and images between OpenGL and OpenCL.
func WaitForEvents(events []*Event) error {
return toError(C.clWaitForEvents(C.cl_uint(len(events)), eventListPtr(events)))
}
func newEvent(clEvent C.cl_event) *Event {
ev := &Event{clEvent: clEvent}
runtime.SetFinalizer(ev, releaseEvent)
return ev
}
func eventListPtr(el []*Event) *C.cl_event {
if el == nil {
return nil
}
elist := make([]C.cl_event, len(el))
for i, e := range el {
elist[i] = e.clEvent
}
return (*C.cl_event)(&elist[0])
}
func clBool(b bool) C.cl_bool {
if b {
return C.CL_TRUE
}
return C.CL_FALSE
}
func sizeT3(i3 [3]int) [3]C.size_t {
var val [3]C.size_t
val[0] = C.size_t(i3[0])
val[1] = C.size_t(i3[1])
val[2] = C.size_t(i3[2])
return val
}
type MappedMemObject struct {
ptr unsafe.Pointer
size int
rowPitch int
slicePitch int
}
func (mb *MappedMemObject) ByteSlice() []byte {
var byteSlice []byte
sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&byteSlice))
sliceHeader.Cap = mb.size
sliceHeader.Len = mb.size
sliceHeader.Data = uintptr(mb.ptr)
return byteSlice
}
func (mb *MappedMemObject) Ptr() unsafe.Pointer {
return mb.ptr
}
func (mb *MappedMemObject) Size() int {
return mb.size
}
func (mb *MappedMemObject) RowPitch() int {
return mb.rowPitch
}
func (mb *MappedMemObject) SlicePitch() int {
return mb.slicePitch
}

View File

@ -0,0 +1,71 @@
// +build cl12
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
const (
ChannelDataTypeUNormInt24 ChannelDataType = C.CL_UNORM_INT24
ChannelOrderDepth ChannelOrder = C.CL_DEPTH
ChannelOrderDepthStencil ChannelOrder = C.CL_DEPTH_STENCIL
MemHostNoAccess MemFlag = C.CL_MEM_HOST_NO_ACCESS // OpenCL 1.2
MemHostReadOnly MemFlag = C.CL_MEM_HOST_READ_ONLY // OpenCL 1.2
MemHostWriteOnly MemFlag = C.CL_MEM_HOST_WRITE_ONLY // OpenCL 1.2
MemObjectTypeImage1D MemObjectType = C.CL_MEM_OBJECT_IMAGE1D
MemObjectTypeImage1DArray MemObjectType = C.CL_MEM_OBJECT_IMAGE1D_ARRAY
MemObjectTypeImage1DBuffer MemObjectType = C.CL_MEM_OBJECT_IMAGE1D_BUFFER
MemObjectTypeImage2DArray MemObjectType = C.CL_MEM_OBJECT_IMAGE2D_ARRAY
// This flag specifies that the region being mapped in the memory object is being mapped for writing.
//
// The contents of the region being mapped are to be discarded. This is typically the case when the
// region being mapped is overwritten by the host. This flag allows the implementation to no longer
// guarantee that the pointer returned by clEnqueueMapBuffer or clEnqueueMapImage contains the
// latest bits in the region being mapped which can be a significant performance enhancement.
MapFlagWriteInvalidateRegion MapFlag = C.CL_MAP_WRITE_INVALIDATE_REGION
)
func init() {
errorMap[C.CL_COMPILE_PROGRAM_FAILURE] = ErrCompileProgramFailure
errorMap[C.CL_DEVICE_PARTITION_FAILED] = ErrDevicePartitionFailed
errorMap[C.CL_INVALID_COMPILER_OPTIONS] = ErrInvalidCompilerOptions
errorMap[C.CL_INVALID_DEVICE_PARTITION_COUNT] = ErrInvalidDevicePartitionCount
errorMap[C.CL_INVALID_IMAGE_DESCRIPTOR] = ErrInvalidImageDescriptor
errorMap[C.CL_INVALID_LINKER_OPTIONS] = ErrInvalidLinkerOptions
errorMap[C.CL_KERNEL_ARG_INFO_NOT_AVAILABLE] = ErrKernelArgInfoNotAvailable
errorMap[C.CL_LINK_PROGRAM_FAILURE] = ErrLinkProgramFailure
errorMap[C.CL_LINKER_NOT_AVAILABLE] = ErrLinkerNotAvailable
channelOrderNameMap[ChannelOrderDepth] = "Depth"
channelOrderNameMap[ChannelOrderDepthStencil] = "DepthStencil"
channelDataTypeNameMap[ChannelDataTypeUNormInt24] = "UNormInt24"
}
type ImageDescription struct {
Type MemObjectType
Width, Height, Depth int
ArraySize, RowPitch, SlicePitch int
NumMipLevels, NumSamples int
Buffer *MemObject
}
func (d ImageDescription) toCl() C.cl_image_desc {
var desc C.cl_image_desc
desc.image_type = C.cl_mem_object_type(d.Type)
desc.image_width = C.size_t(d.Width)
desc.image_height = C.size_t(d.Height)
desc.image_depth = C.size_t(d.Depth)
desc.image_array_size = C.size_t(d.ArraySize)
desc.image_row_pitch = C.size_t(d.RowPitch)
desc.image_slice_pitch = C.size_t(d.SlicePitch)
desc.num_mip_levels = C.cl_uint(d.NumMipLevels)
desc.num_samples = C.cl_uint(d.NumSamples)
desc.buffer = nil
if d.Buffer != nil {
desc.buffer = d.Buffer.clMem
}
return desc
}

View File

@ -0,0 +1,45 @@
package cl
// #ifdef __APPLE__
// #include "OpenCL/opencl.h"
// #else
// #include "cl.h"
// #endif
import "C"
// Extension: cl_APPLE_fixed_alpha_channel_orders
//
// These selectors may be passed to clCreateImage2D() in the cl_image_format.image_channel_order field.
// They are like CL_BGRA and CL_ARGB except that the alpha channel to be ignored. On calls to read_imagef,
// the alpha will be 0xff (1.0f) if the sample falls in the image and 0 if it does not fall in the image.
// On calls to write_imagef, the alpha value is ignored and 0xff (1.0f) is written. These formats are
// currently only available for the CL_UNORM_INT8 cl_channel_type. They are intended to support legacy
// image formats.
const (
ChannelOrder1RGBApple ChannelOrder = C.CL_1RGB_APPLE // Introduced in MacOS X.7.
ChannelOrderBGR1Apple ChannelOrder = C.CL_BGR1_APPLE // Introduced in MacOS X.7.
)
// Extension: cl_APPLE_biased_fixed_point_image_formats
//
// This selector may be passed to clCreateImage2D() in the cl_image_format.image_channel_data_type field.
// It defines a biased signed 1.14 fixed point storage format, with range [-1, 3). The conversion from
// float to this fixed point format is defined as follows:
//
// ushort float_to_sfixed14( float x ){
// int i = convert_int_sat_rte( x * 0x1.0p14f ); // scale [-1, 3.0) to [-16384, 3*16384), round to nearest integer
// i = add_sat( i, 0x4000 ); // apply bias, to convert to [0, 65535) range
// return convert_ushort_sat(i); // clamp to destination size
// }
//
// The inverse conversion is the reverse process. The formats are currently only available on the CPU with
// the CL_RGBA channel layout.
const (
ChannelDataTypeSFixed14Apple ChannelDataType = C.CL_SFIXED14_APPLE // Introduced in MacOS X.7.
)
func init() {
channelOrderNameMap[ChannelOrder1RGBApple] = "1RGBApple"
channelOrderNameMap[ChannelOrderBGR1Apple] = "RGB1Apple"
channelDataTypeNameMap[ChannelDataTypeSFixed14Apple] = "SFixed14Apple"
}

View File

@ -1,5 +1,12 @@
language: go
go: 1.1
sudo: false
go:
- 1.0.3
- 1.1.2
- 1.2.2
- 1.3.3
- 1.4.2
script:
- go vet ./...

View File

@ -1,18 +1,17 @@
[![Coverage](http://gocover.io/_badge/github.com/codegangsta/cli?0)](http://gocover.io/github.com/codegangsta/cli)
[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli)
[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/codegangsta/cli)
# cli.go
cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
You can view the API docs here:
http://godoc.org/github.com/codegangsta/cli
`cli.go` is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
## Overview
Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app.
**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive!
**This is where `cli.go` comes into play.** `cli.go` makes command line programming fun, organized, and expressive!
## Installation
Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html).
Make sure you have a working Go environment (go 1.1+ is *required*). [See the install instructions](http://golang.org/doc/install.html).
To install `cli.go`, simply run:
```
@ -25,7 +24,7 @@ export PATH=$PATH:$GOPATH/bin
```
## Getting Started
One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`.
One of the philosophies behind `cli.go` is that an API should be playful and full of discovery. So a `cli.go` app can be as little as one line of code in `main()`.
``` go
package main
@ -103,7 +102,8 @@ $ greet
Hello friend!
```
cli.go also generates some bitchass help text:
`cli.go` also generates neat help text:
```
$ greet help
NAME:
@ -158,6 +158,8 @@ app.Action = func(c *cli.Context) {
...
```
See full list of flags at http://godoc.org/github.com/codegangsta/cli
#### Alternate Names
You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g.
@ -289,6 +291,21 @@ setting the `PROG` variable to the name of your program:
`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
#### To Distribute
Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
it to the name of the program you wish to add autocomplete support for (or
automatically install it there if you are distributing a package). Don't forget
to source the file to make it active in the current shell.
```
sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
source /etc/bash_completion.d/<myprogram>
```
Alternatively, you can just document that users should source the generic
`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
to the name of their program (as above).
## Contribution Guidelines
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.

View File

@ -5,19 +5,20 @@ import (
"io"
"io/ioutil"
"os"
"strings"
"text/tabwriter"
"text/template"
"time"
)
// App is the main structure of a cli application. It is recomended that
// and app be created with the cli.NewApp() function
// an app be created with the cli.NewApp() function
type App struct {
// The name of the program. Defaults to os.Args[0]
Name string
// Full name of command for help, defaults to Name
HelpName string
// Description of the program.
Usage string
// Description of the program argument format.
ArgsUsage string
// Version of the program
Version string
// List of commands to execute
@ -46,6 +47,8 @@ type App struct {
Compiled time.Time
// List of all authors who contributed
Authors []Author
// Copyright of the binary if any
Copyright string
// Name of Author (Note: Use App.Authors, this is deprecated)
Author string
// Email of Author (Note: Use App.Authors, this is deprecated)
@ -68,6 +71,7 @@ func compileTime() time.Time {
func NewApp() *App {
return &App{
Name: os.Args[0],
HelpName: os.Args[0],
Usage: "A new cli application",
Version: "0.0.0",
BashComplete: DefaultAppComplete,
@ -83,25 +87,14 @@ func (a *App) Run(arguments []string) (err error) {
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
}
if HelpPrinter == nil {
defer func() {
HelpPrinter = nil
}()
HelpPrinter = func(templ string, data interface{}) {
funcMap := template.FuncMap{
"join": strings.Join,
}
w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data)
if err != nil {
panic(err)
}
w.Flush()
newCmds := []Command{}
for _, c := range a.Commands {
if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
}
newCmds = append(newCmds, c)
}
a.Commands = newCmds
// append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
@ -127,17 +120,16 @@ func (a *App) Run(arguments []string) (err error) {
nerr := normalizeFlags(a.Flags, set)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
context := NewContext(a, set, set)
context := NewContext(a, set, nil)
ShowAppHelp(context)
fmt.Fprintln(a.Writer)
return nerr
}
context := NewContext(a, set, set)
context := NewContext(a, set, nil)
if err != nil {
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
ShowAppHelp(context)
fmt.Fprintln(a.Writer, "Incorrect Usage.")
fmt.Fprintln(a.Writer)
ShowAppHelp(context)
return err
}
@ -145,20 +137,26 @@ func (a *App) Run(arguments []string) (err error) {
return nil
}
if checkHelp(context) {
if !a.HideHelp && checkHelp(context) {
ShowAppHelp(context)
return nil
}
if checkVersion(context) {
if !a.HideVersion && checkVersion(context) {
ShowVersion(context)
return nil
}
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
afterErr := a.After(context)
if afterErr != nil {
if err != nil {
err = NewMultiError(err, afterErr)
} else {
err = afterErr
}
}
}()
}
@ -203,6 +201,15 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
}
}
newCmds := []Command{}
for _, c := range a.Commands {
if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
}
newCmds = append(newCmds, c)
}
a.Commands = newCmds
// append flags
if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag)
@ -213,21 +220,22 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
set.SetOutput(ioutil.Discard)
err = set.Parse(ctx.Args().Tail())
nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, ctx.globalSet)
context := NewContext(a, set, ctx)
if nerr != nil {
fmt.Fprintln(a.Writer, nerr)
fmt.Fprintln(a.Writer)
if len(a.Commands) > 0 {
ShowSubcommandHelp(context)
} else {
ShowCommandHelp(ctx, context.Args().First())
}
fmt.Fprintln(a.Writer)
return nerr
}
if err != nil {
fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
fmt.Fprintln(a.Writer, "Incorrect Usage.")
fmt.Fprintln(a.Writer)
ShowSubcommandHelp(context)
return err
}
@ -248,10 +256,14 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
afterErr := a.After(context)
if afterErr != nil {
if err != nil {
err = NewMultiError(err, afterErr)
} else {
err = afterErr
}
}
}()
}

View File

@ -1,622 +0,0 @@
package cli_test
import (
"flag"
"fmt"
"os"
"testing"
"github.com/codegangsta/cli"
)
func ExampleApp() {
// set args for examples sake
os.Args = []string{"greet", "--name", "Jeremy"}
app := cli.NewApp()
app.Name = "greet"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Action = func(c *cli.Context) {
fmt.Printf("Hello %v\n", c.String("name"))
}
app.Author = "Harrison"
app.Email = "harrison@lolwut.com"
app.Authors = []cli.Author{cli.Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
app.Run(os.Args)
// Output:
// Hello Jeremy
}
func ExampleAppSubcommand() {
// set args for examples sake
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
app := cli.NewApp()
app.Name = "say"
app.Commands = []cli.Command{
{
Name: "hello",
Aliases: []string{"hi"},
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []cli.Command{
{
Name: "english",
Aliases: []string{"en"},
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *cli.Context) {
fmt.Println("Hello,", c.String("name"))
},
},
},
},
}
app.Run(os.Args)
// Output:
// Hello, Jeremy
}
func ExampleAppHelp() {
// set args for examples sake
os.Args = []string{"greet", "h", "describeit"}
app := cli.NewApp()
app.Name = "greet"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Commands = []cli.Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) {
fmt.Printf("i like to describe things")
},
},
}
app.Run(os.Args)
// Output:
// NAME:
// describeit - use it to see a description
//
// USAGE:
// command describeit [arguments...]
//
// DESCRIPTION:
// This is how we describe describeit the function
}
func ExampleAppBashComplete() {
// set args for examples sake
os.Args = []string{"greet", "--generate-bash-completion"}
app := cli.NewApp()
app.Name = "greet"
app.EnableBashCompletion = true
app.Commands = []cli.Command{
{
Name: "describeit",
Aliases: []string{"d"},
Usage: "use it to see a description",
Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) {
fmt.Printf("i like to describe things")
},
}, {
Name: "next",
Usage: "next example",
Description: "more stuff to see when generating bash completion",
Action: func(c *cli.Context) {
fmt.Printf("the next example")
},
},
}
app.Run(os.Args)
// Output:
// describeit
// d
// next
// help
// h
}
func TestApp_Run(t *testing.T) {
s := ""
app := cli.NewApp()
app.Action = func(c *cli.Context) {
s = s + c.Args().First()
}
err := app.Run([]string{"command", "foo"})
expect(t, err, nil)
err = app.Run([]string{"command", "bar"})
expect(t, err, nil)
expect(t, s, "foobar")
}
var commandAppTests = []struct {
name string
expected bool
}{
{"foobar", true},
{"batbaz", true},
{"b", true},
{"f", true},
{"bat", false},
{"nothing", false},
}
func TestApp_Command(t *testing.T) {
app := cli.NewApp()
fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}}
batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}}
app.Commands = []cli.Command{
fooCommand,
batCommand,
}
for _, test := range commandAppTests {
expect(t, app.Command(test.name) != nil, test.expected)
}
}
func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
var parsedOption, firstArg string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *cli.Context) {
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"})
expect(t, parsedOption, "my-option")
expect(t, firstArg, "my-arg")
}
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
var context *cli.Context
a := cli.NewApp()
a.Commands = []cli.Command{
{
Name: "foo",
Action: func(c *cli.Context) {
context = c
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
},
Before: func(_ *cli.Context) error { return nil },
},
}
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
expect(t, context.Args().Get(0), "abcd")
expect(t, context.String("lang"), "spanish")
}
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
var parsedOption string
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *cli.Context) {
parsedOption = c.String("option")
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
expect(t, parsedOption, "my-option")
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "--notARealFlag")
}
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Action: func(c *cli.Context) {
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "notAFlagAtAll")
}
func TestApp_Float64Flag(t *testing.T) {
var meters float64
app := cli.NewApp()
app.Flags = []cli.Flag{
cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
}
app.Action = func(c *cli.Context) {
meters = c.Float64("height")
}
app.Run([]string{"", "--height", "1.93"})
expect(t, meters, 1.93)
}
func TestApp_ParseSliceFlags(t *testing.T) {
var parsedOption, firstArg string
var parsedIntSlice []int
var parsedStringSlice []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"},
cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"},
},
Action: func(c *cli.Context) {
parsedIntSlice = c.IntSlice("p")
parsedStringSlice = c.StringSlice("ip")
parsedOption = c.String("option")
firstArg = c.Args().First()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"})
IntsEquals := func(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
StrsEquals := func(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
var expectedIntSlice = []int{22, 80}
var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"}
if !IntsEquals(parsedIntSlice, expectedIntSlice) {
t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice)
}
if !StrsEquals(parsedStringSlice, expectedStringSlice) {
t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice)
}
}
func TestApp_DefaultStdout(t *testing.T) {
app := cli.NewApp()
if app.Writer != os.Stdout {
t.Error("Default output writer not set.")
}
}
type mockWriter struct {
written []byte
}
func (fw *mockWriter) Write(p []byte) (n int, err error) {
if fw.written == nil {
fw.written = p
} else {
fw.written = append(fw.written, p...)
}
return len(p), nil
}
func (fw *mockWriter) GetWritten() (b []byte) {
return fw.written
}
func TestApp_SetStdout(t *testing.T) {
w := &mockWriter{}
app := cli.NewApp()
app.Name = "test"
app.Writer = w
err := app.Run([]string{"help"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if len(w.written) == 0 {
t.Error("App did not write output to desired writer.")
}
}
func TestApp_BeforeFunc(t *testing.T) {
beforeRun, subcommandRun := false, false
beforeError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.Before = func(c *cli.Context) error {
beforeRun = true
s := c.String("opt")
if s == "fail" {
return beforeError
}
return nil
}
app.Commands = []cli.Command{
cli.Command{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the Before() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
beforeRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != beforeError {
t.Errorf("Run error expected, but not received")
}
if beforeRun == false {
t.Errorf("Before() not executed when expected")
}
if subcommandRun == true {
t.Errorf("Subcommand executed when NOT expected")
}
}
func TestApp_AfterFunc(t *testing.T) {
afterRun, subcommandRun := false, false
afterError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.After = func(c *cli.Context) error {
afterRun = true
s := c.String("opt")
if s == "fail" {
return afterError
}
return nil
}
app.Commands = []cli.Command{
cli.Command{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the After() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
afterRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != afterError {
t.Errorf("Run error expected, but not received")
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
}
func TestAppNoHelpFlag(t *testing.T) {
oldFlag := cli.HelpFlag
defer func() {
cli.HelpFlag = oldFlag
}()
cli.HelpFlag = cli.BoolFlag{}
app := cli.NewApp()
err := app.Run([]string{"test", "-h"})
if err != flag.ErrHelp {
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
}
}
func TestAppHelpPrinter(t *testing.T) {
oldPrinter := cli.HelpPrinter
defer func() {
cli.HelpPrinter = oldPrinter
}()
var wasCalled = false
cli.HelpPrinter = func(template string, data interface{}) {
wasCalled = true
}
app := cli.NewApp()
app.Run([]string{"-h"})
if wasCalled == false {
t.Errorf("Help printer expected to be called, but was not")
}
}
func TestAppVersionPrinter(t *testing.T) {
oldPrinter := cli.VersionPrinter
defer func() {
cli.VersionPrinter = oldPrinter
}()
var wasCalled = false
cli.VersionPrinter = func(c *cli.Context) {
wasCalled = true
}
app := cli.NewApp()
ctx := cli.NewContext(app, nil, nil)
cli.ShowVersion(ctx)
if wasCalled == false {
t.Errorf("Version printer expected to be called, but was not")
}
}
func TestAppCommandNotFound(t *testing.T) {
beforeRun, subcommandRun := false, false
app := cli.NewApp()
app.CommandNotFound = func(c *cli.Context, command string) {
beforeRun = true
}
app.Commands = []cli.Command{
cli.Command{
Name: "bar",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Run([]string{"command", "foo"})
expect(t, beforeRun, true)
expect(t, subcommandRun, false)
}
func TestGlobalFlagsInSubcommands(t *testing.T) {
subcommandRun := false
app := cli.NewApp()
app.Flags = []cli.Flag{
cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
}
app.Commands = []cli.Command{
cli.Command{
Name: "foo",
Subcommands: []cli.Command{
{
Name: "bar",
Action: func(c *cli.Context) {
if c.GlobalBool("debug") {
subcommandRun = true
}
},
},
},
},
}
app.Run([]string{"command", "-d", "foo", "bar"})
expect(t, subcommandRun, true)
}

View File

@ -1,5 +1,7 @@
#! /bin/bash
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
local cur prev opts base
COMPREPLY=()

View File

@ -17,3 +17,24 @@
// app.Run(os.Args)
// }
package cli
import (
"strings"
)
type MultiError struct {
Errors []error
}
func NewMultiError(err ...error) MultiError {
return MultiError{Errors: err}
}
func (m MultiError) Error() string {
errs := make([]string, len(m.Errors))
for i, err := range m.Errors {
errs[i] = err.Error()
}
return strings.Join(errs, "\n")
}

View File

@ -1,100 +0,0 @@
package cli_test
import (
"os"
"github.com/codegangsta/cli"
)
func Example() {
app := cli.NewApp()
app.Name = "todo"
app.Usage = "task list on the command line"
app.Commands = []cli.Command{
{
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) {
println("added task: ", c.Args().First())
},
},
{
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) {
println("completed task: ", c.Args().First())
},
},
}
app.Run(os.Args)
}
func ExampleSubcommand() {
app := cli.NewApp()
app.Name = "say"
app.Commands = []cli.Command{
{
Name: "hello",
Aliases: []string{"hi"},
Usage: "use it to see a description",
Description: "This is how we describe hello the function",
Subcommands: []cli.Command{
{
Name: "english",
Aliases: []string{"en"},
Usage: "sends a greeting in english",
Description: "greets someone in english",
Flags: []cli.Flag{
cli.StringFlag{
Name: "name",
Value: "Bob",
Usage: "Name of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Hello, ", c.String("name"))
},
}, {
Name: "spanish",
Aliases: []string{"sp"},
Usage: "sends a greeting in spanish",
Flags: []cli.Flag{
cli.StringFlag{
Name: "surname",
Value: "Jones",
Usage: "Surname of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Hola, ", c.String("surname"))
},
}, {
Name: "french",
Aliases: []string{"fr"},
Usage: "sends a greeting in french",
Flags: []cli.Flag{
cli.StringFlag{
Name: "nickname",
Value: "Stevie",
Usage: "Nickname of the person to greet",
},
},
Action: func(c *cli.Context) {
println("Bonjour, ", c.String("nickname"))
},
},
},
}, {
Name: "bye",
Usage: "says goodbye",
Action: func(c *cli.Context) {
println("bye")
},
},
}
app.Run(os.Args)
}

View File

@ -18,6 +18,8 @@ type Command struct {
Usage string
// A longer explanation of how the command works
Description string
// A short description of the arguments of this command
ArgsUsage string
// The function to call when checking for bash command completions
BashComplete func(context *Context)
// An action to execute before any sub-subcommands are run, but after the context is ready
@ -36,11 +38,23 @@ type Command struct {
SkipFlagParsing bool
// Boolean to hide built-in help command
HideHelp bool
// Full name of command for help, defaults to full command name, including parent commands.
HelpName string
commandNamePath []string
}
// Returns the full name of the command.
// For subcommands this ensures that parent commands are part of the command path
func (c Command) FullName() string {
if c.commandNamePath == nil {
return c.Name
}
return strings.Join(c.commandNamePath, " ")
}
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) error {
if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
return c.startApp(ctx)
}
@ -91,9 +105,9 @@ func (c Command) Run(ctx *Context) error {
}
if err != nil {
fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n")
ShowCommandHelp(ctx, c.Name)
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
return err
}
@ -102,10 +116,9 @@ func (c Command) Run(ctx *Context) error {
fmt.Fprintln(ctx.App.Writer, nerr)
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
fmt.Fprintln(ctx.App.Writer)
return nerr
}
context := NewContext(ctx.App, set, ctx.globalSet)
context := NewContext(ctx.App, set, ctx)
if checkCommandCompletions(context, c.Name) {
return nil
@ -144,6 +157,12 @@ func (c Command) startApp(ctx *Context) error {
// set the name and usage
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
if c.HelpName == "" {
app.HelpName = c.HelpName
} else {
app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
}
if c.Description != "" {
app.Usage = c.Description
} else {
@ -158,6 +177,13 @@ func (c Command) startApp(ctx *Context) error {
app.Flags = c.Flags
app.HideHelp = c.HideHelp
app.Version = ctx.App.Version
app.HideVersion = ctx.App.HideVersion
app.Compiled = ctx.App.Compiled
app.Author = ctx.App.Author
app.Email = ctx.App.Email
app.Writer = ctx.App.Writer
// bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion
if c.BashComplete != nil {
@ -173,5 +199,12 @@ func (c Command) startApp(ctx *Context) error {
app.Action = helpSubcommand.Action
}
var newCmds []Command
for _, cc := range app.Commands {
cc.commandNamePath = []string{c.Name, cc.Name}
newCmds = append(newCmds, cc)
}
app.Commands = newCmds
return app.RunAsSubcommand(ctx)
}

View File

@ -1,49 +0,0 @@
package cli_test
import (
"flag"
"testing"
"github.com/codegangsta/cli"
)
func TestCommandDoNotIgnoreFlags(t *testing.T) {
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah", "-break"}
set.Parse(test)
c := cli.NewContext(app, set, set)
command := cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *cli.Context) {},
}
err := command.Run(c)
expect(t, err.Error(), "flag provided but not defined: -break")
}
func TestCommandIgnoreFlags(t *testing.T) {
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"blah", "blah"}
set.Parse(test)
c := cli.NewContext(app, set, set)
command := cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(_ *cli.Context) {},
SkipFlagParsing: true,
}
err := command.Run(c)
expect(t, err, nil)
}

View File

@ -16,14 +16,14 @@ type Context struct {
App *App
Command Command
flagSet *flag.FlagSet
globalSet *flag.FlagSet
setFlags map[string]bool
globalSetFlags map[string]bool
parentContext *Context
}
// Creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context {
return &Context{App: app, flagSet: set, globalSet: globalSet}
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
return &Context{App: app, flagSet: set, parentContext: parentCtx}
}
// Looks up the value of a local int flag, returns 0 if no int flag exists
@ -73,37 +73,58 @@ func (c *Context) Generic(name string) interface{} {
// Looks up the value of a global int flag, returns 0 if no int flag exists
func (c *Context) GlobalInt(name string) int {
return lookupInt(name, c.globalSet)
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupInt(name, fs)
}
return 0
}
// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists
func (c *Context) GlobalDuration(name string) time.Duration {
return lookupDuration(name, c.globalSet)
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupDuration(name, fs)
}
return 0
}
// Looks up the value of a global bool flag, returns false if no bool flag exists
func (c *Context) GlobalBool(name string) bool {
return lookupBool(name, c.globalSet)
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupBool(name, fs)
}
return false
}
// Looks up the value of a global string flag, returns "" if no string flag exists
func (c *Context) GlobalString(name string) string {
return lookupString(name, c.globalSet)
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupString(name, fs)
}
return ""
}
// Looks up the value of a global string slice flag, returns nil if no string slice flag exists
func (c *Context) GlobalStringSlice(name string) []string {
return lookupStringSlice(name, c.globalSet)
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupStringSlice(name, fs)
}
return nil
}
// Looks up the value of a global int slice flag, returns nil if no int slice flag exists
func (c *Context) GlobalIntSlice(name string) []int {
return lookupIntSlice(name, c.globalSet)
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupIntSlice(name, fs)
}
return nil
}
// Looks up the value of a global generic flag, returns nil if no generic flag exists
func (c *Context) GlobalGeneric(name string) interface{} {
return lookupGeneric(name, c.globalSet)
if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupGeneric(name, fs)
}
return nil
}
// Returns the number of flags set
@ -126,11 +147,17 @@ func (c *Context) IsSet(name string) bool {
func (c *Context) GlobalIsSet(name string) bool {
if c.globalSetFlags == nil {
c.globalSetFlags = make(map[string]bool)
c.globalSet.Visit(func(f *flag.Flag) {
c.globalSetFlags[f.Name] = true
})
ctx := c
if ctx.parentContext != nil {
ctx = ctx.parentContext
}
for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext {
ctx.flagSet.Visit(func(f *flag.Flag) {
c.globalSetFlags[f.Name] = true
})
}
}
return c.globalSetFlags[name] == true
return c.globalSetFlags[name]
}
// Returns a slice of flag names used in this context.
@ -157,6 +184,11 @@ func (c *Context) GlobalFlagNames() (names []string) {
return
}
// Returns the parent context, if any
func (c *Context) Parent() *Context {
return c.parentContext
}
type Args []string
// Returns the command line arguments associated with the context.
@ -201,6 +233,18 @@ func (a Args) Swap(from, to int) error {
return nil
}
func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
if ctx.parentContext != nil {
ctx = ctx.parentContext
}
for ; ctx != nil; ctx = ctx.parentContext {
if f := ctx.flagSet.Lookup(name); f != nil {
return ctx.flagSet
}
}
return nil
}
func lookupInt(name string, set *flag.FlagSet) int {
f := set.Lookup(name)
if f != nil {

View File

@ -1,111 +0,0 @@
package cli_test
import (
"flag"
"testing"
"time"
"github.com/codegangsta/cli"
)
func TestNewContext(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Int("myflag", 42, "doc")
command := cli.Command{Name: "mycommand"}
c := cli.NewContext(nil, set, globalSet)
c.Command = command
expect(t, c.Int("myflag"), 12)
expect(t, c.GlobalInt("myflag"), 42)
expect(t, c.Command.Name, "mycommand")
}
func TestContext_Int(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Int("myflag", 12, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Int("myflag"), 12)
}
func TestContext_Duration(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Duration("myflag", time.Duration(12*time.Second), "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Duration("myflag"), time.Duration(12*time.Second))
}
func TestContext_String(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String("myflag", "hello world", "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.String("myflag"), "hello world")
}
func TestContext_Bool(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.Bool("myflag"), false)
}
func TestContext_BoolT(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", true, "doc")
c := cli.NewContext(nil, set, set)
expect(t, c.BoolT("myflag"), true)
}
func TestContext_Args(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
c := cli.NewContext(nil, set, set)
set.Parse([]string{"--myflag", "bat", "baz"})
expect(t, len(c.Args()), 2)
expect(t, c.Bool("myflag"), true)
}
func TestContext_IsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.IsSet("myflag"), true)
expect(t, c.IsSet("otherflag"), false)
expect(t, c.IsSet("bogusflag"), false)
expect(t, c.IsSet("myflagGlobal"), false)
}
func TestContext_GlobalIsSet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
globalSet.Bool("myflagGlobalUnset", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "bat", "baz"})
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
expect(t, c.GlobalIsSet("myflag"), false)
expect(t, c.GlobalIsSet("otherflag"), false)
expect(t, c.GlobalIsSet("bogusflag"), false)
expect(t, c.GlobalIsSet("myflagGlobal"), true)
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
expect(t, c.GlobalIsSet("bogusGlobal"), false)
}
func TestContext_NumFlags(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "--otherflag=foo"})
globalSet.Parse([]string{"--myflagGlobal"})
expect(t, c.NumFlags(), 2)
}

View File

@ -99,21 +99,27 @@ func (f GenericFlag) getName() string {
return f.Name
}
// StringSlice is an opaque type for []string to satisfy flag.Value
type StringSlice []string
// Set appends the string value to the list of values
func (f *StringSlice) Set(value string) error {
*f = append(*f, value)
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (f *StringSlice) String() string {
return fmt.Sprintf("%s", *f)
}
// Value returns the slice of strings set by this flag
func (f *StringSlice) Value() []string {
return *f
}
// StringSlice is a string flag that can be specified multiple times on the
// command-line
type StringSliceFlag struct {
Name string
Value *StringSlice
@ -121,12 +127,14 @@ type StringSliceFlag struct {
EnvVar string
}
// String returns the usage
func (f StringSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
@ -144,6 +152,9 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
if f.Value == nil {
f.Value = &StringSlice{}
}
set.Var(f.Value, name, f.Usage)
})
}
@ -152,10 +163,11 @@ func (f StringSliceFlag) getName() string {
return f.Name
}
// StringSlice is an opaque type for []int to satisfy flag.Value
type IntSlice []int
// Set parses the value into an integer and appends it to the list of values
func (f *IntSlice) Set(value string) error {
tmp, err := strconv.Atoi(value)
if err != nil {
return err
@ -165,14 +177,18 @@ func (f *IntSlice) Set(value string) error {
return nil
}
// String returns a readable representation of this value (for usage defaults)
func (f *IntSlice) String() string {
return fmt.Sprintf("%d", *f)
}
// Value returns the slice of ints set by this flag
func (f *IntSlice) Value() []int {
return *f
}
// IntSliceFlag is an int flag that can be specified multiple times on the
// command-line
type IntSliceFlag struct {
Name string
Value *IntSlice
@ -180,12 +196,14 @@ type IntSliceFlag struct {
EnvVar string
}
// String returns the usage
func (f IntSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
@ -206,6 +224,9 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) {
}
eachName(f.Name, func(name string) {
if f.Value == nil {
f.Value = &IntSlice{}
}
set.Var(f.Value, name, f.Usage)
})
}
@ -214,16 +235,19 @@ func (f IntSliceFlag) getName() string {
return f.Name
}
// BoolFlag is a switch that defaults to false
type BoolFlag struct {
Name string
Usage string
EnvVar string
}
// String returns a readable representation of this value (for usage defaults)
func (f BoolFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f BoolFlag) Apply(set *flag.FlagSet) {
val := false
if f.EnvVar != "" {
@ -248,16 +272,20 @@ func (f BoolFlag) getName() string {
return f.Name
}
// BoolTFlag this represents a boolean flag that is true by default, but can
// still be set to false by --some-flag=false
type BoolTFlag struct {
Name string
Usage string
EnvVar string
}
// String returns a readable representation of this value (for usage defaults)
func (f BoolTFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f BoolTFlag) Apply(set *flag.FlagSet) {
val := true
if f.EnvVar != "" {
@ -282,6 +310,7 @@ func (f BoolTFlag) getName() string {
return f.Name
}
// StringFlag represents a flag that takes as string value
type StringFlag struct {
Name string
Value string
@ -289,6 +318,7 @@ type StringFlag struct {
EnvVar string
}
// String returns the usage
func (f StringFlag) String() string {
var fmtString string
fmtString = "%s %v\t%v"
@ -302,6 +332,7 @@ func (f StringFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f StringFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
@ -322,6 +353,8 @@ func (f StringFlag) getName() string {
return f.Name
}
// IntFlag is a flag that takes an integer
// Errors if the value provided cannot be parsed
type IntFlag struct {
Name string
Value int
@ -329,10 +362,12 @@ type IntFlag struct {
EnvVar string
}
// String returns the usage
func (f IntFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f IntFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
@ -356,6 +391,8 @@ func (f IntFlag) getName() string {
return f.Name
}
// DurationFlag is a flag that takes a duration specified in Go's duration
// format: https://golang.org/pkg/time/#ParseDuration
type DurationFlag struct {
Name string
Value time.Duration
@ -363,10 +400,12 @@ type DurationFlag struct {
EnvVar string
}
// String returns a readable representation of this value (for usage defaults)
func (f DurationFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f DurationFlag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {
@ -390,6 +429,8 @@ func (f DurationFlag) getName() string {
return f.Name
}
// Float64Flag is a flag that takes an float value
// Errors if the value provided cannot be parsed
type Float64Flag struct {
Name string
Value float64
@ -397,10 +438,12 @@ type Float64Flag struct {
EnvVar string
}
// String returns the usage
func (f Float64Flag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
}
// Apply populates the flag given the flag set and environment
func (f Float64Flag) Apply(set *flag.FlagSet) {
if f.EnvVar != "" {
for _, envVar := range strings.Split(f.EnvVar, ",") {

View File

@ -1,742 +0,0 @@
package cli_test
import (
"fmt"
"os"
"reflect"
"strings"
"testing"
"github.com/codegangsta/cli"
)
var boolFlagTests = []struct {
name string
expected string
}{
{"help", "--help\t"},
{"h", "-h\t"},
}
func TestBoolFlagHelpOutput(t *testing.T) {
for _, test := range boolFlagTests {
flag := cli.BoolFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
var stringFlagTests = []struct {
name string
value string
expected string
}{
{"help", "", "--help \t"},
{"h", "", "-h \t"},
{"h", "", "-h \t"},
{"test", "Something", "--test \"Something\"\t"},
}
func TestStringFlagHelpOutput(t *testing.T) {
for _, test := range stringFlagTests {
flag := cli.StringFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "derp")
for _, test := range stringFlagTests {
flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_FOO]") {
t.Errorf("%s does not end with [$APP_FOO]", output)
}
}
}
var stringSliceFlagTests = []struct {
name string
value *cli.StringSlice
expected string
}{
{"help", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "--help [--help option --help option]\t"},
{"h", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"h", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("")
return s
}(), "-h [-h option -h option]\t"},
{"test", func() *cli.StringSlice {
s := &cli.StringSlice{}
s.Set("Something")
return s
}(), "--test [--test option --test option]\t"},
}
func TestStringSliceFlagHelpOutput(t *testing.T) {
for _, test := range stringSliceFlagTests {
flag := cli.StringSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_QWWX", "11,4")
for _, test := range stringSliceFlagTests {
flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_QWWX]") {
t.Errorf("%q does not end with [$APP_QWWX]", output)
}
}
}
var intFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestIntFlagHelpOutput(t *testing.T) {
for _, test := range intFlagTests {
flag := cli.IntFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2")
for _, test := range intFlagTests {
flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var durationFlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestDurationFlagHelpOutput(t *testing.T) {
for _, test := range durationFlagTests {
flag := cli.DurationFlag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAR", "2h3m6s")
for _, test := range durationFlagTests {
flag := cli.DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAR]") {
t.Errorf("%s does not end with [$APP_BAR]", output)
}
}
}
var intSliceFlagTests = []struct {
name string
value *cli.IntSlice
expected string
}{
{"help", &cli.IntSlice{}, "--help [--help option --help option]\t"},
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"test", func() *cli.IntSlice {
i := &cli.IntSlice{}
i.Set("9")
return i
}(), "--test [--test option --test option]\t"},
}
func TestIntSliceFlagHelpOutput(t *testing.T) {
for _, test := range intSliceFlagTests {
flag := cli.IntSliceFlag{Name: test.name, Value: test.value}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SMURF", "42,3")
for _, test := range intSliceFlagTests {
flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_SMURF]") {
t.Errorf("%q does not end with [$APP_SMURF]", output)
}
}
}
var float64FlagTests = []struct {
name string
expected string
}{
{"help", "--help \"0\"\t"},
{"h", "-h \"0\"\t"},
}
func TestFloat64FlagHelpOutput(t *testing.T) {
for _, test := range float64FlagTests {
flag := cli.Float64Flag{Name: test.name}
output := flag.String()
if output != test.expected {
t.Errorf("%s does not match %s", output, test.expected)
}
}
}
func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_BAZ", "99.4")
for _, test := range float64FlagTests {
flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_BAZ]") {
t.Errorf("%s does not end with [$APP_BAZ]", output)
}
}
}
var genericFlagTests = []struct {
name string
value cli.Generic
expected string
}{
{"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"},
{"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"},
}
func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests {
flag := cli.GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := flag.String()
if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected)
}
}
}
func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_ZAP", "3")
for _, test := range genericFlagTests {
flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
output := flag.String()
if !strings.HasSuffix(output, " [$APP_ZAP]") {
t.Errorf("%s does not end with [$APP_ZAP]", output)
}
}
}
func TestParseMultiString(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.String("serve") != "10" {
t.Errorf("main name not set")
}
if ctx.String("s") != "10" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10"})
}
func TestParseMultiStringFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
},
Action: func(ctx *cli.Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_COUNT", "20")
(&cli.App{
Flags: []cli.Flag{
cli.StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
},
Action: func(ctx *cli.Context) {
if ctx.String("count") != "20" {
t.Errorf("main name not set")
}
if ctx.String("c") != "20" {
t.Errorf("short name not set")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSlice(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiStringSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiInt(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("serve") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("s") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10"})
}
func TestParseMultiIntFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "10")
a := cli.App{
Flags: []cli.Flag{
cli.IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Int("timeout") != 10 {
t.Errorf("main name not set")
}
if ctx.Int("t") != 10 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiIntSlice(t *testing.T) {
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
t.Errorf("short name not set")
}
},
}).Run([]string{"run", "-s", "10", "-s", "20"})
}
func TestParseMultiIntSliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "20,30,40")
(&cli.App{
Flags: []cli.Flag{
cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
t.Errorf("short name not set from env")
}
},
}).Run([]string{"run"})
}
func TestParseMultiFloat64(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("serve") != 10.2 {
t.Errorf("main name not set")
}
if ctx.Float64("s") != 10.2 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10.2"})
}
func TestParseMultiFloat64FromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
a := cli.App{
Flags: []cli.Flag{
cli.Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
},
Action: func(ctx *cli.Context) {
if ctx.Float64("timeout") != 15.5 {
t.Errorf("main name not set")
}
if ctx.Float64("t") != 15.5 {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBool(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("serve") != true {
t.Errorf("main name not set")
}
if ctx.Bool("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "1")
a := cli.App{
Flags: []cli.Flag{
cli.BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.Bool("debug") != true {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != true {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolT(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "serve, s"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("serve") != true {
t.Errorf("main name not set")
}
if ctx.BoolT("s") != true {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "--serve"})
}
func TestParseMultiBoolTFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_DEBUG", "0")
a := cli.App{
Flags: []cli.Flag{
cli.BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
},
Action: func(ctx *cli.Context) {
if ctx.BoolT("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.BoolT("d") != false {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
type Parser [2]string
func (p *Parser) Set(value string) error {
parts := strings.Split(value, ",")
if len(parts) != 2 {
return fmt.Errorf("invalid format")
}
(*p)[0] = parts[0]
(*p)[1] = parts[1]
return nil
}
func (p *Parser) String() string {
return fmt.Sprintf("%s,%s", p[0], p[1])
}
func TestParseGeneric(t *testing.T) {
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "serve, s", Value: &Parser{}},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
t.Errorf("main name not set")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) {
t.Errorf("short name not set")
}
},
}
a.Run([]string{"run", "-s", "10,20"})
}
func TestParseGenericFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_SERVE", "20,30")
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
t.Errorf("main name not set from env")
}
if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) {
t.Errorf("short name not set from env")
}
},
}
a.Run([]string{"run"})
}
func TestParseGenericFromEnvCascade(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "99,2000")
a := cli.App{
Flags: []cli.Flag{
cli.GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
},
Action: func(ctx *cli.Context) {
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
t.Errorf("value not set from env")
}
},
}
a.Run([]string{"run"})
}

View File

@ -1,6 +1,12 @@
package cli
import "fmt"
import (
"fmt"
"io"
"strings"
"text/tabwriter"
"text/template"
)
// The text template for the Default help topic.
// cli.go uses text/template to render templates. You can
@ -9,30 +15,33 @@ var AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
{{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
{{if .Version}}
VERSION:
{{.Version}}
{{end}}{{if len .Authors}}
AUTHOR(S):
{{range .Authors}}{{ . }}
{{end}}
{{range .Authors}}{{ . }}{{end}}
{{end}}{{if .Commands}}
COMMANDS:
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}}
{{end}}{{end}}{{if .Flags}}
GLOBAL OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{end}}
{{end}}{{end}}{{if .Copyright }}
COPYRIGHT:
{{.Copyright}}
{{end}}
`
// The text template for the command help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var CommandHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
{{.HelpName}} - {{.Usage}}
USAGE:
command {{.Name}}{{if .Flags}} [command options]{{end}} [arguments...]{{if .Description}}
{{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .Flags}}
@ -46,10 +55,10 @@ OPTIONS:
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var SubcommandHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
{{.HelpName}} - {{.Usage}}
USAGE:
{{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...]
{{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
COMMANDS:
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
@ -60,9 +69,10 @@ OPTIONS:
`
var helpCommand = Command{
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
ArgsUsage: "[command]",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
@ -74,9 +84,10 @@ var helpCommand = Command{
}
var helpSubcommand = Command{
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
Name: "help",
Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command",
ArgsUsage: "[command]",
Action: func(c *Context) {
args := c.Args()
if args.Present() {
@ -87,16 +98,16 @@ var helpSubcommand = Command{
},
}
// Prints help for the App
type helpPrinter func(templ string, data interface{})
// Prints help for the App or Command
type helpPrinter func(w io.Writer, templ string, data interface{})
var HelpPrinter helpPrinter = nil
var HelpPrinter helpPrinter = printHelp
// Prints version for the App
var VersionPrinter = printVersion
func ShowAppHelp(c *Context) {
HelpPrinter(AppHelpTemplate, c.App)
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
}
// Prints the list of subcommands as the default app completion method
@ -109,24 +120,24 @@ func DefaultAppComplete(c *Context) {
}
// Prints help for the given command
func ShowCommandHelp(c *Context, command string) {
func ShowCommandHelp(ctx *Context, command string) {
// show the subcommand help for a command with subcommands
if command == "" {
HelpPrinter(SubcommandHelpTemplate, c.App)
HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
return
}
for _, c := range c.App.Commands {
for _, c := range ctx.App.Commands {
if c.HasName(command) {
HelpPrinter(CommandHelpTemplate, c)
HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
return
}
}
if c.App.CommandNotFound != nil {
c.App.CommandNotFound(c, command)
if ctx.App.CommandNotFound != nil {
ctx.App.CommandNotFound(ctx, command)
} else {
fmt.Fprintf(c.App.Writer, "No help topic for '%v'\n", command)
fmt.Fprintf(ctx.App.Writer, "No help topic for '%v'\n", command)
}
}
@ -160,22 +171,42 @@ func ShowCommandCompletions(ctx *Context, command string) {
}
}
func checkVersion(c *Context) bool {
if c.GlobalBool("version") {
ShowVersion(c)
return true
func printHelp(out io.Writer, templ string, data interface{}) {
funcMap := template.FuncMap{
"join": strings.Join,
}
return false
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data)
if err != nil {
panic(err)
}
w.Flush()
}
func checkVersion(c *Context) bool {
found := false
if VersionFlag.Name != "" {
eachName(VersionFlag.Name, func(name string) {
if c.GlobalBool(name) || c.Bool(name) {
found = true
}
})
}
return found
}
func checkHelp(c *Context) bool {
if c.GlobalBool("h") || c.GlobalBool("help") {
ShowAppHelp(c)
return true
found := false
if HelpFlag.Name != "" {
eachName(HelpFlag.Name, func(name string) {
if c.GlobalBool(name) || c.Bool(name) {
found = true
}
})
}
return false
return found
}
func checkCommandHelp(c *Context, name string) bool {

View File

@ -1,19 +0,0 @@
package cli_test
import (
"reflect"
"testing"
)
/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func refute(t *testing.T, a interface{}, b interface{}) {
if a == b {
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,21 @@
// Copyright 2015 The go-ethereum Authors
// Copyright 2015 Lefteris Karapetsas <lefteris@refu.co>
// Copyright 2015 Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package ethash
/*
@ -30,8 +48,8 @@ import (
)
var (
minDifficulty = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
sharedLight = new(Light)
maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
sharedLight = new(Light)
)
const (
@ -100,31 +118,47 @@ type Light struct {
func (l *Light) Verify(block pow.Block) bool {
// TODO: do ethash_quick_verify before getCache in order
// to prevent DOS attacks.
var (
blockNum = block.NumberU64()
difficulty = block.Difficulty()
cache = l.getCache(blockNum)
dagSize = C.ethash_get_datasize(C.uint64_t(blockNum))
)
if l.test {
dagSize = dagSizeForTesting
}
blockNum := block.NumberU64()
if blockNum >= epochLength*2048 {
glog.V(logger.Debug).Infof("block number %d too high, limit is %d", epochLength*2048)
return false
}
difficulty := block.Difficulty()
/* Cannot happen if block header diff is validated prior to PoW, but can
happen if PoW is checked first due to parallel PoW checking.
We could check the minimum valid difficulty but for SoC we avoid (duplicating)
Ethereum protocol consensus rules here which are not in scope of Ethash
*/
if difficulty.Cmp(common.Big0) == 0 {
glog.V(logger.Debug).Infof("invalid block difficulty")
return false
}
cache := l.getCache(blockNum)
dagSize := C.ethash_get_datasize(C.uint64_t(blockNum))
if l.test {
dagSize = dagSizeForTesting
}
// Recompute the hash using the cache.
hash := hashToH256(block.HashNoNonce())
ret := C.ethash_light_compute_internal(cache.ptr, dagSize, hash, C.uint64_t(block.Nonce()))
if !ret.success {
return false
}
// avoid mixdigest malleability as it's not included in a block's "hashNononce"
if block.MixDigest() != h256ToHash(ret.mix_hash) {
return false
}
// Make sure cache is live until after the C call.
// This is important because a GC might happen and execute
// the finalizer before the call completes.
_ = cache
// The actual check.
target := new(big.Int).Div(minDifficulty, difficulty)
target := new(big.Int).Div(maxUint256, difficulty)
return h256ToHash(ret.result).Big().Cmp(target) <= 0
}
@ -183,7 +217,7 @@ func (d *dag) generate() {
if d.dir == "" {
d.dir = DefaultDir
}
glog.V(logger.Info).Infof("Generating DAG for epoch %d (%x)", d.epoch, seedHash)
glog.V(logger.Info).Infof("Generating DAG for epoch %d (size %d) (%x)", d.epoch, dagSize, seedHash)
// Generate a temporary cache.
// TODO: this could share the cache with Light
cache := C.ethash_light_new_internal(cacheSize, (*C.ethash_h256_t)(unsafe.Pointer(&seedHash[0])))
@ -204,14 +238,18 @@ func (d *dag) generate() {
})
}
func freeDAG(h *dag) {
C.ethash_full_delete(h.ptr)
h.ptr = nil
func freeDAG(d *dag) {
C.ethash_full_delete(d.ptr)
d.ptr = nil
}
func (d *dag) Ptr() unsafe.Pointer {
return unsafe.Pointer(d.ptr.data)
}
//export ethashGoCallback
func ethashGoCallback(percent C.unsigned) C.int {
glog.V(logger.Info).Infof("Still generating DAG: %d%%", percent)
glog.V(logger.Info).Infof("Generating DAG: %d%%", percent)
return 0
}
@ -257,7 +295,7 @@ func (pow *Full) getDAG(blockNum uint64) (d *dag) {
return d
}
func (pow *Full) Search(block pow.Block, stop <-chan struct{}) (nonce uint64, mixDigest []byte) {
func (pow *Full) Search(block pow.Block, stop <-chan struct{}, index int) (nonce uint64, mixDigest []byte) {
dag := pow.getDAG(block.NumberU64())
r := rand.New(rand.NewSource(time.Now().UnixNano()))
@ -270,7 +308,7 @@ func (pow *Full) Search(block pow.Block, stop <-chan struct{}) (nonce uint64, mi
nonce = uint64(r.Int63())
hash := hashToH256(block.HashNoNonce())
target := new(big.Int).Div(minDifficulty, diff)
target := new(big.Int).Div(maxUint256, diff)
for {
select {
case <-stop:

View File

@ -0,0 +1,629 @@
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build opencl
package ethash
//#cgo LDFLAGS: -w
//#include <stdint.h>
//#include <string.h>
//#include "src/libethash/internal.h"
import "C"
import (
crand "crypto/rand"
"encoding/binary"
"fmt"
"math"
"math/big"
mrand "math/rand"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"unsafe"
"github.com/Gustav-Simonsson/go-opencl/cl"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/pow"
)
/*
This code have two main entry points:
1. The initCL(...) function configures one or more OpenCL device
(for now only GPU) and loads the Ethash DAG onto device memory
2. The Search(...) function loads a Ethash nonce into device(s) memory and
executes the Ethash OpenCL kernel.
Throughout the code, we refer to "host memory" and "device memory".
For most systems (e.g. regular PC GPU miner) the host memory is RAM and
device memory is the GPU global memory (e.g. GDDR5).
References mentioned in code comments:
1. https://github.com/ethereum/wiki/wiki/Ethash
2. https://github.com/ethereum/cpp-ethereum/blob/develop/libethash-cl/ethash_cl_miner.cpp
3. https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/
4. http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_OpenCL_Programming_User_Guide.pdf
*/
type OpenCLDevice struct {
deviceId int
device *cl.Device
openCL11 bool // OpenCL version 1.1 and 1.2 are handled a bit different
openCL12 bool
dagBuf *cl.MemObject // Ethash full DAG in device mem
headerBuf *cl.MemObject // Hash of block-to-mine in device mem
searchBuffers []*cl.MemObject
searchKernel *cl.Kernel
hashKernel *cl.Kernel
queue *cl.CommandQueue
ctx *cl.Context
workGroupSize int
nonceRand *mrand.Rand // seeded by crypto/rand, see comments where it's initialised
result common.Hash
}
type OpenCLMiner struct {
mu sync.Mutex
ethash *Ethash // Ethash full DAG & cache in host mem
deviceIds []int
devices []*OpenCLDevice
dagSize uint64
hashRate int32 // Go atomics & uint64 have some issues; int32 is supported on all platforms
}
type pendingSearch struct {
bufIndex uint32
startNonce uint64
}
const (
SIZEOF_UINT32 = 4
// See [1]
ethashMixBytesLen = 128
ethashAccesses = 64
// See [4]
workGroupSize = 32 // must be multiple of 8
maxSearchResults = 63
searchBufSize = 2
globalWorkSize = 1024 * 256
)
func NewCL(deviceIds []int) *OpenCLMiner {
ids := make([]int, len(deviceIds))
copy(ids, deviceIds)
return &OpenCLMiner{
ethash: New(),
dagSize: 0, // to see if we need to update DAG.
deviceIds: ids,
}
}
func PrintDevices() {
fmt.Println("=============================================")
fmt.Println("============ OpenCL Device Info =============")
fmt.Println("=============================================")
var found []*cl.Device
platforms, err := cl.GetPlatforms()
if err != nil {
fmt.Println("Plaform error (check your OpenCL installation): %v", err)
return
}
for i, p := range platforms {
fmt.Println("Platform id ", i)
fmt.Println("Platform Name ", p.Name())
fmt.Println("Platform Vendor ", p.Vendor())
fmt.Println("Platform Version ", p.Version())
fmt.Println("Platform Extensions ", p.Extensions())
fmt.Println("Platform Profile ", p.Profile())
fmt.Println("")
devices, err := cl.GetDevices(p, cl.DeviceTypeGPU)
if err != nil {
fmt.Println("Device error (check your GPU drivers) :", err)
return
}
for _, d := range devices {
fmt.Println("Device OpenCL id ", i)
fmt.Println("Device id for mining ", len(found))
fmt.Println("Device Name ", d.Name())
fmt.Println("Vendor ", d.Vendor())
fmt.Println("Version ", d.Version())
fmt.Println("Driver version ", d.DriverVersion())
fmt.Println("Address bits ", d.AddressBits())
fmt.Println("Max clock freq ", d.MaxClockFrequency())
fmt.Println("Global mem size ", d.GlobalMemSize())
fmt.Println("Max constant buffer size", d.MaxConstantBufferSize())
fmt.Println("Max mem alloc size ", d.MaxMemAllocSize())
fmt.Println("Max compute units ", d.MaxComputeUnits())
fmt.Println("Max work group size ", d.MaxWorkGroupSize())
fmt.Println("Max work item sizes ", d.MaxWorkItemSizes())
fmt.Println("=============================================")
found = append(found, d)
}
}
if len(found) == 0 {
fmt.Println("Found no GPU(s). Check that your OS can see the GPU(s)")
} else {
var idsFormat string
for i := 0; i < len(found); i++ {
idsFormat += strconv.Itoa(i)
if i != len(found)-1 {
idsFormat += ","
}
}
fmt.Printf("Found %v devices. Benchmark first GPU: geth gpubench 0\n", len(found))
fmt.Printf("Mine using all GPUs: geth --minegpu %v\n", idsFormat)
}
}
// See [2]. We basically do the same here, but the Go OpenCL bindings
// are at a slightly higher abtraction level.
func InitCL(blockNum uint64, c *OpenCLMiner) error {
platforms, err := cl.GetPlatforms()
if err != nil {
return fmt.Errorf("Plaform error: %v\nCheck your OpenCL installation and then run geth gpuinfo", err)
}
var devices []*cl.Device
for _, p := range platforms {
ds, err := cl.GetDevices(p, cl.DeviceTypeGPU)
if err != nil {
return fmt.Errorf("Devices error: %v\nCheck your GPU drivers and then run geth gpuinfo", err)
}
for _, d := range ds {
devices = append(devices, d)
}
}
pow := New()
_ = pow.getDAG(blockNum) // generates DAG if we don't have it
pow.Light.getCache(blockNum) // and cache
c.ethash = pow
dagSize := uint64(C.ethash_get_datasize(C.uint64_t(blockNum)))
c.dagSize = dagSize
for _, id := range c.deviceIds {
if id > len(devices)-1 {
return fmt.Errorf("Device id not found. See available device ids with: geth gpuinfo")
} else {
err := initCLDevice(id, devices[id], c)
if err != nil {
return err
}
}
}
if len(c.devices) == 0 {
return fmt.Errorf("No GPU devices found")
}
return nil
}
func initCLDevice(deviceId int, device *cl.Device, c *OpenCLMiner) error {
devMaxAlloc := uint64(device.MaxMemAllocSize())
devGlobalMem := uint64(device.GlobalMemSize())
// TODO: more fine grained version logic
if device.Version() == "OpenCL 1.0" {
fmt.Println("Device OpenCL version not supported: ", device.Version())
return fmt.Errorf("opencl version not supported")
}
var cl11, cl12 bool
if device.Version() == "OpenCL 1.1" {
cl11 = true
}
if device.Version() == "OpenCL 1.2" {
cl12 = true
}
// log warnings but carry on; some device drivers report inaccurate values
if c.dagSize > devGlobalMem {
fmt.Printf("WARNING: device memory may be insufficient: %v. DAG size: %v.\n", devGlobalMem, c.dagSize)
}
if c.dagSize > devMaxAlloc {
fmt.Printf("WARNING: DAG size (%v) larger than device max memory allocation size (%v).\n", c.dagSize, devMaxAlloc)
fmt.Printf("You probably have to export GPU_MAX_ALLOC_PERCENT=95\n")
}
fmt.Printf("Initialising device %v: %v\n", deviceId, device.Name())
context, err := cl.CreateContext([]*cl.Device{device})
if err != nil {
return fmt.Errorf("failed creating context:", err)
}
// TODO: test running with CL_QUEUE_PROFILING_ENABLE for profiling?
queue, err := context.CreateCommandQueue(device, 0)
if err != nil {
return fmt.Errorf("command queue err:", err)
}
// See [4] section 3.2 and [3] "clBuildProgram".
// The OpenCL kernel code is compiled at run-time.
kvs := make(map[string]string, 4)
kvs["GROUP_SIZE"] = strconv.FormatUint(workGroupSize, 10)
kvs["DAG_SIZE"] = strconv.FormatUint(c.dagSize/ethashMixBytesLen, 10)
kvs["ACCESSES"] = strconv.FormatUint(ethashAccesses, 10)
kvs["MAX_OUTPUTS"] = strconv.FormatUint(maxSearchResults, 10)
kernelCode := replaceWords(kernel, kvs)
program, err := context.CreateProgramWithSource([]string{kernelCode})
if err != nil {
return fmt.Errorf("program err:", err)
}
/* if using AMD OpenCL impl, you can set this to debug on x86 CPU device.
see AMD OpenCL programming guide section 4.2
export in shell before running:
export AMD_OCL_BUILD_OPTIONS_APPEND="-g -O0"
export CPU_MAX_COMPUTE_UNITS=1
buildOpts := "-g -cl-opt-disable"
*/
buildOpts := ""
err = program.BuildProgram([]*cl.Device{device}, buildOpts)
if err != nil {
return fmt.Errorf("program build err:", err)
}
var searchKernelName, hashKernelName string
searchKernelName = "ethash_search"
hashKernelName = "ethash_hash"
searchKernel, err := program.CreateKernel(searchKernelName)
hashKernel, err := program.CreateKernel(hashKernelName)
if err != nil {
return fmt.Errorf("kernel err:", err)
}
// TODO: when this DAG size appears, patch the Go bindings
// (context.go) to work with uint64 as size_t
if c.dagSize > math.MaxInt32 {
fmt.Println("DAG too large for allocation.")
return fmt.Errorf("DAG too large for alloc")
}
// TODO: patch up Go bindings to work with size_t, will overflow if > maxint32
// TODO: fuck. shit's gonna overflow around 2017-06-09 12:17:02
dagBuf := *(new(*cl.MemObject))
dagBuf, err = context.CreateEmptyBuffer(cl.MemReadOnly, int(c.dagSize))
if err != nil {
return fmt.Errorf("allocating dag buf failed: ", err)
}
// write DAG to device mem
dagPtr := unsafe.Pointer(c.ethash.Full.current.ptr.data)
_, err = queue.EnqueueWriteBuffer(dagBuf, true, 0, int(c.dagSize), dagPtr, nil)
if err != nil {
return fmt.Errorf("writing to dag buf failed: ", err)
}
searchBuffers := make([]*cl.MemObject, searchBufSize)
for i := 0; i < searchBufSize; i++ {
searchBuff, err := context.CreateEmptyBuffer(cl.MemWriteOnly, (1+maxSearchResults)*SIZEOF_UINT32)
if err != nil {
return fmt.Errorf("search buffer err:", err)
}
searchBuffers[i] = searchBuff
}
headerBuf, err := context.CreateEmptyBuffer(cl.MemReadOnly, 32)
if err != nil {
return fmt.Errorf("header buffer err:", err)
}
// Unique, random nonces are crucial for mining efficieny.
// While we do not need cryptographically secure PRNG for nonces,
// we want to have uniform distribution and minimal repetition of nonces.
// We could guarantee strict uniqueness of nonces by generating unique ranges,
// but a int64 seed from crypto/rand should be good enough.
// we then use math/rand for speed and to avoid draining OS entropy pool
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
if err != nil {
return err
}
nonceRand := mrand.New(mrand.NewSource(seed.Int64()))
deviceStruct := &OpenCLDevice{
deviceId: deviceId,
device: device,
openCL11: cl11,
openCL12: cl12,
dagBuf: dagBuf,
headerBuf: headerBuf,
searchBuffers: searchBuffers,
searchKernel: searchKernel,
hashKernel: hashKernel,
queue: queue,
ctx: context,
workGroupSize: workGroupSize,
nonceRand: nonceRand,
}
c.devices = append(c.devices, deviceStruct)
return nil
}
func (c *OpenCLMiner) Search(block pow.Block, stop <-chan struct{}, index int) (uint64, []byte) {
c.mu.Lock()
newDagSize := uint64(C.ethash_get_datasize(C.uint64_t(block.NumberU64())))
if newDagSize > c.dagSize {
// TODO: clean up buffers from previous DAG?
err := InitCL(block.NumberU64(), c)
if err != nil {
fmt.Println("OpenCL init error: ", err)
return 0, []byte{0}
}
}
defer c.mu.Unlock()
// Avoid unneeded OpenCL initialisation if we received stop while running InitCL
select {
case <-stop:
return 0, []byte{0}
default:
}
headerHash := block.HashNoNonce()
diff := block.Difficulty()
target256 := new(big.Int).Div(maxUint256, diff)
target64 := new(big.Int).Rsh(target256, 192).Uint64()
var zero uint32 = 0
d := c.devices[index]
_, err := d.queue.EnqueueWriteBuffer(d.headerBuf, false, 0, 32, unsafe.Pointer(&headerHash[0]), nil)
if err != nil {
fmt.Println("Error in Search clEnqueueWriterBuffer : ", err)
return 0, []byte{0}
}
for i := 0; i < searchBufSize; i++ {
_, err := d.queue.EnqueueWriteBuffer(d.searchBuffers[i], false, 0, 4, unsafe.Pointer(&zero), nil)
if err != nil {
fmt.Println("Error in Search clEnqueueWriterBuffer : ", err)
return 0, []byte{0}
}
}
// wait for all search buffers to complete
err = d.queue.Finish()
if err != nil {
fmt.Println("Error in Search clFinish : ", err)
return 0, []byte{0}
}
err = d.searchKernel.SetArg(1, d.headerBuf)
if err != nil {
fmt.Println("Error in Search clSetKernelArg : ", err)
return 0, []byte{0}
}
err = d.searchKernel.SetArg(2, d.dagBuf)
if err != nil {
fmt.Println("Error in Search clSetKernelArg : ", err)
return 0, []byte{0}
}
err = d.searchKernel.SetArg(4, target64)
if err != nil {
fmt.Println("Error in Search clSetKernelArg : ", err)
return 0, []byte{0}
}
err = d.searchKernel.SetArg(5, uint32(math.MaxUint32))
if err != nil {
fmt.Println("Error in Search clSetKernelArg : ", err)
return 0, []byte{0}
}
// wait on this before returning
var preReturnEvent *cl.Event
if d.openCL12 {
preReturnEvent, err = d.ctx.CreateUserEvent()
if err != nil {
fmt.Println("Error in Search create CL user event : ", err)
return 0, []byte{0}
}
}
pending := make([]pendingSearch, 0, searchBufSize)
var p *pendingSearch
searchBufIndex := uint32(0)
var checkNonce uint64
loops := int64(0)
prevHashRate := int32(0)
start := time.Now().UnixNano()
// we grab a single random nonce and sets this as argument to the kernel search function
// the device will then add each local threads gid to the nonce, creating a unique nonce
// for each device computing unit executing in parallel
initNonce := uint64(d.nonceRand.Int63())
for nonce := initNonce; ; nonce += uint64(globalWorkSize) {
select {
case <-stop:
/*
if d.openCL12 {
err = cl.WaitForEvents([]*cl.Event{preReturnEvent})
if err != nil {
fmt.Println("Error in Search WaitForEvents: ", err)
}
}
*/
atomic.AddInt32(&c.hashRate, -prevHashRate)
return 0, []byte{0}
default:
}
if (loops % (1 << 7)) == 0 {
elapsed := time.Now().UnixNano() - start
// TODO: verify if this is correct hash rate calculation
hashes := (float64(1e9) / float64(elapsed)) * float64(loops*1024*256)
hashrateDiff := int32(hashes) - prevHashRate
prevHashRate = int32(hashes)
atomic.AddInt32(&c.hashRate, hashrateDiff)
}
loops++
err = d.searchKernel.SetArg(0, d.searchBuffers[searchBufIndex])
if err != nil {
fmt.Println("Error in Search clSetKernelArg : ", err)
return 0, []byte{0}
}
err = d.searchKernel.SetArg(3, nonce)
if err != nil {
fmt.Println("Error in Search clSetKernelArg : ", err)
return 0, []byte{0}
}
// execute kernel
_, err := d.queue.EnqueueNDRangeKernel(
d.searchKernel,
[]int{0},
[]int{globalWorkSize},
[]int{d.workGroupSize},
nil)
if err != nil {
fmt.Println("Error in Search clEnqueueNDRangeKernel : ", err)
return 0, []byte{0}
}
pending = append(pending, pendingSearch{bufIndex: searchBufIndex, startNonce: nonce})
searchBufIndex = (searchBufIndex + 1) % searchBufSize
if len(pending) == searchBufSize {
p = &(pending[searchBufIndex])
cres, _, err := d.queue.EnqueueMapBuffer(d.searchBuffers[p.bufIndex], true,
cl.MapFlagRead, 0, (1+maxSearchResults)*SIZEOF_UINT32,
nil)
if err != nil {
fmt.Println("Error in Search clEnqueueMapBuffer: ", err)
return 0, []byte{0}
}
results := cres.ByteSlice()
nfound := binary.LittleEndian.Uint32(results)
nfound = uint32(math.Min(float64(nfound), float64(maxSearchResults)))
// OpenCL returns the offsets from the start nonce
for i := uint32(0); i < nfound; i++ {
lo := (i + 1) * SIZEOF_UINT32
hi := (i + 2) * SIZEOF_UINT32
upperNonce := uint64(binary.LittleEndian.Uint32(results[lo:hi]))
checkNonce = p.startNonce + upperNonce
if checkNonce != 0 {
cn := C.uint64_t(checkNonce)
ds := C.uint64_t(c.dagSize)
// We verify that the nonce is indeed a solution by
// executing the Ethash verification function (on the CPU).
ret := C.ethash_light_compute_internal(c.ethash.Light.current.ptr, ds, hashToH256(headerHash), cn)
// TODO: return result first
if ret.success && h256ToHash(ret.result).Big().Cmp(target256) <= 0 {
_, err = d.queue.EnqueueUnmapMemObject(d.searchBuffers[p.bufIndex], cres, nil)
if err != nil {
fmt.Println("Error in Search clEnqueueUnmapMemObject: ", err)
}
if d.openCL12 {
err = cl.WaitForEvents([]*cl.Event{preReturnEvent})
if err != nil {
fmt.Println("Error in Search WaitForEvents: ", err)
}
}
return checkNonce, C.GoBytes(unsafe.Pointer(&ret.mix_hash), C.int(32))
}
_, err := d.queue.EnqueueWriteBuffer(d.searchBuffers[p.bufIndex], false, 0, 4, unsafe.Pointer(&zero), nil)
if err != nil {
fmt.Println("Error in Search cl: EnqueueWriteBuffer", err)
return 0, []byte{0}
}
}
}
_, err = d.queue.EnqueueUnmapMemObject(d.searchBuffers[p.bufIndex], cres, nil)
if err != nil {
fmt.Println("Error in Search clEnqueueUnMapMemObject: ", err)
return 0, []byte{0}
}
pending = append(pending[:searchBufIndex], pending[searchBufIndex+1:]...)
}
}
if d.openCL12 {
err := cl.WaitForEvents([]*cl.Event{preReturnEvent})
if err != nil {
fmt.Println("Error in Search clWaitForEvents: ", err)
return 0, []byte{0}
}
}
return 0, []byte{0}
}
func (c *OpenCLMiner) Verify(block pow.Block) bool {
return c.ethash.Light.Verify(block)
}
func (c *OpenCLMiner) GetHashrate() int64 {
return int64(atomic.LoadInt32(&c.hashRate))
}
func (c *OpenCLMiner) Turbo(on bool) {
// This is GPU mining. Always be turbo.
}
func replaceWords(text string, kvs map[string]string) string {
for k, v := range kvs {
text = strings.Replace(text, k, v, -1)
}
return text
}
func logErr(err error) {
if err != nil {
fmt.Println("Error in OpenCL call:", err)
}
}
func argErr(err error) error {
return fmt.Errorf("arg err: %v", err)
}

View File

@ -1,3 +1,14 @@
package ethash
/* DO NOT EDIT!!!
This code is version controlled at
https://github.com/ethereum/cpp-ethereum/blob/develop/libethash-cl/ethash_cl_miner_kernel.cl
If needed change it there first, then copy over here.
*/
const kernel = `
// author Tim Hughes <tim@twistedfury.com>
// Tested on Radeon HD 7850
// Hashrate: 15940347 hashes/s
@ -243,6 +254,40 @@ hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
return init;
}
uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate)
{
uint4 mix = init;
// share init0
if (thread_id == 0)
*share = mix.x;
barrier(CLK_LOCAL_MEM_FENCE);
uint init0 = *share;
uint a = 0;
do
{
bool update_share = thread_id == (a/4) % THREADS_PER_HASH;
#pragma unroll
for (uint i = 0; i != 4; ++i)
{
if (update_share)
{
uint m[4] = { mix.x, mix.y, mix.z, mix.w };
*share = fnv(init0 ^ (a+i), m[i]) % DAG_SIZE;
}
barrier(CLK_LOCAL_MEM_FENCE);
mix = fnv4(mix, *share>=3 * DAG_SIZE / 4 ? g_dag3[*share - 3 * DAG_SIZE / 4].uint4s[thread_id] : *share>=DAG_SIZE / 2 ? g_dag2[*share - DAG_SIZE / 2].uint4s[thread_id] : *share>=DAG_SIZE / 4 ? g_dag1[*share - DAG_SIZE / 4].uint4s[thread_id]:g_dag[*share].uint4s[thread_id]);
}
} while ((a += 4) != (ACCESSES & isolate));
return fnv_reduce(mix);
}
uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
{
uint4 mix = init;
@ -276,6 +321,7 @@ uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash12
return fnv_reduce(mix);
}
hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
{
ulong state[25];
@ -347,6 +393,7 @@ typedef union
hash32_t mix;
} compute_hash_share;
hash32_t compute_hash(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
@ -390,6 +437,53 @@ hash32_t compute_hash(
return final_hash(&init, &mix, isolate);
}
hash32_t compute_hash_chunks(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
__global hash128_t const* g_dag1,
__global hash128_t const* g_dag2,
__global hash128_t const* g_dag3,
ulong nonce,
uint isolate
)
{
uint const gid = get_global_id(0);
// Compute one init hash per work item.
hash64_t init = init_hash(g_header, nonce, isolate);
// Threads work together in this phase in groups of 8.
uint const thread_id = gid % THREADS_PER_HASH;
uint const hash_id = (gid % GROUP_SIZE) / THREADS_PER_HASH;
hash32_t mix;
uint i = 0;
do
{
// share init with other threads
if (i == thread_id)
share[hash_id].init = init;
barrier(CLK_LOCAL_MEM_FENCE);
uint4 thread_init = share[hash_id].init.uint4s[thread_id % (64 / sizeof(uint4))];
barrier(CLK_LOCAL_MEM_FENCE);
uint thread_mix = inner_loop_chunks(thread_init, thread_id, share[hash_id].mix.uints, g_dag, g_dag1, g_dag2, g_dag3, isolate);
share[hash_id].mix.uints[thread_id] = thread_mix;
barrier(CLK_LOCAL_MEM_FENCE);
if (i == thread_id)
mix = share[hash_id].mix;
barrier(CLK_LOCAL_MEM_FENCE);
}
while (++i != (THREADS_PER_HASH & isolate));
return final_hash(&init, &mix, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash_simple(
__global hash32_t* g_hashes,
@ -415,13 +509,15 @@ __kernel void ethash_search_simple(
{
uint const gid = get_global_id(0);
hash32_t hash = compute_hash_simple(g_header, g_dag, start_nonce + gid, isolate);
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
if (hash.ulongs[countof(hash.ulongs)-1] < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
uint slot = min(convert_uint(MAX_OUTPUTS), convert_uint(atomic_inc(&g_output[0]) + 1));
g_output[slot] = gid;
}
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash(
__global hash32_t* g_hashes,
@ -454,7 +550,51 @@ __kernel void ethash_search(
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
{
uint slot = min(MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
uint slot = min((uint)MAX_OUTPUTS, atomic_inc(&g_output[0]) + 1);
g_output[slot] = gid;
}
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_hash_chunks(
__global hash32_t* g_hashes,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
__global hash128_t const* g_dag1,
__global hash128_t const* g_dag2,
__global hash128_t const* g_dag3,
ulong start_nonce,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
g_hashes[gid] = compute_hash_chunks(share, g_header, g_dag, g_dag1, g_dag2, g_dag3,start_nonce + gid, isolate);
}
__attribute__((reqd_work_group_size(GROUP_SIZE, 1, 1)))
__kernel void ethash_search_chunks(
__global volatile uint* restrict g_output,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
__global hash128_t const* g_dag1,
__global hash128_t const* g_dag2,
__global hash128_t const* g_dag3,
ulong start_nonce,
ulong target,
uint isolate
)
{
__local compute_hash_share share[HASHES_PER_LOOP];
uint const gid = get_global_id(0);
hash32_t hash = compute_hash_chunks(share, g_header, g_dag, g_dag1, g_dag2, g_dag3, start_nonce + gid, isolate);
if (as_ulong(as_uchar8(hash.ulongs[0]).s76543210) < target)
{
uint slot = min(convert_uint(MAX_OUTPUTS), convert_uint(atomic_inc(&g_output[0]) + 1));
g_output[slot] = gid;
}
}
`

View File

@ -1,3 +1,20 @@
// Copyright 2015 The go-ethereum Authors
// Copyright 2015 Lefteris Karapetsas <lefteris@refu.co>
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package ethash
import (
@ -11,6 +28,7 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
func init() {
@ -39,6 +57,7 @@ var validBlocks = []*testBlock{
hashNoNonce: common.HexToHash("372eca2454ead349c3df0ab5d00b0b706b23e49d469387db91811cee0358fc6d"),
difficulty: big.NewInt(132416),
nonce: 0x495732e0ed7a801c,
mixDigest: common.HexToHash("2f74cdeb198af0b9abe65d22d372e22fb2d474371774a9583c1cc427a07939f5"),
},
// from proof of concept nine testnet, epoch 1
{
@ -46,6 +65,7 @@ var validBlocks = []*testBlock{
hashNoNonce: common.HexToHash("7e44356ee3441623bc72a683fd3708fdf75e971bbe294f33e539eedad4b92b34"),
difficulty: big.NewInt(1532671),
nonce: 0x318df1c8adef7e5e,
mixDigest: common.HexToHash("144b180aad09ae3c81fb07be92c8e6351b5646dda80e6844ae1b697e55ddde84"),
},
// from proof of concept nine testnet, epoch 2
{
@ -53,9 +73,18 @@ var validBlocks = []*testBlock{
hashNoNonce: common.HexToHash("5fc898f16035bf5ac9c6d9077ae1e3d5fc1ecc3c9fd5bee8bb00e810fdacbaa0"),
difficulty: big.NewInt(2467358),
nonce: 0x50377003e5d830ca,
mixDigest: common.HexToHash("ab546a5b73c452ae86dadd36f0ed83a6745226717d3798832d1b20b489e82063"),
},
}
var invalidZeroDiffBlock = testBlock{
number: 61440000,
hashNoNonce: crypto.Sha3Hash([]byte("foo")),
difficulty: big.NewInt(0),
nonce: 0xcafebabec00000fe,
mixDigest: crypto.Sha3Hash([]byte("bar")),
}
func TestEthashVerifyValid(t *testing.T) {
eth := New()
for i, block := range validBlocks {
@ -65,6 +94,13 @@ func TestEthashVerifyValid(t *testing.T) {
}
}
func TestEthashVerifyInvalid(t *testing.T) {
eth := New()
if eth.Verify(&invalidZeroDiffBlock) {
t.Errorf("should not validate - we just ensure it does not panic on this block")
}
}
func TestEthashConcurrentVerify(t *testing.T) {
eth, err := NewForTesting()
if err != nil {
@ -73,8 +109,9 @@ func TestEthashConcurrentVerify(t *testing.T) {
defer os.RemoveAll(eth.Full.Dir)
block := &testBlock{difficulty: big.NewInt(10)}
nonce, _ := eth.Search(block, nil)
nonce, md := eth.Search(block, nil, 0)
block.nonce = nonce
block.mixDigest = common.BytesToHash(md)
// Verify the block concurrently to check for data races.
var wg sync.WaitGroup
@ -98,21 +135,26 @@ func TestEthashConcurrentSearch(t *testing.T) {
eth.Turbo(true)
defer os.RemoveAll(eth.Full.Dir)
// launch n searches concurrently.
type searchRes struct {
n uint64
md []byte
}
var (
block = &testBlock{difficulty: big.NewInt(35000)}
nsearch = 10
wg = new(sync.WaitGroup)
found = make(chan uint64)
found = make(chan searchRes)
stop = make(chan struct{})
)
rand.Read(block.hashNoNonce[:])
wg.Add(nsearch)
// launch n searches concurrently.
for i := 0; i < nsearch; i++ {
go func() {
nonce, _ := eth.Search(block, stop)
nonce, md := eth.Search(block, stop, 0)
select {
case found <- nonce:
case found <- searchRes{n: nonce, md: md}:
case <-stop:
}
wg.Done()
@ -120,12 +162,14 @@ func TestEthashConcurrentSearch(t *testing.T) {
}
// wait for one of them to find the nonce
nonce := <-found
res := <-found
// stop the others
close(stop)
wg.Wait()
if block.nonce = nonce; !eth.Verify(block) {
block.nonce = res.n
block.mixDigest = common.BytesToHash(res.md)
if !eth.Verify(block) {
t.Error("Block could not be verified")
}
}
@ -140,8 +184,9 @@ func TestEthashSearchAcrossEpoch(t *testing.T) {
for i := epochLength - 40; i < epochLength+40; i++ {
block := &testBlock{number: i, difficulty: big.NewInt(90)}
rand.Read(block.hashNoNonce[:])
nonce, _ := eth.Search(block, nil)
nonce, md := eth.Search(block, nil, 0)
block.nonce = nonce
block.mixDigest = common.BytesToHash(md)
if !eth.Verify(block) {
t.Fatalf("Block could not be verified")
}

View File

@ -1,3 +1,19 @@
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package ethash
/*

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -32,10 +32,17 @@
#include <libkern/OSByteOrder.h>
#define ethash_swap_u32(input_) OSSwapInt32(input_)
#define ethash_swap_u64(input_) OSSwapInt64(input_)
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
#define ethash_swap_u32(input_) bswap32(input_)
#define ethash_swap_u64(input_) bswap64(input_)
#elif defined(__OpenBSD__)
#include <endian.h>
#define ethash_swap_u32(input_) swap32(input_)
#define ethash_swap_u64(input_) swap64(input_)
#else // posix
#include <byteswap.h>
#define ethash_swap_u32(input_) __bswap_32(input_)
#define ethash_swap_u64(input_) __bswap_64(input_)
#define ethash_swap_u32(input_) bswap_32(input_)
#define ethash_swap_u64(input_) bswap_64(input_)
#endif

View File

@ -29,6 +29,10 @@ extern "C" {
#define FNV_PRIME 0x01000193
/* The FNV-1 spec multiplies the prime with the input one byte (octet) in turn.
We instead multiply it with the full 32-bit input.
This gives a different result compared to a canonical FNV-1 implementation.
*/
static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y)
{
return x * FNV_PRIME ^ y;

View File

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

View File

@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash)
memset(hash, 0, 32);
}
// Returns if hash is less than or equal to difficulty
// Returns if hash is less than or equal to boundary (2^256/difficulty)
static inline bool ethash_check_difficulty(
ethash_h256_t const* hash,
ethash_h256_t const* difficulty
ethash_h256_t const* boundary
)
{
// Difficulty is big endian
// Boundary is big endian
for (int i = 0; i < 32; i++) {
if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
continue;
}
return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
}
return true;
}
/**
* Difficulty quick check for POW preverification
*
* @param header_hash The hash of the header
* @param nonce The block's nonce
* @param mix_hash The mix digest hash
* @param boundary The boundary is defined as (2^256 / difficulty)
* @return true for succesful pre-verification and false otherwise
*/
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* difficulty
ethash_h256_t const* boundary
);
struct ethash_light {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Fatih Arslan
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

151
Godeps/_workspace/src/github.com/fatih/color/README.md generated vendored Normal file
View File

@ -0,0 +1,151 @@
# Color [![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/fatih/color) [![Build Status](http://img.shields.io/travis/fatih/color.svg?style=flat-square)](https://travis-ci.org/fatih/color)
Color lets you use colorized outputs in terms of [ANSI Escape Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Go (Golang). It has support for Windows too! The API can be used in several ways, pick one that suits you.
![Color](http://i.imgur.com/c1JI0lA.png)
## Install
```bash
go get github.com/fatih/color
```
## Examples
### Standard colors
```go
// Print with default helper functions
color.Cyan("Prints text in cyan.")
// A newline will be appended automatically
color.Blue("Prints %s in blue.", "text")
// These are using the default foreground colors
color.Red("We have red")
color.Magenta("And many others ..")
```
### Mix and reuse colors
```go
// Create a new color object
c := color.New(color.FgCyan).Add(color.Underline)
c.Println("Prints cyan text with an underline.")
// Or just add them to New()
d := color.New(color.FgCyan, color.Bold)
d.Printf("This prints bold cyan %s\n", "too!.")
// Mix up foreground and background colors, create new mixes!
red := color.New(color.FgRed)
boldRed := red.Add(color.Bold)
boldRed.Println("This will print text in bold red.")
whiteBackground := red.Add(color.BgWhite)
whiteBackground.Println("Red text with white background.")
```
### Custom print functions (PrintFunc)
```go
// Create a custom print function for convenience
red := color.New(color.FgRed).PrintfFunc()
red("Warning")
red("Error: %s", err)
// Mix up multiple attributes
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
notice("Don't forget this...")
```
### Insert into noncolor strings (SprintFunc)
```go
// Create SprintXxx functions to mix strings with other non-colorized strings:
yellow := color.New(color.FgYellow).SprintFunc()
red := color.New(color.FgRed).SprintFunc()
fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
fmt.Printf("This %s rocks!\n", info("package"))
// Use helper functions
fmt.Printf("This", color.RedString("warning"), "should be not neglected.")
fmt.Printf(color.GreenString("Info:"), "an important message." )
// Windows supported too! Just don't forget to change the output to color.Output
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
```
### Plug into existing code
```go
// Use handy standard colors
color.Set(color.FgYellow)
fmt.Println("Existing text will now be in yellow")
fmt.Printf("This one %s\n", "too")
color.Unset() // Don't forget to unset
// You can mix up parameters
color.Set(color.FgMagenta, color.Bold)
defer color.Unset() // Use it in your function
fmt.Println("All text will now be bold magenta.")
```
### Disable color
There might be a case where you want to disable color output (for example to
pipe the standard output of your app to somewhere else). `Color` has support to
disable colors both globally and for single color definition. For example
suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
the color output with:
```go
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
if *flagNoColor {
color.NoColor = true // disables colorized output
}
```
It also has support for single color definitions (local). You can
disable/enable color output on the fly:
```go
c := color.New(color.FgCyan)
c.Println("Prints cyan text")
c.DisableColor()
c.Println("This is printed without any color")
c.EnableColor()
c.Println("This prints again cyan...")
```
## Todo
* Save/Return previous values
* Evaluate fmt.Formatter interface
## Credits
* [Fatih Arslan](https://github.com/fatih)
* Windows support via @shiena: [ansicolor](https://github.com/shiena/ansicolor)
## License
The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details

353
Godeps/_workspace/src/github.com/fatih/color/color.go generated vendored Normal file
View File

@ -0,0 +1,353 @@
package color
import (
"fmt"
"os"
"strconv"
"strings"
"github.com/mattn/go-isatty"
"github.com/shiena/ansicolor"
)
// NoColor defines if the output is colorized or not. It's dynamically set to
// false or true based on the stdout's file descriptor referring to a terminal
// or not. This is a global option and affects all colors. For more control
// over each color block use the methods DisableColor() individually.
var NoColor = !isatty.IsTerminal(os.Stdout.Fd())
// Color defines a custom color object which is defined by SGR parameters.
type Color struct {
params []Attribute
noColor *bool
}
// Attribute defines a single SGR Code
type Attribute int
const escape = "\x1b"
// Base attributes
const (
Reset Attribute = iota
Bold
Faint
Italic
Underline
BlinkSlow
BlinkRapid
ReverseVideo
Concealed
CrossedOut
)
// Foreground text colors
const (
FgBlack Attribute = iota + 30
FgRed
FgGreen
FgYellow
FgBlue
FgMagenta
FgCyan
FgWhite
)
// Background text colors
const (
BgBlack Attribute = iota + 40
BgRed
BgGreen
BgYellow
BgBlue
BgMagenta
BgCyan
BgWhite
)
// New returns a newly created color object.
func New(value ...Attribute) *Color {
c := &Color{params: make([]Attribute, 0)}
c.Add(value...)
return c
}
// Set sets the given parameters immediately. It will change the color of
// output with the given SGR parameters until color.Unset() is called.
func Set(p ...Attribute) *Color {
c := New(p...)
c.Set()
return c
}
// Unset resets all escape attributes and clears the output. Usually should
// be called after Set().
func Unset() {
if NoColor {
return
}
fmt.Fprintf(Output, "%s[%dm", escape, Reset)
}
// Set sets the SGR sequence.
func (c *Color) Set() *Color {
if c.isNoColorSet() {
return c
}
fmt.Fprintf(Output, c.format())
return c
}
func (c *Color) unset() {
if c.isNoColorSet() {
return
}
Unset()
}
// Add is used to chain SGR parameters. Use as many as parameters to combine
// and create custom color objects. Example: Add(color.FgRed, color.Underline).
func (c *Color) Add(value ...Attribute) *Color {
c.params = append(c.params, value...)
return c
}
func (c *Color) prepend(value Attribute) {
c.params = append(c.params, 0)
copy(c.params[1:], c.params[0:])
c.params[0] = value
}
// Output defines the standard output of the print functions. By default
// os.Stdout is used.
var Output = ansicolor.NewAnsiColorWriter(os.Stdout)
// Print formats using the default formats for its operands and writes to
// standard output. Spaces are added between operands when neither is a
// string. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Print(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprint(Output, a...)
}
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
// This is the standard fmt.Printf() method wrapped with the given color.
func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintf(Output, format, a...)
}
// Println formats using the default formats for its operands and writes to
// standard output. Spaces are always added between operands and a newline is
// appended. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Println(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintln(Output, a...)
}
// PrintFunc returns a new function that prints the passed arguments as
// colorized with color.Print().
func (c *Color) PrintFunc() func(a ...interface{}) {
return func(a ...interface{}) { c.Print(a...) }
}
// PrintfFunc returns a new function that prints the passed arguments as
// colorized with color.Printf().
func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
return func(format string, a ...interface{}) { c.Printf(format, a...) }
}
// PrintlnFunc returns a new function that prints the passed arguments as
// colorized with color.Println().
func (c *Color) PrintlnFunc() func(a ...interface{}) {
return func(a ...interface{}) { c.Println(a...) }
}
// SprintFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprint(). Useful to put into or mix into other
// string. Windows users should use this in conjuction with color.Output, example:
//
// put := New(FgYellow).SprintFunc()
// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
func (c *Color) SprintFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprint(a...))
}
}
// SprintfFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintf(). Useful to put into or mix into other
// string. Windows users should use this in conjuction with color.Output.
func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
return func(format string, a ...interface{}) string {
return c.wrap(fmt.Sprintf(format, a...))
}
}
// SprintlnFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintln(). Useful to put into or mix into other
// string. Windows users should use this in conjuction with color.Output.
func (c *Color) SprintlnFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprintln(a...))
}
}
// sequence returns a formated SGR sequence to be plugged into a "\x1b[...m"
// an example output might be: "1;36" -> bold cyan
func (c *Color) sequence() string {
format := make([]string, len(c.params))
for i, v := range c.params {
format[i] = strconv.Itoa(int(v))
}
return strings.Join(format, ";")
}
// wrap wraps the s string with the colors attributes. The string is ready to
// be printed.
func (c *Color) wrap(s string) string {
if c.isNoColorSet() {
return s
}
return c.format() + s + c.unformat()
}
func (c *Color) format() string {
return fmt.Sprintf("%s[%sm", escape, c.sequence())
}
func (c *Color) unformat() string {
return fmt.Sprintf("%s[%dm", escape, Reset)
}
// DisableColor disables the color output. Useful to not change any existing
// code and still being able to output. Can be used for flags like
// "--no-color". To enable back use EnableColor() method.
func (c *Color) DisableColor() {
c.noColor = boolPtr(true)
}
// EnableColor enables the color output. Use it in conjuction with
// DisableColor(). Otherwise this method has no side effects.
func (c *Color) EnableColor() {
c.noColor = boolPtr(false)
}
func (c *Color) isNoColorSet() bool {
// check first if we have user setted action
if c.noColor != nil {
return *c.noColor
}
// if not return the global option, which is disabled by default
return NoColor
}
func boolPtr(v bool) *bool {
return &v
}
// Black is an convenient helper function to print with black foreground. A
// newline is appended to format by default.
func Black(format string, a ...interface{}) { printColor(format, FgBlack, a...) }
// Red is an convenient helper function to print with red foreground. A
// newline is appended to format by default.
func Red(format string, a ...interface{}) { printColor(format, FgRed, a...) }
// Green is an convenient helper function to print with green foreground. A
// newline is appended to format by default.
func Green(format string, a ...interface{}) { printColor(format, FgGreen, a...) }
// Yellow is an convenient helper function to print with yellow foreground.
// A newline is appended to format by default.
func Yellow(format string, a ...interface{}) { printColor(format, FgYellow, a...) }
// Blue is an convenient helper function to print with blue foreground. A
// newline is appended to format by default.
func Blue(format string, a ...interface{}) { printColor(format, FgBlue, a...) }
// Magenta is an convenient helper function to print with magenta foreground.
// A newline is appended to format by default.
func Magenta(format string, a ...interface{}) { printColor(format, FgMagenta, a...) }
// Cyan is an convenient helper function to print with cyan foreground. A
// newline is appended to format by default.
func Cyan(format string, a ...interface{}) { printColor(format, FgCyan, a...) }
// White is an convenient helper function to print with white foreground. A
// newline is appended to format by default.
func White(format string, a ...interface{}) { printColor(format, FgWhite, a...) }
func printColor(format string, p Attribute, a ...interface{}) {
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
c := &Color{params: []Attribute{p}}
c.Printf(format, a...)
}
// BlackString is an convenient helper function to return a string with black
// foreground.
func BlackString(format string, a ...interface{}) string {
return New(FgBlack).SprintfFunc()(format, a...)
}
// RedString is an convenient helper function to return a string with red
// foreground.
func RedString(format string, a ...interface{}) string {
return New(FgRed).SprintfFunc()(format, a...)
}
// GreenString is an convenient helper function to return a string with green
// foreground.
func GreenString(format string, a ...interface{}) string {
return New(FgGreen).SprintfFunc()(format, a...)
}
// YellowString is an convenient helper function to return a string with yellow
// foreground.
func YellowString(format string, a ...interface{}) string {
return New(FgYellow).SprintfFunc()(format, a...)
}
// BlueString is an convenient helper function to return a string with blue
// foreground.
func BlueString(format string, a ...interface{}) string {
return New(FgBlue).SprintfFunc()(format, a...)
}
// MagentaString is an convenient helper function to return a string with magenta
// foreground.
func MagentaString(format string, a ...interface{}) string {
return New(FgMagenta).SprintfFunc()(format, a...)
}
// CyanString is an convenient helper function to return a string with cyan
// foreground.
func CyanString(format string, a ...interface{}) string {
return New(FgCyan).SprintfFunc()(format, a...)
}
// WhiteString is an convenient helper function to return a string with white
// foreground.
func WhiteString(format string, a ...interface{}) string {
return New(FgWhite).SprintfFunc()(format, a...)
}

View File

@ -0,0 +1,176 @@
package color
import (
"bytes"
"fmt"
"os"
"testing"
"github.com/shiena/ansicolor"
)
// Testing colors is kinda different. First we test for given colors and their
// escaped formatted results. Next we create some visual tests to be tested.
// Each visual test includes the color name to be compared.
func TestColor(t *testing.T) {
rb := new(bytes.Buffer)
Output = rb
testColors := []struct {
text string
code Attribute
}{
{text: "black", code: FgBlack},
{text: "red", code: FgRed},
{text: "green", code: FgGreen},
{text: "yellow", code: FgYellow},
{text: "blue", code: FgBlue},
{text: "magent", code: FgMagenta},
{text: "cyan", code: FgCyan},
{text: "white", code: FgWhite},
}
for _, c := range testColors {
New(c.code).Print(c.text)
line, _ := rb.ReadString('\n')
scannedLine := fmt.Sprintf("%q", line)
colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
escapedForm := fmt.Sprintf("%q", colored)
fmt.Printf("%s\t: %s\n", c.text, line)
if scannedLine != escapedForm {
t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
}
}
}
func TestNoColor(t *testing.T) {
rb := new(bytes.Buffer)
Output = rb
testColors := []struct {
text string
code Attribute
}{
{text: "black", code: FgBlack},
{text: "red", code: FgRed},
{text: "green", code: FgGreen},
{text: "yellow", code: FgYellow},
{text: "blue", code: FgBlue},
{text: "magent", code: FgMagenta},
{text: "cyan", code: FgCyan},
{text: "white", code: FgWhite},
}
for _, c := range testColors {
p := New(c.code)
p.DisableColor()
p.Print(c.text)
line, _ := rb.ReadString('\n')
if line != c.text {
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
}
}
// global check
NoColor = true
defer func() {
NoColor = false
}()
for _, c := range testColors {
p := New(c.code)
p.Print(c.text)
line, _ := rb.ReadString('\n')
if line != c.text {
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
}
}
}
func TestColorVisual(t *testing.T) {
// First Visual Test
fmt.Println("")
Output = ansicolor.NewAnsiColorWriter(os.Stdout)
New(FgRed).Printf("red\t")
New(BgRed).Print(" ")
New(FgRed, Bold).Println(" red")
New(FgGreen).Printf("green\t")
New(BgGreen).Print(" ")
New(FgGreen, Bold).Println(" green")
New(FgYellow).Printf("yellow\t")
New(BgYellow).Print(" ")
New(FgYellow, Bold).Println(" yellow")
New(FgBlue).Printf("blue\t")
New(BgBlue).Print(" ")
New(FgBlue, Bold).Println(" blue")
New(FgMagenta).Printf("magenta\t")
New(BgMagenta).Print(" ")
New(FgMagenta, Bold).Println(" magenta")
New(FgCyan).Printf("cyan\t")
New(BgCyan).Print(" ")
New(FgCyan, Bold).Println(" cyan")
New(FgWhite).Printf("white\t")
New(BgWhite).Print(" ")
New(FgWhite, Bold).Println(" white")
fmt.Println("")
// Second Visual test
Black("black")
Red("red")
Green("green")
Yellow("yellow")
Blue("blue")
Magenta("magenta")
Cyan("cyan")
White("white")
// Third visual test
fmt.Println()
Set(FgBlue)
fmt.Println("is this blue?")
Unset()
Set(FgMagenta)
fmt.Println("and this magenta?")
Unset()
// Fourth Visual test
fmt.Println()
blue := New(FgBlue).PrintlnFunc()
blue("blue text with custom print func")
red := New(FgRed).PrintfFunc()
red("red text with a printf func: %d\n", 123)
put := New(FgYellow).SprintFunc()
warn := New(FgRed).SprintFunc()
fmt.Fprintf(Output, "this is a %s and this is %s.\n", put("warning"), warn("error"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Fprintf(Output, "this %s rocks!\n", info("package"))
// Fifth Visual Test
fmt.Println()
fmt.Fprintln(Output, BlackString("black"))
fmt.Fprintln(Output, RedString("red"))
fmt.Fprintln(Output, GreenString("green"))
fmt.Fprintln(Output, YellowString("yellow"))
fmt.Fprintln(Output, BlueString("blue"))
fmt.Fprintln(Output, MagentaString("magenta"))
fmt.Fprintln(Output, CyanString("cyan"))
fmt.Fprintln(Output, WhiteString("white"))
}

114
Godeps/_workspace/src/github.com/fatih/color/doc.go generated vendored Normal file
View File

@ -0,0 +1,114 @@
/*
Package color is an ANSI color package to output colorized or SGR defined
output to the standard output. The API can be used in several way, pick one
that suits you.
Use simple and default helper functions with predefined foreground colors:
color.Cyan("Prints text in cyan.")
// a newline will be appended automatically
color.Blue("Prints %s in blue.", "text")
// More default foreground colors..
color.Red("We have red")
color.Yellow("Yellow color too!")
color.Magenta("And many others ..")
However there are times where custom color mixes are required. Below are some
examples to create custom color objects and use the print functions of each
separate color object.
// Create a new color object
c := color.New(color.FgCyan).Add(color.Underline)
c.Println("Prints cyan text with an underline.")
// Or just add them to New()
d := color.New(color.FgCyan, color.Bold)
d.Printf("This prints bold cyan %s\n", "too!.")
// Mix up foreground and background colors, create new mixes!
red := color.New(color.FgRed)
boldRed := red.Add(color.Bold)
boldRed.Println("This will print text in bold red.")
whiteBackground := red.Add(color.BgWhite)
whiteBackground.Println("Red text with White background.")
You can create PrintXxx functions to simplify even more:
// Create a custom print function for convenient
red := color.New(color.FgRed).PrintfFunc()
red("warning")
red("error: %s", err)
// Mix up multiple attributes
notice := color.New(color.Bold, color.FgGreen).PrintlnFunc()
notice("don't forget this...")
Or create SprintXxx functions to mix strings with other non-colorized strings:
yellow := New(FgYellow).SprintFunc()
red := New(FgRed).SprintFunc()
fmt.Printf("this is a %s and this is %s.\n", yellow("warning"), red("error"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Printf("this %s rocks!\n", info("package"))
Windows support is enabled by default. All Print functions works as intended.
However only for color.SprintXXX functions, user should use fmt.FprintXXX and
set the output to color.Output:
fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS"))
info := New(FgWhite, BgGreen).SprintFunc()
fmt.Fprintf(color.Output, "this %s rocks!\n", info("package"))
Using with existing code is possible. Just use the Set() method to set the
standard output to the given parameters. That way a rewrite of an existing
code is not required.
// Use handy standard colors.
color.Set(color.FgYellow)
fmt.Println("Existing text will be now in Yellow")
fmt.Printf("This one %s\n", "too")
color.Unset() // don't forget to unset
// You can mix up parameters
color.Set(color.FgMagenta, color.Bold)
defer color.Unset() // use it in your function
fmt.Println("All text will be now bold magenta.")
There might be a case where you want to disable color output (for example to
pipe the standard output of your app to somewhere else). `Color` has support to
disable colors both globally and for single color definition. For example
suppose you have a CLI app and a `--no-color` bool flag. You can easily disable
the color output with:
var flagNoColor = flag.Bool("no-color", false, "Disable color output")
if *flagNoColor {
color.NoColor = true // disables colorized output
}
It also has support for single color definitions (local). You can
disable/enable color output on the fly:
c := color.New(color.FgCyan)
c.Println("Prints cyan text")
c.DisableColor()
c.Println("This is printed without any color")
c.EnableColor()
c.Println("This prints again cyan...")
*/
package color

View File

@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@ -0,0 +1,6 @@
language: go
go:
- tip
script: go test -v ./

22
Godeps/_workspace/src/github.com/gizak/termui/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Zack Guo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

159
Godeps/_workspace/src/github.com/gizak/termui/README.md generated vendored Normal file
View File

@ -0,0 +1,159 @@
# termui [![Build Status](https://travis-ci.org/gizak/termui.svg?branch=master)](https://travis-ci.org/gizak/termui) [![Doc Status](https://godoc.org/github.com/gizak/termui?status.png)](https://godoc.org/github.com/gizak/termui)
## Update 23/06/2015
Pull requests and master branch are freezing, waiting for merging from `refactoring` branch.
## Notice
termui comes with ABSOLUTELY NO WARRANTY, and there is a breaking change coming up (see refactoring branch) which will change the `Bufferer` interface and many others. These changes reduce calculation overhead and introduce a new drawing buffer with better capacibilities. We will step into the next stage (call it beta) after merging these changes.
## Introduction
Go terminal dashboard. Inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go.
Cross-platform, easy to compile, and fully-customizable.
__Demo:__ (cast under osx 10.10; Terminal.app; Menlo Regular 12pt.)
<img src="./example/dashboard.gif" alt="demo" width="600">
__Grid layout:__
Expressive syntax, using [12 columns grid system](http://www.w3schools.com/bootstrap/bootstrap_grid_system.asp)
```go
import ui "github.com/gizak/termui"
// init and create widgets...
// build
ui.Body.AddRows(
ui.NewRow(
ui.NewCol(6, 0, widget0),
ui.NewCol(6, 0, widget1)),
ui.NewRow(
ui.NewCol(3, 0, widget2),
ui.NewCol(3, 0, widget30, widget31, widget32),
ui.NewCol(6, 0, widget4)))
// calculate layout
ui.Body.Align()
ui.Render(ui.Body)
```
[demo code:](https://github.com/gizak/termui/blob/master/example/grid.go)
<img src="./example/grid.gif" alt="grid" width="500">
## Installation
go get github.com/gizak/termui
## Usage
Each component's layout is a bit like HTML block (box model), which has border and padding.
The `Border` property can be chosen to hide or display (with its border label), when it comes to display, the label takes 1 padding space (i.e. in css: `padding: 1;`, innerHeight and innerWidth therefore shrunk by 1).
`````go
import ui "github.com/gizak/termui" // <- ui shortcut, optional
func main() {
err := ui.Init()
if err != nil {
panic(err)
}
defer ui.Close()
p := ui.NewPar(":PRESS q TO QUIT DEMO")
p.Height = 3
p.Width = 50
p.TextFgColor = ui.ColorWhite
p.Border.Label = "Text Box"
p.Border.FgColor = ui.ColorCyan
g := ui.NewGauge()
g.Percent = 50
g.Width = 50
g.Height = 3
g.Y = 11
g.Border.Label = "Gauge"
g.BarColor = ui.ColorRed
g.Border.FgColor = ui.ColorWhite
g.Border.LabelFgColor = ui.ColorCyan
ui.Render(p, g)
// event handler...
}
`````
Note that components can be overlapped (I'd rather call this a feature...), `Render(rs ...Renderer)` renders its args from left to right (i.e. each component's weight is arising from left to right).
## Themes
_All_ colors in _all_ components can be changed at _any_ time, while there provides some predefined color schemes:
```go
// for now there are only two themes: default and helloworld
termui.UseTheme("helloworld")
// create components...
```
The `default ` theme's settings depend on the user's terminal color scheme, which is saying if your terminal default font color is white and background is white, it will be like:
<img src="./example/themedefault.png" alt="default" type="image/png" width="600">
The `helloworld` color scheme drops in some colors!
<img src="./example/themehelloworld.png" alt="helloworld" type="image/png" width="600">
## Widgets
#### Par
[demo code](https://github.com/gizak/termui/blob/master/example/par.go)
<img src="./example/par.png" alt="par" type="image/png" width="300">
#### List
[demo code](https://github.com/gizak/termui/blob/master/example/list.go)
<img src="./example/list.png" alt="list" type="image/png" width="200">
#### Gauge
[demo code](https://github.com/gizak/termui/blob/master/example/gauge.go)
<img src="./example/gauge.png" alt="gauge" type="image/png" width="350">
#### Line Chart
[demo code](https://github.com/gizak/termui/blob/master/example/linechart.go)
<img src="./example/linechart.png" alt="linechart" type="image/png" width="450">
#### Bar Chart
[demo code](https://github.com/gizak/termui/blob/master/example/barchart.go)
<img src="./example/barchart.png" alt="barchart" type="image/png" width="150">
#### Mult-Bar / Stacked-Bar Chart
[demo code](https://github.com/gizak/termui/blob/master/example/mbarchart.go)
<img src="./example/mbarchart.png" alt="barchart" type="image/png" width="150">
#### Sparklines
[demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go)
<img src="./example/sparklines.png" alt="sparklines" type="image/png" width="350">
## GoDoc
[godoc](https://godoc.org/github.com/gizak/termui)
## TODO
- [x] Grid layout
- [ ] Event system
- [ ] Canvas widget
- [ ] Refine APIs
- [ ] Focusable widgets
## License
This library is under the [MIT License](http://opensource.org/licenses/MIT)

135
Godeps/_workspace/src/github.com/gizak/termui/bar.go generated vendored Normal file
View File

@ -0,0 +1,135 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import "fmt"
// BarChart creates multiple bars in a widget:
/*
bc := termui.NewBarChart()
data := []int{3, 2, 5, 3, 9, 5}
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
bc.Border.Label = "Bar Chart"
bc.Data = data
bc.Width = 26
bc.Height = 10
bc.DataLabels = bclabels
bc.TextColor = termui.ColorGreen
bc.BarColor = termui.ColorRed
bc.NumColor = termui.ColorYellow
*/
type BarChart struct {
Block
BarColor Attribute
TextColor Attribute
NumColor Attribute
Data []int
DataLabels []string
BarWidth int
BarGap int
labels [][]rune
dataNum [][]rune
numBar int
scale float64
max int
}
// NewBarChart returns a new *BarChart with current theme.
func NewBarChart() *BarChart {
bc := &BarChart{Block: *NewBlock()}
bc.BarColor = theme.BarChartBar
bc.NumColor = theme.BarChartNum
bc.TextColor = theme.BarChartText
bc.BarGap = 1
bc.BarWidth = 3
return bc
}
func (bc *BarChart) layout() {
bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
bc.labels = make([][]rune, bc.numBar)
bc.dataNum = make([][]rune, len(bc.Data))
for i := 0; i < bc.numBar && i < len(bc.DataLabels) && i < len(bc.Data); i++ {
bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
n := bc.Data[i]
s := fmt.Sprint(n)
bc.dataNum[i] = trimStr2Runes(s, bc.BarWidth)
}
//bc.max = bc.Data[0] // what if Data is nil? Sometimes when bar graph is nill it produces panic with panic: runtime error: index out of range
// Asign a negative value to get maxvalue auto-populates
if bc.max == 0 {
bc.max = -1
}
for i := 0; i < len(bc.Data); i++ {
if bc.max < bc.Data[i] {
bc.max = bc.Data[i]
}
}
bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
}
func (bc *BarChart) SetMax(max int) {
if max > 0 {
bc.max = max
}
}
// Buffer implements Bufferer interface.
func (bc *BarChart) Buffer() []Point {
ps := bc.Block.Buffer()
bc.layout()
for i := 0; i < bc.numBar && i < len(bc.Data) && i < len(bc.DataLabels); i++ {
h := int(float64(bc.Data[i]) / bc.scale)
oftX := i * (bc.BarWidth + bc.BarGap)
// plot bar
for j := 0; j < bc.BarWidth; j++ {
for k := 0; k < h; k++ {
p := Point{}
p.Ch = ' '
p.Bg = bc.BarColor
if bc.BarColor == ColorDefault { // when color is default, space char treated as transparent!
p.Bg |= AttrReverse
}
p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
p.Y = bc.innerY + bc.innerHeight - 2 - k
ps = append(ps, p)
}
}
// plot text
for j, k := 0, 0; j < len(bc.labels[i]); j++ {
w := charWidth(bc.labels[i][j])
p := Point{}
p.Ch = bc.labels[i][j]
p.Bg = bc.BgColor
p.Fg = bc.TextColor
p.Y = bc.innerY + bc.innerHeight - 1
p.X = bc.innerX + oftX + k
ps = append(ps, p)
k += w
}
// plot num
for j := 0; j < len(bc.dataNum[i]); j++ {
p := Point{}
p.Ch = bc.dataNum[i][j]
p.Fg = bc.NumColor
p.Bg = bc.BarColor
if bc.BarColor == ColorDefault { // the same as above
p.Bg |= AttrReverse
}
if h == 0 {
p.Bg = bc.BgColor
}
p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i]))/2 + j
p.Y = bc.innerY + bc.innerHeight - 2
ps = append(ps, p)
}
}
return bc.Block.chopOverflow(ps)
}

142
Godeps/_workspace/src/github.com/gizak/termui/block.go generated vendored Normal file
View File

@ -0,0 +1,142 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
// Block is a base struct for all other upper level widgets,
// consider it as css: display:block.
// Normally you do not need to create it manually.
type Block struct {
X int
Y int
Border labeledBorder
IsDisplay bool
HasBorder bool
BgColor Attribute
Width int
Height int
innerWidth int
innerHeight int
innerX int
innerY int
PaddingTop int
PaddingBottom int
PaddingLeft int
PaddingRight int
}
// NewBlock returns a *Block which inherits styles from current theme.
func NewBlock() *Block {
d := Block{}
d.IsDisplay = true
d.HasBorder = theme.HasBorder
d.Border.BgColor = theme.BorderBg
d.Border.FgColor = theme.BorderFg
d.Border.LabelBgColor = theme.BorderLabelTextBg
d.Border.LabelFgColor = theme.BorderLabelTextFg
d.BgColor = theme.BlockBg
d.Width = 2
d.Height = 2
return &d
}
// compute box model
func (d *Block) align() {
d.innerWidth = d.Width - d.PaddingLeft - d.PaddingRight
d.innerHeight = d.Height - d.PaddingTop - d.PaddingBottom
d.innerX = d.X + d.PaddingLeft
d.innerY = d.Y + d.PaddingTop
if d.HasBorder {
d.innerHeight -= 2
d.innerWidth -= 2
d.Border.X = d.X
d.Border.Y = d.Y
d.Border.Width = d.Width
d.Border.Height = d.Height
d.innerX++
d.innerY++
}
if d.innerHeight < 0 {
d.innerHeight = 0
}
if d.innerWidth < 0 {
d.innerWidth = 0
}
}
// InnerBounds returns the internal bounds of the block after aligning and
// calculating the padding and border, if any.
func (d *Block) InnerBounds() (x, y, width, height int) {
d.align()
return d.innerX, d.innerY, d.innerWidth, d.innerHeight
}
// Buffer implements Bufferer interface.
// Draw background and border (if any).
func (d *Block) Buffer() []Point {
d.align()
ps := []Point{}
if !d.IsDisplay {
return ps
}
if d.HasBorder {
ps = d.Border.Buffer()
}
for i := 0; i < d.innerWidth; i++ {
for j := 0; j < d.innerHeight; j++ {
p := Point{}
p.X = d.X + 1 + i
p.Y = d.Y + 1 + j
p.Ch = ' '
p.Bg = d.BgColor
ps = append(ps, p)
}
}
return ps
}
// GetHeight implements GridBufferer.
// It returns current height of the block.
func (d Block) GetHeight() int {
return d.Height
}
// SetX implements GridBufferer interface, which sets block's x position.
func (d *Block) SetX(x int) {
d.X = x
}
// SetY implements GridBufferer interface, it sets y position for block.
func (d *Block) SetY(y int) {
d.Y = y
}
// SetWidth implements GridBuffer interface, it sets block's width.
func (d *Block) SetWidth(w int) {
d.Width = w
}
// chop the overflow parts
func (d *Block) chopOverflow(ps []Point) []Point {
nps := make([]Point, 0, len(ps))
x := d.X
y := d.Y
w := d.Width
h := d.Height
for _, v := range ps {
if v.X >= x &&
v.X < x+w &&
v.Y >= y &&
v.Y < y+h {
nps = append(nps, v)
}
}
return nps
}

View File

@ -0,0 +1,46 @@
package termui
import "testing"
func TestBlock_InnerBounds(t *testing.T) {
b := NewBlock()
b.X = 10
b.Y = 11
b.Width = 12
b.Height = 13
assert := func(name string, x, y, w, h int) {
t.Log(name)
cx, cy, cw, ch := b.InnerBounds()
if cx != x {
t.Errorf("expected x to be %d but got %d", x, cx)
}
if cy != y {
t.Errorf("expected y to be %d but got %d", y, cy)
}
if cw != w {
t.Errorf("expected width to be %d but got %d", w, cw)
}
if ch != h {
t.Errorf("expected height to be %d but got %d", h, ch)
}
}
b.HasBorder = false
assert("no border, no padding", 10, 11, 12, 13)
b.HasBorder = true
assert("border, no padding", 11, 12, 10, 11)
b.PaddingBottom = 2
assert("border, 2b padding", 11, 12, 10, 9)
b.PaddingTop = 3
assert("border, 2b 3t padding", 11, 15, 10, 6)
b.PaddingLeft = 4
assert("border, 2b 3t 4l padding", 15, 15, 6, 6)
b.PaddingRight = 5
assert("border, 2b 3t 4l 5r padding", 15, 15, 1, 6)
}

117
Godeps/_workspace/src/github.com/gizak/termui/box.go generated vendored Normal file
View File

@ -0,0 +1,117 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
type border struct {
X int
Y int
Width int
Height int
FgColor Attribute
BgColor Attribute
}
type hline struct {
X int
Y int
Length int
FgColor Attribute
BgColor Attribute
}
type vline struct {
X int
Y int
Length int
FgColor Attribute
BgColor Attribute
}
// Draw a horizontal line.
func (l hline) Buffer() []Point {
pts := make([]Point, l.Length)
for i := 0; i < l.Length; i++ {
pts[i].X = l.X + i
pts[i].Y = l.Y
pts[i].Ch = HORIZONTAL_LINE
pts[i].Bg = l.BgColor
pts[i].Fg = l.FgColor
}
return pts
}
// Draw a vertical line.
func (l vline) Buffer() []Point {
pts := make([]Point, l.Length)
for i := 0; i < l.Length; i++ {
pts[i].X = l.X
pts[i].Y = l.Y + i
pts[i].Ch = VERTICAL_LINE
pts[i].Bg = l.BgColor
pts[i].Fg = l.FgColor
}
return pts
}
// Draw a box border.
func (b border) Buffer() []Point {
if b.Width < 2 || b.Height < 2 {
return nil
}
pts := make([]Point, 2*b.Width+2*b.Height-4)
pts[0].X = b.X
pts[0].Y = b.Y
pts[0].Fg = b.FgColor
pts[0].Bg = b.BgColor
pts[0].Ch = TOP_LEFT
pts[1].X = b.X + b.Width - 1
pts[1].Y = b.Y
pts[1].Fg = b.FgColor
pts[1].Bg = b.BgColor
pts[1].Ch = TOP_RIGHT
pts[2].X = b.X
pts[2].Y = b.Y + b.Height - 1
pts[2].Fg = b.FgColor
pts[2].Bg = b.BgColor
pts[2].Ch = BOTTOM_LEFT
pts[3].X = b.X + b.Width - 1
pts[3].Y = b.Y + b.Height - 1
pts[3].Fg = b.FgColor
pts[3].Bg = b.BgColor
pts[3].Ch = BOTTOM_RIGHT
copy(pts[4:], (hline{b.X + 1, b.Y, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
copy(pts[4+b.Width-2:], (hline{b.X + 1, b.Y + b.Height - 1, b.Width - 2, b.FgColor, b.BgColor}).Buffer())
copy(pts[4+2*b.Width-4:], (vline{b.X, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
copy(pts[4+2*b.Width-4+b.Height-2:], (vline{b.X + b.Width - 1, b.Y + 1, b.Height - 2, b.FgColor, b.BgColor}).Buffer())
return pts
}
type labeledBorder struct {
border
Label string
LabelFgColor Attribute
LabelBgColor Attribute
}
// Draw a box border with label.
func (lb labeledBorder) Buffer() []Point {
ps := lb.border.Buffer()
maxTxtW := lb.Width - 2
rs := trimStr2Runes(lb.Label, maxTxtW)
for i, j, w := 0, 0, 0; i < len(rs); i++ {
w = charWidth(rs[i])
ps = append(ps, newPointWithAttrs(rs[i], lb.X+1+j, lb.Y, lb.LabelFgColor, lb.LabelBgColor))
j += w
}
return ps
}

View File

@ -0,0 +1,14 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
// +build !windows
package termui
const TOP_RIGHT = '┐'
const VERTICAL_LINE = '│'
const HORIZONTAL_LINE = '─'
const TOP_LEFT = '┌'
const BOTTOM_RIGHT = '┘'
const BOTTOM_LEFT = '└'

View File

@ -0,0 +1,14 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
// +build windows
package termui
const TOP_RIGHT = '+'
const VERTICAL_LINE = '|'
const HORIZONTAL_LINE = '-'
const TOP_LEFT = '+'
const BOTTOM_RIGHT = '+'
const BOTTOM_LEFT = '+'

View File

@ -0,0 +1,74 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
/*
dots:
,___,
|1 4|
|2 5|
|3 6|
|7 8|
`````
*/
var brailleBase = '\u2800'
var brailleOftMap = [4][2]rune{
{'\u0001', '\u0008'},
{'\u0002', '\u0010'},
{'\u0004', '\u0020'},
{'\u0040', '\u0080'}}
// Canvas contains drawing map: i,j -> rune
type Canvas map[[2]int]rune
// NewCanvas returns an empty Canvas
func NewCanvas() Canvas {
return make(map[[2]int]rune)
}
func chOft(x, y int) rune {
return brailleOftMap[y%4][x%2]
}
func (c Canvas) rawCh(x, y int) rune {
if ch, ok := c[[2]int{x, y}]; ok {
return ch
}
return '\u0000' //brailleOffset
}
// return coordinate in terminal
func chPos(x, y int) (int, int) {
return y / 4, x / 2
}
// Set sets a point (x,y) in the virtual coordinate
func (c Canvas) Set(x, y int) {
i, j := chPos(x, y)
ch := c.rawCh(i, j)
ch |= chOft(x, y)
c[[2]int{i, j}] = ch
}
// Unset removes point (x,y)
func (c Canvas) Unset(x, y int) {
i, j := chPos(x, y)
ch := c.rawCh(i, j)
ch &= ^chOft(x, y)
c[[2]int{i, j}] = ch
}
// Buffer returns un-styled points
func (c Canvas) Buffer() []Point {
ps := make([]Point, len(c))
i := 0
for k, v := range c {
ps[i] = newPoint(v+brailleBase, k[0], k[1])
i++
}
return ps
}

View File

@ -0,0 +1,55 @@
package termui
import (
"testing"
"github.com/davecgh/go-spew/spew"
)
func TestCanvasSet(t *testing.T) {
c := NewCanvas()
c.Set(0, 0)
c.Set(0, 1)
c.Set(0, 2)
c.Set(0, 3)
c.Set(1, 3)
c.Set(2, 3)
c.Set(3, 3)
c.Set(4, 3)
c.Set(5, 3)
spew.Dump(c)
}
func TestCanvasUnset(t *testing.T) {
c := NewCanvas()
c.Set(0, 0)
c.Set(0, 1)
c.Set(0, 2)
c.Unset(0, 2)
spew.Dump(c)
c.Unset(0, 3)
spew.Dump(c)
}
func TestCanvasBuffer(t *testing.T) {
c := NewCanvas()
c.Set(0, 0)
c.Set(0, 1)
c.Set(0, 2)
c.Set(0, 3)
c.Set(1, 3)
c.Set(2, 3)
c.Set(3, 3)
c.Set(4, 3)
c.Set(5, 3)
c.Set(6, 3)
c.Set(7, 2)
c.Set(8, 1)
c.Set(9, 0)
bufs := c.Buffer()
rs := make([]rune, len(bufs))
for i, v := range bufs {
rs[i] = v.Ch
}
spew.Dump(string(rs))
}

336
Godeps/_workspace/src/github.com/gizak/termui/chart.go generated vendored Normal file
View File

@ -0,0 +1,336 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
package termui
import (
"fmt"
"math"
)
// only 16 possible combinations, why bother
var braillePatterns = map[[2]int]rune{
[2]int{0, 0}: '⣀',
[2]int{0, 1}: '⡠',
[2]int{0, 2}: '⡐',
[2]int{0, 3}: '⡈',
[2]int{1, 0}: '⢄',
[2]int{1, 1}: '⠤',
[2]int{1, 2}: '⠔',
[2]int{1, 3}: '⠌',
[2]int{2, 0}: '⢂',
[2]int{2, 1}: '⠢',
[2]int{2, 2}: '⠒',
[2]int{2, 3}: '⠊',
[2]int{3, 0}: '⢁',
[2]int{3, 1}: '⠡',
[2]int{3, 2}: '⠑',
[2]int{3, 3}: '⠉',
}
var lSingleBraille = [4]rune{'\u2840', '⠄', '⠂', '⠁'}
var rSingleBraille = [4]rune{'\u2880', '⠠', '⠐', '⠈'}
// LineChart has two modes: braille(default) and dot. Using braille gives 2x capicity as dot mode,
// because one braille char can represent two data points.
/*
lc := termui.NewLineChart()
lc.Border.Label = "braille-mode Line Chart"
lc.Data = [1.2, 1.3, 1.5, 1.7, 1.5, 1.6, 1.8, 2.0]
lc.Width = 50
lc.Height = 12
lc.AxesColor = termui.ColorWhite
lc.LineColor = termui.ColorGreen | termui.AttrBold
// termui.Render(lc)...
*/
type LineChart struct {
Block
Data []float64
DataLabels []string // if unset, the data indices will be used
Mode string // braille | dot
DotStyle rune
LineColor Attribute
scale float64 // data span per cell on y-axis
AxesColor Attribute
drawingX int
drawingY int
axisYHeight int
axisXWidth int
axisYLebelGap int
axisXLebelGap int
topValue float64
bottomValue float64
labelX [][]rune
labelY [][]rune
labelYSpace int
maxY float64
minY float64
}
// NewLineChart returns a new LineChart with current theme.
func NewLineChart() *LineChart {
lc := &LineChart{Block: *NewBlock()}
lc.AxesColor = theme.LineChartAxes
lc.LineColor = theme.LineChartLine
lc.Mode = "braille"
lc.DotStyle = '•'
lc.axisXLebelGap = 2
lc.axisYLebelGap = 1
lc.bottomValue = math.Inf(1)
lc.topValue = math.Inf(-1)
return lc
}
// one cell contains two data points
// so the capicity is 2x as dot-mode
func (lc *LineChart) renderBraille() []Point {
ps := []Point{}
// return: b -> which cell should the point be in
// m -> in the cell, divided into 4 equal height levels, which subcell?
getPos := func(d float64) (b, m int) {
cnt4 := int((d-lc.bottomValue)/(lc.scale/4) + 0.5)
b = cnt4 / 4
m = cnt4 % 4
return
}
// plot points
for i := 0; 2*i+1 < len(lc.Data) && i < lc.axisXWidth; i++ {
b0, m0 := getPos(lc.Data[2*i])
b1, m1 := getPos(lc.Data[2*i+1])
if b0 == b1 {
p := Point{}
p.Ch = braillePatterns[[2]int{m0, m1}]
p.Bg = lc.BgColor
p.Fg = lc.LineColor
p.Y = lc.innerY + lc.innerHeight - 3 - b0
p.X = lc.innerX + lc.labelYSpace + 1 + i
ps = append(ps, p)
} else {
p0 := newPointWithAttrs(lSingleBraille[m0],
lc.innerX+lc.labelYSpace+1+i,
lc.innerY+lc.innerHeight-3-b0,
lc.LineColor,
lc.BgColor)
p1 := newPointWithAttrs(rSingleBraille[m1],
lc.innerX+lc.labelYSpace+1+i,
lc.innerY+lc.innerHeight-3-b1,
lc.LineColor,
lc.BgColor)
ps = append(ps, p0, p1)
}
}
return ps
}
func (lc *LineChart) renderDot() []Point {
ps := []Point{}
for i := 0; i < len(lc.Data) && i < lc.axisXWidth; i++ {
p := Point{}
p.Ch = lc.DotStyle
p.Fg = lc.LineColor
p.Bg = lc.BgColor
p.X = lc.innerX + lc.labelYSpace + 1 + i
p.Y = lc.innerY + lc.innerHeight - 3 - int((lc.Data[i]-lc.bottomValue)/lc.scale+0.5)
ps = append(ps, p)
}
return ps
}
func (lc *LineChart) calcLabelX() {
lc.labelX = [][]rune{}
for i, l := 0, 0; i < len(lc.DataLabels) && l < lc.axisXWidth; i++ {
if lc.Mode == "dot" {
if l >= len(lc.DataLabels) {
break
}
s := str2runes(lc.DataLabels[l])
w := strWidth(lc.DataLabels[l])
if l+w <= lc.axisXWidth {
lc.labelX = append(lc.labelX, s)
}
l += w + lc.axisXLebelGap
} else { // braille
if 2*l >= len(lc.DataLabels) {
break
}
s := str2runes(lc.DataLabels[2*l])
w := strWidth(lc.DataLabels[2*l])
if l+w <= lc.axisXWidth {
lc.labelX = append(lc.labelX, s)
}
l += w + lc.axisXLebelGap
}
}
}
func shortenFloatVal(x float64) string {
s := fmt.Sprintf("%.2f", x)
if len(s)-3 > 3 {
s = fmt.Sprintf("%.2e", x)
}
if x < 0 {
s = fmt.Sprintf("%.2f", x)
}
return s
}
func (lc *LineChart) calcLabelY() {
span := lc.topValue - lc.bottomValue
lc.scale = span / float64(lc.axisYHeight)
n := (1 + lc.axisYHeight) / (lc.axisYLebelGap + 1)
lc.labelY = make([][]rune, n)
maxLen := 0
for i := 0; i < n; i++ {
s := str2runes(shortenFloatVal(lc.bottomValue + float64(i)*span/float64(n)))
if len(s) > maxLen {
maxLen = len(s)
}
lc.labelY[i] = s
}
lc.labelYSpace = maxLen
}
func (lc *LineChart) calcLayout() {
// set datalabels if it is not provided
if lc.DataLabels == nil || len(lc.DataLabels) == 0 {
lc.DataLabels = make([]string, len(lc.Data))
for i := range lc.Data {
lc.DataLabels[i] = fmt.Sprint(i)
}
}
// lazy increase, to avoid y shaking frequently
// update bound Y when drawing is gonna overflow
lc.minY = lc.Data[0]
lc.maxY = lc.Data[0]
// valid visible range
vrange := lc.innerWidth
if lc.Mode == "braille" {
vrange = 2 * lc.innerWidth
}
if vrange > len(lc.Data) {
vrange = len(lc.Data)
}
for _, v := range lc.Data[:vrange] {
if v > lc.maxY {
lc.maxY = v
}
if v < lc.minY {
lc.minY = v
}
}
span := lc.maxY - lc.minY
if lc.minY < lc.bottomValue {
lc.bottomValue = lc.minY - 0.2*span
}
if lc.maxY > lc.topValue {
lc.topValue = lc.maxY + 0.2*span
}
lc.axisYHeight = lc.innerHeight - 2
lc.calcLabelY()
lc.axisXWidth = lc.innerWidth - 1 - lc.labelYSpace
lc.calcLabelX()
lc.drawingX = lc.innerX + 1 + lc.labelYSpace
lc.drawingY = lc.innerY
}
func (lc *LineChart) plotAxes() []Point {
origY := lc.innerY + lc.innerHeight - 2
origX := lc.innerX + lc.labelYSpace
ps := []Point{newPointWithAttrs(ORIGIN, origX, origY, lc.AxesColor, lc.BgColor)}
for x := origX + 1; x < origX+lc.axisXWidth; x++ {
p := Point{}
p.X = x
p.Y = origY
p.Bg = lc.BgColor
p.Fg = lc.AxesColor
p.Ch = HDASH
ps = append(ps, p)
}
for dy := 1; dy <= lc.axisYHeight; dy++ {
p := Point{}
p.X = origX
p.Y = origY - dy
p.Bg = lc.BgColor
p.Fg = lc.AxesColor
p.Ch = VDASH
ps = append(ps, p)
}
// x label
oft := 0
for _, rs := range lc.labelX {
if oft+len(rs) > lc.axisXWidth {
break
}
for j, r := range rs {
p := Point{}
p.Ch = r
p.Fg = lc.AxesColor
p.Bg = lc.BgColor
p.X = origX + oft + j
p.Y = lc.innerY + lc.innerHeight - 1
ps = append(ps, p)
}
oft += len(rs) + lc.axisXLebelGap
}
// y labels
for i, rs := range lc.labelY {
for j, r := range rs {
p := Point{}
p.Ch = r
p.Fg = lc.AxesColor
p.Bg = lc.BgColor
p.X = lc.innerX + j
p.Y = origY - i*(lc.axisYLebelGap+1)
ps = append(ps, p)
}
}
return ps
}
// Buffer implements Bufferer interface.
func (lc *LineChart) Buffer() []Point {
ps := lc.Block.Buffer()
if lc.Data == nil || len(lc.Data) == 0 {
return ps
}
lc.calcLayout()
ps = append(ps, lc.plotAxes()...)
if lc.Mode == "dot" {
ps = append(ps, lc.renderDot()...)
} else {
ps = append(ps, lc.renderBraille()...)
}
return lc.Block.chopOverflow(ps)
}

View File

@ -0,0 +1,11 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
// +build !windows
package termui
const VDASH = '┊'
const HDASH = '┈'
const ORIGIN = '└'

View File

@ -0,0 +1,11 @@
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.
// +build windows
package termui
const VDASH = '|'
const HDASH = '-'
const ORIGIN = '+'

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